Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 1 | /* |
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 Tan | 0fc2fa7 | 2019-08-29 17:22:15 -0700 | [diff] [blame] | 17 | #include "../dispatcher/InputDispatcher.h" |
Siarhei Vishniakou | 2defec0 | 2023-06-08 17:24:44 -0700 | [diff] [blame] | 18 | #include "FakeApplicationHandle.h" |
Prabir Pradhan | 81e89fe | 2024-03-20 21:17:09 +0000 | [diff] [blame] | 19 | #include "FakeInputDispatcherPolicy.h" |
Prabir Pradhan | dc3a2ad | 2024-02-05 19:03:51 +0000 | [diff] [blame] | 20 | #include "FakeInputTracingBackend.h" |
Prabir Pradhan | c534073 | 2024-03-20 22:53:52 +0000 | [diff] [blame] | 21 | #include "FakeWindows.h" |
Prabir Pradhan | e3b28dd | 2023-10-06 04:19:29 +0000 | [diff] [blame] | 22 | #include "TestEventMatchers.h" |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 23 | |
Cody Heiner | 166a5af | 2023-07-07 12:25:00 -0700 | [diff] [blame] | 24 | #include <NotifyArgsBuilders.h> |
Prabir Pradhan | 5893d36 | 2023-11-17 04:30:40 +0000 | [diff] [blame] | 25 | #include <android-base/logging.h> |
Siarhei Vishniakou | 1c494c5 | 2021-08-11 20:25:01 -0700 | [diff] [blame] | 26 | #include <android-base/properties.h> |
Prabir Pradhan | a3ab87a | 2022-01-27 10:00:21 -0800 | [diff] [blame] | 27 | #include <android-base/silent_death_test.h> |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 28 | #include <android-base/stringprintf.h> |
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 29 | #include <android-base/thread_annotations.h> |
Robert Carr | 803535b | 2018-08-02 16:38:15 -0700 | [diff] [blame] | 30 | #include <binder/Binder.h> |
Ameer Armaly | cff4fa5 | 2023-10-04 23:45:11 +0000 | [diff] [blame] | 31 | #include <com_android_input_flags.h> |
Michael Wright | 8e9a856 | 2022-02-09 13:44:29 +0000 | [diff] [blame] | 32 | #include <fcntl.h> |
Ameer Armaly | cff4fa5 | 2023-10-04 23:45:11 +0000 | [diff] [blame] | 33 | #include <flag_macros.h> |
Siarhei Vishniakou | 0b0374d | 2022-11-17 17:40:53 -0800 | [diff] [blame] | 34 | #include <gmock/gmock.h> |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 35 | #include <gtest/gtest.h> |
Siarhei Vishniakou | 3782af6 | 2024-03-07 21:56:39 -0800 | [diff] [blame] | 36 | #include <input/BlockingQueue.h> |
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 37 | #include <input/Input.h> |
Siarhei Vishniakou | 0438ca8 | 2024-03-12 14:27:25 -0700 | [diff] [blame] | 38 | #include <input/InputConsumer.h> |
Siarhei Vishniakou | f404321 | 2023-09-18 19:33:03 -0700 | [diff] [blame] | 39 | #include <input/PrintTools.h> |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 40 | #include <linux/input.h> |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 41 | #include <sys/epoll.h> |
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 42 | |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 43 | #include <cinttypes> |
Siarhei Vishniakou | 487c49b | 2022-12-02 15:48:57 -0800 | [diff] [blame] | 44 | #include <compare> |
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 45 | #include <thread> |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 46 | #include <unordered_set> |
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 47 | #include <vector> |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 48 | |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 49 | using android::base::StringPrintf; |
chaviw | 3277faf | 2021-05-19 16:45:23 -0500 | [diff] [blame] | 50 | using android::gui::FocusRequest; |
51 | using android::gui::TouchOcclusionMode; | ||||
52 | using android::gui::WindowInfo; | ||||
53 | using android::gui::WindowInfoHandle; | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 54 | using android::os::InputEventInjectionResult; |
55 | using android::os::InputEventInjectionSync; | ||||
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 56 | |
Garfield Tan | e84e6f9 | 2019-08-29 17:28:41 -0700 | [diff] [blame] | 57 | namespace android::inputdispatcher { |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 58 | |
Dominik Laskowski | 2f01d77 | 2022-03-23 16:01:29 -0700 | [diff] [blame] | 59 | using namespace ftl::flag_operators; |
Siarhei Vishniakou | 0b0374d | 2022-11-17 17:40:53 -0800 | [diff] [blame] | 60 | using testing::AllOf; |
Prabir Pradhan | 5893d36 | 2023-11-17 04:30:40 +0000 | [diff] [blame] | 61 | using testing::Not; |
Siarhei Vishniakou | 85eb580 | 2024-04-01 11:40:59 -0700 | [diff] [blame] | 62 | using testing::Pointee; |
63 | using testing::UnorderedElementsAre; | ||||
Dominik Laskowski | 2f01d77 | 2022-03-23 16:01:29 -0700 | [diff] [blame] | 64 | |
Siarhei Vishniakou | f404321 | 2023-09-18 19:33:03 -0700 | [diff] [blame] | 65 | namespace { |
66 | |||||
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 67 | // An arbitrary time value. |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 68 | static constexpr nsecs_t ARBITRARY_TIME = 1234; |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 69 | |
70 | // An arbitrary device id. | ||||
Prabir Pradhan | 9205e42 | 2023-05-16 20:06:13 +0000 | [diff] [blame] | 71 | static constexpr int32_t DEVICE_ID = DEFAULT_DEVICE_ID; |
Siarhei Vishniakou | 060f82b | 2023-01-27 06:39:14 -0800 | [diff] [blame] | 72 | static constexpr int32_t SECOND_DEVICE_ID = 2; |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 73 | |
Jeff Brown | f086ddb | 2014-02-11 14:28:48 -0800 | [diff] [blame] | 74 | // An arbitrary display id. |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 75 | static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT; |
76 | static constexpr int32_t SECOND_DISPLAY_ID = 1; | ||||
Jeff Brown | f086ddb | 2014-02-11 14:28:48 -0800 | [diff] [blame] | 77 | |
Prabir Pradhan | 8ede1d1 | 2023-05-08 19:37:44 +0000 | [diff] [blame] | 78 | // Ensure common actions are interchangeable between keys and motions for convenience. |
79 | static_assert(AMOTION_EVENT_ACTION_DOWN == AKEY_EVENT_ACTION_DOWN); | ||||
80 | static_assert(AMOTION_EVENT_ACTION_UP == AKEY_EVENT_ACTION_UP); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 81 | static constexpr int32_t ACTION_DOWN = AMOTION_EVENT_ACTION_DOWN; |
82 | static constexpr int32_t ACTION_MOVE = AMOTION_EVENT_ACTION_MOVE; | ||||
83 | static constexpr int32_t ACTION_UP = AMOTION_EVENT_ACTION_UP; | ||||
84 | static constexpr int32_t ACTION_HOVER_ENTER = AMOTION_EVENT_ACTION_HOVER_ENTER; | ||||
Siarhei Vishniakou | a235c04 | 2023-05-02 09:59:09 -0700 | [diff] [blame] | 85 | static constexpr int32_t ACTION_HOVER_MOVE = AMOTION_EVENT_ACTION_HOVER_MOVE; |
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 86 | static constexpr int32_t ACTION_HOVER_EXIT = AMOTION_EVENT_ACTION_HOVER_EXIT; |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 87 | static constexpr int32_t ACTION_SCROLL = AMOTION_EVENT_ACTION_SCROLL; |
Siarhei Vishniakou | 487c49b | 2022-12-02 15:48:57 -0800 | [diff] [blame] | 88 | static constexpr int32_t ACTION_OUTSIDE = AMOTION_EVENT_ACTION_OUTSIDE; |
Siarhei Vishniakou | 1ae72f1 | 2023-01-29 12:55:30 -0800 | [diff] [blame] | 89 | static constexpr int32_t ACTION_CANCEL = AMOTION_EVENT_ACTION_CANCEL; |
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 90 | /** |
91 | * The POINTER_DOWN(0) is an unusual, but valid, action. It just means that the new pointer in the | ||||
92 | * MotionEvent is at the index 0 rather than 1 (or later). That is, the pointer id=0 (which is at | ||||
93 | * index 0) is the new pointer going down. The same pointer could have been placed at a different | ||||
94 | * index, and the action would become POINTER_1_DOWN, 2, etc..; these would all be valid. In | ||||
95 | * general, we try to place pointer id = 0 at the index 0. Of course, this is not possible if | ||||
96 | * pointer id=0 leaves but the pointer id=1 remains. | ||||
97 | */ | ||||
98 | static constexpr int32_t POINTER_0_DOWN = | ||||
99 | AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); | ||||
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 100 | static constexpr int32_t POINTER_1_DOWN = |
101 | AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); | ||||
Prabir Pradhan | b60b1dc | 2022-03-15 14:02:35 +0000 | [diff] [blame] | 102 | static constexpr int32_t POINTER_2_DOWN = |
103 | AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); | ||||
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 104 | static constexpr int32_t POINTER_3_DOWN = |
105 | AMOTION_EVENT_ACTION_POINTER_DOWN | (3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); | ||||
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 106 | static constexpr int32_t POINTER_0_UP = |
107 | AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); | ||||
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 108 | static constexpr int32_t POINTER_1_UP = |
109 | AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); | ||||
Harry Cutts | b166c00 | 2023-05-09 13:06:05 +0000 | [diff] [blame] | 110 | static constexpr int32_t POINTER_2_UP = |
111 | AMOTION_EVENT_ACTION_POINTER_UP | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); | ||||
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 112 | |
Antonio Kantek | 15beb51 | 2022-06-13 22:35:41 +0000 | [diff] [blame] | 113 | // The default pid and uid for the windows created on the secondary display by the test. |
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 114 | static constexpr gui::Pid SECONDARY_WINDOW_PID{1010}; |
Prabir Pradhan | 8a5c41d | 2023-06-08 19:13:46 +0000 | [diff] [blame] | 115 | static constexpr gui::Uid SECONDARY_WINDOW_UID{1012}; |
Antonio Kantek | 15beb51 | 2022-06-13 22:35:41 +0000 | [diff] [blame] | 116 | |
Siarhei Vishniakou | 58cfc60 | 2020-12-14 23:21:30 +0000 | [diff] [blame] | 117 | // An arbitrary pid of the gesture monitor window |
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 118 | static constexpr gui::Pid MONITOR_PID{2001}; |
Siarhei Vishniakou | 58cfc60 | 2020-12-14 23:21:30 +0000 | [diff] [blame] | 119 | |
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 120 | static constexpr int EXPECTED_WALLPAPER_FLAGS = |
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 121 | AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; |
122 | |||||
Siarhei Vishniakou | 56e7909 | 2023-02-21 19:13:16 -0800 | [diff] [blame] | 123 | using ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID; |
124 | |||||
Gang Wang | 342c927 | 2020-01-13 13:15:04 -0500 | [diff] [blame] | 125 | /** |
126 | * Return a DOWN key event with KEYCODE_A. | ||||
127 | */ | ||||
128 | static KeyEvent getTestKeyEvent() { | ||||
129 | KeyEvent event; | ||||
130 | |||||
Garfield Tan | fbe732e | 2020-01-24 11:26:14 -0800 | [diff] [blame] | 131 | event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, |
132 | INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, | ||||
133 | ARBITRARY_TIME, ARBITRARY_TIME); | ||||
Gang Wang | 342c927 | 2020-01-13 13:15:04 -0500 | [diff] [blame] | 134 | return event; |
135 | } | ||||
136 | |||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 137 | /** |
138 | * Provide a local override for a flag value. The value is restored when the object of this class | ||||
139 | * goes out of scope. | ||||
140 | * This class is not intended to be used directly, because its usage is cumbersome. | ||||
141 | * Instead, a wrapper macro SCOPED_FLAG_OVERRIDE is provided. | ||||
142 | */ | ||||
143 | class ScopedFlagOverride { | ||||
144 | public: | ||||
145 | ScopedFlagOverride(std::function<bool()> read, std::function<void(bool)> write, bool value) | ||||
146 | : mInitialValue(read()), mWriteValue(write) { | ||||
147 | mWriteValue(value); | ||||
148 | } | ||||
149 | ~ScopedFlagOverride() { mWriteValue(mInitialValue); } | ||||
150 | |||||
151 | private: | ||||
152 | const bool mInitialValue; | ||||
153 | std::function<void(bool)> mWriteValue; | ||||
154 | }; | ||||
155 | |||||
156 | typedef bool (*readFlagValueFunction)(); | ||||
157 | typedef void (*writeFlagValueFunction)(bool); | ||||
158 | |||||
159 | /** | ||||
160 | * Use this macro to locally override a flag value. | ||||
161 | * Example usage: | ||||
162 | * SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); | ||||
163 | * Note: this works by creating a local variable in your current scope. Don't call this twice for | ||||
164 | * the same flag, because the variable names will clash! | ||||
165 | */ | ||||
166 | #define SCOPED_FLAG_OVERRIDE(NAME, VALUE) \ | ||||
167 | readFlagValueFunction read##NAME = com::android::input::flags::NAME; \ | ||||
168 | writeFlagValueFunction write##NAME = com::android::input::flags::NAME; \ | ||||
169 | ScopedFlagOverride override##NAME(read##NAME, write##NAME, (VALUE)) | ||||
170 | |||||
Siarhei Vishniakou | f404321 | 2023-09-18 19:33:03 -0700 | [diff] [blame] | 171 | } // namespace |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 172 | |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 173 | // --- InputDispatcherTest --- |
174 | |||||
175 | class InputDispatcherTest : public testing::Test { | ||||
176 | protected: | ||||
Prabir Pradhan | a41d244 | 2023-04-20 21:30:40 +0000 | [diff] [blame] | 177 | std::unique_ptr<FakeInputDispatcherPolicy> mFakePolicy; |
Siarhei Vishniakou | 1805009 | 2021-09-01 13:32:49 -0700 | [diff] [blame] | 178 | std::unique_ptr<InputDispatcher> mDispatcher; |
Prabir Pradhan | c534073 | 2024-03-20 22:53:52 +0000 | [diff] [blame] | 179 | std::shared_ptr<VerifyingTrace> mVerifyingTrace; |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 180 | |
Siarhei Vishniakou | f265212 | 2021-03-05 21:39:46 +0000 | [diff] [blame] | 181 | void SetUp() override { |
Prabir Pradhan | c534073 | 2024-03-20 22:53:52 +0000 | [diff] [blame] | 182 | mVerifyingTrace = std::make_shared<VerifyingTrace>(); |
183 | FakeWindowHandle::sOnEventReceivedCallback = [this](const auto& _1, const auto& _2) { | ||||
184 | handleEventReceivedByWindow(_1, _2); | ||||
185 | }; | ||||
186 | |||||
Prabir Pradhan | a41d244 | 2023-04-20 21:30:40 +0000 | [diff] [blame] | 187 | mFakePolicy = std::make_unique<FakeInputDispatcherPolicy>(); |
Prabir Pradhan | dc3a2ad | 2024-02-05 19:03:51 +0000 | [diff] [blame] | 188 | mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy, |
189 | std::make_unique<FakeInputTracingBackend>( | ||||
Prabir Pradhan | c534073 | 2024-03-20 22:53:52 +0000 | [diff] [blame] | 190 | mVerifyingTrace)); |
Siarhei Vishniakou | a733311 | 2023-10-27 13:33:29 -0700 | [diff] [blame] | 191 | |
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 192 | mDispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false); |
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 193 | // Start InputDispatcher thread |
Prabir Pradhan | 3608aad | 2019-10-02 17:08:26 -0700 | [diff] [blame] | 194 | ASSERT_EQ(OK, mDispatcher->start()); |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 195 | } |
196 | |||||
Siarhei Vishniakou | f265212 | 2021-03-05 21:39:46 +0000 | [diff] [blame] | 197 | void TearDown() override { |
Prabir Pradhan | c534073 | 2024-03-20 22:53:52 +0000 | [diff] [blame] | 198 | ASSERT_NO_FATAL_FAILURE(mVerifyingTrace->verifyExpectedEventsTraced()); |
199 | FakeWindowHandle::sOnEventReceivedCallback = nullptr; | ||||
200 | |||||
Prabir Pradhan | 3608aad | 2019-10-02 17:08:26 -0700 | [diff] [blame] | 201 | ASSERT_EQ(OK, mDispatcher->stop()); |
Prabir Pradhan | a41d244 | 2023-04-20 21:30:40 +0000 | [diff] [blame] | 202 | mFakePolicy.reset(); |
Siarhei Vishniakou | 1805009 | 2021-09-01 13:32:49 -0700 | [diff] [blame] | 203 | mDispatcher.reset(); |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 204 | } |
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 205 | |
Prabir Pradhan | c534073 | 2024-03-20 22:53:52 +0000 | [diff] [blame] | 206 | void handleEventReceivedByWindow(const std::unique_ptr<InputEvent>& event, |
207 | const gui::WindowInfo& info) { | ||||
208 | if (!event) { | ||||
209 | return; | ||||
210 | } | ||||
211 | |||||
212 | switch (event->getType()) { | ||||
213 | case InputEventType::KEY: { | ||||
214 | mVerifyingTrace->expectKeyDispatchTraced(static_cast<KeyEvent&>(*event), info.id); | ||||
215 | break; | ||||
216 | } | ||||
217 | case InputEventType::MOTION: { | ||||
218 | mVerifyingTrace->expectMotionDispatchTraced(static_cast<MotionEvent&>(*event), | ||||
219 | info.id); | ||||
220 | break; | ||||
221 | } | ||||
222 | default: | ||||
223 | break; | ||||
224 | } | ||||
225 | } | ||||
226 | |||||
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 227 | /** |
228 | * Used for debugging when writing the test | ||||
229 | */ | ||||
230 | void dumpDispatcherState() { | ||||
231 | std::string dump; | ||||
232 | mDispatcher->dump(dump); | ||||
233 | std::stringstream ss(dump); | ||||
234 | std::string to; | ||||
235 | |||||
236 | while (std::getline(ss, to, '\n')) { | ||||
237 | ALOGE("%s", to.c_str()); | ||||
238 | } | ||||
239 | } | ||||
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 240 | |
Chavi Weingarten | 847e851 | 2023-03-29 00:26:09 +0000 | [diff] [blame] | 241 | void setFocusedWindow(const sp<WindowInfoHandle>& window) { |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 242 | FocusRequest request; |
243 | request.token = window->getToken(); | ||||
Siarhei Vishniakou | 5d552c4 | 2021-05-21 05:02:22 +0000 | [diff] [blame] | 244 | request.windowName = window->getName(); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 245 | request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC); |
246 | request.displayId = window->getInfo()->displayId; | ||||
247 | mDispatcher->setFocusedWindow(request); | ||||
248 | } | ||||
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 249 | }; |
250 | |||||
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 251 | TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { |
252 | KeyEvent event; | ||||
253 | |||||
254 | // Rejects undefined key actions. | ||||
Garfield Tan | fbe732e | 2020-01-24 11:26:14 -0800 | [diff] [blame] | 255 | event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, |
256 | INVALID_HMAC, | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 257 | /*action=*/-1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, |
Siarhei Vishniakou | 9c858ac | 2020-01-23 14:20:11 -0600 | [diff] [blame] | 258 | ARBITRARY_TIME); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 259 | ASSERT_EQ(InputEventInjectionResult::FAILED, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 260 | mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 261 | 0ms, 0)) |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 262 | << "Should reject key events with undefined action."; |
263 | |||||
264 | // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API. | ||||
Garfield Tan | fbe732e | 2020-01-24 11:26:14 -0800 | [diff] [blame] | 265 | event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, |
266 | INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, | ||||
Siarhei Vishniakou | 9c858ac | 2020-01-23 14:20:11 -0600 | [diff] [blame] | 267 | ARBITRARY_TIME, ARBITRARY_TIME); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 268 | ASSERT_EQ(InputEventInjectionResult::FAILED, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 269 | mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 270 | 0ms, 0)) |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 271 | << "Should reject key events with ACTION_MULTIPLE."; |
272 | } | ||||
273 | |||||
274 | TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { | ||||
275 | MotionEvent event; | ||||
276 | PointerProperties pointerProperties[MAX_POINTERS + 1]; | ||||
277 | PointerCoords pointerCoords[MAX_POINTERS + 1]; | ||||
Siarhei Vishniakou | 0174738 | 2022-01-20 13:23:27 -0800 | [diff] [blame] | 278 | for (size_t i = 0; i <= MAX_POINTERS; i++) { |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 279 | pointerProperties[i].clear(); |
280 | pointerProperties[i].id = i; | ||||
281 | pointerCoords[i].clear(); | ||||
282 | } | ||||
283 | |||||
Siarhei Vishniakou | 49e5922 | 2018-12-28 18:17:15 -0800 | [diff] [blame] | 284 | // Some constants commonly used below |
285 | constexpr int32_t source = AINPUT_SOURCE_TOUCHSCREEN; | ||||
286 | constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE; | ||||
287 | constexpr int32_t metaState = AMETA_NONE; | ||||
288 | constexpr MotionClassification classification = MotionClassification::NONE; | ||||
289 | |||||
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 290 | ui::Transform identityTransform; |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 291 | // Rejects undefined motion actions. |
Garfield Tan | fbe732e | 2020-01-24 11:26:14 -0800 | [diff] [blame] | 292 | event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, |
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 293 | /*action=*/-1, 0, 0, edgeFlags, metaState, 0, classification, |
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 294 | identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, |
Prabir Pradhan | b9b1850 | 2021-08-26 12:30:32 -0700 | [diff] [blame] | 295 | AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, |
296 | ARBITRARY_TIME, | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 297 | /*pointerCount=*/1, pointerProperties, pointerCoords); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 298 | ASSERT_EQ(InputEventInjectionResult::FAILED, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 299 | mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 300 | 0ms, 0)) |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 301 | << "Should reject motion events with undefined action."; |
302 | |||||
303 | // Rejects pointer down with invalid index. | ||||
Garfield Tan | fbe732e | 2020-01-24 11:26:14 -0800 | [diff] [blame] | 304 | event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, |
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 305 | POINTER_1_DOWN, 0, 0, edgeFlags, metaState, 0, classification, |
306 | identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, | ||||
307 | AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, | ||||
308 | ARBITRARY_TIME, | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 309 | /*pointerCount=*/1, pointerProperties, pointerCoords); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 310 | ASSERT_EQ(InputEventInjectionResult::FAILED, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 311 | mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 312 | 0ms, 0)) |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 313 | << "Should reject motion events with pointer down index too large."; |
314 | |||||
Garfield Tan | fbe732e | 2020-01-24 11:26:14 -0800 | [diff] [blame] | 315 | event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, |
Garfield Tan | 00f511d | 2019-06-12 16:55:40 -0700 | [diff] [blame] | 316 | AMOTION_EVENT_ACTION_POINTER_DOWN | |
317 | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), | ||||
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 318 | 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, |
319 | AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, | ||||
Prabir Pradhan | b9b1850 | 2021-08-26 12:30:32 -0700 | [diff] [blame] | 320 | identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, |
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 321 | /*pointerCount=*/1, pointerProperties, pointerCoords); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 322 | ASSERT_EQ(InputEventInjectionResult::FAILED, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 323 | mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 324 | 0ms, 0)) |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 325 | << "Should reject motion events with pointer down index too small."; |
326 | |||||
327 | // Rejects pointer up with invalid index. | ||||
Garfield Tan | fbe732e | 2020-01-24 11:26:14 -0800 | [diff] [blame] | 328 | event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, |
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 329 | POINTER_1_UP, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, |
330 | 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, | ||||
331 | AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, | ||||
332 | ARBITRARY_TIME, | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 333 | /*pointerCount=*/1, pointerProperties, pointerCoords); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 334 | ASSERT_EQ(InputEventInjectionResult::FAILED, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 335 | mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 336 | 0ms, 0)) |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 337 | << "Should reject motion events with pointer up index too large."; |
338 | |||||
Garfield Tan | fbe732e | 2020-01-24 11:26:14 -0800 | [diff] [blame] | 339 | event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, |
Garfield Tan | 00f511d | 2019-06-12 16:55:40 -0700 | [diff] [blame] | 340 | AMOTION_EVENT_ACTION_POINTER_UP | |
341 | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), | ||||
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 342 | 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, |
343 | AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, | ||||
Prabir Pradhan | b9b1850 | 2021-08-26 12:30:32 -0700 | [diff] [blame] | 344 | identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, |
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 345 | /*pointerCount=*/1, pointerProperties, pointerCoords); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 346 | ASSERT_EQ(InputEventInjectionResult::FAILED, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 347 | mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 348 | 0ms, 0)) |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 349 | << "Should reject motion events with pointer up index too small."; |
350 | |||||
351 | // Rejects motion events with invalid number of pointers. | ||||
Garfield Tan | fbe732e | 2020-01-24 11:26:14 -0800 | [diff] [blame] | 352 | event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, |
353 | AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, | ||||
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 354 | identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, |
Prabir Pradhan | b9b1850 | 2021-08-26 12:30:32 -0700 | [diff] [blame] | 355 | AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, |
356 | ARBITRARY_TIME, | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 357 | /*pointerCount=*/0, pointerProperties, pointerCoords); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 358 | ASSERT_EQ(InputEventInjectionResult::FAILED, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 359 | mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 360 | 0ms, 0)) |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 361 | << "Should reject motion events with 0 pointers."; |
362 | |||||
Garfield Tan | fbe732e | 2020-01-24 11:26:14 -0800 | [diff] [blame] | 363 | event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, |
364 | AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, | ||||
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 365 | identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, |
Prabir Pradhan | b9b1850 | 2021-08-26 12:30:32 -0700 | [diff] [blame] | 366 | AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, |
367 | ARBITRARY_TIME, | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 368 | /*pointerCount=*/MAX_POINTERS + 1, pointerProperties, pointerCoords); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 369 | ASSERT_EQ(InputEventInjectionResult::FAILED, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 370 | mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 371 | 0ms, 0)) |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 372 | << "Should reject motion events with more than MAX_POINTERS pointers."; |
373 | |||||
374 | // Rejects motion events with invalid pointer ids. | ||||
375 | pointerProperties[0].id = -1; | ||||
Garfield Tan | fbe732e | 2020-01-24 11:26:14 -0800 | [diff] [blame] | 376 | event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, |
377 | AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, | ||||
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 378 | identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, |
Prabir Pradhan | b9b1850 | 2021-08-26 12:30:32 -0700 | [diff] [blame] | 379 | AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, |
380 | ARBITRARY_TIME, | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 381 | /*pointerCount=*/1, pointerProperties, pointerCoords); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 382 | ASSERT_EQ(InputEventInjectionResult::FAILED, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 383 | mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 384 | 0ms, 0)) |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 385 | << "Should reject motion events with pointer ids less than 0."; |
386 | |||||
387 | pointerProperties[0].id = MAX_POINTER_ID + 1; | ||||
Garfield Tan | fbe732e | 2020-01-24 11:26:14 -0800 | [diff] [blame] | 388 | event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, |
389 | AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, | ||||
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 390 | identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, |
Prabir Pradhan | b9b1850 | 2021-08-26 12:30:32 -0700 | [diff] [blame] | 391 | AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, |
392 | ARBITRARY_TIME, | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 393 | /*pointerCount=*/1, pointerProperties, pointerCoords); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 394 | ASSERT_EQ(InputEventInjectionResult::FAILED, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 395 | mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 396 | 0ms, 0)) |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 397 | << "Should reject motion events with pointer ids greater than MAX_POINTER_ID."; |
398 | |||||
399 | // Rejects motion events with duplicate pointer ids. | ||||
400 | pointerProperties[0].id = 1; | ||||
401 | pointerProperties[1].id = 1; | ||||
Garfield Tan | fbe732e | 2020-01-24 11:26:14 -0800 | [diff] [blame] | 402 | event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, |
403 | AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, | ||||
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 404 | identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, |
Prabir Pradhan | b9b1850 | 2021-08-26 12:30:32 -0700 | [diff] [blame] | 405 | AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, |
406 | ARBITRARY_TIME, | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 407 | /*pointerCount=*/2, pointerProperties, pointerCoords); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 408 | ASSERT_EQ(InputEventInjectionResult::FAILED, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 409 | mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 410 | 0ms, 0)) |
Michael Wright | d02c5b6 | 2014-02-10 15:10:22 -0800 | [diff] [blame] | 411 | << "Should reject motion events with duplicate pointer ids."; |
412 | } | ||||
413 | |||||
Siarhei Vishniakou | 2bfa905 | 2019-11-21 18:10:54 -0800 | [diff] [blame] | 414 | /* Test InputDispatcher for notifyConfigurationChanged and notifySwitch events */ |
415 | |||||
416 | TEST_F(InputDispatcherTest, NotifyConfigurationChanged_CallsPolicy) { | ||||
417 | constexpr nsecs_t eventTime = 20; | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 418 | mDispatcher->notifyConfigurationChanged({/*id=*/10, eventTime}); |
Siarhei Vishniakou | 2bfa905 | 2019-11-21 18:10:54 -0800 | [diff] [blame] | 419 | ASSERT_TRUE(mDispatcher->waitForIdle()); |
420 | |||||
421 | mFakePolicy->assertNotifyConfigurationChangedWasCalled(eventTime); | ||||
422 | } | ||||
423 | |||||
424 | TEST_F(InputDispatcherTest, NotifySwitch_CallsPolicy) { | ||||
Prabir Pradhan | a8fe7c5 | 2023-12-14 22:07:23 +0000 | [diff] [blame] | 425 | NotifySwitchArgs args(InputEvent::nextId(), /*eventTime=*/20, /*policyFlags=*/0, |
426 | /*switchValues=*/1, | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 427 | /*switchMask=*/2); |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 428 | mDispatcher->notifySwitch(args); |
Siarhei Vishniakou | 2bfa905 | 2019-11-21 18:10:54 -0800 | [diff] [blame] | 429 | |
430 | // InputDispatcher adds POLICY_FLAG_TRUSTED because the event went through InputListener | ||||
431 | args.policyFlags |= POLICY_FLAG_TRUSTED; | ||||
432 | mFakePolicy->assertNotifySwitchWasCalled(args); | ||||
433 | } | ||||
434 | |||||
Siarhei Vishniakou | adeb6fa | 2023-05-26 09:11:06 -0700 | [diff] [blame] | 435 | namespace { |
436 | |||||
Siarhei Vishniakou | 097c3db | 2020-05-06 14:18:38 -0700 | [diff] [blame] | 437 | static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 500ms; |
Siarhei Vishniakou | 540dbae | 2020-05-05 18:17:17 -0700 | [diff] [blame] | 438 | |
Prabir Pradhan | 112b1ad | 2023-09-21 09:53:53 +0000 | [diff] [blame] | 439 | class FakeMonitorReceiver { |
440 | public: | ||||
Siarhei Vishniakou | 2defec0 | 2023-06-08 17:24:44 -0700 | [diff] [blame] | 441 | FakeMonitorReceiver(InputDispatcher& dispatcher, const std::string name, int32_t displayId) |
442 | : mInputReceiver(*dispatcher.createInputMonitor(displayId, name, MONITOR_PID), name) {} | ||||
Prabir Pradhan | 112b1ad | 2023-09-21 09:53:53 +0000 | [diff] [blame] | 443 | |
Siarhei Vishniakou | 2defec0 | 2023-06-08 17:24:44 -0700 | [diff] [blame] | 444 | sp<IBinder> getToken() { return mInputReceiver.getToken(); } |
Prabir Pradhan | 112b1ad | 2023-09-21 09:53:53 +0000 | [diff] [blame] | 445 | |
446 | void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) { | ||||
Siarhei Vishniakou | 2defec0 | 2023-06-08 17:24:44 -0700 | [diff] [blame] | 447 | mInputReceiver.consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId, |
448 | expectedFlags); | ||||
Prabir Pradhan | 112b1ad | 2023-09-21 09:53:53 +0000 | [diff] [blame] | 449 | } |
450 | |||||
451 | std::optional<int32_t> receiveEvent() { | ||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 452 | const auto [sequenceNum, _] = mInputReceiver.receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED); |
453 | return sequenceNum; | ||||
Prabir Pradhan | 112b1ad | 2023-09-21 09:53:53 +0000 | [diff] [blame] | 454 | } |
455 | |||||
Siarhei Vishniakou | 2defec0 | 2023-06-08 17:24:44 -0700 | [diff] [blame] | 456 | void finishEvent(uint32_t consumeSeq) { return mInputReceiver.finishEvent(consumeSeq); } |
Prabir Pradhan | 112b1ad | 2023-09-21 09:53:53 +0000 | [diff] [blame] | 457 | |
458 | void consumeMotionDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) { | ||||
Siarhei Vishniakou | 2defec0 | 2023-06-08 17:24:44 -0700 | [diff] [blame] | 459 | mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_DOWN, |
460 | expectedDisplayId, expectedFlags); | ||||
Prabir Pradhan | 112b1ad | 2023-09-21 09:53:53 +0000 | [diff] [blame] | 461 | } |
462 | |||||
463 | void consumeMotionMove(int32_t expectedDisplayId, int32_t expectedFlags = 0) { | ||||
Siarhei Vishniakou | 2defec0 | 2023-06-08 17:24:44 -0700 | [diff] [blame] | 464 | mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_MOVE, |
465 | expectedDisplayId, expectedFlags); | ||||
Prabir Pradhan | 112b1ad | 2023-09-21 09:53:53 +0000 | [diff] [blame] | 466 | } |
467 | |||||
468 | void consumeMotionUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) { | ||||
Siarhei Vishniakou | 2defec0 | 2023-06-08 17:24:44 -0700 | [diff] [blame] | 469 | mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_UP, |
470 | expectedDisplayId, expectedFlags); | ||||
Prabir Pradhan | 112b1ad | 2023-09-21 09:53:53 +0000 | [diff] [blame] | 471 | } |
472 | |||||
473 | void consumeMotionCancel(int32_t expectedDisplayId, int32_t expectedFlags = 0) { | ||||
Siarhei Vishniakou | 2defec0 | 2023-06-08 17:24:44 -0700 | [diff] [blame] | 474 | mInputReceiver.consumeMotionEvent( |
Prabir Pradhan | 112b1ad | 2023-09-21 09:53:53 +0000 | [diff] [blame] | 475 | AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL), |
476 | WithDisplayId(expectedDisplayId), | ||||
477 | WithFlags(expectedFlags | AMOTION_EVENT_FLAG_CANCELED))); | ||||
478 | } | ||||
479 | |||||
480 | void consumeMotionPointerDown(int32_t pointerIdx) { | ||||
481 | int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN | | ||||
482 | (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); | ||||
Siarhei Vishniakou | 2defec0 | 2023-06-08 17:24:44 -0700 | [diff] [blame] | 483 | mInputReceiver.consumeEvent(InputEventType::MOTION, action, ADISPLAY_ID_DEFAULT, |
484 | /*expectedFlags=*/0); | ||||
Prabir Pradhan | 112b1ad | 2023-09-21 09:53:53 +0000 | [diff] [blame] | 485 | } |
486 | |||||
487 | void consumeMotionEvent(const ::testing::Matcher<MotionEvent>& matcher) { | ||||
Siarhei Vishniakou | 2defec0 | 2023-06-08 17:24:44 -0700 | [diff] [blame] | 488 | mInputReceiver.consumeMotionEvent(matcher); |
Prabir Pradhan | 112b1ad | 2023-09-21 09:53:53 +0000 | [diff] [blame] | 489 | } |
490 | |||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 491 | std::unique_ptr<MotionEvent> consumeMotion() { return mInputReceiver.consumeMotion(); } |
Prabir Pradhan | 112b1ad | 2023-09-21 09:53:53 +0000 | [diff] [blame] | 492 | |
Siarhei Vishniakou | ef2b450 | 2023-12-28 11:51:47 -0800 | [diff] [blame] | 493 | void assertNoEvents() { mInputReceiver.assertNoEvents(CONSUME_TIMEOUT_NO_EVENT_EXPECTED); } |
Prabir Pradhan | 112b1ad | 2023-09-21 09:53:53 +0000 | [diff] [blame] | 494 | |
495 | private: | ||||
Siarhei Vishniakou | 2defec0 | 2023-06-08 17:24:44 -0700 | [diff] [blame] | 496 | FakeInputReceiver mInputReceiver; |
Prabir Pradhan | 112b1ad | 2023-09-21 09:53:53 +0000 | [diff] [blame] | 497 | }; |
498 | |||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 499 | static InputEventInjectionResult injectKey( |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 500 | InputDispatcher& dispatcher, int32_t action, int32_t repeatCount, |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 501 | int32_t displayId = ADISPLAY_ID_NONE, |
502 | InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT, | ||||
Prabir Pradhan | 93f342c | 2021-03-11 15:05:30 -0800 | [diff] [blame] | 503 | std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT, |
Prabir Pradhan | 8a5c41d | 2023-06-08 19:13:46 +0000 | [diff] [blame] | 504 | bool allowKeyRepeat = true, std::optional<gui::Uid> targetUid = {}, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 505 | uint32_t policyFlags = DEFAULT_POLICY_FLAGS) { |
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 506 | KeyEvent event; |
507 | nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); | ||||
508 | |||||
509 | // Define a valid key down event. | ||||
Garfield Tan | fbe732e | 2020-01-24 11:26:14 -0800 | [diff] [blame] | 510 | event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 511 | INVALID_HMAC, action, /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, repeatCount, |
512 | currentTime, currentTime); | ||||
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 513 | |
Prabir Pradhan | 93f342c | 2021-03-11 15:05:30 -0800 | [diff] [blame] | 514 | if (!allowKeyRepeat) { |
515 | policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT; | ||||
516 | } | ||||
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 517 | // Inject event until dispatch out. |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 518 | return dispatcher.injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags); |
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 519 | } |
520 | |||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 521 | static void assertInjectedKeyTimesOut(InputDispatcher& dispatcher) { |
522 | InputEventInjectionResult result = | ||||
523 | injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_NONE, | ||||
524 | InputEventInjectionSync::WAIT_FOR_RESULT, CONSUME_TIMEOUT_NO_EVENT_EXPECTED); | ||||
525 | if (result != InputEventInjectionResult::TIMED_OUT) { | ||||
526 | FAIL() << "Injection should have timed out, but got " << ftl::enum_string(result); | ||||
527 | } | ||||
528 | } | ||||
529 | |||||
530 | static InputEventInjectionResult injectKeyDown(InputDispatcher& dispatcher, | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 531 | int32_t displayId = ADISPLAY_ID_NONE) { |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 532 | return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId); |
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 533 | } |
534 | |||||
Prabir Pradhan | 93f342c | 2021-03-11 15:05:30 -0800 | [diff] [blame] | 535 | // Inject a down event that has key repeat disabled. This allows InputDispatcher to idle without |
536 | // sending a subsequent key up. When key repeat is enabled, the dispatcher cannot idle because it | ||||
537 | // has to be woken up to process the repeating key. | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 538 | static InputEventInjectionResult injectKeyDownNoRepeat(InputDispatcher& dispatcher, |
539 | int32_t displayId = ADISPLAY_ID_NONE) { | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 540 | return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId, |
Prabir Pradhan | 93f342c | 2021-03-11 15:05:30 -0800 | [diff] [blame] | 541 | InputEventInjectionSync::WAIT_FOR_RESULT, INJECT_EVENT_TIMEOUT, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 542 | /*allowKeyRepeat=*/false); |
Prabir Pradhan | 93f342c | 2021-03-11 15:05:30 -0800 | [diff] [blame] | 543 | } |
544 | |||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 545 | static InputEventInjectionResult injectKeyUp(InputDispatcher& dispatcher, |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 546 | int32_t displayId = ADISPLAY_ID_NONE) { |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 547 | return injectKey(dispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, displayId); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 548 | } |
549 | |||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 550 | static InputEventInjectionResult injectMotionEvent( |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 551 | InputDispatcher& dispatcher, const MotionEvent& event, |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 552 | std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 553 | InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT, |
Prabir Pradhan | 8a5c41d | 2023-06-08 19:13:46 +0000 | [diff] [blame] | 554 | std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) { |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 555 | return dispatcher.injectInputEvent(&event, targetUid, injectionMode, injectionTimeout, |
556 | policyFlags); | ||||
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 557 | } |
558 | |||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 559 | static InputEventInjectionResult injectMotionEvent( |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 560 | InputDispatcher& dispatcher, int32_t action, int32_t source, int32_t displayId, |
561 | const PointF& position = {100, 200}, | ||||
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 562 | const PointF& cursorPosition = {AMOTION_EVENT_INVALID_CURSOR_POSITION, |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 563 | AMOTION_EVENT_INVALID_CURSOR_POSITION}, |
564 | std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT, | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 565 | InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 566 | nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC), |
Prabir Pradhan | 8a5c41d | 2023-06-08 19:13:46 +0000 | [diff] [blame] | 567 | std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) { |
Siarhei Vishniakou | 90ee478 | 2023-05-08 11:57:24 -0700 | [diff] [blame] | 568 | MotionEventBuilder motionBuilder = |
569 | MotionEventBuilder(action, source) | ||||
570 | .displayId(displayId) | ||||
571 | .eventTime(eventTime) | ||||
572 | .rawXCursorPosition(cursorPosition.x) | ||||
573 | .rawYCursorPosition(cursorPosition.y) | ||||
574 | .pointer( | ||||
575 | PointerBuilder(/*id=*/0, ToolType::FINGER).x(position.x).y(position.y)); | ||||
576 | if (MotionEvent::getActionMasked(action) == ACTION_DOWN) { | ||||
577 | motionBuilder.downTime(eventTime); | ||||
578 | } | ||||
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 579 | |
580 | // Inject event until dispatch out. | ||||
Siarhei Vishniakou | 90ee478 | 2023-05-08 11:57:24 -0700 | [diff] [blame] | 581 | return injectMotionEvent(dispatcher, motionBuilder.build(), injectionTimeout, injectionMode, |
582 | targetUid, policyFlags); | ||||
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 583 | } |
584 | |||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 585 | static InputEventInjectionResult injectMotionDown(InputDispatcher& dispatcher, int32_t source, |
586 | int32_t displayId, | ||||
587 | const PointF& location = {100, 200}) { | ||||
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 588 | return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, location); |
Garfield Tan | 00f511d | 2019-06-12 16:55:40 -0700 | [diff] [blame] | 589 | } |
590 | |||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 591 | static InputEventInjectionResult injectMotionUp(InputDispatcher& dispatcher, int32_t source, |
592 | int32_t displayId, | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 593 | const PointF& location = {100, 200}) { |
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 594 | return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_UP, source, displayId, location); |
Michael Wright | 3a240c4 | 2019-12-10 20:53:41 +0000 | [diff] [blame] | 595 | } |
596 | |||||
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 597 | static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) { |
598 | nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); | ||||
599 | // Define a valid key event. | ||||
Prabir Pradhan | a8fe7c5 | 2023-12-14 22:07:23 +0000 | [diff] [blame] | 600 | NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID, |
601 | AINPUT_SOURCE_KEYBOARD, displayId, POLICY_FLAG_PASS_TO_USER, action, | ||||
602 | /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, currentTime); | ||||
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 603 | |
604 | return args; | ||||
605 | } | ||||
606 | |||||
Josep del Rio | b398162 | 2023-04-18 15:49:45 +0000 | [diff] [blame] | 607 | static NotifyKeyArgs generateSystemShortcutArgs(int32_t action, |
608 | int32_t displayId = ADISPLAY_ID_NONE) { | ||||
609 | nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); | ||||
610 | // Define a valid key event. | ||||
Prabir Pradhan | a8fe7c5 | 2023-12-14 22:07:23 +0000 | [diff] [blame] | 611 | NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID, |
612 | AINPUT_SOURCE_KEYBOARD, displayId, 0, action, /*flags=*/0, AKEYCODE_C, KEY_C, | ||||
613 | AMETA_META_ON, currentTime); | ||||
Josep del Rio | b398162 | 2023-04-18 15:49:45 +0000 | [diff] [blame] | 614 | |
615 | return args; | ||||
616 | } | ||||
617 | |||||
618 | static NotifyKeyArgs generateAssistantKeyArgs(int32_t action, | ||||
619 | int32_t displayId = ADISPLAY_ID_NONE) { | ||||
620 | nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); | ||||
621 | // Define a valid key event. | ||||
Prabir Pradhan | a8fe7c5 | 2023-12-14 22:07:23 +0000 | [diff] [blame] | 622 | NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID, |
623 | AINPUT_SOURCE_KEYBOARD, displayId, 0, action, /*flags=*/0, AKEYCODE_ASSIST, | ||||
624 | KEY_ASSISTANT, AMETA_NONE, currentTime); | ||||
Josep del Rio | b398162 | 2023-04-18 15:49:45 +0000 | [diff] [blame] | 625 | |
626 | return args; | ||||
627 | } | ||||
628 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 629 | [[nodiscard]] static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, |
630 | int32_t displayId, | ||||
631 | const std::vector<PointF>& points) { | ||||
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 632 | size_t pointerCount = points.size(); |
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 633 | if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_UP) { |
634 | EXPECT_EQ(1U, pointerCount) << "Actions DOWN and UP can only contain a single pointer"; | ||||
635 | } | ||||
636 | |||||
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 637 | PointerProperties pointerProperties[pointerCount]; |
638 | PointerCoords pointerCoords[pointerCount]; | ||||
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 639 | |
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 640 | for (size_t i = 0; i < pointerCount; i++) { |
641 | pointerProperties[i].clear(); | ||||
642 | pointerProperties[i].id = i; | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 643 | pointerProperties[i].toolType = ToolType::FINGER; |
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 644 | |
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 645 | pointerCoords[i].clear(); |
646 | pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, points[i].x); | ||||
647 | pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, points[i].y); | ||||
648 | } | ||||
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 649 | |
650 | nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); | ||||
651 | // Define a valid motion event. | ||||
Prabir Pradhan | a8fe7c5 | 2023-12-14 22:07:23 +0000 | [diff] [blame] | 652 | NotifyMotionArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID, source, |
653 | displayId, POLICY_FLAG_PASS_TO_USER, action, /*actionButton=*/0, | ||||
654 | /*flags=*/0, AMETA_NONE, /*buttonState=*/0, MotionClassification::NONE, | ||||
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 655 | AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, pointerProperties, |
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 656 | pointerCoords, /*xPrecision=*/0, /*yPrecision=*/0, |
Garfield Tan | 00f511d | 2019-06-12 16:55:40 -0700 | [diff] [blame] | 657 | AMOTION_EVENT_INVALID_CURSOR_POSITION, |
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 658 | AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /*videoFrames=*/{}); |
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 659 | |
660 | return args; | ||||
661 | } | ||||
662 | |||||
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 663 | static NotifyMotionArgs generateTouchArgs(int32_t action, const std::vector<PointF>& points) { |
664 | return generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, points); | ||||
665 | } | ||||
666 | |||||
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 667 | static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, int32_t displayId) { |
668 | return generateMotionArgs(action, source, displayId, {PointF{100, 200}}); | ||||
669 | } | ||||
670 | |||||
Prabir Pradhan | 5cc1a69 | 2021-08-06 14:01:18 +0000 | [diff] [blame] | 671 | static NotifyPointerCaptureChangedArgs generatePointerCaptureChangedArgs( |
672 | const PointerCaptureRequest& request) { | ||||
Prabir Pradhan | a8fe7c5 | 2023-12-14 22:07:23 +0000 | [diff] [blame] | 673 | return NotifyPointerCaptureChangedArgs(InputEvent::nextId(), systemTime(SYSTEM_TIME_MONOTONIC), |
674 | request); | ||||
Prabir Pradhan | 9998771 | 2020-11-10 18:43:05 -0800 | [diff] [blame] | 675 | } |
676 | |||||
Siarhei Vishniakou | adeb6fa | 2023-05-26 09:11:06 -0700 | [diff] [blame] | 677 | } // namespace |
678 | |||||
Siarhei Vishniakou | 7aa3e94 | 2021-11-18 09:49:11 -0800 | [diff] [blame] | 679 | /** |
680 | * When a window unexpectedly disposes of its input channel, policy should be notified about the | ||||
681 | * broken channel. | ||||
682 | */ | ||||
683 | TEST_F(InputDispatcherTest, WhenInputChannelBreaks_PolicyIsNotified) { | ||||
684 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
685 | sp<FakeWindowHandle> window = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 686 | sp<FakeWindowHandle>::make(application, mDispatcher, |
687 | "Window that breaks its input channel", ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | 7aa3e94 | 2021-11-18 09:49:11 -0800 | [diff] [blame] | 688 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 689 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | 7aa3e94 | 2021-11-18 09:49:11 -0800 | [diff] [blame] | 690 | |
691 | // Window closes its channel, but the window remains. | ||||
692 | window->destroyReceiver(); | ||||
693 | mFakePolicy->assertNotifyInputChannelBrokenWasCalled(window->getInfo()->token); | ||||
694 | } | ||||
695 | |||||
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 696 | TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) { |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 697 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 698 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
699 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 700 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 701 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 702 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 703 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 704 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 705 | |
706 | // Window should receive motion event. | ||||
Siarhei Vishniakou | c5ca85c | 2019-11-15 17:20:00 -0800 | [diff] [blame] | 707 | window->consumeMotionDown(ADISPLAY_ID_DEFAULT); |
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 708 | } |
709 | |||||
Siarhei Vishniakou | aeed0da | 2024-01-09 08:57:13 -0800 | [diff] [blame] | 710 | using InputDispatcherDeathTest = InputDispatcherTest; |
711 | |||||
712 | /** | ||||
713 | * When 'onWindowInfosChanged' arguments contain a duplicate entry for the same window, dispatcher | ||||
714 | * should crash. | ||||
715 | */ | ||||
716 | TEST_F(InputDispatcherDeathTest, DuplicateWindowInfosAbortDispatcher) { | ||||
717 | testing::GTEST_FLAG(death_test_style) = "threadsafe"; | ||||
718 | ScopedSilentDeath _silentDeath; | ||||
719 | |||||
720 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
721 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, | ||||
722 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
723 | ASSERT_DEATH(mDispatcher->onWindowInfosChanged( | ||||
724 | {{*window->getInfo(), *window->getInfo()}, {}, 0, 0}), | ||||
725 | "Incorrect WindowInfosUpdate provided"); | ||||
726 | } | ||||
727 | |||||
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 728 | TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay) { |
729 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 730 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
731 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 732 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 733 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 734 | // Inject a MotionEvent to an unknown display. |
735 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 736 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_NONE)) |
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 737 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
738 | |||||
739 | // Window should receive motion event. | ||||
740 | window->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
741 | } | ||||
742 | |||||
Siarhei Vishniakou | fb9fcda | 2020-05-04 14:59:19 -0700 | [diff] [blame] | 743 | /** |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 744 | * Calling onWindowInfosChanged once should not cause any issues. |
745 | * This test serves as a sanity check for the next test, where onWindowInfosChanged is | ||||
Siarhei Vishniakou | fb9fcda | 2020-05-04 14:59:19 -0700 | [diff] [blame] | 746 | * called twice. |
747 | */ | ||||
Prabir Pradhan | 76bdecb | 2022-01-31 11:14:15 -0800 | [diff] [blame] | 748 | TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) { |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 749 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 750 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
751 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | fb9fcda | 2020-05-04 14:59:19 -0700 | [diff] [blame] | 752 | window->setFrame(Rect(0, 0, 100, 100)); |
Siarhei Vishniakou | fb9fcda | 2020-05-04 14:59:19 -0700 | [diff] [blame] | 753 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 754 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 755 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 756 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | fb9fcda | 2020-05-04 14:59:19 -0700 | [diff] [blame] | 757 | {50, 50})) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 758 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
Siarhei Vishniakou | fb9fcda | 2020-05-04 14:59:19 -0700 | [diff] [blame] | 759 | |
760 | // Window should receive motion event. | ||||
761 | window->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
762 | } | ||||
763 | |||||
764 | /** | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 765 | * Calling onWindowInfosChanged twice, with the same info, should not cause any issues. |
Siarhei Vishniakou | fb9fcda | 2020-05-04 14:59:19 -0700 | [diff] [blame] | 766 | */ |
767 | TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) { | ||||
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 768 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 769 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
770 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | fb9fcda | 2020-05-04 14:59:19 -0700 | [diff] [blame] | 771 | window->setFrame(Rect(0, 0, 100, 100)); |
Siarhei Vishniakou | fb9fcda | 2020-05-04 14:59:19 -0700 | [diff] [blame] | 772 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 773 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
774 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 775 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 776 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | fb9fcda | 2020-05-04 14:59:19 -0700 | [diff] [blame] | 777 | {50, 50})) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 778 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
Siarhei Vishniakou | fb9fcda | 2020-05-04 14:59:19 -0700 | [diff] [blame] | 779 | |
780 | // Window should receive motion event. | ||||
781 | window->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
782 | } | ||||
783 | |||||
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 784 | // The foreground window should receive the first touch down event. |
785 | TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) { | ||||
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 786 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 787 | sp<FakeWindowHandle> windowTop = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 788 | sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); |
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 789 | sp<FakeWindowHandle> windowSecond = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 790 | sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); |
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 791 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 792 | mDispatcher->onWindowInfosChanged( |
793 | {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 794 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 795 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 796 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 797 | |
798 | // Top window should receive the touch down event. Second window should not receive anything. | ||||
Siarhei Vishniakou | c5ca85c | 2019-11-15 17:20:00 -0800 | [diff] [blame] | 799 | windowTop->consumeMotionDown(ADISPLAY_ID_DEFAULT); |
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 800 | windowSecond->assertNoEvents(); |
801 | } | ||||
802 | |||||
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 803 | /** |
804 | * Two windows: A top window, and a wallpaper behind the window. | ||||
805 | * Touch goes to the top window, and then top window disappears. Ensure that wallpaper window | ||||
806 | * gets ACTION_CANCEL. | ||||
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 807 | * 1. foregroundWindow <-- dup touch to wallpaper |
808 | * 2. wallpaperWindow <-- is wallpaper | ||||
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 809 | */ |
810 | TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) { | ||||
811 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
812 | sp<FakeWindowHandle> foregroundWindow = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 813 | sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); |
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 814 | foregroundWindow->setDupTouchToWallpaper(true); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 815 | sp<FakeWindowHandle> wallpaperWindow = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 816 | sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); |
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 817 | wallpaperWindow->setIsWallpaper(true); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 818 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 819 | mDispatcher->onWindowInfosChanged( |
820 | {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 821 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | d908f5a | 2023-11-16 10:25:12 -0800 | [diff] [blame] | 822 | injectMotionEvent(*mDispatcher, |
823 | MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
824 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(200)) | ||||
825 | .build())) | ||||
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 826 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
827 | |||||
828 | // Both foreground window and its wallpaper should receive the touch down | ||||
829 | foregroundWindow->consumeMotionDown(); | ||||
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 830 | wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 831 | |
832 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | d908f5a | 2023-11-16 10:25:12 -0800 | [diff] [blame] | 833 | injectMotionEvent(*mDispatcher, |
834 | MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
835 | .pointer(PointerBuilder(0, ToolType::FINGER).x(110).y(200)) | ||||
836 | .build())) | ||||
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 837 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
838 | |||||
Siarhei Vishniakou | d908f5a | 2023-11-16 10:25:12 -0800 | [diff] [blame] | 839 | foregroundWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); |
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 840 | wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 841 | |
842 | // Now the foreground window goes away, but the wallpaper stays | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 843 | mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 844 | foregroundWindow->consumeMotionCancel(); |
845 | // Since the "parent" window of the wallpaper is gone, wallpaper should receive cancel, too. | ||||
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 846 | wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 847 | } |
848 | |||||
849 | /** | ||||
Siarhei Vishniakou | 82dc042 | 2023-02-17 23:12:52 -0800 | [diff] [blame] | 850 | * Two fingers down on the window, and lift off the first finger. |
851 | * Next, cancel the gesture to the window by removing the window. Make sure that the CANCEL event | ||||
852 | * contains a single pointer. | ||||
853 | */ | ||||
854 | TEST_F(InputDispatcherTest, CancelAfterPointer0Up) { | ||||
855 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
856 | sp<FakeWindowHandle> window = | ||||
857 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
858 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 859 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | 82dc042 | 2023-02-17 23:12:52 -0800 | [diff] [blame] | 860 | // First touch pointer down on right window |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 861 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
862 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
863 | .build()); | ||||
Siarhei Vishniakou | 82dc042 | 2023-02-17 23:12:52 -0800 | [diff] [blame] | 864 | // Second touch pointer down |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 865 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
866 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
867 | .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100)) | ||||
868 | .build()); | ||||
Siarhei Vishniakou | 82dc042 | 2023-02-17 23:12:52 -0800 | [diff] [blame] | 869 | // First touch pointer lifts. The second one remains down |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 870 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN) |
871 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
872 | .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100)) | ||||
873 | .build()); | ||||
Siarhei Vishniakou | 82dc042 | 2023-02-17 23:12:52 -0800 | [diff] [blame] | 874 | window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); |
875 | window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); | ||||
876 | window->consumeMotionEvent(WithMotionAction(POINTER_0_UP)); | ||||
877 | |||||
878 | // Remove the window. The gesture should be canceled | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 879 | mDispatcher->onWindowInfosChanged({{}, {}, 0, 0}); |
Siarhei Vishniakou | 82dc042 | 2023-02-17 23:12:52 -0800 | [diff] [blame] | 880 | const std::map<int32_t, PointF> expectedPointers{{1, PointF{110, 100}}}; |
881 | window->consumeMotionEvent( | ||||
882 | AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedPointers))); | ||||
883 | } | ||||
884 | |||||
885 | /** | ||||
Siarhei Vishniakou | 2b03097 | 2021-11-18 10:01:27 -0800 | [diff] [blame] | 886 | * Same test as WhenForegroundWindowDisappears_WallpaperTouchIsCanceled above, |
887 | * with the following differences: | ||||
888 | * After ACTION_DOWN, Wallpaper window hangs up its channel, which forces the dispatcher to | ||||
889 | * clean up the connection. | ||||
890 | * This later may crash dispatcher during ACTION_CANCEL synthesis, if the dispatcher is not careful. | ||||
891 | * Ensure that there's no crash in the dispatcher. | ||||
892 | */ | ||||
893 | TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { | ||||
894 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
895 | sp<FakeWindowHandle> foregroundWindow = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 896 | sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); |
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 897 | foregroundWindow->setDupTouchToWallpaper(true); |
Siarhei Vishniakou | 2b03097 | 2021-11-18 10:01:27 -0800 | [diff] [blame] | 898 | sp<FakeWindowHandle> wallpaperWindow = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 899 | sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); |
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 900 | wallpaperWindow->setIsWallpaper(true); |
Siarhei Vishniakou | 2b03097 | 2021-11-18 10:01:27 -0800 | [diff] [blame] | 901 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 902 | mDispatcher->onWindowInfosChanged( |
903 | {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | 2b03097 | 2021-11-18 10:01:27 -0800 | [diff] [blame] | 904 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 905 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | 2b03097 | 2021-11-18 10:01:27 -0800 | [diff] [blame] | 906 | {100, 200})) |
907 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
908 | |||||
909 | // Both foreground window and its wallpaper should receive the touch down | ||||
910 | foregroundWindow->consumeMotionDown(); | ||||
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 911 | wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); |
Siarhei Vishniakou | 2b03097 | 2021-11-18 10:01:27 -0800 | [diff] [blame] | 912 | |
913 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 914 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
Siarhei Vishniakou | 2b03097 | 2021-11-18 10:01:27 -0800 | [diff] [blame] | 915 | ADISPLAY_ID_DEFAULT, {110, 200})) |
916 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
917 | |||||
918 | foregroundWindow->consumeMotionMove(); | ||||
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 919 | wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); |
Siarhei Vishniakou | 2b03097 | 2021-11-18 10:01:27 -0800 | [diff] [blame] | 920 | |
921 | // Wallpaper closes its channel, but the window remains. | ||||
922 | wallpaperWindow->destroyReceiver(); | ||||
923 | mFakePolicy->assertNotifyInputChannelBrokenWasCalled(wallpaperWindow->getInfo()->token); | ||||
924 | |||||
925 | // Now the foreground window goes away, but the wallpaper stays, even though its channel | ||||
926 | // is no longer valid. | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 927 | mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | 2b03097 | 2021-11-18 10:01:27 -0800 | [diff] [blame] | 928 | foregroundWindow->consumeMotionCancel(); |
929 | } | ||||
930 | |||||
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 931 | /** |
932 | * Two windows: left and right, and a separate wallpaper window underneath each. Device A sends a | ||||
933 | * down event to the left window. Device B sends a down event to the right window. Next, the right | ||||
934 | * window disappears. Both the right window and its wallpaper window should receive cancel event. | ||||
935 | * The left window and its wallpaper window should not receive any events. | ||||
936 | */ | ||||
937 | TEST_F(InputDispatcherTest, MultiDeviceDisappearingWindowWithWallpaperWindows) { | ||||
938 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
939 | sp<FakeWindowHandle> leftForegroundWindow = | ||||
940 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left foreground window", | ||||
941 | ADISPLAY_ID_DEFAULT); | ||||
942 | leftForegroundWindow->setFrame(Rect(0, 0, 100, 100)); | ||||
943 | leftForegroundWindow->setDupTouchToWallpaper(true); | ||||
944 | sp<FakeWindowHandle> leftWallpaperWindow = | ||||
945 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left wallpaper window", | ||||
946 | ADISPLAY_ID_DEFAULT); | ||||
947 | leftWallpaperWindow->setFrame(Rect(0, 0, 100, 100)); | ||||
948 | leftWallpaperWindow->setIsWallpaper(true); | ||||
949 | |||||
950 | sp<FakeWindowHandle> rightForegroundWindow = | ||||
951 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right foreground window", | ||||
952 | ADISPLAY_ID_DEFAULT); | ||||
953 | rightForegroundWindow->setFrame(Rect(100, 0, 200, 100)); | ||||
954 | rightForegroundWindow->setDupTouchToWallpaper(true); | ||||
955 | sp<FakeWindowHandle> rightWallpaperWindow = | ||||
956 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right wallpaper window", | ||||
957 | ADISPLAY_ID_DEFAULT); | ||||
958 | rightWallpaperWindow->setFrame(Rect(100, 0, 200, 100)); | ||||
959 | rightWallpaperWindow->setIsWallpaper(true); | ||||
960 | |||||
961 | mDispatcher->onWindowInfosChanged( | ||||
962 | {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(), | ||||
963 | *rightForegroundWindow->getInfo(), *rightWallpaperWindow->getInfo()}, | ||||
964 | {}, | ||||
965 | 0, | ||||
966 | 0}); | ||||
967 | |||||
968 | const DeviceId deviceA = 9; | ||||
969 | const DeviceId deviceB = 3; | ||||
970 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
971 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
972 | .deviceId(deviceA) | ||||
973 | .build()); | ||||
974 | leftForegroundWindow->consumeMotionEvent( | ||||
975 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA))); | ||||
976 | leftWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), | ||||
977 | WithDeviceId(deviceA), | ||||
978 | WithFlags(EXPECTED_WALLPAPER_FLAGS))); | ||||
979 | |||||
980 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
981 | .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) | ||||
982 | .deviceId(deviceB) | ||||
983 | .build()); | ||||
984 | rightForegroundWindow->consumeMotionEvent( | ||||
985 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB))); | ||||
986 | rightWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), | ||||
987 | WithDeviceId(deviceB), | ||||
988 | WithFlags(EXPECTED_WALLPAPER_FLAGS))); | ||||
989 | |||||
990 | // Now right foreground window disappears, but right wallpaper window remains. | ||||
991 | mDispatcher->onWindowInfosChanged( | ||||
992 | {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(), | ||||
993 | *rightWallpaperWindow->getInfo()}, | ||||
994 | {}, | ||||
995 | 0, | ||||
996 | 0}); | ||||
997 | |||||
998 | // Left foreground window and left wallpaper window still exist, and should not receive any | ||||
999 | // events. | ||||
1000 | leftForegroundWindow->assertNoEvents(); | ||||
1001 | leftWallpaperWindow->assertNoEvents(); | ||||
1002 | // Since right foreground window disappeared, right wallpaper window and right foreground window | ||||
1003 | // should receive cancel events. | ||||
1004 | rightForegroundWindow->consumeMotionEvent( | ||||
1005 | AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB))); | ||||
1006 | rightWallpaperWindow->consumeMotionEvent( | ||||
1007 | AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB), | ||||
1008 | WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_CANCELED))); | ||||
1009 | } | ||||
1010 | |||||
1011 | /** | ||||
1012 | * Three windows arranged horizontally and without any overlap. Every window has a | ||||
1013 | * wallpaper window underneath. The middle window also has SLIPPERY flag. | ||||
1014 | * Device A sends a down event to the left window. Device B sends a down event to the middle window. | ||||
1015 | * Next, device B sends move event to the right window. Touch for device B should slip from the | ||||
1016 | * middle window to the right window. Also, the right wallpaper window should receive a down event. | ||||
1017 | * The middle window and its wallpaper window should receive a cancel event. The left window should | ||||
1018 | * not receive any events. If device B continues to report events, the right window and its | ||||
1019 | * wallpaper window should receive remaining events. | ||||
1020 | */ | ||||
1021 | TEST_F(InputDispatcherTest, MultiDeviceSlipperyTouchWithWallpaperWindow) { | ||||
1022 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
1023 | sp<FakeWindowHandle> leftForegroundWindow = | ||||
1024 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left foreground window", | ||||
1025 | ADISPLAY_ID_DEFAULT); | ||||
1026 | leftForegroundWindow->setFrame(Rect(0, 0, 100, 100)); | ||||
1027 | leftForegroundWindow->setDupTouchToWallpaper(true); | ||||
1028 | sp<FakeWindowHandle> leftWallpaperWindow = | ||||
1029 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left wallpaper window", | ||||
1030 | ADISPLAY_ID_DEFAULT); | ||||
1031 | leftWallpaperWindow->setFrame(Rect(0, 0, 100, 100)); | ||||
1032 | leftWallpaperWindow->setIsWallpaper(true); | ||||
1033 | |||||
1034 | sp<FakeWindowHandle> middleForegroundWindow = | ||||
1035 | sp<FakeWindowHandle>::make(application, mDispatcher, "Middle foreground window", | ||||
1036 | ADISPLAY_ID_DEFAULT); | ||||
1037 | middleForegroundWindow->setFrame(Rect(100, 0, 200, 100)); | ||||
1038 | middleForegroundWindow->setDupTouchToWallpaper(true); | ||||
1039 | middleForegroundWindow->setSlippery(true); | ||||
1040 | sp<FakeWindowHandle> middleWallpaperWindow = | ||||
1041 | sp<FakeWindowHandle>::make(application, mDispatcher, "Middle wallpaper window", | ||||
1042 | ADISPLAY_ID_DEFAULT); | ||||
1043 | middleWallpaperWindow->setFrame(Rect(100, 0, 200, 100)); | ||||
1044 | middleWallpaperWindow->setIsWallpaper(true); | ||||
1045 | |||||
1046 | sp<FakeWindowHandle> rightForegroundWindow = | ||||
1047 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right foreground window", | ||||
1048 | ADISPLAY_ID_DEFAULT); | ||||
1049 | rightForegroundWindow->setFrame(Rect(200, 0, 300, 100)); | ||||
1050 | rightForegroundWindow->setDupTouchToWallpaper(true); | ||||
1051 | sp<FakeWindowHandle> rightWallpaperWindow = | ||||
1052 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right wallpaper window", | ||||
1053 | ADISPLAY_ID_DEFAULT); | ||||
1054 | rightWallpaperWindow->setFrame(Rect(200, 0, 300, 100)); | ||||
1055 | rightWallpaperWindow->setIsWallpaper(true); | ||||
1056 | |||||
1057 | mDispatcher->onWindowInfosChanged( | ||||
1058 | {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(), | ||||
1059 | *middleForegroundWindow->getInfo(), *middleWallpaperWindow->getInfo(), | ||||
1060 | *rightForegroundWindow->getInfo(), *rightWallpaperWindow->getInfo()}, | ||||
1061 | {}, | ||||
1062 | 0, | ||||
1063 | 0}); | ||||
1064 | |||||
1065 | const DeviceId deviceA = 9; | ||||
1066 | const DeviceId deviceB = 3; | ||||
1067 | // Device A sends a DOWN event to the left window | ||||
1068 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1069 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
1070 | .deviceId(deviceA) | ||||
1071 | .build()); | ||||
1072 | leftForegroundWindow->consumeMotionEvent( | ||||
1073 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA))); | ||||
1074 | leftWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), | ||||
1075 | WithDeviceId(deviceA), | ||||
1076 | WithFlags(EXPECTED_WALLPAPER_FLAGS))); | ||||
1077 | // Device B sends a DOWN event to the middle window | ||||
1078 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1079 | .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) | ||||
1080 | .deviceId(deviceB) | ||||
1081 | .build()); | ||||
1082 | middleForegroundWindow->consumeMotionEvent( | ||||
1083 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB))); | ||||
1084 | middleWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), | ||||
1085 | WithDeviceId(deviceB), | ||||
1086 | WithFlags(EXPECTED_WALLPAPER_FLAGS))); | ||||
1087 | // Move the events of device B to the top of the right window. | ||||
1088 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1089 | .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(50)) | ||||
1090 | .deviceId(deviceB) | ||||
1091 | .build()); | ||||
1092 | middleForegroundWindow->consumeMotionEvent( | ||||
1093 | AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB))); | ||||
1094 | middleWallpaperWindow->consumeMotionEvent( | ||||
1095 | AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB), | ||||
1096 | WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_CANCELED))); | ||||
1097 | rightForegroundWindow->consumeMotionEvent( | ||||
1098 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB))); | ||||
1099 | rightWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), | ||||
1100 | WithDeviceId(deviceB), | ||||
1101 | WithFlags(EXPECTED_WALLPAPER_FLAGS))); | ||||
1102 | // Make sure the window on the right can receive the remaining events. | ||||
1103 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1104 | .pointer(PointerBuilder(0, ToolType::FINGER).x(251).y(51)) | ||||
1105 | .deviceId(deviceB) | ||||
1106 | .build()); | ||||
1107 | leftForegroundWindow->assertNoEvents(); | ||||
1108 | leftWallpaperWindow->assertNoEvents(); | ||||
1109 | middleForegroundWindow->assertNoEvents(); | ||||
1110 | middleWallpaperWindow->assertNoEvents(); | ||||
1111 | rightForegroundWindow->consumeMotionEvent( | ||||
1112 | AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB))); | ||||
1113 | rightWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), | ||||
1114 | WithDeviceId(deviceB), | ||||
1115 | WithFlags(EXPECTED_WALLPAPER_FLAGS))); | ||||
1116 | } | ||||
1117 | |||||
1118 | /** | ||||
1119 | * Similar to the test above, we have three windows, they are arranged horizontally and without any | ||||
1120 | * overlap, and every window has a wallpaper window. The middle window is a simple window, without | ||||
1121 | * any special flags. Device A reports a down event that lands in left window. Device B sends a down | ||||
1122 | * event to the middle window and then touch is transferred from the middle window to the right | ||||
1123 | * window. The right window and its wallpaper window should receive a down event. The middle window | ||||
1124 | * and its wallpaper window should receive a cancel event. The left window should not receive any | ||||
1125 | * events. Subsequent events reported by device B should go to the right window and its wallpaper. | ||||
1126 | */ | ||||
1127 | TEST_F(InputDispatcherTest, MultiDeviceTouchTransferWithWallpaperWindows) { | ||||
1128 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
1129 | sp<FakeWindowHandle> leftForegroundWindow = | ||||
1130 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left foreground window", | ||||
1131 | ADISPLAY_ID_DEFAULT); | ||||
1132 | leftForegroundWindow->setFrame(Rect(0, 0, 100, 100)); | ||||
1133 | leftForegroundWindow->setDupTouchToWallpaper(true); | ||||
1134 | sp<FakeWindowHandle> leftWallpaperWindow = | ||||
1135 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left wallpaper window", | ||||
1136 | ADISPLAY_ID_DEFAULT); | ||||
1137 | leftWallpaperWindow->setFrame(Rect(0, 0, 100, 100)); | ||||
1138 | leftWallpaperWindow->setIsWallpaper(true); | ||||
1139 | |||||
1140 | sp<FakeWindowHandle> middleForegroundWindow = | ||||
1141 | sp<FakeWindowHandle>::make(application, mDispatcher, "Middle foreground window", | ||||
1142 | ADISPLAY_ID_DEFAULT); | ||||
1143 | middleForegroundWindow->setFrame(Rect(100, 0, 200, 100)); | ||||
1144 | middleForegroundWindow->setDupTouchToWallpaper(true); | ||||
1145 | sp<FakeWindowHandle> middleWallpaperWindow = | ||||
1146 | sp<FakeWindowHandle>::make(application, mDispatcher, "Middle wallpaper window", | ||||
1147 | ADISPLAY_ID_DEFAULT); | ||||
1148 | middleWallpaperWindow->setFrame(Rect(100, 0, 200, 100)); | ||||
1149 | middleWallpaperWindow->setIsWallpaper(true); | ||||
1150 | |||||
1151 | sp<FakeWindowHandle> rightForegroundWindow = | ||||
1152 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right foreground window", | ||||
1153 | ADISPLAY_ID_DEFAULT); | ||||
1154 | rightForegroundWindow->setFrame(Rect(200, 0, 300, 100)); | ||||
1155 | rightForegroundWindow->setDupTouchToWallpaper(true); | ||||
1156 | sp<FakeWindowHandle> rightWallpaperWindow = | ||||
1157 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right wallpaper window", | ||||
1158 | ADISPLAY_ID_DEFAULT); | ||||
1159 | rightWallpaperWindow->setFrame(Rect(200, 0, 300, 100)); | ||||
1160 | rightWallpaperWindow->setIsWallpaper(true); | ||||
1161 | |||||
1162 | mDispatcher->onWindowInfosChanged( | ||||
1163 | {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(), | ||||
1164 | *middleForegroundWindow->getInfo(), *middleWallpaperWindow->getInfo(), | ||||
1165 | *rightForegroundWindow->getInfo(), *rightWallpaperWindow->getInfo()}, | ||||
1166 | {}, | ||||
1167 | 0, | ||||
1168 | 0}); | ||||
1169 | |||||
1170 | const DeviceId deviceA = 9; | ||||
1171 | const DeviceId deviceB = 3; | ||||
1172 | // Device A touch down on the left window | ||||
1173 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1174 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
1175 | .deviceId(deviceA) | ||||
1176 | .build()); | ||||
1177 | leftForegroundWindow->consumeMotionEvent( | ||||
1178 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA))); | ||||
1179 | leftWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), | ||||
1180 | WithDeviceId(deviceA), | ||||
1181 | WithFlags(EXPECTED_WALLPAPER_FLAGS))); | ||||
1182 | // Device B touch down on the middle window | ||||
1183 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1184 | .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) | ||||
1185 | .deviceId(deviceB) | ||||
1186 | .build()); | ||||
1187 | middleForegroundWindow->consumeMotionEvent( | ||||
1188 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB))); | ||||
1189 | middleWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), | ||||
1190 | WithDeviceId(deviceB), | ||||
1191 | WithFlags(EXPECTED_WALLPAPER_FLAGS))); | ||||
1192 | |||||
1193 | // Transfer touch from the middle window to the right window. | ||||
1194 | ASSERT_TRUE(mDispatcher->transferTouchGesture(middleForegroundWindow->getToken(), | ||||
1195 | rightForegroundWindow->getToken())); | ||||
1196 | |||||
1197 | middleForegroundWindow->consumeMotionEvent( | ||||
1198 | AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB))); | ||||
1199 | middleWallpaperWindow->consumeMotionEvent( | ||||
1200 | AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB), | ||||
1201 | WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_CANCELED))); | ||||
1202 | rightForegroundWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), | ||||
1203 | WithDeviceId(deviceB), | ||||
1204 | WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))); | ||||
1205 | rightWallpaperWindow->consumeMotionEvent( | ||||
1206 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB), | ||||
1207 | WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))); | ||||
1208 | |||||
1209 | // Make sure the right window can receive the remaining events. | ||||
1210 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1211 | .pointer(PointerBuilder(0, ToolType::FINGER).x(251).y(51)) | ||||
1212 | .deviceId(deviceB) | ||||
1213 | .build()); | ||||
1214 | leftForegroundWindow->assertNoEvents(); | ||||
1215 | leftWallpaperWindow->assertNoEvents(); | ||||
1216 | middleForegroundWindow->assertNoEvents(); | ||||
1217 | middleWallpaperWindow->assertNoEvents(); | ||||
1218 | rightForegroundWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), | ||||
1219 | WithDeviceId(deviceB), | ||||
1220 | WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))); | ||||
1221 | rightWallpaperWindow->consumeMotionEvent( | ||||
1222 | AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB), | ||||
1223 | WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))); | ||||
1224 | } | ||||
1225 | |||||
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 1226 | class ShouldSplitTouchFixture : public InputDispatcherTest, |
1227 | public ::testing::WithParamInterface<bool> {}; | ||||
1228 | INSTANTIATE_TEST_SUITE_P(InputDispatcherTest, ShouldSplitTouchFixture, | ||||
1229 | ::testing::Values(true, false)); | ||||
Siarhei Vishniakou | 2b03097 | 2021-11-18 10:01:27 -0800 | [diff] [blame] | 1230 | /** |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1231 | * A single window that receives touch (on top), and a wallpaper window underneath it. |
1232 | * The top window gets a multitouch gesture. | ||||
1233 | * Ensure that wallpaper gets the same gesture. | ||||
1234 | */ | ||||
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 1235 | TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1236 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 1237 | sp<FakeWindowHandle> foregroundWindow = |
1238 | sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); | ||||
1239 | foregroundWindow->setDupTouchToWallpaper(true); | ||||
1240 | foregroundWindow->setPreventSplitting(GetParam()); | ||||
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1241 | |
1242 | sp<FakeWindowHandle> wallpaperWindow = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 1243 | sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); |
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 1244 | wallpaperWindow->setIsWallpaper(true); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1245 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 1246 | mDispatcher->onWindowInfosChanged( |
1247 | {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1248 | |
1249 | // Touch down on top window | ||||
1250 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1251 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1252 | {100, 100})) |
1253 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
1254 | |||||
1255 | // Both top window and its wallpaper should receive the touch down | ||||
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 1256 | foregroundWindow->consumeMotionDown(); |
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 1257 | wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1258 | |
1259 | // Second finger down on the top window | ||||
1260 | const MotionEvent secondFingerDownEvent = | ||||
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 1261 | MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1262 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) |
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 1263 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100)) |
1264 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150)) | ||||
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1265 | .build(); |
1266 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1267 | injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1268 | InputEventInjectionSync::WAIT_FOR_RESULT)) |
1269 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
1270 | |||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 1271 | foregroundWindow->consumeMotionPointerDown(/*pointerIndex=*/1); |
1272 | wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ADISPLAY_ID_DEFAULT, | ||||
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 1273 | EXPECTED_WALLPAPER_FLAGS); |
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 1274 | |
1275 | const MotionEvent secondFingerUpEvent = | ||||
1276 | MotionEventBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1277 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
1278 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 1279 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100)) |
1280 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150)) | ||||
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 1281 | .build(); |
1282 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1283 | injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, |
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 1284 | InputEventInjectionSync::WAIT_FOR_RESULT)) |
1285 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
1286 | foregroundWindow->consumeMotionPointerUp(0); | ||||
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 1287 | wallpaperWindow->consumeMotionPointerUp(0, ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); |
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 1288 | |
1289 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1290 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 92c8fd5 | 2023-01-29 14:57:43 -0800 | [diff] [blame] | 1291 | MotionEventBuilder(AMOTION_EVENT_ACTION_UP, |
1292 | AINPUT_SOURCE_TOUCHSCREEN) | ||||
1293 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
1294 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 1295 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER) |
Siarhei Vishniakou | 92c8fd5 | 2023-01-29 14:57:43 -0800 | [diff] [blame] | 1296 | .x(100) |
1297 | .y(100)) | ||||
1298 | .build(), | ||||
1299 | INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) | ||||
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 1300 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
1301 | foregroundWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); | ||||
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 1302 | wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1303 | } |
1304 | |||||
1305 | /** | ||||
1306 | * Two windows: a window on the left and window on the right. | ||||
1307 | * A third window, wallpaper, is behind both windows, and spans both top windows. | ||||
1308 | * The first touch down goes to the left window. A second pointer touches down on the right window. | ||||
1309 | * The touch is split, so both left and right windows should receive ACTION_DOWN. | ||||
1310 | * The wallpaper will get the full event, so it should receive ACTION_DOWN followed by | ||||
1311 | * ACTION_POINTER_DOWN(1). | ||||
1312 | */ | ||||
1313 | TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { | ||||
1314 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
1315 | sp<FakeWindowHandle> leftWindow = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 1316 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1317 | leftWindow->setFrame(Rect(0, 0, 200, 200)); |
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 1318 | leftWindow->setDupTouchToWallpaper(true); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1319 | |
1320 | sp<FakeWindowHandle> rightWindow = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 1321 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1322 | rightWindow->setFrame(Rect(200, 0, 400, 200)); |
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 1323 | rightWindow->setDupTouchToWallpaper(true); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1324 | |
1325 | sp<FakeWindowHandle> wallpaperWindow = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 1326 | sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1327 | wallpaperWindow->setFrame(Rect(0, 0, 400, 200)); |
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 1328 | wallpaperWindow->setIsWallpaper(true); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1329 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 1330 | mDispatcher->onWindowInfosChanged( |
1331 | {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()}, | ||||
1332 | {}, | ||||
1333 | 0, | ||||
1334 | 0}); | ||||
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1335 | |
1336 | // Touch down on left window | ||||
1337 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1338 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1339 | {100, 100})) |
1340 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
1341 | |||||
1342 | // Both foreground window and its wallpaper should receive the touch down | ||||
1343 | leftWindow->consumeMotionDown(); | ||||
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 1344 | wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1345 | |
1346 | // Second finger down on the right window | ||||
1347 | const MotionEvent secondFingerDownEvent = | ||||
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 1348 | MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1349 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) |
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 1350 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100)) |
1351 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(300).y(100)) | ||||
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1352 | .build(); |
1353 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1354 | injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1355 | InputEventInjectionSync::WAIT_FOR_RESULT)) |
1356 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
1357 | |||||
1358 | leftWindow->consumeMotionMove(); | ||||
1359 | // Since the touch is split, right window gets ACTION_DOWN | ||||
1360 | rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 1361 | wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ADISPLAY_ID_DEFAULT, |
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 1362 | EXPECTED_WALLPAPER_FLAGS); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1363 | |
1364 | // Now, leftWindow, which received the first finger, disappears. | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 1365 | mDispatcher->onWindowInfosChanged( |
1366 | {{*rightWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1367 | leftWindow->consumeMotionCancel(); |
1368 | // Since a "parent" window of the wallpaper is gone, wallpaper should receive cancel, too. | ||||
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 1369 | wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1370 | |
1371 | // The pointer that's still down on the right window moves, and goes to the right window only. | ||||
1372 | // As far as the dispatcher's concerned though, both pointers are still present. | ||||
1373 | const MotionEvent secondFingerMoveEvent = | ||||
1374 | MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1375 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 1376 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100)) |
1377 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(310).y(110)) | ||||
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1378 | .build(); |
1379 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1380 | injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT, |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 1381 | InputEventInjectionSync::WAIT_FOR_RESULT)); |
1382 | rightWindow->consumeMotionMove(); | ||||
1383 | |||||
1384 | leftWindow->assertNoEvents(); | ||||
1385 | rightWindow->assertNoEvents(); | ||||
1386 | wallpaperWindow->assertNoEvents(); | ||||
1387 | } | ||||
1388 | |||||
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 1389 | /** |
1390 | * Two windows: a window on the left with dup touch to wallpaper and window on the right without it. | ||||
1391 | * The touch slips to the right window. so left window and wallpaper should receive ACTION_CANCEL | ||||
1392 | * The right window should receive ACTION_DOWN. | ||||
1393 | */ | ||||
1394 | TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) { | ||||
Arthur Hung | 74c248d | 2022-11-23 07:09:59 +0000 | [diff] [blame] | 1395 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 1396 | sp<FakeWindowHandle> leftWindow = |
1397 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); | ||||
1398 | leftWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
1399 | leftWindow->setDupTouchToWallpaper(true); | ||||
1400 | leftWindow->setSlippery(true); | ||||
1401 | |||||
1402 | sp<FakeWindowHandle> rightWindow = | ||||
1403 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); | ||||
1404 | rightWindow->setFrame(Rect(200, 0, 400, 200)); | ||||
Arthur Hung | 74c248d | 2022-11-23 07:09:59 +0000 | [diff] [blame] | 1405 | |
1406 | sp<FakeWindowHandle> wallpaperWindow = | ||||
1407 | sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); | ||||
1408 | wallpaperWindow->setIsWallpaper(true); | ||||
Arthur Hung | 74c248d | 2022-11-23 07:09:59 +0000 | [diff] [blame] | 1409 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 1410 | mDispatcher->onWindowInfosChanged( |
1411 | {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()}, | ||||
1412 | {}, | ||||
1413 | 0, | ||||
1414 | 0}); | ||||
Arthur Hung | 74c248d | 2022-11-23 07:09:59 +0000 | [diff] [blame] | 1415 | |
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 1416 | // Touch down on left window |
Arthur Hung | 74c248d | 2022-11-23 07:09:59 +0000 | [diff] [blame] | 1417 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1418 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 1419 | {100, 100})) |
Arthur Hung | 74c248d | 2022-11-23 07:09:59 +0000 | [diff] [blame] | 1420 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 1421 | |
1422 | // Both foreground window and its wallpaper should receive the touch down | ||||
1423 | leftWindow->consumeMotionDown(); | ||||
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 1424 | wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); |
Arthur Hung | 74c248d | 2022-11-23 07:09:59 +0000 | [diff] [blame] | 1425 | |
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 1426 | // Move to right window, the left window should receive cancel. |
Arthur Hung | 74c248d | 2022-11-23 07:09:59 +0000 | [diff] [blame] | 1427 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1428 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 1429 | ADISPLAY_ID_DEFAULT, {201, 100})) |
Arthur Hung | 74c248d | 2022-11-23 07:09:59 +0000 | [diff] [blame] | 1430 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
1431 | |||||
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 1432 | leftWindow->consumeMotionCancel(); |
1433 | rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 1434 | wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); |
Arthur Hung | 74c248d | 2022-11-23 07:09:59 +0000 | [diff] [blame] | 1435 | } |
1436 | |||||
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 1437 | /** |
Siarhei Vishniakou | 5bf25d9 | 2023-02-08 15:43:38 -0800 | [diff] [blame] | 1438 | * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not |
1439 | * interactive, it might stop sending this flag. | ||||
1440 | * In this test, we check that if the policy stops sending this flag mid-gesture, we still ensure | ||||
1441 | * to have a consistent input stream. | ||||
1442 | * | ||||
1443 | * Test procedure: | ||||
1444 | * DOWN -> POINTER_DOWN -> (stop sending POLICY_FLAG_PASS_TO_USER) -> CANCEL. | ||||
1445 | * DOWN (new gesture). | ||||
1446 | * | ||||
1447 | * In the bad implementation, we could potentially drop the CANCEL event, and get an inconsistent | ||||
1448 | * state in the dispatcher. This would cause the final DOWN event to not be delivered to the app. | ||||
1449 | * | ||||
1450 | * We technically just need a single window here, but we are using two windows (spy on top and a | ||||
1451 | * regular window below) to emulate the actual situation where it happens on the device. | ||||
1452 | */ | ||||
1453 | TEST_F(InputDispatcherTest, TwoPointerCancelInconsistentPolicy) { | ||||
1454 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
1455 | sp<FakeWindowHandle> spyWindow = | ||||
1456 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); | ||||
1457 | spyWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
1458 | spyWindow->setTrustedOverlay(true); | ||||
1459 | spyWindow->setSpy(true); | ||||
1460 | |||||
1461 | sp<FakeWindowHandle> window = | ||||
1462 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
1463 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
1464 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 1465 | mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | 5bf25d9 | 2023-02-08 15:43:38 -0800 | [diff] [blame] | 1466 | const int32_t touchDeviceId = 4; |
Siarhei Vishniakou | 5bf25d9 | 2023-02-08 15:43:38 -0800 | [diff] [blame] | 1467 | |
1468 | // Two pointers down | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 1469 | mDispatcher->notifyMotion( |
1470 | MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1471 | .deviceId(touchDeviceId) | ||||
1472 | .policyFlags(DEFAULT_POLICY_FLAGS) | ||||
1473 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
1474 | .build()); | ||||
Siarhei Vishniakou | 5bf25d9 | 2023-02-08 15:43:38 -0800 | [diff] [blame] | 1475 | |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 1476 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
1477 | .deviceId(touchDeviceId) | ||||
1478 | .policyFlags(DEFAULT_POLICY_FLAGS) | ||||
1479 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
1480 | .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120)) | ||||
1481 | .build()); | ||||
Siarhei Vishniakou | 5bf25d9 | 2023-02-08 15:43:38 -0800 | [diff] [blame] | 1482 | spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); |
1483 | spyWindow->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); | ||||
1484 | window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); | ||||
1485 | window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); | ||||
1486 | |||||
1487 | // Cancel the current gesture. Send the cancel without the default policy flags. | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 1488 | mDispatcher->notifyMotion( |
1489 | MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1490 | .deviceId(touchDeviceId) | ||||
1491 | .policyFlags(0) | ||||
1492 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
1493 | .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120)) | ||||
1494 | .build()); | ||||
Siarhei Vishniakou | 5bf25d9 | 2023-02-08 15:43:38 -0800 | [diff] [blame] | 1495 | spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL)); |
1496 | window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL)); | ||||
1497 | |||||
1498 | // We don't need to reset the device to reproduce the issue, but the reset event typically | ||||
1499 | // follows, so we keep it here to model the actual listener behaviour more closely. | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 1500 | mDispatcher->notifyDeviceReset({/*id=*/1, systemTime(SYSTEM_TIME_MONOTONIC), touchDeviceId}); |
Siarhei Vishniakou | 5bf25d9 | 2023-02-08 15:43:38 -0800 | [diff] [blame] | 1501 | |
1502 | // Start new gesture | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 1503 | mDispatcher->notifyMotion( |
1504 | MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1505 | .deviceId(touchDeviceId) | ||||
1506 | .policyFlags(DEFAULT_POLICY_FLAGS) | ||||
1507 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
1508 | .build()); | ||||
Siarhei Vishniakou | 5bf25d9 | 2023-02-08 15:43:38 -0800 | [diff] [blame] | 1509 | spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); |
1510 | window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); | ||||
1511 | |||||
1512 | // No more events | ||||
1513 | spyWindow->assertNoEvents(); | ||||
1514 | window->assertNoEvents(); | ||||
1515 | } | ||||
1516 | |||||
1517 | /** | ||||
Linnan Li | 907ae73 | 2023-09-05 17:14:21 +0800 | [diff] [blame] | 1518 | * Same as the above 'TwoPointerCancelInconsistentPolicy' test, but for hovers. |
1519 | * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not | ||||
1520 | * interactive, it might stop sending this flag. | ||||
1521 | * We've already ensured the consistency of the touch event in this case, and we should also ensure | ||||
1522 | * the consistency of the hover event in this case. | ||||
1523 | * | ||||
1524 | * Test procedure: | ||||
1525 | * HOVER_ENTER -> HOVER_MOVE -> (stop sending POLICY_FLAG_PASS_TO_USER) -> HOVER_EXIT | ||||
1526 | * HOVER_ENTER -> HOVER_MOVE -> HOVER_EXIT | ||||
1527 | * | ||||
1528 | * We expect to receive two full streams of hover events. | ||||
1529 | */ | ||||
1530 | TEST_F(InputDispatcherTest, HoverEventInconsistentPolicy) { | ||||
1531 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
1532 | |||||
1533 | sp<FakeWindowHandle> window = | ||||
1534 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
1535 | window->setFrame(Rect(0, 0, 300, 300)); | ||||
1536 | |||||
1537 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
1538 | |||||
1539 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
1540 | .policyFlags(DEFAULT_POLICY_FLAGS) | ||||
1541 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101)) | ||||
1542 | .build()); | ||||
1543 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
1544 | |||||
1545 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) | ||||
1546 | .policyFlags(DEFAULT_POLICY_FLAGS) | ||||
1547 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102)) | ||||
1548 | .build()); | ||||
1549 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE)); | ||||
1550 | |||||
1551 | // Send hover exit without the default policy flags. | ||||
1552 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) | ||||
1553 | .policyFlags(0) | ||||
1554 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102)) | ||||
1555 | .build()); | ||||
1556 | |||||
1557 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); | ||||
1558 | |||||
1559 | // Send a simple hover event stream, ensure dispatcher not crashed and window can receive | ||||
1560 | // right event. | ||||
1561 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
1562 | .policyFlags(DEFAULT_POLICY_FLAGS) | ||||
1563 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(200).y(201)) | ||||
1564 | .build()); | ||||
1565 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
1566 | |||||
1567 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) | ||||
1568 | .policyFlags(DEFAULT_POLICY_FLAGS) | ||||
1569 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202)) | ||||
1570 | .build()); | ||||
1571 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE)); | ||||
1572 | |||||
1573 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) | ||||
1574 | .policyFlags(DEFAULT_POLICY_FLAGS) | ||||
1575 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202)) | ||||
1576 | .build()); | ||||
1577 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); | ||||
1578 | } | ||||
1579 | |||||
1580 | /** | ||||
Siarhei Vishniakou | e0431e4 | 2023-01-28 17:01:39 -0800 | [diff] [blame] | 1581 | * Two windows: a window on the left and a window on the right. |
1582 | * Mouse is hovered from the right window into the left window. | ||||
1583 | * Next, we tap on the left window, where the cursor was last seen. | ||||
1584 | * The second tap is done onto the right window. | ||||
1585 | * The mouse and tap are from two different devices. | ||||
1586 | * We technically don't need to set the downtime / eventtime for these events, but setting these | ||||
1587 | * explicitly helps during debugging. | ||||
1588 | * This test reproduces a crash where there is a mismatch between the downTime and eventTime. | ||||
1589 | * In the buggy implementation, a tap on the right window would cause a crash. | ||||
1590 | */ | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 1591 | TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap_legacy) { |
1592 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); | ||||
1593 | |||||
Siarhei Vishniakou | e0431e4 | 2023-01-28 17:01:39 -0800 | [diff] [blame] | 1594 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
1595 | sp<FakeWindowHandle> leftWindow = | ||||
1596 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); | ||||
1597 | leftWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
1598 | |||||
1599 | sp<FakeWindowHandle> rightWindow = | ||||
1600 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); | ||||
1601 | rightWindow->setFrame(Rect(200, 0, 400, 200)); | ||||
1602 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 1603 | mDispatcher->onWindowInfosChanged( |
1604 | {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | e0431e4 | 2023-01-28 17:01:39 -0800 | [diff] [blame] | 1605 | // All times need to start at the current time, otherwise the dispatcher will drop the events as |
1606 | // stale. | ||||
1607 | const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC); | ||||
1608 | const int32_t mouseDeviceId = 6; | ||||
1609 | const int32_t touchDeviceId = 4; | ||||
1610 | // Move the cursor from right | ||||
1611 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1612 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | e0431e4 | 2023-01-28 17:01:39 -0800 | [diff] [blame] | 1613 | MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, |
1614 | AINPUT_SOURCE_MOUSE) | ||||
1615 | .deviceId(mouseDeviceId) | ||||
1616 | .downTime(baseTime + 10) | ||||
1617 | .eventTime(baseTime + 20) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1618 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100)) |
Siarhei Vishniakou | e0431e4 | 2023-01-28 17:01:39 -0800 | [diff] [blame] | 1619 | .build())); |
1620 | rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); | ||||
1621 | |||||
1622 | // .. to the left window | ||||
1623 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1624 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | e0431e4 | 2023-01-28 17:01:39 -0800 | [diff] [blame] | 1625 | MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, |
1626 | AINPUT_SOURCE_MOUSE) | ||||
1627 | .deviceId(mouseDeviceId) | ||||
1628 | .downTime(baseTime + 10) | ||||
1629 | .eventTime(baseTime + 30) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1630 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100)) |
Siarhei Vishniakou | e0431e4 | 2023-01-28 17:01:39 -0800 | [diff] [blame] | 1631 | .build())); |
1632 | rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); | ||||
1633 | leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); | ||||
1634 | // Now tap the left window | ||||
1635 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1636 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | e0431e4 | 2023-01-28 17:01:39 -0800 | [diff] [blame] | 1637 | MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, |
1638 | AINPUT_SOURCE_TOUCHSCREEN) | ||||
1639 | .deviceId(touchDeviceId) | ||||
1640 | .downTime(baseTime + 40) | ||||
1641 | .eventTime(baseTime + 40) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1642 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) |
Siarhei Vishniakou | e0431e4 | 2023-01-28 17:01:39 -0800 | [diff] [blame] | 1643 | .build())); |
1644 | leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); | ||||
1645 | leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); | ||||
1646 | |||||
1647 | // release tap | ||||
1648 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1649 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | e0431e4 | 2023-01-28 17:01:39 -0800 | [diff] [blame] | 1650 | MotionEventBuilder(AMOTION_EVENT_ACTION_UP, |
1651 | AINPUT_SOURCE_TOUCHSCREEN) | ||||
1652 | .deviceId(touchDeviceId) | ||||
1653 | .downTime(baseTime + 40) | ||||
1654 | .eventTime(baseTime + 50) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1655 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) |
Siarhei Vishniakou | e0431e4 | 2023-01-28 17:01:39 -0800 | [diff] [blame] | 1656 | .build())); |
1657 | leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP)); | ||||
1658 | |||||
1659 | // Tap the window on the right | ||||
1660 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1661 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | e0431e4 | 2023-01-28 17:01:39 -0800 | [diff] [blame] | 1662 | MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, |
1663 | AINPUT_SOURCE_TOUCHSCREEN) | ||||
1664 | .deviceId(touchDeviceId) | ||||
1665 | .downTime(baseTime + 60) | ||||
1666 | .eventTime(baseTime + 60) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1667 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) |
Siarhei Vishniakou | e0431e4 | 2023-01-28 17:01:39 -0800 | [diff] [blame] | 1668 | .build())); |
1669 | rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); | ||||
1670 | |||||
1671 | // release tap | ||||
1672 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1673 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | e0431e4 | 2023-01-28 17:01:39 -0800 | [diff] [blame] | 1674 | MotionEventBuilder(AMOTION_EVENT_ACTION_UP, |
1675 | AINPUT_SOURCE_TOUCHSCREEN) | ||||
1676 | .deviceId(touchDeviceId) | ||||
1677 | .downTime(baseTime + 60) | ||||
1678 | .eventTime(baseTime + 70) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 1679 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) |
Siarhei Vishniakou | e0431e4 | 2023-01-28 17:01:39 -0800 | [diff] [blame] | 1680 | .build())); |
1681 | rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP)); | ||||
1682 | |||||
1683 | // No more events | ||||
1684 | leftWindow->assertNoEvents(); | ||||
1685 | rightWindow->assertNoEvents(); | ||||
1686 | } | ||||
1687 | |||||
1688 | /** | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 1689 | * Two windows: a window on the left and a window on the right. |
1690 | * Mouse is hovered from the right window into the left window. | ||||
1691 | * Next, we tap on the left window, where the cursor was last seen. | ||||
1692 | * The second tap is done onto the right window. | ||||
1693 | * The mouse and tap are from two different devices. | ||||
1694 | * We technically don't need to set the downtime / eventtime for these events, but setting these | ||||
1695 | * explicitly helps during debugging. | ||||
1696 | * This test reproduces a crash where there is a mismatch between the downTime and eventTime. | ||||
1697 | * In the buggy implementation, a tap on the right window would cause a crash. | ||||
1698 | */ | ||||
1699 | TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) { | ||||
1700 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
1701 | |||||
1702 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
1703 | sp<FakeWindowHandle> leftWindow = | ||||
1704 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); | ||||
1705 | leftWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
1706 | |||||
1707 | sp<FakeWindowHandle> rightWindow = | ||||
1708 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); | ||||
1709 | rightWindow->setFrame(Rect(200, 0, 400, 200)); | ||||
1710 | |||||
1711 | mDispatcher->onWindowInfosChanged( | ||||
1712 | {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); | ||||
1713 | // All times need to start at the current time, otherwise the dispatcher will drop the events as | ||||
1714 | // stale. | ||||
1715 | const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC); | ||||
1716 | const int32_t mouseDeviceId = 6; | ||||
1717 | const int32_t touchDeviceId = 4; | ||||
1718 | // Move the cursor from right | ||||
1719 | mDispatcher->notifyMotion( | ||||
1720 | MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) | ||||
1721 | .deviceId(mouseDeviceId) | ||||
1722 | .downTime(baseTime + 10) | ||||
1723 | .eventTime(baseTime + 20) | ||||
1724 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100)) | ||||
1725 | .build()); | ||||
1726 | rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); | ||||
1727 | |||||
1728 | // .. to the left window | ||||
1729 | mDispatcher->notifyMotion( | ||||
1730 | MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) | ||||
1731 | .deviceId(mouseDeviceId) | ||||
1732 | .downTime(baseTime + 10) | ||||
1733 | .eventTime(baseTime + 30) | ||||
1734 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100)) | ||||
1735 | .build()); | ||||
1736 | rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); | ||||
1737 | leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); | ||||
1738 | // Now tap the left window | ||||
1739 | mDispatcher->notifyMotion( | ||||
1740 | MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1741 | .deviceId(touchDeviceId) | ||||
1742 | .downTime(baseTime + 40) | ||||
1743 | .eventTime(baseTime + 40) | ||||
1744 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
1745 | .build()); | ||||
1746 | leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); | ||||
1747 | |||||
1748 | // release tap | ||||
1749 | mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1750 | .deviceId(touchDeviceId) | ||||
1751 | .downTime(baseTime + 40) | ||||
1752 | .eventTime(baseTime + 50) | ||||
1753 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
1754 | .build()); | ||||
1755 | leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP)); | ||||
1756 | |||||
1757 | // Tap the window on the right | ||||
1758 | mDispatcher->notifyMotion( | ||||
1759 | MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1760 | .deviceId(touchDeviceId) | ||||
1761 | .downTime(baseTime + 60) | ||||
1762 | .eventTime(baseTime + 60) | ||||
1763 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
1764 | .build()); | ||||
1765 | rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); | ||||
1766 | |||||
1767 | // release tap | ||||
1768 | mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1769 | .deviceId(touchDeviceId) | ||||
1770 | .downTime(baseTime + 60) | ||||
1771 | .eventTime(baseTime + 70) | ||||
1772 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
1773 | .build()); | ||||
1774 | rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP)); | ||||
1775 | |||||
1776 | // No more events | ||||
1777 | leftWindow->assertNoEvents(); | ||||
1778 | rightWindow->assertNoEvents(); | ||||
1779 | } | ||||
1780 | |||||
1781 | /** | ||||
Siarhei Vishniakou | a235c04 | 2023-05-02 09:59:09 -0700 | [diff] [blame] | 1782 | * Start hovering in a window. While this hover is still active, make another window appear on top. |
1783 | * The top, obstructing window has no input channel, so it's not supposed to receive input. | ||||
1784 | * While the top window is present, the hovering is stopped. | ||||
1785 | * Later, hovering gets resumed again. | ||||
1786 | * Ensure that new hover gesture is handled correctly. | ||||
1787 | * This test reproduces a crash where the HOVER_EXIT event wasn't getting dispatched correctly | ||||
1788 | * to the window that's currently being hovered over. | ||||
1789 | */ | ||||
1790 | TEST_F(InputDispatcherTest, HoverWhileWindowAppears) { | ||||
1791 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
1792 | sp<FakeWindowHandle> window = | ||||
1793 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
1794 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
1795 | |||||
1796 | // Only a single window is present at first | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 1797 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | a235c04 | 2023-05-02 09:59:09 -0700 | [diff] [blame] | 1798 | |
1799 | // Start hovering in the window | ||||
1800 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
1801 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100)) | ||||
1802 | .build()); | ||||
1803 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
1804 | |||||
1805 | // Now, an obscuring window appears! | ||||
1806 | sp<FakeWindowHandle> obscuringWindow = | ||||
1807 | sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window", | ||||
1808 | ADISPLAY_ID_DEFAULT, | ||||
Prabir Pradhan | e7cc69c | 2024-01-05 21:35:28 +0000 | [diff] [blame] | 1809 | /*createInputChannel=*/false); |
Siarhei Vishniakou | a235c04 | 2023-05-02 09:59:09 -0700 | [diff] [blame] | 1810 | obscuringWindow->setFrame(Rect(0, 0, 200, 200)); |
1811 | obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED); | ||||
1812 | obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID); | ||||
1813 | obscuringWindow->setNoInputChannel(true); | ||||
1814 | obscuringWindow->setFocusable(false); | ||||
1815 | obscuringWindow->setAlpha(1.0); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 1816 | mDispatcher->onWindowInfosChanged( |
1817 | {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | a235c04 | 2023-05-02 09:59:09 -0700 | [diff] [blame] | 1818 | |
1819 | // While this new obscuring window is present, the hovering is stopped | ||||
1820 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) | ||||
1821 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100)) | ||||
1822 | .build()); | ||||
1823 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); | ||||
1824 | |||||
1825 | // Now the obscuring window goes away. | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 1826 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | a235c04 | 2023-05-02 09:59:09 -0700 | [diff] [blame] | 1827 | |
1828 | // And a new hover gesture starts. | ||||
1829 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
1830 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100)) | ||||
1831 | .build()); | ||||
1832 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
1833 | } | ||||
1834 | |||||
1835 | /** | ||||
1836 | * Same test as 'HoverWhileWindowAppears' above, but here, we also send some HOVER_MOVE events to | ||||
1837 | * the obscuring window. | ||||
1838 | */ | ||||
1839 | TEST_F(InputDispatcherTest, HoverMoveWhileWindowAppears) { | ||||
1840 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
1841 | sp<FakeWindowHandle> window = | ||||
1842 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
1843 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
1844 | |||||
1845 | // Only a single window is present at first | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 1846 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | a235c04 | 2023-05-02 09:59:09 -0700 | [diff] [blame] | 1847 | |
1848 | // Start hovering in the window | ||||
1849 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
1850 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100)) | ||||
1851 | .build()); | ||||
1852 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
1853 | |||||
1854 | // Now, an obscuring window appears! | ||||
1855 | sp<FakeWindowHandle> obscuringWindow = | ||||
1856 | sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window", | ||||
1857 | ADISPLAY_ID_DEFAULT, | ||||
Prabir Pradhan | e7cc69c | 2024-01-05 21:35:28 +0000 | [diff] [blame] | 1858 | /*createInputChannel=*/false); |
Siarhei Vishniakou | a235c04 | 2023-05-02 09:59:09 -0700 | [diff] [blame] | 1859 | obscuringWindow->setFrame(Rect(0, 0, 200, 200)); |
1860 | obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED); | ||||
1861 | obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID); | ||||
1862 | obscuringWindow->setNoInputChannel(true); | ||||
1863 | obscuringWindow->setFocusable(false); | ||||
1864 | obscuringWindow->setAlpha(1.0); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 1865 | mDispatcher->onWindowInfosChanged( |
1866 | {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | a235c04 | 2023-05-02 09:59:09 -0700 | [diff] [blame] | 1867 | |
1868 | // While this new obscuring window is present, the hovering continues. The event can't go to the | ||||
1869 | // bottom window due to obstructed touches, so it should generate HOVER_EXIT for that window. | ||||
1870 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) | ||||
1871 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100)) | ||||
1872 | .build()); | ||||
1873 | obscuringWindow->assertNoEvents(); | ||||
1874 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); | ||||
1875 | |||||
1876 | // Now the obscuring window goes away. | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 1877 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | a235c04 | 2023-05-02 09:59:09 -0700 | [diff] [blame] | 1878 | |
1879 | // Hovering continues in the same position. The hovering pointer re-enters the bottom window, | ||||
1880 | // so it should generate a HOVER_ENTER | ||||
1881 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) | ||||
1882 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100)) | ||||
1883 | .build()); | ||||
1884 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
1885 | |||||
1886 | // Now the MOVE should be getting dispatched normally | ||||
1887 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) | ||||
1888 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110)) | ||||
1889 | .build()); | ||||
1890 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE)); | ||||
1891 | } | ||||
1892 | |||||
1893 | /** | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 1894 | * Hover mouse over a window, and then send ACTION_SCROLL. Ensure both the hover and the scroll |
1895 | * events are delivered to the window. | ||||
1896 | */ | ||||
1897 | TEST_F(InputDispatcherTest, HoverMoveAndScroll) { | ||||
1898 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
1899 | sp<FakeWindowHandle> window = | ||||
1900 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
1901 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
1902 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
1903 | |||||
1904 | // Start hovering in the window | ||||
1905 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) | ||||
1906 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110)) | ||||
1907 | .build()); | ||||
1908 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
1909 | |||||
1910 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) | ||||
1911 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120)) | ||||
1912 | .build()); | ||||
1913 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE)); | ||||
1914 | |||||
1915 | // Scroll with the mouse | ||||
1916 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_SCROLL, AINPUT_SOURCE_MOUSE) | ||||
1917 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120)) | ||||
1918 | .build()); | ||||
1919 | window->consumeMotionEvent(WithMotionAction(ACTION_SCROLL)); | ||||
1920 | } | ||||
1921 | |||||
1922 | using InputDispatcherMultiDeviceTest = InputDispatcherTest; | ||||
1923 | |||||
1924 | /** | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 1925 | * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that |
1926 | * touch is dropped, because stylus should be preferred over touch. | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 1927 | */ |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 1928 | TEST_F(InputDispatcherMultiDeviceTest, StylusDownBlocksTouchDown) { |
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 1929 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 1930 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
1931 | sp<FakeWindowHandle> window = | ||||
1932 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
1933 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
1934 | |||||
1935 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
1936 | |||||
1937 | constexpr int32_t touchDeviceId = 4; | ||||
1938 | constexpr int32_t stylusDeviceId = 2; | ||||
1939 | |||||
1940 | // Stylus down | ||||
1941 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) | ||||
1942 | .deviceId(stylusDeviceId) | ||||
1943 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110)) | ||||
1944 | .build()); | ||||
1945 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); | ||||
1946 | |||||
1947 | // Touch down | ||||
1948 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1949 | .deviceId(touchDeviceId) | ||||
1950 | .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145)) | ||||
1951 | .build()); | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 1952 | |
1953 | // Touch move | ||||
1954 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1955 | .deviceId(touchDeviceId) | ||||
1956 | .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146)) | ||||
1957 | .build()); | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 1958 | // Touch is ignored because stylus is already down |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 1959 | |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 1960 | // Subsequent stylus movements are delivered correctly |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 1961 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) |
1962 | .deviceId(stylusDeviceId) | ||||
1963 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111)) | ||||
1964 | .build()); | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 1965 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId), |
1966 | WithCoords(101, 111))); | ||||
1967 | |||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 1968 | window->assertNoEvents(); |
1969 | } | ||||
1970 | |||||
1971 | /** | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 1972 | * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that |
1973 | * touch is not dropped, because multiple devices are allowed to be active in the same window. | ||||
1974 | */ | ||||
1975 | TEST_F(InputDispatcherMultiDeviceTest, StylusDownDoesNotBlockTouchDown) { | ||||
1976 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
1977 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
1978 | sp<FakeWindowHandle> window = | ||||
1979 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
1980 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
1981 | |||||
1982 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
1983 | |||||
1984 | constexpr int32_t touchDeviceId = 4; | ||||
1985 | constexpr int32_t stylusDeviceId = 2; | ||||
1986 | |||||
1987 | // Stylus down | ||||
1988 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) | ||||
1989 | .deviceId(stylusDeviceId) | ||||
1990 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110)) | ||||
1991 | .build()); | ||||
1992 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); | ||||
1993 | |||||
1994 | // Touch down | ||||
1995 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
1996 | .deviceId(touchDeviceId) | ||||
1997 | .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145)) | ||||
1998 | .build()); | ||||
1999 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
2000 | |||||
2001 | // Touch move | ||||
2002 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2003 | .deviceId(touchDeviceId) | ||||
2004 | .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146)) | ||||
2005 | .build()); | ||||
2006 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); | ||||
2007 | |||||
2008 | // Stylus move | ||||
2009 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) | ||||
2010 | .deviceId(stylusDeviceId) | ||||
2011 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111)) | ||||
2012 | .build()); | ||||
2013 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId), | ||||
2014 | WithCoords(101, 111))); | ||||
2015 | |||||
2016 | window->assertNoEvents(); | ||||
2017 | } | ||||
2018 | |||||
2019 | /** | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2020 | * One window and one spy window. Stylus down on the window. Next, touch from another device goes |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2021 | * down. Ensure that touch is dropped, because stylus should be preferred over touch. |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2022 | * Similar test as above, but with added SPY window. |
2023 | */ | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2024 | TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyBlocksTouchDown) { |
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 2025 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2026 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
2027 | sp<FakeWindowHandle> window = | ||||
2028 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
2029 | sp<FakeWindowHandle> spyWindow = | ||||
2030 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); | ||||
2031 | spyWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
2032 | spyWindow->setTrustedOverlay(true); | ||||
2033 | spyWindow->setSpy(true); | ||||
2034 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
2035 | |||||
2036 | mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); | ||||
2037 | |||||
2038 | constexpr int32_t touchDeviceId = 4; | ||||
2039 | constexpr int32_t stylusDeviceId = 2; | ||||
2040 | |||||
2041 | // Stylus down | ||||
2042 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) | ||||
2043 | .deviceId(stylusDeviceId) | ||||
2044 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110)) | ||||
2045 | .build()); | ||||
2046 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); | ||||
2047 | spyWindow->consumeMotionEvent( | ||||
2048 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); | ||||
2049 | |||||
2050 | // Touch down | ||||
2051 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2052 | .deviceId(touchDeviceId) | ||||
2053 | .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145)) | ||||
2054 | .build()); | ||||
2055 | |||||
2056 | // Touch move | ||||
2057 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2058 | .deviceId(touchDeviceId) | ||||
2059 | .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146)) | ||||
2060 | .build()); | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2061 | |
2062 | // Touch is ignored because stylus is already down | ||||
2063 | |||||
2064 | // Subsequent stylus movements are delivered correctly | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2065 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) |
2066 | .deviceId(stylusDeviceId) | ||||
2067 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111)) | ||||
2068 | .build()); | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2069 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId), |
2070 | WithCoords(101, 111))); | ||||
2071 | spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId), | ||||
2072 | WithCoords(101, 111))); | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2073 | |
2074 | window->assertNoEvents(); | ||||
2075 | spyWindow->assertNoEvents(); | ||||
2076 | } | ||||
2077 | |||||
2078 | /** | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 2079 | * One window and one spy window. Stylus down on the window. Next, touch from another device goes |
2080 | * down. Ensure that touch is not dropped, because multiple devices can be active at the same time. | ||||
2081 | * Similar test as above, but with added SPY window. | ||||
2082 | */ | ||||
2083 | TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyDoesNotBlockTouchDown) { | ||||
2084 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
2085 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
2086 | sp<FakeWindowHandle> window = | ||||
2087 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
2088 | sp<FakeWindowHandle> spyWindow = | ||||
2089 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); | ||||
2090 | spyWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
2091 | spyWindow->setTrustedOverlay(true); | ||||
2092 | spyWindow->setSpy(true); | ||||
2093 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
2094 | |||||
2095 | mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); | ||||
2096 | |||||
2097 | constexpr int32_t touchDeviceId = 4; | ||||
2098 | constexpr int32_t stylusDeviceId = 2; | ||||
2099 | |||||
2100 | // Stylus down | ||||
2101 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) | ||||
2102 | .deviceId(stylusDeviceId) | ||||
2103 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110)) | ||||
2104 | .build()); | ||||
2105 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); | ||||
2106 | spyWindow->consumeMotionEvent( | ||||
2107 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); | ||||
2108 | |||||
2109 | // Touch down | ||||
2110 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2111 | .deviceId(touchDeviceId) | ||||
2112 | .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145)) | ||||
2113 | .build()); | ||||
2114 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
2115 | spyWindow->consumeMotionEvent( | ||||
2116 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
2117 | |||||
2118 | // Touch move | ||||
2119 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2120 | .deviceId(touchDeviceId) | ||||
2121 | .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146)) | ||||
2122 | .build()); | ||||
2123 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); | ||||
2124 | spyWindow->consumeMotionEvent( | ||||
2125 | AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); | ||||
2126 | |||||
2127 | // Subsequent stylus movements are delivered correctly | ||||
2128 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) | ||||
2129 | .deviceId(stylusDeviceId) | ||||
2130 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111)) | ||||
2131 | .build()); | ||||
2132 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId), | ||||
2133 | WithCoords(101, 111))); | ||||
2134 | spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId), | ||||
2135 | WithCoords(101, 111))); | ||||
2136 | |||||
2137 | window->assertNoEvents(); | ||||
2138 | spyWindow->assertNoEvents(); | ||||
2139 | } | ||||
2140 | |||||
2141 | /** | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2142 | * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that |
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 2143 | * touch is dropped, because stylus hover takes precedence. |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2144 | */ |
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 2145 | TEST_F(InputDispatcherMultiDeviceTest, StylusHoverBlocksTouchDown) { |
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 2146 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2147 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
2148 | sp<FakeWindowHandle> window = | ||||
2149 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
2150 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
2151 | |||||
2152 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
2153 | |||||
2154 | constexpr int32_t touchDeviceId = 4; | ||||
2155 | constexpr int32_t stylusDeviceId = 2; | ||||
2156 | |||||
2157 | // Stylus down on the window | ||||
2158 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
2159 | .deviceId(stylusDeviceId) | ||||
2160 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110)) | ||||
2161 | .build()); | ||||
2162 | window->consumeMotionEvent( | ||||
2163 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId))); | ||||
2164 | |||||
2165 | // Touch down on window | ||||
2166 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2167 | .deviceId(touchDeviceId) | ||||
2168 | .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145)) | ||||
2169 | .build()); | ||||
2170 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2171 | .deviceId(touchDeviceId) | ||||
2172 | .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146)) | ||||
2173 | .build()); | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2174 | |
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 2175 | // Touch is ignored because stylus is hovering |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2176 | |
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 2177 | // Subsequent stylus movements are delivered correctly |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2178 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) |
2179 | .deviceId(stylusDeviceId) | ||||
2180 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111)) | ||||
2181 | .build()); | ||||
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 2182 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), |
2183 | WithDeviceId(stylusDeviceId), WithCoords(101, 111))); | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2184 | |
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 2185 | // and subsequent touches continue to be ignored |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2186 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) |
2187 | .deviceId(touchDeviceId) | ||||
2188 | .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147)) | ||||
2189 | .build()); | ||||
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 2190 | window->assertNoEvents(); |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2191 | } |
2192 | |||||
2193 | /** | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 2194 | * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that |
2195 | * touch is not dropped, because stylus hover and touch can be both active at the same time. | ||||
2196 | */ | ||||
2197 | TEST_F(InputDispatcherMultiDeviceTest, StylusHoverDoesNotBlockTouchDown) { | ||||
2198 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
2199 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
2200 | sp<FakeWindowHandle> window = | ||||
2201 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
2202 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
2203 | |||||
2204 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
2205 | |||||
2206 | constexpr int32_t touchDeviceId = 4; | ||||
2207 | constexpr int32_t stylusDeviceId = 2; | ||||
2208 | |||||
2209 | // Stylus down on the window | ||||
2210 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
2211 | .deviceId(stylusDeviceId) | ||||
2212 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110)) | ||||
2213 | .build()); | ||||
2214 | window->consumeMotionEvent( | ||||
2215 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId))); | ||||
2216 | |||||
2217 | // Touch down on window | ||||
2218 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2219 | .deviceId(touchDeviceId) | ||||
2220 | .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145)) | ||||
2221 | .build()); | ||||
2222 | // Touch move on window | ||||
2223 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
2224 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2225 | .deviceId(touchDeviceId) | ||||
2226 | .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146)) | ||||
2227 | .build()); | ||||
2228 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); | ||||
2229 | |||||
2230 | // Subsequent stylus movements are delivered correctly | ||||
2231 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) | ||||
2232 | .deviceId(stylusDeviceId) | ||||
2233 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111)) | ||||
2234 | .build()); | ||||
2235 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), | ||||
2236 | WithDeviceId(stylusDeviceId), WithCoords(101, 111))); | ||||
2237 | |||||
2238 | // and subsequent touches continue to work | ||||
2239 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2240 | .deviceId(touchDeviceId) | ||||
2241 | .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147)) | ||||
2242 | .build()); | ||||
2243 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); | ||||
2244 | window->assertNoEvents(); | ||||
2245 | } | ||||
2246 | |||||
2247 | /** | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2248 | * One window. Touch down on the window. Then, stylus hover on the window from another device. |
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 2249 | * Ensure that touch is canceled, because stylus hover should take precedence. |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2250 | */ |
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 2251 | TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusHover) { |
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 2252 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2253 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
2254 | sp<FakeWindowHandle> window = | ||||
2255 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
2256 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
2257 | |||||
2258 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
2259 | |||||
2260 | constexpr int32_t touchDeviceId = 4; | ||||
2261 | constexpr int32_t stylusDeviceId = 2; | ||||
2262 | |||||
2263 | // Touch down on window | ||||
2264 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2265 | .deviceId(touchDeviceId) | ||||
2266 | .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145)) | ||||
2267 | .build()); | ||||
2268 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2269 | .deviceId(touchDeviceId) | ||||
2270 | .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146)) | ||||
2271 | .build()); | ||||
2272 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
2273 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); | ||||
2274 | |||||
2275 | // Stylus hover on the window | ||||
2276 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
2277 | .deviceId(stylusDeviceId) | ||||
2278 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110)) | ||||
2279 | .build()); | ||||
2280 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) | ||||
2281 | .deviceId(stylusDeviceId) | ||||
2282 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111)) | ||||
2283 | .build()); | ||||
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 2284 | // Stylus hover movement causes touch to be canceled |
2285 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId), | ||||
2286 | WithCoords(141, 146))); | ||||
2287 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER), | ||||
2288 | WithDeviceId(stylusDeviceId), WithCoords(100, 110))); | ||||
2289 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), | ||||
2290 | WithDeviceId(stylusDeviceId), WithCoords(101, 111))); | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2291 | |
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 2292 | // Subsequent touch movements are ignored |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2293 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) |
2294 | .deviceId(touchDeviceId) | ||||
2295 | .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147)) | ||||
2296 | .build()); | ||||
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 2297 | |
2298 | window->assertNoEvents(); | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2299 | } |
2300 | |||||
2301 | /** | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 2302 | * One window. Touch down on the window. Then, stylus hover on the window from another device. |
2303 | * Ensure that touch is not canceled, because stylus hover can be active at the same time as touch. | ||||
2304 | */ | ||||
2305 | TEST_F(InputDispatcherMultiDeviceTest, TouchIsNotCanceledByStylusHover) { | ||||
2306 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
2307 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
2308 | sp<FakeWindowHandle> window = | ||||
2309 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
2310 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
2311 | |||||
2312 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
2313 | |||||
2314 | constexpr int32_t touchDeviceId = 4; | ||||
2315 | constexpr int32_t stylusDeviceId = 2; | ||||
2316 | |||||
2317 | // Touch down on window | ||||
2318 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2319 | .deviceId(touchDeviceId) | ||||
2320 | .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145)) | ||||
2321 | .build()); | ||||
2322 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2323 | .deviceId(touchDeviceId) | ||||
2324 | .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146)) | ||||
2325 | .build()); | ||||
2326 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
2327 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); | ||||
2328 | |||||
2329 | // Stylus hover on the window | ||||
2330 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
2331 | .deviceId(stylusDeviceId) | ||||
2332 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110)) | ||||
2333 | .build()); | ||||
2334 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) | ||||
2335 | .deviceId(stylusDeviceId) | ||||
2336 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111)) | ||||
2337 | .build()); | ||||
2338 | // Stylus hover movement is received normally | ||||
2339 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER), | ||||
2340 | WithDeviceId(stylusDeviceId), WithCoords(100, 110))); | ||||
2341 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), | ||||
2342 | WithDeviceId(stylusDeviceId), WithCoords(101, 111))); | ||||
2343 | |||||
2344 | // Subsequent touch movements also work | ||||
2345 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2346 | .deviceId(touchDeviceId) | ||||
2347 | .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147)) | ||||
2348 | .build()); | ||||
2349 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId), | ||||
2350 | WithCoords(142, 147))); | ||||
2351 | |||||
2352 | window->assertNoEvents(); | ||||
2353 | } | ||||
2354 | |||||
2355 | /** | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2356 | * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that |
2357 | * the latest stylus takes over. That is, old stylus should be canceled and the new stylus should | ||||
2358 | * become active. | ||||
2359 | */ | ||||
2360 | TEST_F(InputDispatcherMultiDeviceTest, LatestStylusWins) { | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 2361 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2362 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
2363 | sp<FakeWindowHandle> window = | ||||
2364 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
2365 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
2366 | |||||
2367 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
2368 | |||||
2369 | constexpr int32_t stylusDeviceId1 = 3; | ||||
2370 | constexpr int32_t stylusDeviceId2 = 5; | ||||
2371 | |||||
2372 | // Touch down on window | ||||
2373 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) | ||||
2374 | .deviceId(stylusDeviceId1) | ||||
2375 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100)) | ||||
2376 | .build()); | ||||
2377 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) | ||||
2378 | .deviceId(stylusDeviceId1) | ||||
2379 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101)) | ||||
2380 | .build()); | ||||
2381 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1))); | ||||
2382 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1))); | ||||
2383 | |||||
2384 | // Second stylus down | ||||
2385 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) | ||||
2386 | .deviceId(stylusDeviceId2) | ||||
2387 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10)) | ||||
2388 | .build()); | ||||
2389 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) | ||||
2390 | .deviceId(stylusDeviceId2) | ||||
2391 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11)) | ||||
2392 | .build()); | ||||
2393 | |||||
2394 | // First stylus is canceled, second one takes over. | ||||
2395 | window->consumeMotionEvent( | ||||
2396 | AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId1))); | ||||
2397 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2))); | ||||
2398 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2))); | ||||
2399 | |||||
2400 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) | ||||
2401 | .deviceId(stylusDeviceId1) | ||||
2402 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102)) | ||||
2403 | .build()); | ||||
2404 | // Subsequent stylus movements are delivered correctly | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2405 | window->assertNoEvents(); |
2406 | } | ||||
2407 | |||||
2408 | /** | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 2409 | * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that |
2410 | * both stylus devices can function simultaneously. | ||||
2411 | */ | ||||
2412 | TEST_F(InputDispatcherMultiDeviceTest, TwoStylusDevicesActiveAtTheSameTime) { | ||||
2413 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
2414 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
2415 | sp<FakeWindowHandle> window = | ||||
2416 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
2417 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
2418 | |||||
2419 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
2420 | |||||
2421 | constexpr int32_t stylusDeviceId1 = 3; | ||||
2422 | constexpr int32_t stylusDeviceId2 = 5; | ||||
2423 | |||||
2424 | // Touch down on window | ||||
2425 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) | ||||
2426 | .deviceId(stylusDeviceId1) | ||||
2427 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100)) | ||||
2428 | .build()); | ||||
2429 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) | ||||
2430 | .deviceId(stylusDeviceId1) | ||||
2431 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101)) | ||||
2432 | .build()); | ||||
2433 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1))); | ||||
2434 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1))); | ||||
2435 | |||||
2436 | // Second stylus down | ||||
2437 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) | ||||
2438 | .deviceId(stylusDeviceId2) | ||||
2439 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10)) | ||||
2440 | .build()); | ||||
2441 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) | ||||
2442 | .deviceId(stylusDeviceId2) | ||||
2443 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11)) | ||||
2444 | .build()); | ||||
2445 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2))); | ||||
2446 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2))); | ||||
2447 | |||||
2448 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) | ||||
2449 | .deviceId(stylusDeviceId1) | ||||
2450 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102)) | ||||
2451 | .build()); | ||||
2452 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1))); | ||||
2453 | window->assertNoEvents(); | ||||
2454 | } | ||||
2455 | |||||
2456 | /** | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2457 | * One window. Touch down on the window. Then, stylus down on the window from another device. |
2458 | * Ensure that is canceled, because stylus down should be preferred over touch. | ||||
2459 | */ | ||||
2460 | TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusDown) { | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 2461 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2462 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
2463 | sp<FakeWindowHandle> window = | ||||
2464 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
2465 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
2466 | |||||
2467 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
2468 | |||||
2469 | constexpr int32_t touchDeviceId = 4; | ||||
2470 | constexpr int32_t stylusDeviceId = 2; | ||||
2471 | |||||
2472 | // Touch down on window | ||||
2473 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2474 | .deviceId(touchDeviceId) | ||||
2475 | .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145)) | ||||
2476 | .build()); | ||||
2477 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2478 | .deviceId(touchDeviceId) | ||||
2479 | .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146)) | ||||
2480 | .build()); | ||||
2481 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
2482 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); | ||||
2483 | |||||
2484 | // Stylus down on the window | ||||
2485 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) | ||||
2486 | .deviceId(stylusDeviceId) | ||||
2487 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110)) | ||||
2488 | .build()); | ||||
2489 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId))); | ||||
2490 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); | ||||
2491 | |||||
2492 | // Subsequent stylus movements are delivered correctly | ||||
2493 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) | ||||
2494 | .deviceId(stylusDeviceId) | ||||
2495 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111)) | ||||
2496 | .build()); | ||||
2497 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId), | ||||
2498 | WithCoords(101, 111))); | ||||
2499 | } | ||||
2500 | |||||
2501 | /** | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 2502 | * One window. Touch down on the window. Then, stylus down on the window from another device. |
2503 | * Ensure that both touch and stylus are functioning independently. | ||||
2504 | */ | ||||
2505 | TEST_F(InputDispatcherMultiDeviceTest, TouchIsNotCanceledByStylusDown) { | ||||
2506 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
2507 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
2508 | sp<FakeWindowHandle> window = | ||||
2509 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
2510 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
2511 | |||||
2512 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
2513 | |||||
2514 | constexpr int32_t touchDeviceId = 4; | ||||
2515 | constexpr int32_t stylusDeviceId = 2; | ||||
2516 | |||||
2517 | // Touch down on window | ||||
2518 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2519 | .deviceId(touchDeviceId) | ||||
2520 | .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145)) | ||||
2521 | .build()); | ||||
2522 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2523 | .deviceId(touchDeviceId) | ||||
2524 | .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146)) | ||||
2525 | .build()); | ||||
2526 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
2527 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); | ||||
2528 | |||||
2529 | // Stylus down on the window | ||||
2530 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) | ||||
2531 | .deviceId(stylusDeviceId) | ||||
2532 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110)) | ||||
2533 | .build()); | ||||
2534 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); | ||||
2535 | |||||
2536 | // Subsequent stylus movements are delivered correctly | ||||
2537 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) | ||||
2538 | .deviceId(stylusDeviceId) | ||||
2539 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111)) | ||||
2540 | .build()); | ||||
2541 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId), | ||||
2542 | WithCoords(101, 111))); | ||||
2543 | |||||
2544 | // Touch continues to work too | ||||
2545 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2546 | .deviceId(touchDeviceId) | ||||
2547 | .pointer(PointerBuilder(0, ToolType::FINGER).x(148).y(149)) | ||||
2548 | .build()); | ||||
2549 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); | ||||
2550 | } | ||||
2551 | |||||
2552 | /** | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 2553 | * Two windows: a window on the left and a window on the right. |
2554 | * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains | ||||
2555 | * down. Then, on the left window, also place second touch pointer down. | ||||
2556 | * This test tries to reproduce a crash. | ||||
2557 | * In the buggy implementation, second pointer down on the left window would cause a crash. | ||||
2558 | */ | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 2559 | TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch_legacy) { |
2560 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 2561 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
2562 | sp<FakeWindowHandle> leftWindow = | ||||
2563 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); | ||||
2564 | leftWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
2565 | |||||
2566 | sp<FakeWindowHandle> rightWindow = | ||||
2567 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); | ||||
2568 | rightWindow->setFrame(Rect(200, 0, 400, 200)); | ||||
2569 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 2570 | mDispatcher->onWindowInfosChanged( |
2571 | {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 2572 | |
2573 | const int32_t touchDeviceId = 4; | ||||
2574 | const int32_t mouseDeviceId = 6; | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 2575 | |
2576 | // Start hovering over the left window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 2577 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) |
2578 | .deviceId(mouseDeviceId) | ||||
2579 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) | ||||
2580 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 2581 | leftWindow->consumeMotionEvent( |
2582 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); | ||||
2583 | |||||
2584 | // Mouse down on left window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 2585 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) |
2586 | .deviceId(mouseDeviceId) | ||||
2587 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
2588 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) | ||||
2589 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 2590 | |
2591 | leftWindow->consumeMotionEvent( | ||||
2592 | AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId))); | ||||
2593 | leftWindow->consumeMotionEvent( | ||||
2594 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); | ||||
2595 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 2596 | mDispatcher->notifyMotion( |
2597 | MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) | ||||
2598 | .deviceId(mouseDeviceId) | ||||
2599 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
2600 | .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
2601 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) | ||||
2602 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 2603 | leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); |
2604 | |||||
2605 | // First touch pointer down on right window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 2606 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
2607 | .deviceId(touchDeviceId) | ||||
2608 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
2609 | .build()); | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2610 | leftWindow->assertNoEvents(); |
2611 | |||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 2612 | rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); |
2613 | |||||
2614 | // Second touch pointer down on left window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 2615 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
2616 | .deviceId(touchDeviceId) | ||||
2617 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
2618 | .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100)) | ||||
2619 | .build()); | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2620 | // Since this is now a new splittable pointer going down on the left window, and it's coming |
2621 | // from a different device, the current gesture in the left window (pointer down) should first | ||||
2622 | // be canceled. | ||||
2623 | leftWindow->consumeMotionEvent( | ||||
2624 | AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(mouseDeviceId))); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 2625 | leftWindow->consumeMotionEvent( |
2626 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
2627 | // This MOVE event is not necessary (doesn't carry any new information), but it's there in the | ||||
2628 | // current implementation. | ||||
2629 | const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}}; | ||||
2630 | rightWindow->consumeMotionEvent( | ||||
2631 | AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers))); | ||||
2632 | |||||
2633 | leftWindow->assertNoEvents(); | ||||
2634 | rightWindow->assertNoEvents(); | ||||
2635 | } | ||||
2636 | |||||
2637 | /** | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2638 | * Two windows: a window on the left and a window on the right. |
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 2639 | * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains |
2640 | * down. Then, on the left window, also place second touch pointer down. | ||||
2641 | * This test tries to reproduce a crash. | ||||
2642 | * In the buggy implementation, second pointer down on the left window would cause a crash. | ||||
2643 | */ | ||||
2644 | TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch) { | ||||
2645 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
2646 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
2647 | sp<FakeWindowHandle> leftWindow = | ||||
2648 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); | ||||
2649 | leftWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
2650 | |||||
2651 | sp<FakeWindowHandle> rightWindow = | ||||
2652 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); | ||||
2653 | rightWindow->setFrame(Rect(200, 0, 400, 200)); | ||||
2654 | |||||
2655 | mDispatcher->onWindowInfosChanged( | ||||
2656 | {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); | ||||
2657 | |||||
2658 | const int32_t touchDeviceId = 4; | ||||
2659 | const int32_t mouseDeviceId = 6; | ||||
2660 | |||||
2661 | // Start hovering over the left window | ||||
2662 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) | ||||
2663 | .deviceId(mouseDeviceId) | ||||
2664 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) | ||||
2665 | .build()); | ||||
2666 | leftWindow->consumeMotionEvent( | ||||
2667 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); | ||||
2668 | |||||
2669 | // Mouse down on left window | ||||
2670 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) | ||||
2671 | .deviceId(mouseDeviceId) | ||||
2672 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
2673 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) | ||||
2674 | .build()); | ||||
2675 | |||||
2676 | leftWindow->consumeMotionEvent( | ||||
2677 | AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId))); | ||||
2678 | leftWindow->consumeMotionEvent( | ||||
2679 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); | ||||
2680 | |||||
2681 | mDispatcher->notifyMotion( | ||||
2682 | MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) | ||||
2683 | .deviceId(mouseDeviceId) | ||||
2684 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
2685 | .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
2686 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) | ||||
2687 | .build()); | ||||
2688 | leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); | ||||
2689 | |||||
2690 | // First touch pointer down on right window | ||||
2691 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2692 | .deviceId(touchDeviceId) | ||||
2693 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
2694 | .build()); | ||||
2695 | leftWindow->assertNoEvents(); | ||||
2696 | |||||
2697 | rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); | ||||
2698 | |||||
2699 | // Second touch pointer down on left window | ||||
2700 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2701 | .deviceId(touchDeviceId) | ||||
2702 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
2703 | .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100)) | ||||
2704 | .build()); | ||||
2705 | // Since this is now a new splittable pointer going down on the left window, and it's coming | ||||
2706 | // from a different device, it will be split and delivered to left window separately. | ||||
2707 | leftWindow->consumeMotionEvent( | ||||
2708 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
2709 | // This MOVE event is not necessary (doesn't carry any new information), but it's there in the | ||||
2710 | // current implementation. | ||||
2711 | const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}}; | ||||
2712 | rightWindow->consumeMotionEvent( | ||||
2713 | AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers))); | ||||
2714 | |||||
2715 | leftWindow->assertNoEvents(); | ||||
2716 | rightWindow->assertNoEvents(); | ||||
2717 | } | ||||
2718 | |||||
2719 | /** | ||||
2720 | * Two windows: a window on the left and a window on the right. | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2721 | * Mouse is hovered on the left window and stylus is hovered on the right window. |
2722 | */ | ||||
2723 | TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHover) { | ||||
2724 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
2725 | sp<FakeWindowHandle> leftWindow = | ||||
2726 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); | ||||
2727 | leftWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
2728 | |||||
2729 | sp<FakeWindowHandle> rightWindow = | ||||
2730 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); | ||||
2731 | rightWindow->setFrame(Rect(200, 0, 400, 200)); | ||||
2732 | |||||
2733 | mDispatcher->onWindowInfosChanged( | ||||
2734 | {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); | ||||
2735 | |||||
2736 | const int32_t stylusDeviceId = 3; | ||||
2737 | const int32_t mouseDeviceId = 6; | ||||
2738 | |||||
2739 | // Start hovering over the left window | ||||
2740 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) | ||||
2741 | .deviceId(mouseDeviceId) | ||||
2742 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110)) | ||||
2743 | .build()); | ||||
2744 | leftWindow->consumeMotionEvent( | ||||
2745 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); | ||||
2746 | |||||
2747 | // Stylus hovered on right window | ||||
2748 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
2749 | .deviceId(stylusDeviceId) | ||||
2750 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(300).y(100)) | ||||
2751 | .build()); | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2752 | rightWindow->consumeMotionEvent( |
2753 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId))); | ||||
2754 | |||||
2755 | // Subsequent HOVER_MOVE events are dispatched correctly. | ||||
2756 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) | ||||
2757 | .deviceId(mouseDeviceId) | ||||
2758 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120)) | ||||
2759 | .build()); | ||||
2760 | leftWindow->consumeMotionEvent( | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2761 | AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(mouseDeviceId))); |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2762 | |
2763 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) | ||||
2764 | .deviceId(stylusDeviceId) | ||||
2765 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(310).y(110)) | ||||
2766 | .build()); | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2767 | rightWindow->consumeMotionEvent( |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2768 | AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId))); |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2769 | |
2770 | leftWindow->assertNoEvents(); | ||||
2771 | rightWindow->assertNoEvents(); | ||||
2772 | } | ||||
2773 | |||||
2774 | /** | ||||
2775 | * Three windows: a window on the left and a window on the right. | ||||
2776 | * And a spy window that's positioned above all of them. | ||||
2777 | * Stylus down on the left window and remains down. Touch goes down on the right and remains down. | ||||
2778 | * Check the stream that's received by the spy. | ||||
2779 | */ | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 2780 | TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy_legacy) { |
2781 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2782 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
2783 | |||||
2784 | sp<FakeWindowHandle> spyWindow = | ||||
2785 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); | ||||
2786 | spyWindow->setFrame(Rect(0, 0, 400, 400)); | ||||
2787 | spyWindow->setTrustedOverlay(true); | ||||
2788 | spyWindow->setSpy(true); | ||||
2789 | |||||
2790 | sp<FakeWindowHandle> leftWindow = | ||||
2791 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); | ||||
2792 | leftWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
2793 | |||||
2794 | sp<FakeWindowHandle> rightWindow = | ||||
2795 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); | ||||
2796 | |||||
2797 | rightWindow->setFrame(Rect(200, 0, 400, 200)); | ||||
2798 | |||||
2799 | mDispatcher->onWindowInfosChanged( | ||||
2800 | {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); | ||||
2801 | |||||
2802 | const int32_t stylusDeviceId = 1; | ||||
2803 | const int32_t touchDeviceId = 2; | ||||
2804 | |||||
2805 | // Stylus down on the left window | ||||
2806 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) | ||||
2807 | .deviceId(stylusDeviceId) | ||||
2808 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100)) | ||||
2809 | .build()); | ||||
2810 | leftWindow->consumeMotionEvent( | ||||
2811 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); | ||||
2812 | spyWindow->consumeMotionEvent( | ||||
2813 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); | ||||
2814 | |||||
2815 | // Touch down on the right window | ||||
2816 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2817 | .deviceId(touchDeviceId) | ||||
2818 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
2819 | .build()); | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2820 | leftWindow->assertNoEvents(); |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2821 | rightWindow->consumeMotionEvent( |
2822 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2823 | |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2824 | // Spy window does not receive touch events, because stylus events take precedence, and it |
2825 | // already has an active stylus gesture. | ||||
2826 | |||||
2827 | // Stylus movements continue. They should be delivered to the left window and to the spy window | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2828 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) |
2829 | .deviceId(stylusDeviceId) | ||||
2830 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110)) | ||||
2831 | .build()); | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2832 | leftWindow->consumeMotionEvent( |
2833 | AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId))); | ||||
2834 | spyWindow->consumeMotionEvent( | ||||
2835 | AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId))); | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2836 | |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2837 | // Further MOVE events keep going to the right window only |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2838 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) |
2839 | .deviceId(touchDeviceId) | ||||
2840 | .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110)) | ||||
2841 | .build()); | ||||
2842 | rightWindow->consumeMotionEvent( | ||||
2843 | AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2844 | |
2845 | spyWindow->assertNoEvents(); | ||||
2846 | leftWindow->assertNoEvents(); | ||||
2847 | rightWindow->assertNoEvents(); | ||||
2848 | } | ||||
2849 | |||||
2850 | /** | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 2851 | * Three windows: a window on the left and a window on the right. |
2852 | * And a spy window that's positioned above all of them. | ||||
2853 | * Stylus down on the left window and remains down. Touch goes down on the right and remains down. | ||||
2854 | * Check the stream that's received by the spy. | ||||
2855 | */ | ||||
2856 | TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy) { | ||||
2857 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
2858 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
2859 | |||||
2860 | sp<FakeWindowHandle> spyWindow = | ||||
2861 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); | ||||
2862 | spyWindow->setFrame(Rect(0, 0, 400, 400)); | ||||
2863 | spyWindow->setTrustedOverlay(true); | ||||
2864 | spyWindow->setSpy(true); | ||||
2865 | |||||
2866 | sp<FakeWindowHandle> leftWindow = | ||||
2867 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); | ||||
2868 | leftWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
2869 | |||||
2870 | sp<FakeWindowHandle> rightWindow = | ||||
2871 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); | ||||
2872 | |||||
2873 | rightWindow->setFrame(Rect(200, 0, 400, 200)); | ||||
2874 | |||||
2875 | mDispatcher->onWindowInfosChanged( | ||||
2876 | {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); | ||||
2877 | |||||
2878 | const int32_t stylusDeviceId = 1; | ||||
2879 | const int32_t touchDeviceId = 2; | ||||
2880 | |||||
2881 | // Stylus down on the left window | ||||
2882 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) | ||||
2883 | .deviceId(stylusDeviceId) | ||||
2884 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100)) | ||||
2885 | .build()); | ||||
2886 | leftWindow->consumeMotionEvent( | ||||
2887 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); | ||||
2888 | spyWindow->consumeMotionEvent( | ||||
2889 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); | ||||
2890 | |||||
2891 | // Touch down on the right window | ||||
2892 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2893 | .deviceId(touchDeviceId) | ||||
2894 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
2895 | .build()); | ||||
2896 | leftWindow->assertNoEvents(); | ||||
2897 | rightWindow->consumeMotionEvent( | ||||
2898 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
2899 | spyWindow->consumeMotionEvent( | ||||
2900 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
2901 | |||||
2902 | // Stylus movements continue. They should be delivered to the left window and to the spy window | ||||
2903 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) | ||||
2904 | .deviceId(stylusDeviceId) | ||||
2905 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110)) | ||||
2906 | .build()); | ||||
2907 | leftWindow->consumeMotionEvent( | ||||
2908 | AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId))); | ||||
2909 | spyWindow->consumeMotionEvent( | ||||
2910 | AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId))); | ||||
2911 | |||||
2912 | // Further touch MOVE events keep going to the right window and to the spy | ||||
2913 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
2914 | .deviceId(touchDeviceId) | ||||
2915 | .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110)) | ||||
2916 | .build()); | ||||
2917 | rightWindow->consumeMotionEvent( | ||||
2918 | AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); | ||||
2919 | spyWindow->consumeMotionEvent( | ||||
2920 | AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); | ||||
2921 | |||||
2922 | spyWindow->assertNoEvents(); | ||||
2923 | leftWindow->assertNoEvents(); | ||||
2924 | rightWindow->assertNoEvents(); | ||||
2925 | } | ||||
2926 | |||||
2927 | /** | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2928 | * Three windows: a window on the left, a window on the right, and a spy window positioned above |
2929 | * both. | ||||
2930 | * Check hover in left window and touch down in the right window. | ||||
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 2931 | * At first, spy should receive hover. Spy shouldn't receive touch while stylus is hovering. |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2932 | * At the same time, left and right should be getting independent streams of hovering and touch, |
2933 | * respectively. | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2934 | */ |
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 2935 | TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverBlocksTouchWithSpy) { |
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 2936 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2937 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
2938 | |||||
2939 | sp<FakeWindowHandle> spyWindow = | ||||
2940 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); | ||||
2941 | spyWindow->setFrame(Rect(0, 0, 400, 400)); | ||||
2942 | spyWindow->setTrustedOverlay(true); | ||||
2943 | spyWindow->setSpy(true); | ||||
2944 | |||||
2945 | sp<FakeWindowHandle> leftWindow = | ||||
2946 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); | ||||
2947 | leftWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
2948 | |||||
2949 | sp<FakeWindowHandle> rightWindow = | ||||
2950 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); | ||||
2951 | rightWindow->setFrame(Rect(200, 0, 400, 200)); | ||||
2952 | |||||
2953 | mDispatcher->onWindowInfosChanged( | ||||
2954 | {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); | ||||
2955 | |||||
2956 | const int32_t stylusDeviceId = 1; | ||||
2957 | const int32_t touchDeviceId = 2; | ||||
2958 | |||||
2959 | // Stylus hover on the left window | ||||
2960 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
2961 | .deviceId(stylusDeviceId) | ||||
2962 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100)) | ||||
2963 | .build()); | ||||
2964 | leftWindow->consumeMotionEvent( | ||||
2965 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId))); | ||||
2966 | spyWindow->consumeMotionEvent( | ||||
2967 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId))); | ||||
2968 | |||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2969 | // Touch down on the right window. Spy doesn't receive this touch because it already has |
2970 | // stylus hovering there. | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2971 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
2972 | .deviceId(touchDeviceId) | ||||
2973 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
2974 | .build()); | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2975 | leftWindow->assertNoEvents(); |
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 2976 | spyWindow->assertNoEvents(); |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2977 | rightWindow->consumeMotionEvent( |
2978 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
2979 | |||||
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 2980 | // Stylus movements continue. They should be delivered to the left window and the spy. |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2981 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) |
2982 | .deviceId(stylusDeviceId) | ||||
2983 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110)) | ||||
2984 | .build()); | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 2985 | leftWindow->consumeMotionEvent( |
2986 | AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId))); | ||||
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 2987 | spyWindow->consumeMotionEvent( |
2988 | AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId))); | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2989 | |
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 2990 | // Touch movements continue. They should be delivered to the right window only |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2991 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) |
2992 | .deviceId(touchDeviceId) | ||||
2993 | .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101)) | ||||
2994 | .build()); | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 2995 | rightWindow->consumeMotionEvent( |
2996 | AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); | ||||
2997 | |||||
2998 | spyWindow->assertNoEvents(); | ||||
2999 | leftWindow->assertNoEvents(); | ||||
3000 | rightWindow->assertNoEvents(); | ||||
3001 | } | ||||
3002 | |||||
3003 | /** | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 3004 | * Three windows: a window on the left, a window on the right, and a spy window positioned above |
3005 | * both. | ||||
3006 | * Check hover in left window and touch down in the right window. | ||||
3007 | * At first, spy should receive hover. Next, spy should receive touch. | ||||
3008 | * At the same time, left and right should be getting independent streams of hovering and touch, | ||||
3009 | * respectively. | ||||
3010 | */ | ||||
3011 | TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverDoesNotBlockTouchWithSpy) { | ||||
3012 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
3013 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
3014 | |||||
3015 | sp<FakeWindowHandle> spyWindow = | ||||
3016 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); | ||||
3017 | spyWindow->setFrame(Rect(0, 0, 400, 400)); | ||||
3018 | spyWindow->setTrustedOverlay(true); | ||||
3019 | spyWindow->setSpy(true); | ||||
3020 | |||||
3021 | sp<FakeWindowHandle> leftWindow = | ||||
3022 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); | ||||
3023 | leftWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
3024 | |||||
3025 | sp<FakeWindowHandle> rightWindow = | ||||
3026 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); | ||||
3027 | rightWindow->setFrame(Rect(200, 0, 400, 200)); | ||||
3028 | |||||
3029 | mDispatcher->onWindowInfosChanged( | ||||
3030 | {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); | ||||
3031 | |||||
3032 | const int32_t stylusDeviceId = 1; | ||||
3033 | const int32_t touchDeviceId = 2; | ||||
3034 | |||||
3035 | // Stylus hover on the left window | ||||
3036 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
3037 | .deviceId(stylusDeviceId) | ||||
3038 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100)) | ||||
3039 | .build()); | ||||
3040 | leftWindow->consumeMotionEvent( | ||||
3041 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId))); | ||||
3042 | spyWindow->consumeMotionEvent( | ||||
3043 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId))); | ||||
3044 | |||||
3045 | // Touch down on the right window. | ||||
3046 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3047 | .deviceId(touchDeviceId) | ||||
3048 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
3049 | .build()); | ||||
3050 | leftWindow->assertNoEvents(); | ||||
3051 | spyWindow->consumeMotionEvent( | ||||
3052 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
3053 | rightWindow->consumeMotionEvent( | ||||
3054 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
3055 | |||||
3056 | // Stylus movements continue. They should be delivered to the left window and the spy. | ||||
3057 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) | ||||
3058 | .deviceId(stylusDeviceId) | ||||
3059 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110)) | ||||
3060 | .build()); | ||||
3061 | leftWindow->consumeMotionEvent( | ||||
3062 | AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId))); | ||||
3063 | spyWindow->consumeMotionEvent( | ||||
3064 | AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId))); | ||||
3065 | |||||
3066 | // Touch movements continue. They should be delivered to the right window and the spy | ||||
3067 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3068 | .deviceId(touchDeviceId) | ||||
3069 | .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101)) | ||||
3070 | .build()); | ||||
3071 | rightWindow->consumeMotionEvent( | ||||
3072 | AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); | ||||
3073 | spyWindow->consumeMotionEvent( | ||||
3074 | AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); | ||||
3075 | |||||
3076 | spyWindow->assertNoEvents(); | ||||
3077 | leftWindow->assertNoEvents(); | ||||
3078 | rightWindow->assertNoEvents(); | ||||
3079 | } | ||||
3080 | |||||
3081 | /** | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3082 | * On a single window, use two different devices: mouse and touch. |
3083 | * Touch happens first, with two pointers going down, and then the first pointer leaving. | ||||
3084 | * Mouse is clicked next, which causes the touch stream to be aborted with ACTION_CANCEL. | ||||
3085 | * Finally, a second touch pointer goes down again. Ensure the second touch pointer is ignored, | ||||
3086 | * because the mouse is currently down, and a POINTER_DOWN event from the touchscreen does not | ||||
3087 | * represent a new gesture. | ||||
3088 | */ | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 3089 | TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown_legacy) { |
3090 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3091 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
3092 | sp<FakeWindowHandle> window = | ||||
3093 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
3094 | window->setFrame(Rect(0, 0, 400, 400)); | ||||
3095 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 3096 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3097 | |
3098 | const int32_t touchDeviceId = 4; | ||||
3099 | const int32_t mouseDeviceId = 6; | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3100 | |
Siarhei Vishniakou | 4e1ffa5 | 2023-02-21 11:50:34 -0800 | [diff] [blame] | 3101 | // First touch pointer down |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3102 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
3103 | .deviceId(touchDeviceId) | ||||
3104 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
3105 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3106 | // Second touch pointer down |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3107 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
3108 | .deviceId(touchDeviceId) | ||||
3109 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
3110 | .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100)) | ||||
3111 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3112 | // First touch pointer lifts. The second one remains down |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3113 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN) |
3114 | .deviceId(touchDeviceId) | ||||
3115 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
3116 | .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100)) | ||||
3117 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3118 | window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); |
3119 | window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); | ||||
3120 | window->consumeMotionEvent(WithMotionAction(POINTER_0_UP)); | ||||
3121 | |||||
3122 | // Mouse down. The touch should be canceled | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3123 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) |
3124 | .deviceId(mouseDeviceId) | ||||
3125 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
3126 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100)) | ||||
3127 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3128 | |
3129 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId), | ||||
Siarhei Vishniakou | 82dc042 | 2023-02-17 23:12:52 -0800 | [diff] [blame] | 3130 | WithPointerCount(1u))); |
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3131 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); |
3132 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3133 | mDispatcher->notifyMotion( |
3134 | MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) | ||||
3135 | .deviceId(mouseDeviceId) | ||||
3136 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
3137 | .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
3138 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100)) | ||||
3139 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3140 | window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); |
3141 | |||||
3142 | // Second touch pointer down. | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3143 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
3144 | .deviceId(touchDeviceId) | ||||
3145 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
3146 | .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100)) | ||||
3147 | .build()); | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 3148 | // Since we already canceled this touch gesture, it will be ignored until a completely new |
3149 | // gesture is started. This is easier to implement than trying to keep track of the new pointer | ||||
3150 | // and generating an ACTION_DOWN instead of ACTION_POINTER_DOWN. | ||||
3151 | // However, mouse movements should continue to work. | ||||
3152 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE) | ||||
3153 | .deviceId(mouseDeviceId) | ||||
3154 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
3155 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110)) | ||||
3156 | .build()); | ||||
3157 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId))); | ||||
3158 | |||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3159 | window->assertNoEvents(); |
3160 | } | ||||
3161 | |||||
3162 | /** | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 3163 | * On a single window, use two different devices: mouse and touch. |
3164 | * Touch happens first, with two pointers going down, and then the first pointer leaving. | ||||
3165 | * Mouse is clicked next, which should not interfere with the touch stream. | ||||
3166 | * Finally, a second touch pointer goes down again. Ensure the second touch pointer is also | ||||
3167 | * delivered correctly. | ||||
3168 | */ | ||||
3169 | TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown) { | ||||
3170 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
3171 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
3172 | sp<FakeWindowHandle> window = | ||||
3173 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
3174 | window->setFrame(Rect(0, 0, 400, 400)); | ||||
3175 | |||||
3176 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
3177 | |||||
3178 | const int32_t touchDeviceId = 4; | ||||
3179 | const int32_t mouseDeviceId = 6; | ||||
3180 | |||||
3181 | // First touch pointer down | ||||
3182 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3183 | .deviceId(touchDeviceId) | ||||
3184 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
3185 | .build()); | ||||
3186 | // Second touch pointer down | ||||
3187 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3188 | .deviceId(touchDeviceId) | ||||
3189 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
3190 | .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100)) | ||||
3191 | .build()); | ||||
3192 | // First touch pointer lifts. The second one remains down | ||||
3193 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3194 | .deviceId(touchDeviceId) | ||||
3195 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
3196 | .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100)) | ||||
3197 | .build()); | ||||
3198 | window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); | ||||
3199 | window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); | ||||
3200 | window->consumeMotionEvent(WithMotionAction(POINTER_0_UP)); | ||||
3201 | |||||
3202 | // Mouse down | ||||
3203 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) | ||||
3204 | .deviceId(mouseDeviceId) | ||||
3205 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
3206 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100)) | ||||
3207 | .build()); | ||||
3208 | |||||
3209 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); | ||||
3210 | |||||
3211 | mDispatcher->notifyMotion( | ||||
3212 | MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) | ||||
3213 | .deviceId(mouseDeviceId) | ||||
3214 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
3215 | .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
3216 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100)) | ||||
3217 | .build()); | ||||
3218 | window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); | ||||
3219 | |||||
3220 | // Second touch pointer down. | ||||
3221 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3222 | .deviceId(touchDeviceId) | ||||
3223 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
3224 | .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100)) | ||||
3225 | .build()); | ||||
3226 | window->consumeMotionEvent(AllOf(WithMotionAction(POINTER_0_DOWN), WithDeviceId(touchDeviceId), | ||||
3227 | WithPointerCount(2u))); | ||||
3228 | |||||
3229 | // Mouse movements should continue to work | ||||
3230 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE) | ||||
3231 | .deviceId(mouseDeviceId) | ||||
3232 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
3233 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110)) | ||||
3234 | .build()); | ||||
3235 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId))); | ||||
3236 | |||||
3237 | window->assertNoEvents(); | ||||
3238 | } | ||||
3239 | |||||
3240 | /** | ||||
Siarhei Vishniakou | 56e7909 | 2023-02-21 19:13:16 -0800 | [diff] [blame] | 3241 | * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event cancels |
3242 | * the injected event. | ||||
3243 | */ | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 3244 | TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent_legacy) { |
3245 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); | ||||
Siarhei Vishniakou | 56e7909 | 2023-02-21 19:13:16 -0800 | [diff] [blame] | 3246 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
3247 | sp<FakeWindowHandle> window = | ||||
3248 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
3249 | window->setFrame(Rect(0, 0, 400, 400)); | ||||
3250 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 3251 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | 56e7909 | 2023-02-21 19:13:16 -0800 | [diff] [blame] | 3252 | |
3253 | const int32_t touchDeviceId = 4; | ||||
Siarhei Vishniakou | 56e7909 | 2023-02-21 19:13:16 -0800 | [diff] [blame] | 3254 | // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after |
3255 | // completion. | ||||
3256 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3257 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 56e7909 | 2023-02-21 19:13:16 -0800 | [diff] [blame] | 3258 | MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) |
3259 | .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3260 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50)) |
Siarhei Vishniakou | 56e7909 | 2023-02-21 19:13:16 -0800 | [diff] [blame] | 3261 | .build())); |
3262 | window->consumeMotionEvent( | ||||
3263 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID))); | ||||
3264 | |||||
3265 | // Now a real touch comes. Rather than crashing or dropping the real event, the injected pointer | ||||
3266 | // should be canceled and the new gesture should take over. | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3267 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
3268 | .deviceId(touchDeviceId) | ||||
3269 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
3270 | .build()); | ||||
Siarhei Vishniakou | 56e7909 | 2023-02-21 19:13:16 -0800 | [diff] [blame] | 3271 | |
3272 | window->consumeMotionEvent( | ||||
3273 | AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(VIRTUAL_KEYBOARD_ID))); | ||||
3274 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
3275 | } | ||||
3276 | |||||
3277 | /** | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 3278 | * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event runs |
3279 | * parallel to the injected event. | ||||
3280 | */ | ||||
3281 | TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent) { | ||||
3282 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
3283 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
3284 | sp<FakeWindowHandle> window = | ||||
3285 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
3286 | window->setFrame(Rect(0, 0, 400, 400)); | ||||
3287 | |||||
3288 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
3289 | |||||
3290 | const int32_t touchDeviceId = 4; | ||||
3291 | // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after | ||||
3292 | // completion. | ||||
3293 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
3294 | injectMotionEvent(*mDispatcher, | ||||
3295 | MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) | ||||
3296 | .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) | ||||
3297 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50)) | ||||
3298 | .build())); | ||||
3299 | window->consumeMotionEvent( | ||||
3300 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID))); | ||||
3301 | |||||
3302 | // Now a real touch comes. The injected pointer will remain, and the new gesture will also be | ||||
3303 | // allowed through. | ||||
3304 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3305 | .deviceId(touchDeviceId) | ||||
3306 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
3307 | .build()); | ||||
3308 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
3309 | } | ||||
3310 | |||||
3311 | /** | ||||
Siarhei Vishniakou | 6464e46 | 2023-02-06 18:57:59 -0800 | [diff] [blame] | 3312 | * 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 Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 3325 | TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch_legacy) { |
3326 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); | ||||
Siarhei Vishniakou | 6464e46 | 2023-02-06 18:57:59 -0800 | [diff] [blame] | 3327 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
3328 | sp<FakeWindowHandle> leftWindow = | ||||
3329 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); | ||||
3330 | leftWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
3331 | |||||
3332 | sp<FakeWindowHandle> rightWindow = | ||||
3333 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); | ||||
3334 | rightWindow->setFrame(Rect(200, 0, 400, 200)); | ||||
3335 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 3336 | mDispatcher->onWindowInfosChanged( |
3337 | {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | 6464e46 | 2023-02-06 18:57:59 -0800 | [diff] [blame] | 3338 | |
3339 | const int32_t mouseDeviceId = 6; | ||||
3340 | const int32_t touchDeviceId = 4; | ||||
3341 | // Hover over the left window. Keep the cursor there. | ||||
3342 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3343 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 6464e46 | 2023-02-06 18:57:59 -0800 | [diff] [blame] | 3344 | MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, |
3345 | AINPUT_SOURCE_MOUSE) | ||||
3346 | .deviceId(mouseDeviceId) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3347 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50)) |
Siarhei Vishniakou | 6464e46 | 2023-02-06 18:57:59 -0800 | [diff] [blame] | 3348 | .build())); |
3349 | leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); | ||||
3350 | |||||
3351 | // Tap on left window | ||||
3352 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3353 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 6464e46 | 2023-02-06 18:57:59 -0800 | [diff] [blame] | 3354 | MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, |
3355 | AINPUT_SOURCE_TOUCHSCREEN) | ||||
3356 | .deviceId(touchDeviceId) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3357 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) |
Siarhei Vishniakou | 6464e46 | 2023-02-06 18:57:59 -0800 | [diff] [blame] | 3358 | .build())); |
3359 | |||||
3360 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3361 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 6464e46 | 2023-02-06 18:57:59 -0800 | [diff] [blame] | 3362 | MotionEventBuilder(AMOTION_EVENT_ACTION_UP, |
3363 | AINPUT_SOURCE_TOUCHSCREEN) | ||||
3364 | .deviceId(touchDeviceId) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3365 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) |
Siarhei Vishniakou | 6464e46 | 2023-02-06 18:57:59 -0800 | [diff] [blame] | 3366 | .build())); |
3367 | leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); | ||||
3368 | leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); | ||||
3369 | leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP)); | ||||
3370 | |||||
3371 | // First finger down on right window | ||||
3372 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3373 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 6464e46 | 2023-02-06 18:57:59 -0800 | [diff] [blame] | 3374 | MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, |
3375 | AINPUT_SOURCE_TOUCHSCREEN) | ||||
3376 | .deviceId(touchDeviceId) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3377 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) |
Siarhei Vishniakou | 6464e46 | 2023-02-06 18:57:59 -0800 | [diff] [blame] | 3378 | .build())); |
3379 | rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); | ||||
3380 | |||||
3381 | // Second finger down on the left window | ||||
3382 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3383 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 6464e46 | 2023-02-06 18:57:59 -0800 | [diff] [blame] | 3384 | MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
3385 | .deviceId(touchDeviceId) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3386 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) |
3387 | .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100)) | ||||
Siarhei Vishniakou | 6464e46 | 2023-02-06 18:57:59 -0800 | [diff] [blame] | 3388 | .build())); |
3389 | leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); | ||||
3390 | rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE)); | ||||
3391 | |||||
3392 | // No more events | ||||
3393 | leftWindow->assertNoEvents(); | ||||
3394 | rightWindow->assertNoEvents(); | ||||
3395 | } | ||||
3396 | |||||
3397 | /** | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 3398 | * This test is similar to the test above, but the sequence of injected events is different. |
3399 | * | ||||
3400 | * Two windows: a window on the left and a window on the right. | ||||
3401 | * Mouse is hovered over the left window. | ||||
3402 | * Next, we tap on the left window, where the cursor was last seen. | ||||
3403 | * | ||||
3404 | * After that, we send one finger down onto the right window, and then a second finger down onto | ||||
3405 | * the left window. | ||||
3406 | * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right | ||||
3407 | * window (first), and then another on the left window (second). | ||||
3408 | * This test reproduces a crash where there is a mismatch between the downTime and eventTime. | ||||
3409 | * In the buggy implementation, second finger down on the left window would cause a crash. | ||||
3410 | */ | ||||
3411 | TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch) { | ||||
3412 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
3413 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
3414 | sp<FakeWindowHandle> leftWindow = | ||||
3415 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); | ||||
3416 | leftWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
3417 | |||||
3418 | sp<FakeWindowHandle> rightWindow = | ||||
3419 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); | ||||
3420 | rightWindow->setFrame(Rect(200, 0, 400, 200)); | ||||
3421 | |||||
3422 | mDispatcher->onWindowInfosChanged( | ||||
3423 | {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); | ||||
3424 | |||||
3425 | const int32_t mouseDeviceId = 6; | ||||
3426 | const int32_t touchDeviceId = 4; | ||||
3427 | // Hover over the left window. Keep the cursor there. | ||||
3428 | mDispatcher->notifyMotion( | ||||
3429 | MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) | ||||
3430 | .deviceId(mouseDeviceId) | ||||
3431 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50)) | ||||
3432 | .build()); | ||||
3433 | leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); | ||||
3434 | |||||
3435 | // Tap on left window | ||||
3436 | mDispatcher->notifyMotion( | ||||
3437 | MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3438 | .deviceId(touchDeviceId) | ||||
3439 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
3440 | .build()); | ||||
3441 | |||||
3442 | mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3443 | .deviceId(touchDeviceId) | ||||
3444 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
3445 | .build()); | ||||
3446 | leftWindow->consumeMotionEvent( | ||||
3447 | AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
3448 | leftWindow->consumeMotionEvent( | ||||
3449 | AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithDeviceId(touchDeviceId))); | ||||
3450 | |||||
3451 | // First finger down on right window | ||||
3452 | mDispatcher->notifyMotion( | ||||
3453 | MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3454 | .deviceId(touchDeviceId) | ||||
3455 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
3456 | .build()); | ||||
3457 | rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); | ||||
3458 | |||||
3459 | // Second finger down on the left window | ||||
3460 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3461 | .deviceId(touchDeviceId) | ||||
3462 | .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) | ||||
3463 | .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100)) | ||||
3464 | .build()); | ||||
3465 | leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); | ||||
3466 | rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE)); | ||||
3467 | |||||
3468 | // No more events | ||||
3469 | leftWindow->assertNoEvents(); | ||||
3470 | rightWindow->assertNoEvents(); | ||||
3471 | } | ||||
3472 | |||||
3473 | /** | ||||
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3474 | * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs. |
3475 | * While the touch is down, new hover events from the stylus device should be ignored. After the | ||||
3476 | * touch is gone, stylus hovering should start working again. | ||||
3477 | */ | ||||
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 3478 | TEST_F(InputDispatcherMultiDeviceTest, StylusHoverIgnoresTouchTap) { |
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 3479 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); |
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3480 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
3481 | sp<FakeWindowHandle> window = | ||||
3482 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
3483 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
3484 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 3485 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3486 | |
3487 | const int32_t stylusDeviceId = 5; | ||||
3488 | const int32_t touchDeviceId = 4; | ||||
3489 | // Start hovering with stylus | ||||
3490 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3491 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 3492 | MotionEventBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) |
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3493 | .deviceId(stylusDeviceId) |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3494 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) |
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3495 | .build())); |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 3496 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); |
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3497 | |
3498 | // Finger down on the window | ||||
3499 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3500 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 3501 | MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3502 | .deviceId(touchDeviceId) |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3503 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) |
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3504 | .build())); |
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 3505 | // The touch device should be ignored! |
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3506 | |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 3507 | // Continue hovering with stylus. |
3508 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3509 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3510 | MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, |
3511 | AINPUT_SOURCE_STYLUS) | ||||
3512 | .deviceId(stylusDeviceId) | ||||
Siarhei Vishniakou | 25537f8 | 2023-07-18 14:35:47 -0700 | [diff] [blame] | 3513 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60)) |
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3514 | .build())); |
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 3515 | // Hovers continue to work |
3516 | window->consumeMotionEvent( | ||||
3517 | AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId))); | ||||
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3518 | |
3519 | // Lift up the finger | ||||
3520 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3521 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3522 | MotionEventBuilder(AMOTION_EVENT_ACTION_UP, |
3523 | AINPUT_SOURCE_TOUCHSCREEN) | ||||
3524 | .deviceId(touchDeviceId) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3525 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) |
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3526 | .build())); |
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3527 | |
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3528 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 3529 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3530 | MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, |
3531 | AINPUT_SOURCE_STYLUS) | ||||
3532 | .deviceId(stylusDeviceId) | ||||
Siarhei Vishniakou | 25537f8 | 2023-07-18 14:35:47 -0700 | [diff] [blame] | 3533 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70)) |
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3534 | .build())); |
Siarhei Vishniakou | 3ad54f5 | 2023-11-02 16:54:40 -0700 | [diff] [blame] | 3535 | window->consumeMotionEvent( |
3536 | AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId))); | ||||
Siarhei Vishniakou | 2e3e443 | 2023-02-09 18:34:11 -0800 | [diff] [blame] | 3537 | window->assertNoEvents(); |
3538 | } | ||||
3539 | |||||
3540 | /** | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 3541 | * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs. |
3542 | * While the touch is down, hovering from the stylus is not affected. After the touch is gone, | ||||
3543 | * check that the stylus hovering continues to work. | ||||
3544 | */ | ||||
3545 | TEST_F(InputDispatcherMultiDeviceTest, StylusHoverWithTouchTap) { | ||||
3546 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
3547 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
3548 | sp<FakeWindowHandle> window = | ||||
3549 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
3550 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
3551 | |||||
3552 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
3553 | |||||
3554 | const int32_t stylusDeviceId = 5; | ||||
3555 | const int32_t touchDeviceId = 4; | ||||
3556 | // Start hovering with stylus | ||||
3557 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
3558 | .deviceId(stylusDeviceId) | ||||
3559 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) | ||||
3560 | .build()); | ||||
3561 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
3562 | |||||
3563 | // Finger down on the window | ||||
3564 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3565 | .deviceId(touchDeviceId) | ||||
3566 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
3567 | .build()); | ||||
3568 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
3569 | |||||
3570 | // Continue hovering with stylus. | ||||
3571 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) | ||||
3572 | .deviceId(stylusDeviceId) | ||||
3573 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60)) | ||||
3574 | .build()); | ||||
3575 | // Hovers continue to work | ||||
3576 | window->consumeMotionEvent( | ||||
3577 | AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId))); | ||||
3578 | |||||
3579 | // Lift up the finger | ||||
3580 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3581 | .deviceId(touchDeviceId) | ||||
3582 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
3583 | .build()); | ||||
3584 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(touchDeviceId))); | ||||
3585 | |||||
3586 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) | ||||
3587 | .deviceId(stylusDeviceId) | ||||
3588 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70)) | ||||
3589 | .build()); | ||||
3590 | window->consumeMotionEvent( | ||||
3591 | AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId))); | ||||
3592 | window->assertNoEvents(); | ||||
3593 | } | ||||
3594 | |||||
3595 | /** | ||||
Siarhei Vishniakou | f77f60a | 2023-10-23 17:26:05 -0700 | [diff] [blame] | 3596 | * If stylus is down anywhere on the screen, then touches should not be delivered to windows that |
3597 | * have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH. | ||||
3598 | * | ||||
3599 | * Two windows: one on the left and one on the right. | ||||
3600 | * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config. | ||||
3601 | * Stylus down on the left window, and then touch down on the right window. | ||||
3602 | * Check that the right window doesn't get touches while the stylus is down on the left window. | ||||
3603 | */ | ||||
3604 | TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusDownBlocksTouch) { | ||||
3605 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
3606 | sp<FakeWindowHandle> leftWindow = | ||||
3607 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left window", | ||||
3608 | ADISPLAY_ID_DEFAULT); | ||||
3609 | leftWindow->setFrame(Rect(0, 0, 100, 100)); | ||||
3610 | |||||
3611 | sp<FakeWindowHandle> sbtRightWindow = | ||||
3612 | sp<FakeWindowHandle>::make(application, mDispatcher, | ||||
3613 | "Stylus blocks touch (right) window", ADISPLAY_ID_DEFAULT); | ||||
3614 | sbtRightWindow->setFrame(Rect(100, 100, 200, 200)); | ||||
3615 | sbtRightWindow->setGlobalStylusBlocksTouch(true); | ||||
3616 | |||||
3617 | mDispatcher->onWindowInfosChanged( | ||||
3618 | {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0}); | ||||
3619 | |||||
3620 | const int32_t stylusDeviceId = 5; | ||||
3621 | const int32_t touchDeviceId = 4; | ||||
3622 | |||||
3623 | // Stylus down in the left window | ||||
3624 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) | ||||
3625 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52)) | ||||
3626 | .deviceId(stylusDeviceId) | ||||
3627 | .build()); | ||||
3628 | leftWindow->consumeMotionEvent( | ||||
3629 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); | ||||
3630 | |||||
3631 | // Finger tap on the right window | ||||
3632 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3633 | .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151)) | ||||
3634 | .deviceId(touchDeviceId) | ||||
3635 | .build()); | ||||
3636 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3637 | .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151)) | ||||
3638 | .deviceId(touchDeviceId) | ||||
3639 | .build()); | ||||
3640 | |||||
3641 | // The touch should be blocked, because stylus is down somewhere else on screen! | ||||
3642 | sbtRightWindow->assertNoEvents(); | ||||
3643 | |||||
3644 | // Continue stylus motion, and ensure it's not impacted. | ||||
3645 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) | ||||
3646 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53)) | ||||
3647 | .deviceId(stylusDeviceId) | ||||
3648 | .build()); | ||||
3649 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS) | ||||
3650 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53)) | ||||
3651 | .deviceId(stylusDeviceId) | ||||
3652 | .build()); | ||||
3653 | leftWindow->consumeMotionEvent( | ||||
3654 | AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId))); | ||||
3655 | leftWindow->consumeMotionEvent( | ||||
3656 | AllOf(WithMotionAction(ACTION_UP), WithDeviceId(stylusDeviceId))); | ||||
3657 | |||||
3658 | // Now that the stylus gesture is done, touches should be getting delivered correctly. | ||||
3659 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3660 | .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153)) | ||||
3661 | .deviceId(touchDeviceId) | ||||
3662 | .build()); | ||||
3663 | sbtRightWindow->consumeMotionEvent( | ||||
3664 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
3665 | } | ||||
3666 | |||||
3667 | /** | ||||
3668 | * If stylus is hovering anywhere on the screen, then touches should not be delivered to windows | ||||
3669 | * that have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH. | ||||
3670 | * | ||||
3671 | * Two windows: one on the left and one on the right. | ||||
3672 | * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config. | ||||
3673 | * Stylus hover on the left window, and then touch down on the right window. | ||||
3674 | * Check that the right window doesn't get touches while the stylus is hovering on the left window. | ||||
3675 | */ | ||||
3676 | TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusHoverBlocksTouch) { | ||||
3677 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
3678 | sp<FakeWindowHandle> leftWindow = | ||||
3679 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left window", | ||||
3680 | ADISPLAY_ID_DEFAULT); | ||||
3681 | leftWindow->setFrame(Rect(0, 0, 100, 100)); | ||||
3682 | |||||
3683 | sp<FakeWindowHandle> sbtRightWindow = | ||||
3684 | sp<FakeWindowHandle>::make(application, mDispatcher, | ||||
3685 | "Stylus blocks touch (right) window", ADISPLAY_ID_DEFAULT); | ||||
3686 | sbtRightWindow->setFrame(Rect(100, 100, 200, 200)); | ||||
3687 | sbtRightWindow->setGlobalStylusBlocksTouch(true); | ||||
3688 | |||||
3689 | mDispatcher->onWindowInfosChanged( | ||||
3690 | {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0}); | ||||
3691 | |||||
3692 | const int32_t stylusDeviceId = 5; | ||||
3693 | const int32_t touchDeviceId = 4; | ||||
3694 | |||||
3695 | // Stylus hover in the left window | ||||
3696 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
3697 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52)) | ||||
3698 | .deviceId(stylusDeviceId) | ||||
3699 | .build()); | ||||
3700 | leftWindow->consumeMotionEvent( | ||||
3701 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId))); | ||||
3702 | |||||
3703 | // Finger tap on the right window | ||||
3704 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3705 | .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151)) | ||||
3706 | .deviceId(touchDeviceId) | ||||
3707 | .build()); | ||||
3708 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3709 | .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151)) | ||||
3710 | .deviceId(touchDeviceId) | ||||
3711 | .build()); | ||||
3712 | |||||
3713 | // The touch should be blocked, because stylus is hovering somewhere else on screen! | ||||
3714 | sbtRightWindow->assertNoEvents(); | ||||
3715 | |||||
3716 | // Continue stylus motion, and ensure it's not impacted. | ||||
3717 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) | ||||
3718 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53)) | ||||
3719 | .deviceId(stylusDeviceId) | ||||
3720 | .build()); | ||||
3721 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) | ||||
3722 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53)) | ||||
3723 | .deviceId(stylusDeviceId) | ||||
3724 | .build()); | ||||
3725 | leftWindow->consumeMotionEvent( | ||||
3726 | AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId))); | ||||
3727 | leftWindow->consumeMotionEvent( | ||||
3728 | AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId))); | ||||
3729 | |||||
3730 | // Now that the stylus gesture is done, touches should be getting delivered correctly. | ||||
3731 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3732 | .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153)) | ||||
3733 | .deviceId(touchDeviceId) | ||||
3734 | .build()); | ||||
3735 | sbtRightWindow->consumeMotionEvent( | ||||
3736 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
3737 | } | ||||
3738 | |||||
3739 | /** | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3740 | * A spy window above a window with no input channel. |
3741 | * Start hovering with a stylus device, and then tap with it. | ||||
3742 | * Ensure spy window receives the entire sequence. | ||||
3743 | */ | ||||
3744 | TEST_F(InputDispatcherTest, StylusHoverAndDownNoInputChannel) { | ||||
3745 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
3746 | sp<FakeWindowHandle> spyWindow = | ||||
3747 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); | ||||
3748 | spyWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
3749 | spyWindow->setTrustedOverlay(true); | ||||
3750 | spyWindow->setSpy(true); | ||||
3751 | sp<FakeWindowHandle> window = | ||||
3752 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
3753 | window->setNoInputChannel(true); | ||||
3754 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
3755 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 3756 | mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3757 | |
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3758 | // Start hovering with stylus |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3759 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) |
3760 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) | ||||
3761 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3762 | spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); |
3763 | // Stop hovering | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3764 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) |
3765 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) | ||||
3766 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3767 | spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); |
3768 | |||||
3769 | // Stylus touches down | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3770 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) |
3771 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) | ||||
3772 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3773 | spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); |
3774 | |||||
3775 | // Stylus goes up | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3776 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS) |
3777 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) | ||||
3778 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3779 | spyWindow->consumeMotionEvent(WithMotionAction(ACTION_UP)); |
3780 | |||||
3781 | // Again hover | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3782 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) |
3783 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) | ||||
3784 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3785 | spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); |
3786 | // Stop hovering | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3787 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) |
3788 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) | ||||
3789 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3790 | spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); |
3791 | |||||
3792 | // No more events | ||||
3793 | spyWindow->assertNoEvents(); | ||||
3794 | window->assertNoEvents(); | ||||
3795 | } | ||||
3796 | |||||
3797 | /** | ||||
Siarhei Vishniakou | 6b71b63 | 2023-10-27 21:34:46 -0700 | [diff] [blame] | 3798 | * A stale stylus HOVER_EXIT event is injected. Since it's a stale event, it should generally be |
3799 | * rejected. But since we already have an ongoing gesture, this event should be processed. | ||||
3800 | * This prevents inconsistent events being handled inside the dispatcher. | ||||
3801 | */ | ||||
3802 | TEST_F(InputDispatcherTest, StaleStylusHoverGestureIsComplete) { | ||||
3803 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
3804 | |||||
3805 | sp<FakeWindowHandle> window = | ||||
3806 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
3807 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
3808 | |||||
3809 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
3810 | |||||
3811 | // Start hovering with stylus | ||||
3812 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
3813 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) | ||||
3814 | .build()); | ||||
3815 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
3816 | |||||
3817 | NotifyMotionArgs hoverExit = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) | ||||
3818 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) | ||||
3819 | .build(); | ||||
3820 | // Make this 'hoverExit' event stale | ||||
3821 | mFakePolicy->setStaleEventTimeout(100ms); | ||||
3822 | std::this_thread::sleep_for(100ms); | ||||
3823 | |||||
3824 | // It shouldn't be dropped by the dispatcher, even though it's stale. | ||||
3825 | mDispatcher->notifyMotion(hoverExit); | ||||
3826 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); | ||||
3827 | |||||
3828 | // Stylus starts hovering again! There should be no crash. | ||||
3829 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
3830 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(51)) | ||||
3831 | .build()); | ||||
3832 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
3833 | } | ||||
3834 | |||||
3835 | /** | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3836 | * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream. |
3837 | * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse | ||||
3838 | * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active. | ||||
3839 | * While the mouse is down, new move events from the touch device should be ignored. | ||||
3840 | */ | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 3841 | TEST_F(InputDispatcherTest, TouchPilferAndMouseMove_legacy) { |
3842 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3843 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
3844 | sp<FakeWindowHandle> spyWindow = | ||||
3845 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); | ||||
3846 | spyWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
3847 | spyWindow->setTrustedOverlay(true); | ||||
3848 | spyWindow->setSpy(true); | ||||
3849 | sp<FakeWindowHandle> window = | ||||
3850 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
3851 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
3852 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 3853 | mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3854 | |
3855 | const int32_t mouseDeviceId = 7; | ||||
3856 | const int32_t touchDeviceId = 4; | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3857 | |
3858 | // Hover a bit with mouse first | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3859 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) |
3860 | .deviceId(mouseDeviceId) | ||||
3861 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) | ||||
3862 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3863 | spyWindow->consumeMotionEvent( |
3864 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); | ||||
3865 | window->consumeMotionEvent( | ||||
3866 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); | ||||
3867 | |||||
3868 | // Start touching | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3869 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
3870 | .deviceId(touchDeviceId) | ||||
3871 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
3872 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3873 | spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); |
3874 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); | ||||
3875 | spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); | ||||
3876 | window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); | ||||
3877 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3878 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) |
3879 | .deviceId(touchDeviceId) | ||||
3880 | .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55)) | ||||
3881 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3882 | spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); |
3883 | window->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); | ||||
3884 | |||||
3885 | // Pilfer the stream | ||||
3886 | EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken())); | ||||
3887 | window->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); | ||||
3888 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3889 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) |
3890 | .deviceId(touchDeviceId) | ||||
3891 | .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60)) | ||||
3892 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3893 | spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); |
3894 | |||||
3895 | // Mouse down | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3896 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) |
3897 | .deviceId(mouseDeviceId) | ||||
3898 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
3899 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) | ||||
3900 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3901 | |
3902 | spyWindow->consumeMotionEvent( | ||||
3903 | AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId))); | ||||
3904 | spyWindow->consumeMotionEvent( | ||||
3905 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); | ||||
3906 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); | ||||
3907 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3908 | mDispatcher->notifyMotion( |
3909 | MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) | ||||
3910 | .deviceId(mouseDeviceId) | ||||
3911 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
3912 | .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
3913 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) | ||||
3914 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3915 | spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); |
3916 | window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); | ||||
3917 | |||||
3918 | // Mouse move! | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3919 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE) |
3920 | .deviceId(mouseDeviceId) | ||||
3921 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
3922 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110)) | ||||
3923 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3924 | spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); |
3925 | window->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); | ||||
3926 | |||||
3927 | // Touch move! | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 3928 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) |
3929 | .deviceId(touchDeviceId) | ||||
3930 | .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65)) | ||||
3931 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 3932 | |
3933 | // No more events | ||||
3934 | spyWindow->assertNoEvents(); | ||||
3935 | window->assertNoEvents(); | ||||
3936 | } | ||||
3937 | |||||
3938 | /** | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 3939 | * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream. |
3940 | * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse | ||||
3941 | * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active. | ||||
3942 | * While the mouse is down, new move events from the touch device should continue to work. | ||||
3943 | */ | ||||
3944 | TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) { | ||||
3945 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
3946 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
3947 | sp<FakeWindowHandle> spyWindow = | ||||
3948 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); | ||||
3949 | spyWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
3950 | spyWindow->setTrustedOverlay(true); | ||||
3951 | spyWindow->setSpy(true); | ||||
3952 | sp<FakeWindowHandle> window = | ||||
3953 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
3954 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
3955 | |||||
3956 | mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); | ||||
3957 | |||||
3958 | const int32_t mouseDeviceId = 7; | ||||
3959 | const int32_t touchDeviceId = 4; | ||||
3960 | |||||
3961 | // Hover a bit with mouse first | ||||
3962 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) | ||||
3963 | .deviceId(mouseDeviceId) | ||||
3964 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) | ||||
3965 | .build()); | ||||
3966 | spyWindow->consumeMotionEvent( | ||||
3967 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); | ||||
3968 | window->consumeMotionEvent( | ||||
3969 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); | ||||
3970 | |||||
3971 | // Start touching | ||||
3972 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3973 | .deviceId(touchDeviceId) | ||||
3974 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
3975 | .build()); | ||||
3976 | |||||
3977 | spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); | ||||
3978 | window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); | ||||
3979 | |||||
3980 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3981 | .deviceId(touchDeviceId) | ||||
3982 | .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55)) | ||||
3983 | .build()); | ||||
3984 | spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); | ||||
3985 | window->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); | ||||
3986 | |||||
3987 | // Pilfer the stream | ||||
3988 | EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken())); | ||||
3989 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId))); | ||||
3990 | // Hover is not pilfered! Only touch. | ||||
3991 | |||||
3992 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
3993 | .deviceId(touchDeviceId) | ||||
3994 | .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60)) | ||||
3995 | .build()); | ||||
3996 | spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); | ||||
3997 | |||||
3998 | // Mouse down | ||||
3999 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) | ||||
4000 | .deviceId(mouseDeviceId) | ||||
4001 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
4002 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) | ||||
4003 | .build()); | ||||
4004 | |||||
4005 | spyWindow->consumeMotionEvent( | ||||
4006 | AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId))); | ||||
4007 | spyWindow->consumeMotionEvent( | ||||
4008 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); | ||||
4009 | window->consumeMotionEvent( | ||||
4010 | AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId))); | ||||
4011 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); | ||||
4012 | |||||
4013 | mDispatcher->notifyMotion( | ||||
4014 | MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) | ||||
4015 | .deviceId(mouseDeviceId) | ||||
4016 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
4017 | .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
4018 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) | ||||
4019 | .build()); | ||||
4020 | spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); | ||||
4021 | window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); | ||||
4022 | |||||
4023 | // Mouse move! | ||||
4024 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE) | ||||
4025 | .deviceId(mouseDeviceId) | ||||
4026 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
4027 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110)) | ||||
4028 | .build()); | ||||
4029 | spyWindow->consumeMotionEvent( | ||||
4030 | AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId))); | ||||
4031 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId))); | ||||
4032 | |||||
4033 | // Touch move! | ||||
4034 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
4035 | .deviceId(touchDeviceId) | ||||
4036 | .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65)) | ||||
4037 | .build()); | ||||
4038 | spyWindow->consumeMotionEvent( | ||||
4039 | AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); | ||||
4040 | |||||
4041 | // No more events | ||||
4042 | spyWindow->assertNoEvents(); | ||||
4043 | window->assertNoEvents(); | ||||
4044 | } | ||||
4045 | |||||
4046 | /** | ||||
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 4047 | * On the display, have a single window, and also an area where there's no window. |
4048 | * First pointer touches the "no window" area of the screen. Second pointer touches the window. | ||||
4049 | * Make sure that the window receives the second pointer, and first pointer is simply ignored. | ||||
4050 | */ | ||||
4051 | TEST_F(InputDispatcherTest, SplitWorksWhenEmptyAreaIsTouched) { | ||||
4052 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
4053 | sp<FakeWindowHandle> window = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 4054 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", DISPLAY_ID); |
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 4055 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4056 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 4057 | |
4058 | // Touch down on the empty space | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4059 | mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{-1, -1}})); |
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 4060 | |
4061 | mDispatcher->waitForIdle(); | ||||
4062 | window->assertNoEvents(); | ||||
4063 | |||||
4064 | // Now touch down on the window with another pointer | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4065 | mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{-1, -1}, {10, 10}})); |
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 4066 | mDispatcher->waitForIdle(); |
4067 | window->consumeMotionDown(); | ||||
4068 | } | ||||
4069 | |||||
4070 | /** | ||||
4071 | * Same test as above, but instead of touching the empty space, the first touch goes to | ||||
4072 | * non-touchable window. | ||||
4073 | */ | ||||
4074 | TEST_F(InputDispatcherTest, SplitWorksWhenNonTouchableWindowIsTouched) { | ||||
4075 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
4076 | sp<FakeWindowHandle> window1 = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 4077 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID); |
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 4078 | window1->setTouchableRegion(Region{{0, 0, 100, 100}}); |
4079 | window1->setTouchable(false); | ||||
4080 | sp<FakeWindowHandle> window2 = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 4081 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID); |
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 4082 | window2->setTouchableRegion(Region{{100, 0, 200, 100}}); |
4083 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4084 | mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 4085 | |
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 4086 | // Touch down on the non-touchable window |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4087 | mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}})); |
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 4088 | |
4089 | mDispatcher->waitForIdle(); | ||||
4090 | window1->assertNoEvents(); | ||||
4091 | window2->assertNoEvents(); | ||||
4092 | |||||
4093 | // Now touch down on the window with another pointer | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4094 | mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}})); |
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 4095 | mDispatcher->waitForIdle(); |
4096 | window2->consumeMotionDown(); | ||||
4097 | } | ||||
4098 | |||||
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4099 | /** |
4100 | * When splitting touch events the downTime should be adjusted such that the downTime corresponds | ||||
4101 | * to the event time of the first ACTION_DOWN sent to the particular window. | ||||
4102 | */ | ||||
4103 | TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) { | ||||
4104 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
4105 | sp<FakeWindowHandle> window1 = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 4106 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID); |
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4107 | window1->setTouchableRegion(Region{{0, 0, 100, 100}}); |
4108 | sp<FakeWindowHandle> window2 = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 4109 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID); |
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4110 | window2->setTouchableRegion(Region{{100, 0, 200, 100}}); |
4111 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4112 | mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0}); |
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4113 | |
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4114 | // Touch down on the first window |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4115 | mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}})); |
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4116 | mDispatcher->waitForIdle(); |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4117 | |
Prabir Pradhan | 9d5f9ce | 2024-01-24 00:03:41 +0000 | [diff] [blame] | 4118 | const std::unique_ptr<MotionEvent> firstDown = |
4119 | window1->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN))); | ||||
4120 | ASSERT_EQ(firstDown->getDownTime(), firstDown->getEventTime()); | ||||
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4121 | window2->assertNoEvents(); |
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4122 | |
4123 | // Now touch down on the window with another pointer | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4124 | mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}})); |
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4125 | mDispatcher->waitForIdle(); |
Prabir Pradhan | 9d5f9ce | 2024-01-24 00:03:41 +0000 | [diff] [blame] | 4126 | |
4127 | const std::unique_ptr<MotionEvent> secondDown = | ||||
4128 | window2->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN))); | ||||
4129 | ASSERT_EQ(secondDown->getDownTime(), secondDown->getEventTime()); | ||||
4130 | ASSERT_NE(firstDown->getDownTime(), secondDown->getDownTime()); | ||||
4131 | // We currently send MOVE events to all windows receiving a split touch when there is any change | ||||
4132 | // in the touch state, even when none of the pointers in the split window actually moved. | ||||
4133 | // Document this behavior in the test. | ||||
4134 | window1->consumeMotionMove(); | ||||
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4135 | |
4136 | // Now move the pointer on the second window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4137 | mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}})); |
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4138 | mDispatcher->waitForIdle(); |
Prabir Pradhan | 9d5f9ce | 2024-01-24 00:03:41 +0000 | [diff] [blame] | 4139 | |
4140 | window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime())); | ||||
4141 | window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime())); | ||||
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4142 | |
4143 | // Now add new touch down on the second window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4144 | mDispatcher->notifyMotion(generateTouchArgs(POINTER_2_DOWN, {{50, 50}, {151, 51}, {150, 50}})); |
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4145 | mDispatcher->waitForIdle(); |
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4146 | |
Prabir Pradhan | 9d5f9ce | 2024-01-24 00:03:41 +0000 | [diff] [blame] | 4147 | window2->consumeMotionEvent( |
4148 | AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(secondDown->getDownTime()))); | ||||
4149 | window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime())); | ||||
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4150 | |
4151 | // Now move the pointer on the first window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4152 | mDispatcher->notifyMotion( |
4153 | generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}, {150, 50}})); | ||||
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4154 | mDispatcher->waitForIdle(); |
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4155 | |
Prabir Pradhan | 9d5f9ce | 2024-01-24 00:03:41 +0000 | [diff] [blame] | 4156 | window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime())); |
4157 | window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime())); | ||||
4158 | |||||
4159 | // Now add new touch down on the first window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4160 | mDispatcher->notifyMotion( |
4161 | generateTouchArgs(POINTER_3_DOWN, {{51, 51}, {151, 51}, {150, 50}, {50, 50}})); | ||||
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4162 | mDispatcher->waitForIdle(); |
Prabir Pradhan | 9d5f9ce | 2024-01-24 00:03:41 +0000 | [diff] [blame] | 4163 | |
4164 | window1->consumeMotionEvent( | ||||
4165 | AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(firstDown->getDownTime()))); | ||||
4166 | window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime())); | ||||
Vaibhav Devmurari | 882bd9b | 2022-06-23 14:54:54 +0000 | [diff] [blame] | 4167 | } |
4168 | |||||
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4169 | TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 4170 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4171 | sp<FakeWindowHandle> windowLeft = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 4172 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4173 | windowLeft->setFrame(Rect(0, 0, 600, 800)); |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4174 | sp<FakeWindowHandle> windowRight = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 4175 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4176 | windowRight->setFrame(Rect(600, 0, 1200, 800)); |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4177 | |
4178 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); | ||||
4179 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4180 | mDispatcher->onWindowInfosChanged( |
4181 | {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0}); | ||||
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4182 | |
4183 | // Start cursor position in right window so that we can move the cursor to left window. | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 4184 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4185 | injectMotionEvent(*mDispatcher, |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4186 | MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, |
4187 | AINPUT_SOURCE_MOUSE) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 4188 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400)) |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4189 | .build())); |
Siarhei Vishniakou | 5cee1e3 | 2022-11-29 12:35:39 -0800 | [diff] [blame] | 4190 | windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4191 | |
4192 | // Move cursor into left window | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 4193 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4194 | injectMotionEvent(*mDispatcher, |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4195 | MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, |
4196 | AINPUT_SOURCE_MOUSE) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 4197 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4198 | .build())); |
Siarhei Vishniakou | 5cee1e3 | 2022-11-29 12:35:39 -0800 | [diff] [blame] | 4199 | windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); |
4200 | windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); | ||||
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4201 | |
4202 | // Inject a series of mouse events for a mouse click | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 4203 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4204 | injectMotionEvent(*mDispatcher, |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4205 | MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) |
4206 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 4207 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4208 | .build())); |
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 4209 | windowLeft->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); |
4210 | windowLeft->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); | ||||
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4211 | |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 4212 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4213 | injectMotionEvent(*mDispatcher, |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4214 | MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, |
4215 | AINPUT_SOURCE_MOUSE) | ||||
4216 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
4217 | .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 4218 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4219 | .build())); |
Siarhei Vishniakou | 5cee1e3 | 2022-11-29 12:35:39 -0800 | [diff] [blame] | 4220 | windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4221 | |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 4222 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4223 | injectMotionEvent(*mDispatcher, |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4224 | MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE, |
4225 | AINPUT_SOURCE_MOUSE) | ||||
4226 | .buttonState(0) | ||||
4227 | .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 4228 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4229 | .build())); |
Siarhei Vishniakou | 5cee1e3 | 2022-11-29 12:35:39 -0800 | [diff] [blame] | 4230 | windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE)); |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4231 | |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 4232 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4233 | injectMotionEvent(*mDispatcher, |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4234 | MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE) |
4235 | .buttonState(0) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 4236 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4237 | .build())); |
4238 | windowLeft->consumeMotionUp(ADISPLAY_ID_DEFAULT); | ||||
4239 | |||||
4240 | // Move mouse cursor back to right window | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 4241 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4242 | injectMotionEvent(*mDispatcher, |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4243 | MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, |
4244 | AINPUT_SOURCE_MOUSE) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 4245 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400)) |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4246 | .build())); |
Siarhei Vishniakou | 5cee1e3 | 2022-11-29 12:35:39 -0800 | [diff] [blame] | 4247 | windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); |
Siarhei Vishniakou | 5cee1e3 | 2022-11-29 12:35:39 -0800 | [diff] [blame] | 4248 | |
4249 | // No more events | ||||
4250 | windowLeft->assertNoEvents(); | ||||
4251 | windowRight->assertNoEvents(); | ||||
4252 | } | ||||
4253 | |||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 4254 | /** |
4255 | * Put two fingers down (and don't release them) and click the mouse button. | ||||
4256 | * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the | ||||
4257 | * currently active gesture should be canceled, and the new one should proceed. | ||||
4258 | */ | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 4259 | TEST_F(InputDispatcherTest, TwoPointersDownMouseClick_legacy) { |
4260 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 4261 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
4262 | sp<FakeWindowHandle> window = | ||||
4263 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
4264 | window->setFrame(Rect(0, 0, 600, 800)); | ||||
4265 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4266 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 4267 | |
4268 | const int32_t touchDeviceId = 4; | ||||
4269 | const int32_t mouseDeviceId = 6; | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 4270 | |
4271 | // Two pointers down | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4272 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
4273 | .deviceId(touchDeviceId) | ||||
4274 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
4275 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 4276 | |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4277 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
4278 | .deviceId(touchDeviceId) | ||||
4279 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
4280 | .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120)) | ||||
4281 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 4282 | window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); |
4283 | window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); | ||||
4284 | |||||
4285 | // Inject a series of mouse events for a mouse click | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4286 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) |
4287 | .deviceId(mouseDeviceId) | ||||
4288 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
4289 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) | ||||
4290 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 4291 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId), |
4292 | WithPointerCount(2u))); | ||||
4293 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); | ||||
4294 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4295 | mDispatcher->notifyMotion( |
4296 | MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) | ||||
4297 | .deviceId(mouseDeviceId) | ||||
4298 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
4299 | .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
4300 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) | ||||
4301 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 4302 | window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); |
4303 | |||||
4304 | // Try to send more touch events while the mouse is down. Since it's a continuation of an | ||||
4305 | // already canceled gesture, it should be ignored. | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4306 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) |
4307 | .deviceId(touchDeviceId) | ||||
4308 | .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101)) | ||||
4309 | .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121)) | ||||
4310 | .build()); | ||||
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 4311 | window->assertNoEvents(); |
4312 | } | ||||
4313 | |||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 4314 | /** |
4315 | * Put two fingers down (and don't release them) and click the mouse button. | ||||
4316 | * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the | ||||
4317 | * currently active gesture should not be canceled, and the new one should proceed in parallel. | ||||
4318 | */ | ||||
4319 | TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) { | ||||
4320 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
4321 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
4322 | sp<FakeWindowHandle> window = | ||||
4323 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
4324 | window->setFrame(Rect(0, 0, 600, 800)); | ||||
4325 | |||||
4326 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
4327 | |||||
4328 | const int32_t touchDeviceId = 4; | ||||
4329 | const int32_t mouseDeviceId = 6; | ||||
4330 | |||||
4331 | // Two pointers down | ||||
4332 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
4333 | .deviceId(touchDeviceId) | ||||
4334 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
4335 | .build()); | ||||
4336 | |||||
4337 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
4338 | .deviceId(touchDeviceId) | ||||
4339 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
4340 | .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120)) | ||||
4341 | .build()); | ||||
4342 | window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); | ||||
4343 | window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); | ||||
4344 | |||||
4345 | // Send a series of mouse events for a mouse click | ||||
4346 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) | ||||
4347 | .deviceId(mouseDeviceId) | ||||
4348 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
4349 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) | ||||
4350 | .build()); | ||||
4351 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); | ||||
4352 | |||||
4353 | mDispatcher->notifyMotion( | ||||
4354 | MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) | ||||
4355 | .deviceId(mouseDeviceId) | ||||
4356 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
4357 | .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
4358 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) | ||||
4359 | .build()); | ||||
4360 | window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); | ||||
4361 | |||||
4362 | // Try to send more touch events while the mouse is down. Since it's a continuation of an | ||||
4363 | // already active gesture, it should be sent normally. | ||||
4364 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
4365 | .deviceId(touchDeviceId) | ||||
4366 | .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101)) | ||||
4367 | .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121)) | ||||
4368 | .build()); | ||||
4369 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); | ||||
4370 | window->assertNoEvents(); | ||||
4371 | } | ||||
4372 | |||||
Siarhei Vishniakou | 5cee1e3 | 2022-11-29 12:35:39 -0800 | [diff] [blame] | 4373 | TEST_F(InputDispatcherTest, HoverWithSpyWindows) { |
4374 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
4375 | |||||
4376 | sp<FakeWindowHandle> spyWindow = | ||||
4377 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); | ||||
4378 | spyWindow->setFrame(Rect(0, 0, 600, 800)); | ||||
4379 | spyWindow->setTrustedOverlay(true); | ||||
4380 | spyWindow->setSpy(true); | ||||
4381 | sp<FakeWindowHandle> window = | ||||
4382 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
4383 | window->setFrame(Rect(0, 0, 600, 800)); | ||||
4384 | |||||
4385 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4386 | mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | 5cee1e3 | 2022-11-29 12:35:39 -0800 | [diff] [blame] | 4387 | |
4388 | // Send mouse cursor to the window | ||||
4389 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4390 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 5cee1e3 | 2022-11-29 12:35:39 -0800 | [diff] [blame] | 4391 | MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, |
4392 | AINPUT_SOURCE_MOUSE) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4393 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) |
Siarhei Vishniakou | 5cee1e3 | 2022-11-29 12:35:39 -0800 | [diff] [blame] | 4394 | .build())); |
4395 | |||||
4396 | window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), | ||||
4397 | WithSource(AINPUT_SOURCE_MOUSE))); | ||||
4398 | spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), | ||||
4399 | WithSource(AINPUT_SOURCE_MOUSE))); | ||||
4400 | |||||
4401 | window->assertNoEvents(); | ||||
4402 | spyWindow->assertNoEvents(); | ||||
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4403 | } |
4404 | |||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 4405 | TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows_legacy) { |
4406 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); | ||||
Siarhei Vishniakou | 060f82b | 2023-01-27 06:39:14 -0800 | [diff] [blame] | 4407 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
4408 | |||||
4409 | sp<FakeWindowHandle> spyWindow = | ||||
4410 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); | ||||
4411 | spyWindow->setFrame(Rect(0, 0, 600, 800)); | ||||
4412 | spyWindow->setTrustedOverlay(true); | ||||
4413 | spyWindow->setSpy(true); | ||||
4414 | sp<FakeWindowHandle> window = | ||||
4415 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
4416 | window->setFrame(Rect(0, 0, 600, 800)); | ||||
4417 | |||||
4418 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4419 | mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | 060f82b | 2023-01-27 06:39:14 -0800 | [diff] [blame] | 4420 | |
4421 | // Send mouse cursor to the window | ||||
4422 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4423 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 060f82b | 2023-01-27 06:39:14 -0800 | [diff] [blame] | 4424 | MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, |
4425 | AINPUT_SOURCE_MOUSE) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4426 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) |
Siarhei Vishniakou | 060f82b | 2023-01-27 06:39:14 -0800 | [diff] [blame] | 4427 | .build())); |
4428 | |||||
4429 | // Move mouse cursor | ||||
4430 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4431 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 060f82b | 2023-01-27 06:39:14 -0800 | [diff] [blame] | 4432 | MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, |
4433 | AINPUT_SOURCE_MOUSE) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4434 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110)) |
Siarhei Vishniakou | 060f82b | 2023-01-27 06:39:14 -0800 | [diff] [blame] | 4435 | .build())); |
4436 | |||||
4437 | window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), | ||||
4438 | WithSource(AINPUT_SOURCE_MOUSE))); | ||||
4439 | spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), | ||||
4440 | WithSource(AINPUT_SOURCE_MOUSE))); | ||||
4441 | window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), | ||||
4442 | WithSource(AINPUT_SOURCE_MOUSE))); | ||||
4443 | spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), | ||||
4444 | WithSource(AINPUT_SOURCE_MOUSE))); | ||||
4445 | // Touch down on the window | ||||
4446 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4447 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 060f82b | 2023-01-27 06:39:14 -0800 | [diff] [blame] | 4448 | MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, |
4449 | AINPUT_SOURCE_TOUCHSCREEN) | ||||
4450 | .deviceId(SECOND_DEVICE_ID) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4451 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200)) |
Siarhei Vishniakou | 060f82b | 2023-01-27 06:39:14 -0800 | [diff] [blame] | 4452 | .build())); |
4453 | window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT), | ||||
4454 | WithSource(AINPUT_SOURCE_MOUSE))); | ||||
4455 | spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT), | ||||
4456 | WithSource(AINPUT_SOURCE_MOUSE))); | ||||
4457 | window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), | ||||
4458 | WithSource(AINPUT_SOURCE_TOUCHSCREEN))); | ||||
4459 | spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), | ||||
4460 | WithSource(AINPUT_SOURCE_TOUCHSCREEN))); | ||||
4461 | |||||
4462 | // pilfer the motion, retaining the gesture on the spy window. | ||||
4463 | EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken())); | ||||
4464 | window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL), | ||||
4465 | WithSource(AINPUT_SOURCE_TOUCHSCREEN))); | ||||
4466 | |||||
4467 | // Touch UP on the window | ||||
4468 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4469 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 060f82b | 2023-01-27 06:39:14 -0800 | [diff] [blame] | 4470 | MotionEventBuilder(AMOTION_EVENT_ACTION_UP, |
4471 | AINPUT_SOURCE_TOUCHSCREEN) | ||||
4472 | .deviceId(SECOND_DEVICE_ID) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4473 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200)) |
Siarhei Vishniakou | 060f82b | 2023-01-27 06:39:14 -0800 | [diff] [blame] | 4474 | .build())); |
4475 | spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), | ||||
4476 | WithSource(AINPUT_SOURCE_TOUCHSCREEN))); | ||||
4477 | |||||
4478 | // Previously, a touch was pilfered. However, that gesture was just finished. Now, we are going | ||||
4479 | // to send a new gesture. It should again go to both windows (spy and the window below), just | ||||
4480 | // like the first gesture did, before pilfering. The window configuration has not changed. | ||||
4481 | |||||
4482 | // One more tap - DOWN | ||||
4483 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4484 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 060f82b | 2023-01-27 06:39:14 -0800 | [diff] [blame] | 4485 | MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, |
4486 | AINPUT_SOURCE_TOUCHSCREEN) | ||||
4487 | .deviceId(SECOND_DEVICE_ID) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4488 | .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250)) |
Siarhei Vishniakou | 060f82b | 2023-01-27 06:39:14 -0800 | [diff] [blame] | 4489 | .build())); |
4490 | window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), | ||||
4491 | WithSource(AINPUT_SOURCE_TOUCHSCREEN))); | ||||
4492 | spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), | ||||
4493 | WithSource(AINPUT_SOURCE_TOUCHSCREEN))); | ||||
4494 | |||||
4495 | // Touch UP on the window | ||||
4496 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4497 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | 060f82b | 2023-01-27 06:39:14 -0800 | [diff] [blame] | 4498 | MotionEventBuilder(AMOTION_EVENT_ACTION_UP, |
4499 | AINPUT_SOURCE_TOUCHSCREEN) | ||||
4500 | .deviceId(SECOND_DEVICE_ID) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4501 | .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250)) |
Siarhei Vishniakou | 060f82b | 2023-01-27 06:39:14 -0800 | [diff] [blame] | 4502 | .build())); |
4503 | window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), | ||||
4504 | WithSource(AINPUT_SOURCE_TOUCHSCREEN))); | ||||
4505 | spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), | ||||
4506 | WithSource(AINPUT_SOURCE_TOUCHSCREEN))); | ||||
4507 | |||||
4508 | window->assertNoEvents(); | ||||
4509 | spyWindow->assertNoEvents(); | ||||
4510 | } | ||||
4511 | |||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 4512 | TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) { |
4513 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
4514 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
4515 | |||||
4516 | sp<FakeWindowHandle> spyWindow = | ||||
4517 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); | ||||
4518 | spyWindow->setFrame(Rect(0, 0, 600, 800)); | ||||
4519 | spyWindow->setTrustedOverlay(true); | ||||
4520 | spyWindow->setSpy(true); | ||||
4521 | sp<FakeWindowHandle> window = | ||||
4522 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
4523 | window->setFrame(Rect(0, 0, 600, 800)); | ||||
4524 | |||||
4525 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); | ||||
4526 | mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); | ||||
4527 | |||||
4528 | // Send mouse cursor to the window | ||||
4529 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) | ||||
4530 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) | ||||
4531 | .build()); | ||||
4532 | |||||
4533 | // Move mouse cursor | ||||
4534 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) | ||||
4535 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110)) | ||||
4536 | .build()); | ||||
4537 | |||||
4538 | window->consumeMotionEvent( | ||||
4539 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithSource(AINPUT_SOURCE_MOUSE))); | ||||
4540 | spyWindow->consumeMotionEvent( | ||||
4541 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithSource(AINPUT_SOURCE_MOUSE))); | ||||
4542 | window->consumeMotionEvent( | ||||
4543 | AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE))); | ||||
4544 | spyWindow->consumeMotionEvent( | ||||
4545 | AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE))); | ||||
4546 | // Touch down on the window | ||||
4547 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
4548 | .deviceId(SECOND_DEVICE_ID) | ||||
4549 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200)) | ||||
4550 | .build()); | ||||
4551 | window->consumeMotionEvent( | ||||
4552 | AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN))); | ||||
4553 | spyWindow->consumeMotionEvent( | ||||
4554 | AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN))); | ||||
4555 | |||||
4556 | // pilfer the motion, retaining the gesture on the spy window. | ||||
4557 | EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken())); | ||||
4558 | window->consumeMotionEvent( | ||||
4559 | AllOf(WithMotionAction(ACTION_CANCEL), WithSource(AINPUT_SOURCE_TOUCHSCREEN))); | ||||
4560 | // Mouse hover is not pilfered | ||||
4561 | |||||
4562 | // Touch UP on the window | ||||
4563 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
4564 | .deviceId(SECOND_DEVICE_ID) | ||||
4565 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200)) | ||||
4566 | .build()); | ||||
4567 | spyWindow->consumeMotionEvent( | ||||
4568 | AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN))); | ||||
4569 | |||||
4570 | // Previously, a touch was pilfered. However, that gesture was just finished. Now, we are going | ||||
4571 | // to send a new gesture. It should again go to both windows (spy and the window below), just | ||||
4572 | // like the first gesture did, before pilfering. The window configuration has not changed. | ||||
4573 | |||||
4574 | // One more tap - DOWN | ||||
4575 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
4576 | .deviceId(SECOND_DEVICE_ID) | ||||
4577 | .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250)) | ||||
4578 | .build()); | ||||
4579 | window->consumeMotionEvent( | ||||
4580 | AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN))); | ||||
4581 | spyWindow->consumeMotionEvent( | ||||
4582 | AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN))); | ||||
4583 | |||||
4584 | // Touch UP on the window | ||||
4585 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
4586 | .deviceId(SECOND_DEVICE_ID) | ||||
4587 | .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250)) | ||||
4588 | .build()); | ||||
4589 | window->consumeMotionEvent( | ||||
4590 | AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN))); | ||||
4591 | spyWindow->consumeMotionEvent( | ||||
4592 | AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN))); | ||||
4593 | |||||
4594 | // Mouse movement continues normally as well | ||||
4595 | // Move mouse cursor | ||||
4596 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) | ||||
4597 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(120).y(130)) | ||||
4598 | .build()); | ||||
4599 | window->consumeMotionEvent( | ||||
4600 | AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE))); | ||||
4601 | spyWindow->consumeMotionEvent( | ||||
4602 | AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE))); | ||||
4603 | |||||
4604 | window->assertNoEvents(); | ||||
4605 | spyWindow->assertNoEvents(); | ||||
4606 | } | ||||
4607 | |||||
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4608 | // This test is different from the test above that HOVER_ENTER and HOVER_EXIT events are injected |
4609 | // directly in this test. | ||||
4610 | TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { | ||||
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 4611 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4612 | sp<FakeWindowHandle> window = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 4613 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4614 | window->setFrame(Rect(0, 0, 1200, 800)); |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4615 | |
4616 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); | ||||
4617 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4618 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4619 | |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 4620 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4621 | injectMotionEvent(*mDispatcher, |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4622 | MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, |
4623 | AINPUT_SOURCE_MOUSE) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 4624 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4625 | .build())); |
Siarhei Vishniakou | 5cee1e3 | 2022-11-29 12:35:39 -0800 | [diff] [blame] | 4626 | window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4627 | // Inject a series of mouse events for a mouse click |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 4628 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4629 | injectMotionEvent(*mDispatcher, |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4630 | MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) |
4631 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 4632 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4633 | .build())); |
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 4634 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); |
4635 | window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); | ||||
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4636 | |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 4637 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4638 | injectMotionEvent(*mDispatcher, |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4639 | MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, |
4640 | AINPUT_SOURCE_MOUSE) | ||||
4641 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
4642 | .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 4643 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4644 | .build())); |
Siarhei Vishniakou | 5cee1e3 | 2022-11-29 12:35:39 -0800 | [diff] [blame] | 4645 | window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4646 | |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 4647 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4648 | injectMotionEvent(*mDispatcher, |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4649 | MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE, |
4650 | AINPUT_SOURCE_MOUSE) | ||||
4651 | .buttonState(0) | ||||
4652 | .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 4653 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4654 | .build())); |
Siarhei Vishniakou | 5cee1e3 | 2022-11-29 12:35:39 -0800 | [diff] [blame] | 4655 | window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE)); |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4656 | |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 4657 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4658 | injectMotionEvent(*mDispatcher, |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4659 | MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE) |
4660 | .buttonState(0) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 4661 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4662 | .build())); |
4663 | window->consumeMotionUp(ADISPLAY_ID_DEFAULT); | ||||
4664 | |||||
Siarhei Vishniakou | a235c04 | 2023-05-02 09:59:09 -0700 | [diff] [blame] | 4665 | // We already canceled the hovering implicitly by injecting the "DOWN" event without lifting the |
4666 | // hover first. Therefore, injection of HOVER_EXIT is inconsistent, and should fail. | ||||
4667 | ASSERT_EQ(InputEventInjectionResult::FAILED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4668 | injectMotionEvent(*mDispatcher, |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4669 | MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT, |
4670 | AINPUT_SOURCE_MOUSE) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 4671 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4672 | .build())); |
Siarhei Vishniakou | f372b81 | 2023-02-14 18:06:51 -0800 | [diff] [blame] | 4673 | window->assertNoEvents(); |
Garfield Tan | df26e86 | 2020-07-01 20:18:19 -0700 | [diff] [blame] | 4674 | } |
4675 | |||||
Siarhei Vishniakou | 0b0374d | 2022-11-17 17:40:53 -0800 | [diff] [blame] | 4676 | /** |
Siarhei Vishniakou | b581f7f | 2022-12-07 20:23:06 +0000 | [diff] [blame] | 4677 | * Hover over a window, and then remove that window. Make sure that HOVER_EXIT for that event |
4678 | * is generated. | ||||
4679 | */ | ||||
4680 | TEST_F(InputDispatcherTest, HoverExitIsSentToRemovedWindow) { | ||||
4681 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
4682 | sp<FakeWindowHandle> window = | ||||
4683 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
4684 | window->setFrame(Rect(0, 0, 1200, 800)); | ||||
4685 | |||||
4686 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); | ||||
4687 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4688 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | b581f7f | 2022-12-07 20:23:06 +0000 | [diff] [blame] | 4689 | |
4690 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4691 | injectMotionEvent(*mDispatcher, |
Siarhei Vishniakou | b581f7f | 2022-12-07 20:23:06 +0000 | [diff] [blame] | 4692 | MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, |
4693 | AINPUT_SOURCE_MOUSE) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4694 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) |
Siarhei Vishniakou | b581f7f | 2022-12-07 20:23:06 +0000 | [diff] [blame] | 4695 | .build())); |
4696 | window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); | ||||
4697 | |||||
4698 | // Remove the window, but keep the channel. | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4699 | mDispatcher->onWindowInfosChanged({{}, {}, 0, 0}); |
Siarhei Vishniakou | b581f7f | 2022-12-07 20:23:06 +0000 | [diff] [blame] | 4700 | window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); |
4701 | } | ||||
4702 | |||||
4703 | /** | ||||
Daniel Norman | 7487dfa | 2023-08-02 16:39:45 -0700 | [diff] [blame] | 4704 | * Test that invalid HOVER events sent by accessibility do not cause a fatal crash. |
4705 | */ | ||||
Ameer Armaly | cff4fa5 | 2023-10-04 23:45:11 +0000 | [diff] [blame] | 4706 | TEST_F_WITH_FLAGS(InputDispatcherTest, InvalidA11yHoverStreamDoesNotCrash, |
4707 | REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(com::android::input::flags, | ||||
4708 | a11y_crash_on_inconsistent_event_stream))) { | ||||
Daniel Norman | 7487dfa | 2023-08-02 16:39:45 -0700 | [diff] [blame] | 4709 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
4710 | sp<FakeWindowHandle> window = | ||||
4711 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
4712 | window->setFrame(Rect(0, 0, 1200, 800)); | ||||
4713 | |||||
4714 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); | ||||
4715 | |||||
4716 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
4717 | |||||
4718 | MotionEventBuilder hoverEnterBuilder = | ||||
4719 | MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) | ||||
4720 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) | ||||
4721 | .addFlag(AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT); | ||||
4722 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
4723 | injectMotionEvent(*mDispatcher, hoverEnterBuilder.build())); | ||||
4724 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
4725 | injectMotionEvent(*mDispatcher, hoverEnterBuilder.build())); | ||||
4726 | window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); | ||||
4727 | window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); | ||||
4728 | } | ||||
4729 | |||||
4730 | /** | ||||
Siarhei Vishniakou | 4e1ffa5 | 2023-02-21 11:50:34 -0800 | [diff] [blame] | 4731 | * If mouse is hovering when the touch goes down, the hovering should be stopped via HOVER_EXIT. |
4732 | */ | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 4733 | TEST_F(InputDispatcherTest, TouchDownAfterMouseHover_legacy) { |
4734 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); | ||||
Siarhei Vishniakou | 4e1ffa5 | 2023-02-21 11:50:34 -0800 | [diff] [blame] | 4735 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
4736 | sp<FakeWindowHandle> window = | ||||
4737 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
4738 | window->setFrame(Rect(0, 0, 100, 100)); | ||||
4739 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4740 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | 4e1ffa5 | 2023-02-21 11:50:34 -0800 | [diff] [blame] | 4741 | |
4742 | const int32_t mouseDeviceId = 7; | ||||
4743 | const int32_t touchDeviceId = 4; | ||||
Siarhei Vishniakou | 4e1ffa5 | 2023-02-21 11:50:34 -0800 | [diff] [blame] | 4744 | |
4745 | // Start hovering with the mouse | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4746 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) |
4747 | .deviceId(mouseDeviceId) | ||||
4748 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10)) | ||||
4749 | .build()); | ||||
Siarhei Vishniakou | 4e1ffa5 | 2023-02-21 11:50:34 -0800 | [diff] [blame] | 4750 | window->consumeMotionEvent( |
4751 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); | ||||
4752 | |||||
4753 | // Touch goes down | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4754 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
4755 | .deviceId(touchDeviceId) | ||||
4756 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
4757 | .build()); | ||||
Siarhei Vishniakou | 4e1ffa5 | 2023-02-21 11:50:34 -0800 | [diff] [blame] | 4758 | |
4759 | window->consumeMotionEvent( | ||||
4760 | AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId))); | ||||
4761 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
4762 | } | ||||
4763 | |||||
4764 | /** | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 4765 | * If mouse is hovering when the touch goes down, the hovering should not be stopped. |
4766 | */ | ||||
4767 | TEST_F(InputDispatcherTest, TouchDownAfterMouseHover) { | ||||
4768 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
4769 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
4770 | sp<FakeWindowHandle> window = | ||||
4771 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
4772 | window->setFrame(Rect(0, 0, 100, 100)); | ||||
4773 | |||||
4774 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
4775 | |||||
4776 | const int32_t mouseDeviceId = 7; | ||||
4777 | const int32_t touchDeviceId = 4; | ||||
4778 | |||||
4779 | // Start hovering with the mouse | ||||
4780 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) | ||||
4781 | .deviceId(mouseDeviceId) | ||||
4782 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10)) | ||||
4783 | .build()); | ||||
4784 | window->consumeMotionEvent( | ||||
4785 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); | ||||
4786 | |||||
4787 | // Touch goes down | ||||
4788 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
4789 | .deviceId(touchDeviceId) | ||||
4790 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
4791 | .build()); | ||||
4792 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
4793 | } | ||||
4794 | |||||
4795 | /** | ||||
Siarhei Vishniakou | 0b0374d | 2022-11-17 17:40:53 -0800 | [diff] [blame] | 4796 | * Inject a mouse hover event followed by a tap from touchscreen. |
Siarhei Vishniakou | b581f7f | 2022-12-07 20:23:06 +0000 | [diff] [blame] | 4797 | * The tap causes a HOVER_EXIT event to be generated because the current event |
4798 | * stream's source has been switched. | ||||
Siarhei Vishniakou | 0b0374d | 2022-11-17 17:40:53 -0800 | [diff] [blame] | 4799 | */ |
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 4800 | TEST_F(InputDispatcherTest, MouseHoverAndTouchTap_legacy) { |
4801 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); | ||||
Siarhei Vishniakou | 0b0374d | 2022-11-17 17:40:53 -0800 | [diff] [blame] | 4802 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
4803 | sp<FakeWindowHandle> window = | ||||
4804 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
4805 | window->setFrame(Rect(0, 0, 100, 100)); | ||||
4806 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4807 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 4808 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) |
4809 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50)) | ||||
4810 | .build()); | ||||
Siarhei Vishniakou | 0b0374d | 2022-11-17 17:40:53 -0800 | [diff] [blame] | 4811 | ASSERT_NO_FATAL_FAILURE( |
4812 | window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), | ||||
4813 | WithSource(AINPUT_SOURCE_MOUSE)))); | ||||
Siarhei Vishniakou | 0b0374d | 2022-11-17 17:40:53 -0800 | [diff] [blame] | 4814 | |
4815 | // Tap on the window | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 4816 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
4817 | .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10)) | ||||
4818 | .build()); | ||||
Siarhei Vishniakou | 0b0374d | 2022-11-17 17:40:53 -0800 | [diff] [blame] | 4819 | ASSERT_NO_FATAL_FAILURE( |
Siarhei Vishniakou | b581f7f | 2022-12-07 20:23:06 +0000 | [diff] [blame] | 4820 | window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT), |
4821 | WithSource(AINPUT_SOURCE_MOUSE)))); | ||||
4822 | |||||
4823 | ASSERT_NO_FATAL_FAILURE( | ||||
Siarhei Vishniakou | 0b0374d | 2022-11-17 17:40:53 -0800 | [diff] [blame] | 4824 | window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), |
4825 | WithSource(AINPUT_SOURCE_TOUCHSCREEN)))); | ||||
4826 | |||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 4827 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) |
4828 | .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10)) | ||||
4829 | .build()); | ||||
Siarhei Vishniakou | 0b0374d | 2022-11-17 17:40:53 -0800 | [diff] [blame] | 4830 | ASSERT_NO_FATAL_FAILURE( |
4831 | window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), | ||||
4832 | WithSource(AINPUT_SOURCE_TOUCHSCREEN)))); | ||||
4833 | } | ||||
4834 | |||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 4835 | /** |
4836 | * Send a mouse hover event followed by a tap from touchscreen. | ||||
4837 | * The tap causes a HOVER_EXIT event to be generated because the current event | ||||
4838 | * stream's source has been switched. | ||||
4839 | */ | ||||
4840 | TEST_F(InputDispatcherTest, MouseHoverAndTouchTap) { | ||||
4841 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
4842 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
4843 | sp<FakeWindowHandle> window = | ||||
4844 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
4845 | window->setFrame(Rect(0, 0, 100, 100)); | ||||
4846 | |||||
4847 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
4848 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) | ||||
4849 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50)) | ||||
4850 | .build()); | ||||
4851 | |||||
4852 | window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), | ||||
4853 | WithSource(AINPUT_SOURCE_MOUSE))); | ||||
4854 | |||||
4855 | // Tap on the window | ||||
4856 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
4857 | .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10)) | ||||
4858 | .build()); | ||||
4859 | |||||
4860 | window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT), | ||||
4861 | WithSource(AINPUT_SOURCE_MOUSE))); | ||||
4862 | |||||
4863 | window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), | ||||
4864 | WithSource(AINPUT_SOURCE_TOUCHSCREEN))); | ||||
4865 | |||||
4866 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
4867 | .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10)) | ||||
4868 | .build()); | ||||
4869 | |||||
4870 | window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), | ||||
4871 | WithSource(AINPUT_SOURCE_TOUCHSCREEN))); | ||||
4872 | } | ||||
4873 | |||||
Tommy Nordgren | dae9dfc | 2022-10-13 11:25:57 +0200 | [diff] [blame] | 4874 | TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) { |
4875 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
4876 | sp<FakeWindowHandle> windowDefaultDisplay = | ||||
4877 | sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay", | ||||
4878 | ADISPLAY_ID_DEFAULT); | ||||
4879 | windowDefaultDisplay->setFrame(Rect(0, 0, 600, 800)); | ||||
4880 | sp<FakeWindowHandle> windowSecondDisplay = | ||||
4881 | sp<FakeWindowHandle>::make(application, mDispatcher, "SecondDisplay", | ||||
4882 | SECOND_DISPLAY_ID); | ||||
4883 | windowSecondDisplay->setFrame(Rect(0, 0, 600, 800)); | ||||
4884 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4885 | mDispatcher->onWindowInfosChanged( |
4886 | {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0}); | ||||
Tommy Nordgren | dae9dfc | 2022-10-13 11:25:57 +0200 | [diff] [blame] | 4887 | |
4888 | // Set cursor position in window in default display and check that hover enter and move | ||||
4889 | // events are generated. | ||||
4890 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4891 | injectMotionEvent(*mDispatcher, |
Tommy Nordgren | dae9dfc | 2022-10-13 11:25:57 +0200 | [diff] [blame] | 4892 | MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, |
4893 | AINPUT_SOURCE_MOUSE) | ||||
4894 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4895 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(600)) |
Tommy Nordgren | dae9dfc | 2022-10-13 11:25:57 +0200 | [diff] [blame] | 4896 | .build())); |
Siarhei Vishniakou | 5cee1e3 | 2022-11-29 12:35:39 -0800 | [diff] [blame] | 4897 | windowDefaultDisplay->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); |
Tommy Nordgren | dae9dfc | 2022-10-13 11:25:57 +0200 | [diff] [blame] | 4898 | |
4899 | // Remove all windows in secondary display and check that no event happens on window in | ||||
4900 | // primary display. | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4901 | mDispatcher->onWindowInfosChanged({{*windowDefaultDisplay->getInfo()}, {}, 0, 0}); |
4902 | |||||
Tommy Nordgren | dae9dfc | 2022-10-13 11:25:57 +0200 | [diff] [blame] | 4903 | windowDefaultDisplay->assertNoEvents(); |
4904 | |||||
4905 | // Move cursor position in window in default display and check that only hover move | ||||
4906 | // event is generated and not hover enter event. | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4907 | mDispatcher->onWindowInfosChanged( |
4908 | {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0}); | ||||
Tommy Nordgren | dae9dfc | 2022-10-13 11:25:57 +0200 | [diff] [blame] | 4909 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4910 | injectMotionEvent(*mDispatcher, |
Tommy Nordgren | dae9dfc | 2022-10-13 11:25:57 +0200 | [diff] [blame] | 4911 | MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, |
4912 | AINPUT_SOURCE_MOUSE) | ||||
4913 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4914 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(400).y(700)) |
Tommy Nordgren | dae9dfc | 2022-10-13 11:25:57 +0200 | [diff] [blame] | 4915 | .build())); |
Siarhei Vishniakou | 5cee1e3 | 2022-11-29 12:35:39 -0800 | [diff] [blame] | 4916 | windowDefaultDisplay->consumeMotionEvent( |
4917 | AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), | ||||
4918 | WithSource(AINPUT_SOURCE_MOUSE))); | ||||
Tommy Nordgren | dae9dfc | 2022-10-13 11:25:57 +0200 | [diff] [blame] | 4919 | windowDefaultDisplay->assertNoEvents(); |
4920 | } | ||||
4921 | |||||
Garfield Tan | 00f511d | 2019-06-12 16:55:40 -0700 | [diff] [blame] | 4922 | TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) { |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 4923 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Garfield Tan | 00f511d | 2019-06-12 16:55:40 -0700 | [diff] [blame] | 4924 | |
4925 | sp<FakeWindowHandle> windowLeft = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 4926 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); |
Garfield Tan | 00f511d | 2019-06-12 16:55:40 -0700 | [diff] [blame] | 4927 | windowLeft->setFrame(Rect(0, 0, 600, 800)); |
Garfield Tan | 00f511d | 2019-06-12 16:55:40 -0700 | [diff] [blame] | 4928 | sp<FakeWindowHandle> windowRight = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 4929 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); |
Garfield Tan | 00f511d | 2019-06-12 16:55:40 -0700 | [diff] [blame] | 4930 | windowRight->setFrame(Rect(600, 0, 1200, 800)); |
Garfield Tan | 00f511d | 2019-06-12 16:55:40 -0700 | [diff] [blame] | 4931 | |
4932 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); | ||||
4933 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4934 | mDispatcher->onWindowInfosChanged( |
4935 | {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0}); | ||||
Garfield Tan | 00f511d | 2019-06-12 16:55:40 -0700 | [diff] [blame] | 4936 | |
4937 | // Inject an event with coordinate in the area of right window, with mouse cursor in the area of | ||||
4938 | // left window. This event should be dispatched to the left window. | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 4939 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 4940 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE, |
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 4941 | ADISPLAY_ID_DEFAULT, {610, 400}, {599, 400})); |
Siarhei Vishniakou | c5ca85c | 2019-11-15 17:20:00 -0800 | [diff] [blame] | 4942 | windowLeft->consumeMotionDown(ADISPLAY_ID_DEFAULT); |
Garfield Tan | 00f511d | 2019-06-12 16:55:40 -0700 | [diff] [blame] | 4943 | windowRight->assertNoEvents(); |
4944 | } | ||||
4945 | |||||
Siarhei Vishniakou | 2bfa905 | 2019-11-21 18:10:54 -0800 | [diff] [blame] | 4946 | TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) { |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 4947 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 4948 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
4949 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
Vishnu Nair | 47074b8 | 2020-08-14 11:54:47 -0700 | [diff] [blame] | 4950 | window->setFocusable(true); |
Siarhei Vishniakou | 2bfa905 | 2019-11-21 18:10:54 -0800 | [diff] [blame] | 4951 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4952 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 4953 | setFocusedWindow(window); |
4954 | |||||
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 4955 | window->consumeFocusEvent(true); |
Siarhei Vishniakou | 2bfa905 | 2019-11-21 18:10:54 -0800 | [diff] [blame] | 4956 | |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4957 | mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); |
Siarhei Vishniakou | 2bfa905 | 2019-11-21 18:10:54 -0800 | [diff] [blame] | 4958 | |
4959 | // Window should receive key down event. | ||||
4960 | window->consumeKeyDown(ADISPLAY_ID_DEFAULT); | ||||
4961 | |||||
4962 | // When device reset happens, that key stream should be terminated with FLAG_CANCELED | ||||
4963 | // on the app side. | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4964 | mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID}); |
Prabir Pradhan | 7662a8d | 2023-12-15 01:58:14 +0000 | [diff] [blame] | 4965 | window->consumeKeyUp(ADISPLAY_ID_DEFAULT, AKEY_EVENT_FLAG_CANCELED); |
Siarhei Vishniakou | 2bfa905 | 2019-11-21 18:10:54 -0800 | [diff] [blame] | 4966 | } |
4967 | |||||
4968 | TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) { | ||||
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 4969 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 4970 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
4971 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | 2bfa905 | 2019-11-21 18:10:54 -0800 | [diff] [blame] | 4972 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4973 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | 2bfa905 | 2019-11-21 18:10:54 -0800 | [diff] [blame] | 4974 | |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4975 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
4976 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); | ||||
Siarhei Vishniakou | 2bfa905 | 2019-11-21 18:10:54 -0800 | [diff] [blame] | 4977 | |
4978 | // Window should receive motion down event. | ||||
4979 | window->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
4980 | |||||
4981 | // When device reset happens, that motion stream should be terminated with ACTION_CANCEL | ||||
4982 | // on the app side. | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 4983 | mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID}); |
Siarhei Vishniakou | 1ae72f1 | 2023-01-29 12:55:30 -0800 | [diff] [blame] | 4984 | window->consumeMotionEvent( |
4985 | AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT))); | ||||
Siarhei Vishniakou | 2bfa905 | 2019-11-21 18:10:54 -0800 | [diff] [blame] | 4986 | } |
4987 | |||||
Siarhei Vishniakou | 0686f0c | 2023-05-02 11:56:15 -0700 | [diff] [blame] | 4988 | TEST_F(InputDispatcherTest, NotifyDeviceResetCancelsHoveringStream) { |
4989 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
4990 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, | ||||
4991 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
4992 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 4993 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | 0686f0c | 2023-05-02 11:56:15 -0700 | [diff] [blame] | 4994 | |
4995 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
4996 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(10)) | ||||
4997 | .build()); | ||||
4998 | |||||
4999 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
5000 | |||||
5001 | // When device reset happens, that hover stream should be terminated with ACTION_HOVER_EXIT | ||||
5002 | mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID}); | ||||
5003 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); | ||||
5004 | |||||
5005 | // After the device has been reset, a new hovering stream can be sent to the window | ||||
5006 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
5007 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(15).y(15)) | ||||
5008 | .build()); | ||||
5009 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
5010 | } | ||||
5011 | |||||
Arthur Hung | 2ee6d0b | 2022-03-03 20:19:38 +0800 | [diff] [blame] | 5012 | TEST_F(InputDispatcherTest, InterceptKeyByPolicy) { |
5013 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 5014 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
5015 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
Arthur Hung | 2ee6d0b | 2022-03-03 20:19:38 +0800 | [diff] [blame] | 5016 | window->setFocusable(true); |
5017 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 5018 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Arthur Hung | 2ee6d0b | 2022-03-03 20:19:38 +0800 | [diff] [blame] | 5019 | setFocusedWindow(window); |
5020 | |||||
5021 | window->consumeFocusEvent(true); | ||||
5022 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 5023 | const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); |
Arthur Hung | 2ee6d0b | 2022-03-03 20:19:38 +0800 | [diff] [blame] | 5024 | const std::chrono::milliseconds interceptKeyTimeout = 50ms; |
5025 | const nsecs_t injectTime = keyArgs.eventTime; | ||||
5026 | mFakePolicy->setInterceptKeyTimeout(interceptKeyTimeout); | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 5027 | mDispatcher->notifyKey(keyArgs); |
Arthur Hung | 2ee6d0b | 2022-03-03 20:19:38 +0800 | [diff] [blame] | 5028 | // The dispatching time should be always greater than or equal to intercept key timeout. |
5029 | window->consumeKeyDown(ADISPLAY_ID_DEFAULT); | ||||
5030 | ASSERT_TRUE((systemTime(SYSTEM_TIME_MONOTONIC) - injectTime) >= | ||||
5031 | std::chrono::nanoseconds(interceptKeyTimeout).count()); | ||||
5032 | } | ||||
5033 | |||||
Siarhei Vishniakou | f54d2ab | 2023-06-09 13:23:53 -0700 | [diff] [blame] | 5034 | /** |
5035 | * Keys with ACTION_UP are delivered immediately, even if a long 'intercept key timeout' is set. | ||||
5036 | */ | ||||
Arthur Hung | 2ee6d0b | 2022-03-03 20:19:38 +0800 | [diff] [blame] | 5037 | TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) { |
5038 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 5039 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
5040 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
Arthur Hung | 2ee6d0b | 2022-03-03 20:19:38 +0800 | [diff] [blame] | 5041 | window->setFocusable(true); |
5042 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 5043 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Arthur Hung | 2ee6d0b | 2022-03-03 20:19:38 +0800 | [diff] [blame] | 5044 | setFocusedWindow(window); |
5045 | |||||
5046 | window->consumeFocusEvent(true); | ||||
5047 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 5048 | mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); |
Arthur Hung | 2ee6d0b | 2022-03-03 20:19:38 +0800 | [diff] [blame] | 5049 | window->consumeKeyDown(ADISPLAY_ID_DEFAULT); |
Siarhei Vishniakou | f54d2ab | 2023-06-09 13:23:53 -0700 | [diff] [blame] | 5050 | |
5051 | // Set a value that's significantly larger than the default consumption timeout. If the | ||||
5052 | // implementation is correct, the actual value doesn't matter; it won't slow down the test. | ||||
5053 | mFakePolicy->setInterceptKeyTimeout(600ms); | ||||
5054 | mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT)); | ||||
5055 | // Window should receive key event immediately when same key up. | ||||
Arthur Hung | 2ee6d0b | 2022-03-03 20:19:38 +0800 | [diff] [blame] | 5056 | window->consumeKeyUp(ADISPLAY_ID_DEFAULT); |
5057 | } | ||||
5058 | |||||
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 5059 | /** |
Siarhei Vishniakou | 487c49b | 2022-12-02 15:48:57 -0800 | [diff] [blame] | 5060 | * Two windows. First is a regular window. Second does not overlap with the first, and has |
5061 | * WATCH_OUTSIDE_TOUCH. | ||||
5062 | * Both windows are owned by the same UID. | ||||
5063 | * Tap first window. Make sure that the second window receives ACTION_OUTSIDE with correct, non-zero | ||||
5064 | * coordinates. The coordinates are not zeroed out because both windows are owned by the same UID. | ||||
5065 | */ | ||||
5066 | TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinates) { | ||||
5067 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 5068 | sp<FakeWindowHandle> window = |
5069 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | 487c49b | 2022-12-02 15:48:57 -0800 | [diff] [blame] | 5070 | window->setFrame(Rect{0, 0, 100, 100}); |
5071 | |||||
5072 | sp<FakeWindowHandle> outsideWindow = | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 5073 | sp<FakeWindowHandle>::make(application, mDispatcher, "Outside Window", |
Siarhei Vishniakou | 487c49b | 2022-12-02 15:48:57 -0800 | [diff] [blame] | 5074 | ADISPLAY_ID_DEFAULT); |
5075 | outsideWindow->setFrame(Rect{100, 100, 200, 200}); | ||||
5076 | outsideWindow->setWatchOutsideTouch(true); | ||||
5077 | // outsideWindow must be above 'window' to receive ACTION_OUTSIDE events when 'window' is tapped | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 5078 | mDispatcher->onWindowInfosChanged({{*outsideWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | 487c49b | 2022-12-02 15:48:57 -0800 | [diff] [blame] | 5079 | |
5080 | // Tap on first window. | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 5081 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
5082 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
5083 | {PointF{50, 50}})); | ||||
Siarhei Vishniakou | 487c49b | 2022-12-02 15:48:57 -0800 | [diff] [blame] | 5084 | window->consumeMotionDown(); |
5085 | // The coordinates of the tap in 'outsideWindow' are relative to its top left corner. | ||||
5086 | // Therefore, we should offset them by (100, 100) relative to the screen's top left corner. | ||||
5087 | outsideWindow->consumeMotionEvent( | ||||
5088 | AllOf(WithMotionAction(ACTION_OUTSIDE), WithCoords(-50, -50))); | ||||
Prabir Pradhan | 502a725 | 2023-12-01 16:11:24 +0000 | [diff] [blame] | 5089 | |
5090 | // Ensure outsideWindow doesn't get any more events for the gesture. | ||||
5091 | mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, | ||||
5092 | ADISPLAY_ID_DEFAULT, {PointF{51, 51}})); | ||||
5093 | window->consumeMotionMove(); | ||||
5094 | outsideWindow->assertNoEvents(); | ||||
Siarhei Vishniakou | 487c49b | 2022-12-02 15:48:57 -0800 | [diff] [blame] | 5095 | } |
5096 | |||||
5097 | /** | ||||
Linnan Li | ccf6ce3 | 2024-04-11 20:32:13 +0800 | [diff] [blame] | 5098 | * Three windows: |
5099 | * - Left window | ||||
5100 | * - Right window | ||||
5101 | * - Outside window(watch for ACTION_OUTSIDE events) | ||||
5102 | * The windows "left" and "outside" share the same owner, the window "right" has a different owner, | ||||
5103 | * In order to allow the outside window can receive the ACTION_OUTSIDE events, the outside window is | ||||
5104 | * positioned above the "left" and "right" windows, and it doesn't overlap with them. | ||||
5105 | * | ||||
5106 | * First, device A report a down event landed in the right window, the outside window can receive | ||||
5107 | * an ACTION_OUTSIDE event that with zeroed coordinates, the device B report a down event landed | ||||
5108 | * in the left window, the outside window can receive an ACTION_OUTSIDE event the with valid | ||||
5109 | * coordinates, after these, device A and device B continue report MOVE event, the right and left | ||||
5110 | * window can receive it, but outside window event can't receive it. | ||||
5111 | */ | ||||
5112 | TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinatesWhenMultiDevice) { | ||||
5113 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
5114 | sp<FakeWindowHandle> leftWindow = | ||||
5115 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window", | ||||
5116 | ADISPLAY_ID_DEFAULT); | ||||
5117 | leftWindow->setFrame(Rect{0, 0, 100, 100}); | ||||
5118 | leftWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101}); | ||||
5119 | |||||
5120 | sp<FakeWindowHandle> outsideWindow = | ||||
5121 | sp<FakeWindowHandle>::make(application, mDispatcher, "Outside Window", | ||||
5122 | ADISPLAY_ID_DEFAULT); | ||||
5123 | outsideWindow->setFrame(Rect{100, 100, 200, 200}); | ||||
5124 | outsideWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101}); | ||||
5125 | outsideWindow->setWatchOutsideTouch(true); | ||||
5126 | |||||
5127 | std::shared_ptr<FakeApplicationHandle> anotherApplication = | ||||
5128 | std::make_shared<FakeApplicationHandle>(); | ||||
5129 | sp<FakeWindowHandle> rightWindow = | ||||
5130 | sp<FakeWindowHandle>::make(anotherApplication, mDispatcher, "Right Window", | ||||
5131 | ADISPLAY_ID_DEFAULT); | ||||
5132 | rightWindow->setFrame(Rect{100, 0, 200, 100}); | ||||
5133 | rightWindow->setOwnerInfo(gui::Pid{2}, gui::Uid{202}); | ||||
5134 | |||||
5135 | // OutsideWindow must be above left window and right window to receive ACTION_OUTSIDE events | ||||
5136 | // when left window or right window is tapped | ||||
5137 | mDispatcher->onWindowInfosChanged( | ||||
5138 | {{*outsideWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, | ||||
5139 | {}, | ||||
5140 | 0, | ||||
5141 | 0}); | ||||
5142 | |||||
5143 | const DeviceId deviceA = 9; | ||||
5144 | const DeviceId deviceB = 3; | ||||
5145 | |||||
5146 | // Tap on right window use device A | ||||
5147 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
5148 | .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) | ||||
5149 | .deviceId(deviceA) | ||||
5150 | .build()); | ||||
5151 | leftWindow->assertNoEvents(); | ||||
5152 | rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA))); | ||||
5153 | // Right window is belonged to another owner, so outsideWindow should receive ACTION_OUTSIDE | ||||
5154 | // with zeroed coords. | ||||
5155 | outsideWindow->consumeMotionEvent( | ||||
5156 | AllOf(WithMotionAction(ACTION_OUTSIDE), WithDeviceId(deviceA), WithCoords(0, 0))); | ||||
5157 | |||||
5158 | // Tap on left window use device B | ||||
5159 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
5160 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
5161 | .deviceId(deviceB) | ||||
5162 | .build()); | ||||
5163 | leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB))); | ||||
5164 | rightWindow->assertNoEvents(); | ||||
5165 | // Because new gesture down on the left window that has the same owner with outside Window, the | ||||
5166 | // outside Window should receive the ACTION_OUTSIDE with coords. | ||||
5167 | outsideWindow->consumeMotionEvent( | ||||
5168 | AllOf(WithMotionAction(ACTION_OUTSIDE), WithDeviceId(deviceB), WithCoords(-50, -50))); | ||||
5169 | |||||
5170 | // Ensure that windows that can only accept outside do not receive remaining gestures | ||||
5171 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
5172 | .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51)) | ||||
5173 | .deviceId(deviceA) | ||||
5174 | .build()); | ||||
5175 | leftWindow->assertNoEvents(); | ||||
5176 | rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA))); | ||||
5177 | |||||
5178 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
5179 | .pointer(PointerBuilder(0, ToolType::FINGER).x(51).y(51)) | ||||
5180 | .deviceId(deviceB) | ||||
5181 | .build()); | ||||
5182 | leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB))); | ||||
5183 | rightWindow->assertNoEvents(); | ||||
5184 | outsideWindow->assertNoEvents(); | ||||
5185 | } | ||||
5186 | |||||
5187 | /** | ||||
Prabir Pradhan | b60b1dc | 2022-03-15 14:02:35 +0000 | [diff] [blame] | 5188 | * This test documents the behavior of WATCH_OUTSIDE_TOUCH. The window will get ACTION_OUTSIDE when |
5189 | * a another pointer causes ACTION_DOWN to be sent to another window for the first time. Only one | ||||
5190 | * ACTION_OUTSIDE event is sent per gesture. | ||||
5191 | */ | ||||
5192 | TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) { | ||||
5193 | // There are three windows that do not overlap. `window` wants to WATCH_OUTSIDE_TOUCH. | ||||
5194 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 5195 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
5196 | "First Window", ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | b60b1dc | 2022-03-15 14:02:35 +0000 | [diff] [blame] | 5197 | window->setWatchOutsideTouch(true); |
5198 | window->setFrame(Rect{0, 0, 100, 100}); | ||||
5199 | sp<FakeWindowHandle> secondWindow = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 5200 | sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", |
5201 | ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | b60b1dc | 2022-03-15 14:02:35 +0000 | [diff] [blame] | 5202 | secondWindow->setFrame(Rect{100, 100, 200, 200}); |
5203 | sp<FakeWindowHandle> thirdWindow = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 5204 | sp<FakeWindowHandle>::make(application, mDispatcher, "Third Window", |
5205 | ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | b60b1dc | 2022-03-15 14:02:35 +0000 | [diff] [blame] | 5206 | thirdWindow->setFrame(Rect{200, 200, 300, 300}); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 5207 | mDispatcher->onWindowInfosChanged( |
5208 | {{*window->getInfo(), *secondWindow->getInfo(), *thirdWindow->getInfo()}, {}, 0, 0}); | ||||
Prabir Pradhan | b60b1dc | 2022-03-15 14:02:35 +0000 | [diff] [blame] | 5209 | |
5210 | // First pointer lands outside all windows. `window` does not get ACTION_OUTSIDE. | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 5211 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
5212 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
5213 | {PointF{-10, -10}})); | ||||
Prabir Pradhan | b60b1dc | 2022-03-15 14:02:35 +0000 | [diff] [blame] | 5214 | window->assertNoEvents(); |
5215 | secondWindow->assertNoEvents(); | ||||
5216 | |||||
5217 | // The second pointer lands inside `secondWindow`, which should receive a DOWN event. | ||||
5218 | // Now, `window` should get ACTION_OUTSIDE. | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 5219 | mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, |
5220 | ADISPLAY_ID_DEFAULT, | ||||
5221 | {PointF{-10, -10}, PointF{105, 105}})); | ||||
Siarhei Vishniakou | 487c49b | 2022-12-02 15:48:57 -0800 | [diff] [blame] | 5222 | const std::map<int32_t, PointF> expectedPointers{{0, PointF{-10, -10}}, {1, PointF{105, 105}}}; |
5223 | window->consumeMotionEvent( | ||||
5224 | AllOf(WithMotionAction(ACTION_OUTSIDE), WithPointers(expectedPointers))); | ||||
Prabir Pradhan | b60b1dc | 2022-03-15 14:02:35 +0000 | [diff] [blame] | 5225 | secondWindow->consumeMotionDown(); |
5226 | thirdWindow->assertNoEvents(); | ||||
5227 | |||||
5228 | // The third pointer lands inside `thirdWindow`, which should receive a DOWN event. There is | ||||
5229 | // no ACTION_OUTSIDE sent to `window` because one has already been sent for this gesture. | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 5230 | mDispatcher->notifyMotion( |
5231 | generateMotionArgs(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
5232 | {PointF{-10, -10}, PointF{105, 105}, PointF{205, 205}})); | ||||
Prabir Pradhan | b60b1dc | 2022-03-15 14:02:35 +0000 | [diff] [blame] | 5233 | window->assertNoEvents(); |
5234 | secondWindow->consumeMotionMove(); | ||||
5235 | thirdWindow->consumeMotionDown(); | ||||
5236 | } | ||||
5237 | |||||
Prabir Pradhan | 814fe08 | 2022-07-22 20:22:18 +0000 | [diff] [blame] | 5238 | TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) { |
5239 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 5240 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
5241 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | 814fe08 | 2022-07-22 20:22:18 +0000 | [diff] [blame] | 5242 | window->setFocusable(true); |
5243 | |||||
Patrick Williams | d828f30 | 2023-04-28 17:52:08 -0500 | [diff] [blame] | 5244 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | 814fe08 | 2022-07-22 20:22:18 +0000 | [diff] [blame] | 5245 | setFocusedWindow(window); |
5246 | |||||
5247 | window->consumeFocusEvent(true); | ||||
5248 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 5249 | const NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); |
5250 | const NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); | ||||
5251 | mDispatcher->notifyKey(keyDown); | ||||
5252 | mDispatcher->notifyKey(keyUp); | ||||
Prabir Pradhan | 814fe08 | 2022-07-22 20:22:18 +0000 | [diff] [blame] | 5253 | |
5254 | window->consumeKeyDown(ADISPLAY_ID_DEFAULT); | ||||
5255 | window->consumeKeyUp(ADISPLAY_ID_DEFAULT); | ||||
5256 | |||||
5257 | // All windows are removed from the display. Ensure that we can no longer dispatch to it. | ||||
Patrick Williams | d828f30 | 2023-04-28 17:52:08 -0500 | [diff] [blame] | 5258 | mDispatcher->onWindowInfosChanged({{}, {}, 0, 0}); |
Prabir Pradhan | 814fe08 | 2022-07-22 20:22:18 +0000 | [diff] [blame] | 5259 | |
5260 | window->consumeFocusEvent(false); | ||||
5261 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 5262 | mDispatcher->notifyKey(keyDown); |
5263 | mDispatcher->notifyKey(keyUp); | ||||
Prabir Pradhan | 814fe08 | 2022-07-22 20:22:18 +0000 | [diff] [blame] | 5264 | window->assertNoEvents(); |
5265 | } | ||||
5266 | |||||
Arthur Hung | 9648374 | 2022-11-15 03:30:48 +0000 | [diff] [blame] | 5267 | TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) { |
5268 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
5269 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, | ||||
5270 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
5271 | // Ensure window is non-split and have some transform. | ||||
5272 | window->setPreventSplitting(true); | ||||
5273 | window->setWindowOffset(20, 40); | ||||
Patrick Williams | d828f30 | 2023-04-28 17:52:08 -0500 | [diff] [blame] | 5274 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Arthur Hung | 9648374 | 2022-11-15 03:30:48 +0000 | [diff] [blame] | 5275 | |
5276 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 5277 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Arthur Hung | 9648374 | 2022-11-15 03:30:48 +0000 | [diff] [blame] | 5278 | {50, 50})) |
5279 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
5280 | window->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
5281 | |||||
5282 | const MotionEvent secondFingerDownEvent = | ||||
5283 | MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
5284 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
5285 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 5286 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) |
5287 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(-30).y(-50)) | ||||
Arthur Hung | 9648374 | 2022-11-15 03:30:48 +0000 | [diff] [blame] | 5288 | .build(); |
5289 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 5290 | injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, |
Arthur Hung | 9648374 | 2022-11-15 03:30:48 +0000 | [diff] [blame] | 5291 | InputEventInjectionSync::WAIT_FOR_RESULT)) |
5292 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
5293 | |||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 5294 | std::unique_ptr<MotionEvent> event = window->consumeMotionEvent(); |
5295 | ASSERT_NE(nullptr, event); | ||||
5296 | EXPECT_EQ(POINTER_1_DOWN, event->getAction()); | ||||
5297 | EXPECT_EQ(70, event->getX(0)); // 50 + 20 | ||||
5298 | EXPECT_EQ(90, event->getY(0)); // 50 + 40 | ||||
5299 | EXPECT_EQ(-10, event->getX(1)); // -30 + 20 | ||||
5300 | EXPECT_EQ(-10, event->getY(1)); // -50 + 40 | ||||
Arthur Hung | 9648374 | 2022-11-15 03:30:48 +0000 | [diff] [blame] | 5301 | } |
5302 | |||||
Siarhei Vishniakou | 25537f8 | 2023-07-18 14:35:47 -0700 | [diff] [blame] | 5303 | /** |
5304 | * Two windows: a splittable and a non-splittable. | ||||
5305 | * The non-splittable window shouldn't receive any "incomplete" gestures. | ||||
5306 | * Send the first pointer to the splittable window, and then touch the non-splittable window. | ||||
5307 | * The second pointer should be dropped because the initial window is splittable, so it won't get | ||||
5308 | * any pointers outside of it, and the second window is non-splittable, so it shouldn't get any | ||||
5309 | * "incomplete" gestures. | ||||
5310 | */ | ||||
5311 | TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) { | ||||
5312 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
5313 | sp<FakeWindowHandle> leftWindow = | ||||
5314 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left splittable Window", | ||||
5315 | ADISPLAY_ID_DEFAULT); | ||||
5316 | leftWindow->setPreventSplitting(false); | ||||
5317 | leftWindow->setFrame(Rect(0, 0, 100, 100)); | ||||
5318 | sp<FakeWindowHandle> rightWindow = | ||||
5319 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right non-splittable Window", | ||||
5320 | ADISPLAY_ID_DEFAULT); | ||||
5321 | rightWindow->setPreventSplitting(true); | ||||
5322 | rightWindow->setFrame(Rect(100, 100, 200, 200)); | ||||
5323 | mDispatcher->onWindowInfosChanged( | ||||
5324 | {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); | ||||
5325 | |||||
5326 | // Touch down on left, splittable window | ||||
5327 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
5328 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
5329 | .build()); | ||||
5330 | leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); | ||||
5331 | |||||
5332 | mDispatcher->notifyMotion( | ||||
5333 | MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
5334 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) | ||||
5335 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150)) | ||||
5336 | .build()); | ||||
5337 | leftWindow->assertNoEvents(); | ||||
5338 | rightWindow->assertNoEvents(); | ||||
5339 | } | ||||
5340 | |||||
Harry Cutts | b166c00 | 2023-05-09 13:06:05 +0000 | [diff] [blame] | 5341 | TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) { |
5342 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
5343 | sp<FakeWindowHandle> window = | ||||
5344 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
5345 | window->setFrame(Rect(0, 0, 400, 400)); | ||||
5346 | sp<FakeWindowHandle> trustedOverlay = | ||||
5347 | sp<FakeWindowHandle>::make(application, mDispatcher, "Trusted Overlay", | ||||
5348 | ADISPLAY_ID_DEFAULT); | ||||
5349 | trustedOverlay->setSpy(true); | ||||
5350 | trustedOverlay->setTrustedOverlay(true); | ||||
5351 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 5352 | mDispatcher->onWindowInfosChanged({{*trustedOverlay->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Harry Cutts | b166c00 | 2023-05-09 13:06:05 +0000 | [diff] [blame] | 5353 | |
5354 | // Start a three-finger touchpad swipe | ||||
5355 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) | ||||
5356 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100)) | ||||
5357 | .classification(MotionClassification::MULTI_FINGER_SWIPE) | ||||
5358 | .build()); | ||||
5359 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE) | ||||
5360 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100)) | ||||
5361 | .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100)) | ||||
5362 | .classification(MotionClassification::MULTI_FINGER_SWIPE) | ||||
5363 | .build()); | ||||
5364 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE) | ||||
5365 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100)) | ||||
5366 | .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100)) | ||||
5367 | .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100)) | ||||
5368 | .classification(MotionClassification::MULTI_FINGER_SWIPE) | ||||
5369 | .build()); | ||||
5370 | |||||
5371 | trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); | ||||
5372 | trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); | ||||
5373 | trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_DOWN)); | ||||
5374 | |||||
5375 | // Move the swipe a bit | ||||
5376 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE) | ||||
5377 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) | ||||
5378 | .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105)) | ||||
5379 | .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105)) | ||||
5380 | .classification(MotionClassification::MULTI_FINGER_SWIPE) | ||||
5381 | .build()); | ||||
5382 | |||||
5383 | trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); | ||||
5384 | |||||
5385 | // End the swipe | ||||
5386 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE) | ||||
5387 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) | ||||
5388 | .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105)) | ||||
5389 | .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105)) | ||||
5390 | .classification(MotionClassification::MULTI_FINGER_SWIPE) | ||||
5391 | .build()); | ||||
5392 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE) | ||||
5393 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) | ||||
5394 | .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105)) | ||||
5395 | .classification(MotionClassification::MULTI_FINGER_SWIPE) | ||||
5396 | .build()); | ||||
5397 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE) | ||||
5398 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) | ||||
5399 | .classification(MotionClassification::MULTI_FINGER_SWIPE) | ||||
5400 | .build()); | ||||
5401 | |||||
5402 | trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_UP)); | ||||
5403 | trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_UP)); | ||||
5404 | trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_UP)); | ||||
5405 | |||||
5406 | window->assertNoEvents(); | ||||
5407 | } | ||||
5408 | |||||
5409 | TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeNotSentToSingleWindow) { | ||||
5410 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
5411 | sp<FakeWindowHandle> window = | ||||
5412 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
5413 | window->setFrame(Rect(0, 0, 400, 400)); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 5414 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Harry Cutts | b166c00 | 2023-05-09 13:06:05 +0000 | [diff] [blame] | 5415 | |
5416 | // Start a three-finger touchpad swipe | ||||
5417 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) | ||||
5418 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100)) | ||||
5419 | .classification(MotionClassification::MULTI_FINGER_SWIPE) | ||||
5420 | .build()); | ||||
5421 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE) | ||||
5422 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100)) | ||||
5423 | .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100)) | ||||
5424 | .classification(MotionClassification::MULTI_FINGER_SWIPE) | ||||
5425 | .build()); | ||||
5426 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE) | ||||
5427 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100)) | ||||
5428 | .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100)) | ||||
5429 | .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100)) | ||||
5430 | .classification(MotionClassification::MULTI_FINGER_SWIPE) | ||||
5431 | .build()); | ||||
5432 | |||||
5433 | // Move the swipe a bit | ||||
5434 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE) | ||||
5435 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) | ||||
5436 | .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105)) | ||||
5437 | .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105)) | ||||
5438 | .classification(MotionClassification::MULTI_FINGER_SWIPE) | ||||
5439 | .build()); | ||||
5440 | |||||
5441 | // End the swipe | ||||
5442 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE) | ||||
5443 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) | ||||
5444 | .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105)) | ||||
5445 | .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105)) | ||||
5446 | .classification(MotionClassification::MULTI_FINGER_SWIPE) | ||||
5447 | .build()); | ||||
5448 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE) | ||||
5449 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) | ||||
5450 | .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105)) | ||||
5451 | .classification(MotionClassification::MULTI_FINGER_SWIPE) | ||||
5452 | .build()); | ||||
5453 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE) | ||||
5454 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105)) | ||||
5455 | .classification(MotionClassification::MULTI_FINGER_SWIPE) | ||||
5456 | .build()); | ||||
5457 | |||||
5458 | window->assertNoEvents(); | ||||
5459 | } | ||||
5460 | |||||
Prabir Pradhan | b60b1dc | 2022-03-15 14:02:35 +0000 | [diff] [blame] | 5461 | /** |
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 5462 | * Send a two-pointer gesture to a single window. The window's orientation changes in response to |
5463 | * the first pointer. | ||||
Prabir Pradhan | 69d00bf | 2023-06-23 19:55:18 +0000 | [diff] [blame] | 5464 | * Ensure that the second pointer and the subsequent gesture is correctly delivered to the window. |
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 5465 | */ |
5466 | TEST_F(InputDispatcherTest, MultiplePointersWithRotatingWindow) { | ||||
5467 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
5468 | sp<FakeWindowHandle> window = | ||||
5469 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
5470 | window->setFrame(Rect(0, 0, 400, 400)); | ||||
Siarhei Vishniakou | 700424c | 2023-07-18 17:18:42 -0700 | [diff] [blame] | 5471 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 5472 | |
5473 | const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC); | ||||
5474 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
5475 | .downTime(baseTime + 10) | ||||
5476 | .eventTime(baseTime + 10) | ||||
5477 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
5478 | .build()); | ||||
5479 | |||||
5480 | window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); | ||||
5481 | |||||
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 5482 | // Change the transform so that the orientation is now different from original. |
Siarhei Vishniakou | 700424c | 2023-07-18 17:18:42 -0700 | [diff] [blame] | 5483 | window->setWindowTransform(0, -1, 1, 0); |
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 5484 | |
Siarhei Vishniakou | 700424c | 2023-07-18 17:18:42 -0700 | [diff] [blame] | 5485 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 5486 | |
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 5487 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
5488 | .downTime(baseTime + 10) | ||||
5489 | .eventTime(baseTime + 30) | ||||
5490 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
5491 | .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200)) | ||||
5492 | .build()); | ||||
5493 | |||||
Prabir Pradhan | 69d00bf | 2023-06-23 19:55:18 +0000 | [diff] [blame] | 5494 | window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); |
5495 | |||||
5496 | // Finish the gesture and start a new one. Ensure all events are sent to the window. | ||||
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 5497 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) |
5498 | .downTime(baseTime + 10) | ||||
5499 | .eventTime(baseTime + 40) | ||||
5500 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
5501 | .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200)) | ||||
5502 | .build()); | ||||
Prabir Pradhan | 69d00bf | 2023-06-23 19:55:18 +0000 | [diff] [blame] | 5503 | |
5504 | window->consumeMotionEvent(WithMotionAction(POINTER_1_UP)); | ||||
5505 | |||||
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 5506 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) |
5507 | .downTime(baseTime + 10) | ||||
5508 | .eventTime(baseTime + 50) | ||||
5509 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) | ||||
5510 | .build()); | ||||
5511 | |||||
Prabir Pradhan | 69d00bf | 2023-06-23 19:55:18 +0000 | [diff] [blame] | 5512 | window->consumeMotionEvent(WithMotionAction(ACTION_UP)); |
5513 | |||||
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 5514 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
5515 | .downTime(baseTime + 60) | ||||
5516 | .eventTime(baseTime + 60) | ||||
5517 | .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40)) | ||||
5518 | .build()); | ||||
5519 | |||||
Siarhei Vishniakou | 700424c | 2023-07-18 17:18:42 -0700 | [diff] [blame] | 5520 | window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); |
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 5521 | } |
5522 | |||||
5523 | /** | ||||
Hu Guo | 771a769 | 2023-09-17 20:51:08 +0800 | [diff] [blame] | 5524 | * When there are multiple screens, such as screen projection to TV or screen recording, if the |
5525 | * cancel event occurs, the coordinates of the cancel event should be sent to the target screen, and | ||||
5526 | * its coordinates should be converted by the transform of the windows of target screen. | ||||
5527 | */ | ||||
5528 | TEST_F(InputDispatcherTest, WhenMultiDisplayWindowSameToken_DispatchCancelToTargetDisplay) { | ||||
5529 | // This case will create a window and a spy window on the default display and mirror | ||||
5530 | // window on the second display. cancel event is sent through spy window pilferPointers | ||||
5531 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
5532 | |||||
5533 | sp<FakeWindowHandle> spyWindowDefaultDisplay = | ||||
5534 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); | ||||
5535 | spyWindowDefaultDisplay->setTrustedOverlay(true); | ||||
5536 | spyWindowDefaultDisplay->setSpy(true); | ||||
5537 | |||||
5538 | sp<FakeWindowHandle> windowDefaultDisplay = | ||||
5539 | sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay", | ||||
5540 | ADISPLAY_ID_DEFAULT); | ||||
5541 | windowDefaultDisplay->setWindowTransform(1, 0, 0, 1); | ||||
5542 | |||||
5543 | sp<FakeWindowHandle> windowSecondDisplay = windowDefaultDisplay->clone(SECOND_DISPLAY_ID); | ||||
5544 | windowSecondDisplay->setWindowTransform(2, 0, 0, 2); | ||||
5545 | |||||
5546 | // Add the windows to the dispatcher | ||||
5547 | mDispatcher->onWindowInfosChanged( | ||||
5548 | {{*spyWindowDefaultDisplay->getInfo(), *windowDefaultDisplay->getInfo(), | ||||
5549 | *windowSecondDisplay->getInfo()}, | ||||
5550 | {}, | ||||
5551 | 0, | ||||
5552 | 0}); | ||||
5553 | |||||
5554 | // Send down to ADISPLAY_ID_DEFAULT | ||||
5555 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
5556 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
5557 | {100, 100})) | ||||
5558 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
5559 | |||||
5560 | spyWindowDefaultDisplay->consumeMotionDown(); | ||||
5561 | windowDefaultDisplay->consumeMotionDown(); | ||||
5562 | |||||
5563 | EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindowDefaultDisplay->getToken())); | ||||
5564 | |||||
5565 | // windowDefaultDisplay gets cancel | ||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 5566 | std::unique_ptr<MotionEvent> event = windowDefaultDisplay->consumeMotionEvent(); |
5567 | ASSERT_NE(nullptr, event); | ||||
5568 | EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event->getAction()); | ||||
Hu Guo | 771a769 | 2023-09-17 20:51:08 +0800 | [diff] [blame] | 5569 | |
5570 | // The cancel event is sent to windowDefaultDisplay of the ADISPLAY_ID_DEFAULT display, so the | ||||
5571 | // coordinates of the cancel are converted by windowDefaultDisplay's transform, the x and y | ||||
5572 | // coordinates are both 100, otherwise if the cancel event is sent to windowSecondDisplay of | ||||
5573 | // SECOND_DISPLAY_ID, the x and y coordinates are 200 | ||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 5574 | EXPECT_EQ(100, event->getX(0)); |
5575 | EXPECT_EQ(100, event->getY(0)); | ||||
Hu Guo | 771a769 | 2023-09-17 20:51:08 +0800 | [diff] [blame] | 5576 | } |
5577 | |||||
5578 | /** | ||||
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 5579 | * Ensure the correct coordinate spaces are used by InputDispatcher. |
5580 | * | ||||
5581 | * InputDispatcher works in the display space, so its coordinate system is relative to the display | ||||
5582 | * panel. Windows get events in the window space, and get raw coordinates in the logical display | ||||
5583 | * space. | ||||
5584 | */ | ||||
5585 | class InputDispatcherDisplayProjectionTest : public InputDispatcherTest { | ||||
5586 | public: | ||||
5587 | void SetUp() override { | ||||
5588 | InputDispatcherTest::SetUp(); | ||||
Prabir Pradhan | 33e3baa | 2022-12-06 20:30:22 +0000 | [diff] [blame] | 5589 | removeAllWindowsAndDisplays(); |
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 5590 | } |
5591 | |||||
5592 | void addDisplayInfo(int displayId, const ui::Transform& transform) { | ||||
5593 | gui::DisplayInfo info; | ||||
5594 | info.displayId = displayId; | ||||
5595 | info.transform = transform; | ||||
5596 | mDisplayInfos.push_back(std::move(info)); | ||||
Patrick Williams | d828f30 | 2023-04-28 17:52:08 -0500 | [diff] [blame] | 5597 | mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0}); |
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 5598 | } |
5599 | |||||
5600 | void addWindow(const sp<WindowInfoHandle>& windowHandle) { | ||||
5601 | mWindowInfos.push_back(*windowHandle->getInfo()); | ||||
Patrick Williams | d828f30 | 2023-04-28 17:52:08 -0500 | [diff] [blame] | 5602 | mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0}); |
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 5603 | } |
5604 | |||||
Prabir Pradhan | 33e3baa | 2022-12-06 20:30:22 +0000 | [diff] [blame] | 5605 | void removeAllWindowsAndDisplays() { |
5606 | mDisplayInfos.clear(); | ||||
5607 | mWindowInfos.clear(); | ||||
5608 | } | ||||
5609 | |||||
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 5610 | // Set up a test scenario where the display has a scaled projection and there are two windows |
5611 | // on the display. | ||||
5612 | std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupScaledDisplayScenario() { | ||||
5613 | // The display has a projection that has a scale factor of 2 and 4 in the x and y directions | ||||
5614 | // respectively. | ||||
5615 | ui::Transform displayTransform; | ||||
5616 | displayTransform.set(2, 0, 0, 4); | ||||
5617 | addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform); | ||||
5618 | |||||
5619 | std::shared_ptr<FakeApplicationHandle> application = | ||||
5620 | std::make_shared<FakeApplicationHandle>(); | ||||
5621 | |||||
5622 | // Add two windows to the display. Their frames are represented in the display space. | ||||
5623 | sp<FakeWindowHandle> firstWindow = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 5624 | sp<FakeWindowHandle>::make(application, mDispatcher, "First Window", |
5625 | ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 5626 | firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform); |
5627 | addWindow(firstWindow); | ||||
5628 | |||||
5629 | sp<FakeWindowHandle> secondWindow = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 5630 | sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", |
5631 | ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 5632 | secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform); |
5633 | addWindow(secondWindow); | ||||
5634 | return {std::move(firstWindow), std::move(secondWindow)}; | ||||
5635 | } | ||||
5636 | |||||
5637 | private: | ||||
5638 | std::vector<gui::DisplayInfo> mDisplayInfos; | ||||
5639 | std::vector<gui::WindowInfo> mWindowInfos; | ||||
5640 | }; | ||||
5641 | |||||
Prabir Pradhan | 33e3baa | 2022-12-06 20:30:22 +0000 | [diff] [blame] | 5642 | TEST_F(InputDispatcherDisplayProjectionTest, HitTestCoordinateSpaceConsistency) { |
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 5643 | auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); |
5644 | // Send down to the first window. The point is represented in the display space. The point is | ||||
Prabir Pradhan | 33e3baa | 2022-12-06 20:30:22 +0000 | [diff] [blame] | 5645 | // selected so that if the hit test was performed with the point and the bounds being in |
5646 | // different coordinate spaces, the event would end up in the incorrect window. | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 5647 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
5648 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
5649 | {PointF{75, 55}})); | ||||
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 5650 | |
5651 | firstWindow->consumeMotionDown(); | ||||
5652 | secondWindow->assertNoEvents(); | ||||
5653 | } | ||||
5654 | |||||
5655 | // Ensure that when a MotionEvent is injected through the InputDispatcher::injectInputEvent() API, | ||||
5656 | // the event should be treated as being in the logical display space. | ||||
5657 | TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) { | ||||
5658 | auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); | ||||
5659 | // Send down to the first window. The point is represented in the logical display space. The | ||||
5660 | // point is selected so that if the hit test was done in logical display space, then it would | ||||
5661 | // end up in the incorrect window. | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 5662 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 5663 | PointF{75 * 2, 55 * 4}); |
5664 | |||||
5665 | firstWindow->consumeMotionDown(); | ||||
5666 | secondWindow->assertNoEvents(); | ||||
5667 | } | ||||
5668 | |||||
Prabir Pradhan | daa2f14 | 2021-12-10 09:30:08 +0000 | [diff] [blame] | 5669 | // Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed |
5670 | // event should be treated as being in the logical display space. | ||||
5671 | TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) { | ||||
5672 | auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); | ||||
5673 | |||||
5674 | const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0}; | ||||
5675 | ui::Transform injectedEventTransform; | ||||
5676 | injectedEventTransform.set(matrix); | ||||
5677 | const vec2 expectedPoint{75, 55}; // The injected point in the logical display space. | ||||
5678 | const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint); | ||||
5679 | |||||
5680 | MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
5681 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
5682 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 5683 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER) |
Prabir Pradhan | daa2f14 | 2021-12-10 09:30:08 +0000 | [diff] [blame] | 5684 | .x(untransformedPoint.x) |
5685 | .y(untransformedPoint.y)) | ||||
5686 | .build(); | ||||
5687 | event.transform(matrix); | ||||
5688 | |||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 5689 | injectMotionEvent(*mDispatcher, event, INJECT_EVENT_TIMEOUT, |
Prabir Pradhan | daa2f14 | 2021-12-10 09:30:08 +0000 | [diff] [blame] | 5690 | InputEventInjectionSync::WAIT_FOR_RESULT); |
5691 | |||||
5692 | firstWindow->consumeMotionDown(); | ||||
5693 | secondWindow->assertNoEvents(); | ||||
5694 | } | ||||
5695 | |||||
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 5696 | TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) { |
5697 | auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); | ||||
5698 | |||||
5699 | // Send down to the second window. | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 5700 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
5701 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
5702 | {PointF{150, 220}})); | ||||
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 5703 | |
5704 | firstWindow->assertNoEvents(); | ||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 5705 | std::unique_ptr<MotionEvent> event = secondWindow->consumeMotionEvent(); |
5706 | ASSERT_NE(nullptr, event); | ||||
5707 | EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event->getAction()); | ||||
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 5708 | |
5709 | // Ensure that the events from the "getRaw" API are in logical display coordinates. | ||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 5710 | EXPECT_EQ(300, event->getRawX(0)); |
5711 | EXPECT_EQ(880, event->getRawY(0)); | ||||
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 5712 | |
5713 | // Ensure that the x and y values are in the window's coordinate space. | ||||
5714 | // The left-top of the second window is at (100, 200) in display space, which is (200, 800) in | ||||
5715 | // the logical display space. This will be the origin of the window space. | ||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 5716 | EXPECT_EQ(100, event->getX(0)); |
5717 | EXPECT_EQ(80, event->getY(0)); | ||||
Prabir Pradhan | c44ce4d | 2021-10-05 05:26:29 -0700 | [diff] [blame] | 5718 | } |
5719 | |||||
Prabir Pradhan | 112b1ad | 2023-09-21 09:53:53 +0000 | [diff] [blame] | 5720 | TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) { |
5721 | auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); | ||||
5722 | // The monitor will always receive events in the logical display's coordinate space, because | ||||
5723 | // it does not have a window. | ||||
Prabir Pradhan | fb54907 | 2023-10-05 19:17:36 +0000 | [diff] [blame] | 5724 | FakeMonitorReceiver monitor{*mDispatcher, "Monitor", ADISPLAY_ID_DEFAULT}; |
Prabir Pradhan | 112b1ad | 2023-09-21 09:53:53 +0000 | [diff] [blame] | 5725 | |
5726 | // Send down to the first window. | ||||
5727 | mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, | ||||
5728 | ADISPLAY_ID_DEFAULT, {PointF{50, 100}})); | ||||
5729 | firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400))); | ||||
5730 | monitor.consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400))); | ||||
5731 | |||||
5732 | // Second pointer goes down on second window. | ||||
5733 | mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, | ||||
5734 | ADISPLAY_ID_DEFAULT, | ||||
5735 | {PointF{50, 100}, PointF{150, 220}})); | ||||
5736 | secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80))); | ||||
5737 | const std::map<int32_t, PointF> expectedMonitorPointers{{0, PointF{100, 400}}, | ||||
5738 | {1, PointF{300, 880}}}; | ||||
5739 | monitor.consumeMotionEvent( | ||||
5740 | AllOf(WithMotionAction(POINTER_1_DOWN), WithPointers(expectedMonitorPointers))); | ||||
5741 | |||||
5742 | mDispatcher->cancelCurrentTouch(); | ||||
5743 | |||||
5744 | firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400))); | ||||
5745 | secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 80))); | ||||
5746 | monitor.consumeMotionEvent( | ||||
5747 | AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedMonitorPointers))); | ||||
5748 | } | ||||
5749 | |||||
Prabir Pradhan | 1c29a09 | 2023-09-21 10:29:29 +0000 | [diff] [blame] | 5750 | TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeDownWithCorrectCoordinates) { |
5751 | auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); | ||||
5752 | |||||
5753 | // Send down to the first window. | ||||
5754 | mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, | ||||
5755 | ADISPLAY_ID_DEFAULT, {PointF{50, 100}})); | ||||
5756 | firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400))); | ||||
5757 | |||||
5758 | // The pointer is transferred to the second window, and the second window receives it in the | ||||
5759 | // correct coordinate space. | ||||
Prabir Pradhan | 367f343 | 2024-02-13 23:05:58 +0000 | [diff] [blame] | 5760 | mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken()); |
Prabir Pradhan | 1c29a09 | 2023-09-21 10:29:29 +0000 | [diff] [blame] | 5761 | firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400))); |
5762 | secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(-100, -400))); | ||||
5763 | } | ||||
5764 | |||||
Prabir Pradhan | 0dfcac7 | 2023-10-05 20:04:21 +0000 | [diff] [blame] | 5765 | TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverEnterExitWithCorrectCoordinates) { |
5766 | auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); | ||||
5767 | |||||
5768 | // Send hover move to the second window, and ensure it shows up as hover enter. | ||||
5769 | mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS, | ||||
5770 | ADISPLAY_ID_DEFAULT, {PointF{150, 220}})); | ||||
5771 | secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER), | ||||
5772 | WithCoords(100, 80), WithRawCoords(300, 880))); | ||||
5773 | |||||
5774 | // Touch down at the same location and ensure a hover exit is synthesized. | ||||
5775 | mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS, | ||||
5776 | ADISPLAY_ID_DEFAULT, {PointF{150, 220}})); | ||||
5777 | secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80), | ||||
5778 | WithRawCoords(300, 880))); | ||||
5779 | secondWindow->consumeMotionEvent( | ||||
5780 | AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880))); | ||||
5781 | secondWindow->assertNoEvents(); | ||||
5782 | firstWindow->assertNoEvents(); | ||||
5783 | } | ||||
5784 | |||||
Prabir Pradhan | 453ae73 | 2023-10-13 14:30:14 +0000 | [diff] [blame] | 5785 | // Same as above, but while the window is being mirrored. |
5786 | TEST_F(InputDispatcherDisplayProjectionTest, | ||||
5787 | SynthesizeHoverEnterExitWithCorrectCoordinatesWhenMirrored) { | ||||
5788 | auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); | ||||
5789 | |||||
5790 | const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0}; | ||||
5791 | ui::Transform secondDisplayTransform; | ||||
5792 | secondDisplayTransform.set(matrix); | ||||
5793 | addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform); | ||||
5794 | |||||
5795 | sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID); | ||||
5796 | secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4); | ||||
5797 | addWindow(secondWindowClone); | ||||
5798 | |||||
5799 | // Send hover move to the second window, and ensure it shows up as hover enter. | ||||
5800 | mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS, | ||||
5801 | ADISPLAY_ID_DEFAULT, {PointF{150, 220}})); | ||||
5802 | secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER), | ||||
5803 | WithCoords(100, 80), WithRawCoords(300, 880))); | ||||
5804 | |||||
5805 | // Touch down at the same location and ensure a hover exit is synthesized for the correct | ||||
5806 | // display. | ||||
5807 | mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS, | ||||
5808 | ADISPLAY_ID_DEFAULT, {PointF{150, 220}})); | ||||
5809 | secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80), | ||||
5810 | WithRawCoords(300, 880))); | ||||
5811 | secondWindow->consumeMotionEvent( | ||||
5812 | AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880))); | ||||
5813 | secondWindow->assertNoEvents(); | ||||
5814 | firstWindow->assertNoEvents(); | ||||
5815 | } | ||||
5816 | |||||
Prabir Pradhan | 0dfcac7 | 2023-10-05 20:04:21 +0000 | [diff] [blame] | 5817 | TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorrectCoordinates) { |
5818 | auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); | ||||
5819 | |||||
5820 | // Send hover enter to second window | ||||
5821 | mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS, | ||||
5822 | ADISPLAY_ID_DEFAULT, {PointF{150, 220}})); | ||||
5823 | secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER), | ||||
5824 | WithCoords(100, 80), WithRawCoords(300, 880))); | ||||
5825 | |||||
5826 | mDispatcher->cancelCurrentTouch(); | ||||
5827 | |||||
5828 | secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80), | ||||
5829 | WithRawCoords(300, 880))); | ||||
5830 | secondWindow->assertNoEvents(); | ||||
5831 | firstWindow->assertNoEvents(); | ||||
5832 | } | ||||
5833 | |||||
Prabir Pradhan | 453ae73 | 2023-10-13 14:30:14 +0000 | [diff] [blame] | 5834 | // Same as above, but while the window is being mirrored. |
Prabir Pradhan | 1646338 | 2023-10-12 23:03:19 +0000 | [diff] [blame] | 5835 | TEST_F(InputDispatcherDisplayProjectionTest, |
5836 | SynthesizeHoverCancelationWithCorrectCoordinatesWhenMirrored) { | ||||
5837 | auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); | ||||
5838 | |||||
5839 | const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0}; | ||||
5840 | ui::Transform secondDisplayTransform; | ||||
5841 | secondDisplayTransform.set(matrix); | ||||
5842 | addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform); | ||||
5843 | |||||
5844 | sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID); | ||||
5845 | secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4); | ||||
5846 | addWindow(secondWindowClone); | ||||
5847 | |||||
5848 | // Send hover enter to second window | ||||
5849 | mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS, | ||||
5850 | ADISPLAY_ID_DEFAULT, {PointF{150, 220}})); | ||||
5851 | secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER), | ||||
5852 | WithCoords(100, 80), WithRawCoords(300, 880), | ||||
5853 | WithDisplayId(ADISPLAY_ID_DEFAULT))); | ||||
5854 | |||||
5855 | mDispatcher->cancelCurrentTouch(); | ||||
5856 | |||||
5857 | // Ensure the cancelation happens with the correct displayId and the correct coordinates. | ||||
5858 | secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80), | ||||
5859 | WithRawCoords(300, 880), | ||||
5860 | WithDisplayId(ADISPLAY_ID_DEFAULT))); | ||||
5861 | secondWindow->assertNoEvents(); | ||||
5862 | firstWindow->assertNoEvents(); | ||||
5863 | } | ||||
5864 | |||||
Prabir Pradhan | 33e3baa | 2022-12-06 20:30:22 +0000 | [diff] [blame] | 5865 | /** Ensure consistent behavior of InputDispatcher in all orientations. */ |
5866 | class InputDispatcherDisplayOrientationFixture | ||||
5867 | : public InputDispatcherDisplayProjectionTest, | ||||
5868 | public ::testing::WithParamInterface<ui::Rotation> {}; | ||||
5869 | |||||
5870 | // This test verifies the touchable region of a window for all rotations of the display by tapping | ||||
5871 | // in different locations on the display, specifically points close to the four corners of a | ||||
5872 | // window. | ||||
5873 | TEST_P(InputDispatcherDisplayOrientationFixture, HitTestInDifferentOrientations) { | ||||
5874 | constexpr static int32_t displayWidth = 400; | ||||
5875 | constexpr static int32_t displayHeight = 800; | ||||
5876 | |||||
5877 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
5878 | |||||
5879 | const auto rotation = GetParam(); | ||||
5880 | |||||
5881 | // Set up the display with the specified rotation. | ||||
5882 | const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270; | ||||
5883 | const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth; | ||||
5884 | const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight; | ||||
5885 | const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation), | ||||
5886 | logicalDisplayWidth, logicalDisplayHeight); | ||||
5887 | addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform); | ||||
5888 | |||||
5889 | // Create a window with its bounds determined in the logical display. | ||||
5890 | const Rect frameInLogicalDisplay(100, 100, 200, 300); | ||||
5891 | const Rect frameInDisplay = displayTransform.inverse().transform(frameInLogicalDisplay); | ||||
5892 | sp<FakeWindowHandle> window = | ||||
5893 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
5894 | window->setFrame(frameInDisplay, displayTransform); | ||||
5895 | addWindow(window); | ||||
5896 | |||||
5897 | // The following points in logical display space should be inside the window. | ||||
5898 | static const std::array<vec2, 4> insidePoints{ | ||||
5899 | {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}}; | ||||
5900 | for (const auto pointInsideWindow : insidePoints) { | ||||
5901 | const vec2 p = displayTransform.inverse().transform(pointInsideWindow); | ||||
5902 | const PointF pointInDisplaySpace{p.x, p.y}; | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 5903 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
5904 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
5905 | {pointInDisplaySpace})); | ||||
Prabir Pradhan | 33e3baa | 2022-12-06 20:30:22 +0000 | [diff] [blame] | 5906 | window->consumeMotionDown(); |
5907 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 5908 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, |
5909 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
5910 | {pointInDisplaySpace})); | ||||
Prabir Pradhan | 33e3baa | 2022-12-06 20:30:22 +0000 | [diff] [blame] | 5911 | window->consumeMotionUp(); |
5912 | } | ||||
5913 | |||||
5914 | // The following points in logical display space should be outside the window. | ||||
5915 | static const std::array<vec2, 5> outsidePoints{ | ||||
5916 | {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}}; | ||||
5917 | for (const auto pointOutsideWindow : outsidePoints) { | ||||
5918 | const vec2 p = displayTransform.inverse().transform(pointOutsideWindow); | ||||
5919 | const PointF pointInDisplaySpace{p.x, p.y}; | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 5920 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
5921 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
5922 | {pointInDisplaySpace})); | ||||
Prabir Pradhan | 33e3baa | 2022-12-06 20:30:22 +0000 | [diff] [blame] | 5923 | |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 5924 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, |
5925 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
5926 | {pointInDisplaySpace})); | ||||
Prabir Pradhan | 33e3baa | 2022-12-06 20:30:22 +0000 | [diff] [blame] | 5927 | } |
5928 | window->assertNoEvents(); | ||||
5929 | } | ||||
5930 | |||||
Linnan Li | 5e5645e | 2024-03-05 14:43:05 +0000 | [diff] [blame] | 5931 | // This test verifies the occlusion detection for all rotations of the display by tapping |
5932 | // in different locations on the display, specifically points close to the four corners of a | ||||
5933 | // window. | ||||
5934 | TEST_P(InputDispatcherDisplayOrientationFixture, BlockUntrustClickInDifferentOrientations) { | ||||
5935 | constexpr static int32_t displayWidth = 400; | ||||
5936 | constexpr static int32_t displayHeight = 800; | ||||
5937 | |||||
5938 | std::shared_ptr<FakeApplicationHandle> untrustedWindowApplication = | ||||
5939 | std::make_shared<FakeApplicationHandle>(); | ||||
5940 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
5941 | |||||
5942 | const auto rotation = GetParam(); | ||||
5943 | |||||
5944 | // Set up the display with the specified rotation. | ||||
5945 | const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270; | ||||
5946 | const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth; | ||||
5947 | const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight; | ||||
5948 | const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation), | ||||
5949 | logicalDisplayWidth, logicalDisplayHeight); | ||||
5950 | addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform); | ||||
5951 | |||||
5952 | // Create a window that not trusted. | ||||
5953 | const Rect untrustedWindowFrameInLogicalDisplay(100, 100, 200, 300); | ||||
5954 | |||||
5955 | const Rect untrustedWindowFrameInDisplay = | ||||
5956 | displayTransform.inverse().transform(untrustedWindowFrameInLogicalDisplay); | ||||
5957 | |||||
5958 | sp<FakeWindowHandle> untrustedWindow = | ||||
5959 | sp<FakeWindowHandle>::make(untrustedWindowApplication, mDispatcher, "UntrustedWindow", | ||||
5960 | ADISPLAY_ID_DEFAULT); | ||||
5961 | untrustedWindow->setFrame(untrustedWindowFrameInDisplay, displayTransform); | ||||
5962 | untrustedWindow->setTrustedOverlay(false); | ||||
5963 | untrustedWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED); | ||||
5964 | untrustedWindow->setTouchable(false); | ||||
5965 | untrustedWindow->setAlpha(1.0f); | ||||
5966 | untrustedWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101}); | ||||
5967 | addWindow(untrustedWindow); | ||||
5968 | |||||
5969 | // Create a simple app window below the untrusted window. | ||||
5970 | const Rect simpleAppWindowFrameInLogicalDisplay(0, 0, 300, 600); | ||||
5971 | const Rect simpleAppWindowFrameInDisplay = | ||||
5972 | displayTransform.inverse().transform(simpleAppWindowFrameInLogicalDisplay); | ||||
5973 | |||||
5974 | sp<FakeWindowHandle> simpleAppWindow = | ||||
5975 | sp<FakeWindowHandle>::make(application, mDispatcher, "SimpleAppWindow", | ||||
5976 | ADISPLAY_ID_DEFAULT); | ||||
5977 | simpleAppWindow->setFrame(simpleAppWindowFrameInDisplay, displayTransform); | ||||
5978 | simpleAppWindow->setOwnerInfo(gui::Pid{2}, gui::Uid{202}); | ||||
5979 | addWindow(simpleAppWindow); | ||||
5980 | |||||
5981 | // The following points in logical display space should be inside the untrusted window, so | ||||
5982 | // the simple window could not receive events that coordinate is these point. | ||||
5983 | static const std::array<vec2, 4> untrustedPoints{ | ||||
5984 | {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}}; | ||||
5985 | |||||
5986 | for (const auto untrustedPoint : untrustedPoints) { | ||||
5987 | const vec2 p = displayTransform.inverse().transform(untrustedPoint); | ||||
5988 | const PointF pointInDisplaySpace{p.x, p.y}; | ||||
5989 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, | ||||
5990 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
5991 | {pointInDisplaySpace})); | ||||
5992 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, | ||||
5993 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
5994 | {pointInDisplaySpace})); | ||||
5995 | } | ||||
5996 | untrustedWindow->assertNoEvents(); | ||||
5997 | simpleAppWindow->assertNoEvents(); | ||||
5998 | // The following points in logical display space should be outside the untrusted window, so | ||||
5999 | // the simple window should receive events that coordinate is these point. | ||||
6000 | static const std::array<vec2, 5> trustedPoints{ | ||||
6001 | {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}}; | ||||
6002 | for (const auto trustedPoint : trustedPoints) { | ||||
6003 | const vec2 p = displayTransform.inverse().transform(trustedPoint); | ||||
6004 | const PointF pointInDisplaySpace{p.x, p.y}; | ||||
6005 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, | ||||
6006 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
6007 | {pointInDisplaySpace})); | ||||
6008 | simpleAppWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, | ||||
6009 | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED); | ||||
6010 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, | ||||
6011 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
6012 | {pointInDisplaySpace})); | ||||
6013 | simpleAppWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, | ||||
6014 | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED); | ||||
6015 | } | ||||
6016 | untrustedWindow->assertNoEvents(); | ||||
6017 | } | ||||
6018 | |||||
Prabir Pradhan | 33e3baa | 2022-12-06 20:30:22 +0000 | [diff] [blame] | 6019 | // Run the precision tests for all rotations. |
6020 | INSTANTIATE_TEST_SUITE_P(InputDispatcherDisplayOrientationTests, | ||||
6021 | InputDispatcherDisplayOrientationFixture, | ||||
6022 | ::testing::Values(ui::ROTATION_0, ui::ROTATION_90, ui::ROTATION_180, | ||||
6023 | ui::ROTATION_270), | ||||
6024 | [](const testing::TestParamInfo<ui::Rotation>& testParamInfo) { | ||||
6025 | return ftl::enum_string(testParamInfo.param); | ||||
6026 | }); | ||||
6027 | |||||
Siarhei Vishniakou | 1805009 | 2021-09-01 13:32:49 -0700 | [diff] [blame] | 6028 | using TransferFunction = std::function<bool(const std::unique_ptr<InputDispatcher>& dispatcher, |
6029 | sp<IBinder>, sp<IBinder>)>; | ||||
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6030 | |
6031 | class TransferTouchFixture : public InputDispatcherTest, | ||||
6032 | public ::testing::WithParamInterface<TransferFunction> {}; | ||||
6033 | |||||
6034 | TEST_P(TransferTouchFixture, TransferTouch_OnePointer) { | ||||
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 6035 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6036 | |
6037 | // Create a couple of windows | ||||
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 6038 | sp<FakeWindowHandle> firstWindow = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6039 | sp<FakeWindowHandle>::make(application, mDispatcher, "First Window", |
6040 | ADISPLAY_ID_DEFAULT); | ||||
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 6041 | firstWindow->setDupTouchToWallpaper(true); |
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 6042 | sp<FakeWindowHandle> secondWindow = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6043 | sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", |
6044 | ADISPLAY_ID_DEFAULT); | ||||
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 6045 | sp<FakeWindowHandle> wallpaper = |
6046 | sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); | ||||
6047 | wallpaper->setIsWallpaper(true); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6048 | // Add the windows to the dispatcher, and ensure the first window is focused |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6049 | mDispatcher->onWindowInfosChanged( |
6050 | {{*firstWindow->getInfo(), *secondWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0}); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6051 | setFocusedWindow(firstWindow); |
6052 | firstWindow->consumeFocusEvent(true); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6053 | |
6054 | // Send down to the first window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6055 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
6056 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); | ||||
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 6057 | |
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6058 | // Only the first window should get the down event |
6059 | firstWindow->consumeMotionDown(); | ||||
6060 | secondWindow->assertNoEvents(); | ||||
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 6061 | wallpaper->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); |
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6062 | // Dispatcher reports pointer down outside focus for the wallpaper |
6063 | mFakePolicy->assertOnPointerDownEquals(wallpaper->getToken()); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6064 | |
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6065 | // Transfer touch to the second window |
6066 | TransferFunction f = GetParam(); | ||||
6067 | const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken()); | ||||
6068 | ASSERT_TRUE(success); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6069 | // The first window gets cancel and the second gets down |
6070 | firstWindow->consumeMotionCancel(); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6071 | secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 6072 | wallpaper->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); |
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6073 | // There should not be any changes to the focused window when transferring touch |
6074 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertOnPointerDownWasNotCalled()); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6075 | |
6076 | // Send up event to the second window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6077 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, |
6078 | ADISPLAY_ID_DEFAULT)); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6079 | // The first window gets no events and the second gets up |
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6080 | firstWindow->assertNoEvents(); |
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6081 | secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 6082 | wallpaper->assertNoEvents(); |
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6083 | } |
6084 | |||||
Siarhei Vishniakou | 7ae7afd | 2022-03-31 15:26:13 -0700 | [diff] [blame] | 6085 | /** |
Prabir Pradhan | 367f343 | 2024-02-13 23:05:58 +0000 | [diff] [blame] | 6086 | * When 'transferTouchGesture' API is invoked, dispatcher needs to find the "best" window to take |
6087 | * touch from. When we have spy windows, there are several windows to choose from: either spy, or | ||||
6088 | * the 'real' (non-spy) window. Always prefer the 'real' window because that's what would be most | ||||
Siarhei Vishniakou | 7ae7afd | 2022-03-31 15:26:13 -0700 | [diff] [blame] | 6089 | * natural to the user. |
6090 | * In this test, we are sending a pointer to both spy window and first window. We then try to | ||||
6091 | * transfer touch to the second window. The dispatcher should identify the first window as the | ||||
6092 | * one that should lose the gesture, and therefore the action should be to move the gesture from | ||||
6093 | * the first window to the second. | ||||
Prabir Pradhan | 367f343 | 2024-02-13 23:05:58 +0000 | [diff] [blame] | 6094 | * The main goal here is to test the behaviour of 'transferTouchGesture' API, but it's still valid |
6095 | * to test the other API, as well. | ||||
Siarhei Vishniakou | 7ae7afd | 2022-03-31 15:26:13 -0700 | [diff] [blame] | 6096 | */ |
6097 | TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) { | ||||
6098 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
6099 | |||||
6100 | // Create a couple of windows + a spy window | ||||
6101 | sp<FakeWindowHandle> spyWindow = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6102 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); |
Siarhei Vishniakou | 7ae7afd | 2022-03-31 15:26:13 -0700 | [diff] [blame] | 6103 | spyWindow->setTrustedOverlay(true); |
6104 | spyWindow->setSpy(true); | ||||
6105 | sp<FakeWindowHandle> firstWindow = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6106 | sp<FakeWindowHandle>::make(application, mDispatcher, "First", ADISPLAY_ID_DEFAULT); |
Siarhei Vishniakou | 7ae7afd | 2022-03-31 15:26:13 -0700 | [diff] [blame] | 6107 | sp<FakeWindowHandle> secondWindow = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6108 | sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); |
Siarhei Vishniakou | 7ae7afd | 2022-03-31 15:26:13 -0700 | [diff] [blame] | 6109 | |
6110 | // Add the windows to the dispatcher | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6111 | mDispatcher->onWindowInfosChanged( |
6112 | {{*spyWindow->getInfo(), *firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | 7ae7afd | 2022-03-31 15:26:13 -0700 | [diff] [blame] | 6113 | |
6114 | // Send down to the first window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6115 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
6116 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); | ||||
Siarhei Vishniakou | 7ae7afd | 2022-03-31 15:26:13 -0700 | [diff] [blame] | 6117 | // Only the first window and spy should get the down event |
6118 | spyWindow->consumeMotionDown(); | ||||
6119 | firstWindow->consumeMotionDown(); | ||||
6120 | |||||
6121 | // Transfer touch to the second window. Non-spy window should be preferred over the spy window | ||||
Prabir Pradhan | 367f343 | 2024-02-13 23:05:58 +0000 | [diff] [blame] | 6122 | // if f === 'transferTouchGesture'. |
Siarhei Vishniakou | 7ae7afd | 2022-03-31 15:26:13 -0700 | [diff] [blame] | 6123 | TransferFunction f = GetParam(); |
6124 | const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken()); | ||||
6125 | ASSERT_TRUE(success); | ||||
6126 | // The first window gets cancel and the second gets down | ||||
6127 | firstWindow->consumeMotionCancel(); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6128 | secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Siarhei Vishniakou | 7ae7afd | 2022-03-31 15:26:13 -0700 | [diff] [blame] | 6129 | |
6130 | // Send up event to the second window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6131 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, |
6132 | ADISPLAY_ID_DEFAULT)); | ||||
Siarhei Vishniakou | 7ae7afd | 2022-03-31 15:26:13 -0700 | [diff] [blame] | 6133 | // The first window gets no events and the second+spy get up |
6134 | firstWindow->assertNoEvents(); | ||||
6135 | spyWindow->consumeMotionUp(); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6136 | secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Siarhei Vishniakou | 7ae7afd | 2022-03-31 15:26:13 -0700 | [diff] [blame] | 6137 | } |
6138 | |||||
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6139 | TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) { |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 6140 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6141 | |
6142 | PointF touchPoint = {10, 10}; | ||||
6143 | |||||
6144 | // Create a couple of windows | ||||
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 6145 | sp<FakeWindowHandle> firstWindow = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6146 | sp<FakeWindowHandle>::make(application, mDispatcher, "First Window", |
6147 | ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | 76bdecb | 2022-01-31 11:14:15 -0800 | [diff] [blame] | 6148 | firstWindow->setPreventSplitting(true); |
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 6149 | sp<FakeWindowHandle> secondWindow = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6150 | sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", |
6151 | ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | 76bdecb | 2022-01-31 11:14:15 -0800 | [diff] [blame] | 6152 | secondWindow->setPreventSplitting(true); |
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6153 | |
6154 | // Add the windows to the dispatcher | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6155 | mDispatcher->onWindowInfosChanged( |
6156 | {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0}); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6157 | |
6158 | // Send down to the first window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6159 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
6160 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
6161 | {touchPoint})); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6162 | // Only the first window should get the down event |
6163 | firstWindow->consumeMotionDown(); | ||||
6164 | secondWindow->assertNoEvents(); | ||||
6165 | |||||
6166 | // Send pointer down to the first window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6167 | mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, |
6168 | ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint})); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6169 | // Only the first window should get the pointer down event |
6170 | firstWindow->consumeMotionPointerDown(1); | ||||
6171 | secondWindow->assertNoEvents(); | ||||
6172 | |||||
6173 | // Transfer touch focus to the second window | ||||
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6174 | TransferFunction f = GetParam(); |
6175 | bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken()); | ||||
6176 | ASSERT_TRUE(success); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6177 | // The first window gets cancel and the second gets down and pointer down |
6178 | firstWindow->consumeMotionCancel(); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6179 | secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
6180 | secondWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT, | ||||
6181 | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6182 | |
6183 | // Send pointer up to the second window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6184 | mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, |
6185 | ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint})); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6186 | // The first window gets nothing and the second gets pointer up |
6187 | firstWindow->assertNoEvents(); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6188 | secondWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT, |
6189 | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6190 | |
6191 | // Send up event to the second window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6192 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, |
6193 | ADISPLAY_ID_DEFAULT)); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6194 | // The first window gets nothing and the second gets up |
6195 | firstWindow->assertNoEvents(); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6196 | secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6197 | } |
6198 | |||||
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 6199 | TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) { |
6200 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
6201 | |||||
6202 | // Create a couple of windows | ||||
6203 | sp<FakeWindowHandle> firstWindow = | ||||
6204 | sp<FakeWindowHandle>::make(application, mDispatcher, "First Window", | ||||
6205 | ADISPLAY_ID_DEFAULT); | ||||
6206 | firstWindow->setDupTouchToWallpaper(true); | ||||
6207 | sp<FakeWindowHandle> secondWindow = | ||||
6208 | sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", | ||||
6209 | ADISPLAY_ID_DEFAULT); | ||||
6210 | secondWindow->setDupTouchToWallpaper(true); | ||||
6211 | |||||
6212 | sp<FakeWindowHandle> wallpaper1 = | ||||
6213 | sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper1", ADISPLAY_ID_DEFAULT); | ||||
6214 | wallpaper1->setIsWallpaper(true); | ||||
6215 | |||||
6216 | sp<FakeWindowHandle> wallpaper2 = | ||||
6217 | sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper2", ADISPLAY_ID_DEFAULT); | ||||
6218 | wallpaper2->setIsWallpaper(true); | ||||
6219 | // Add the windows to the dispatcher | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6220 | mDispatcher->onWindowInfosChanged({{*firstWindow->getInfo(), *wallpaper1->getInfo(), |
6221 | *secondWindow->getInfo(), *wallpaper2->getInfo()}, | ||||
6222 | {}, | ||||
6223 | 0, | ||||
6224 | 0}); | ||||
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 6225 | |
6226 | // Send down to the first window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6227 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
6228 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); | ||||
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 6229 | |
6230 | // Only the first window should get the down event | ||||
6231 | firstWindow->consumeMotionDown(); | ||||
6232 | secondWindow->assertNoEvents(); | ||||
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 6233 | wallpaper1->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); |
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 6234 | wallpaper2->assertNoEvents(); |
6235 | |||||
6236 | // Transfer touch focus to the second window | ||||
6237 | TransferFunction f = GetParam(); | ||||
6238 | bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken()); | ||||
6239 | ASSERT_TRUE(success); | ||||
6240 | |||||
6241 | // The first window gets cancel and the second gets down | ||||
6242 | firstWindow->consumeMotionCancel(); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6243 | secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 6244 | wallpaper1->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); |
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6245 | wallpaper2->consumeMotionDown(ADISPLAY_ID_DEFAULT, |
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 6246 | EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 6247 | |
6248 | // Send up event to the second window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6249 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, |
6250 | ADISPLAY_ID_DEFAULT)); | ||||
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 6251 | // The first window gets no events and the second gets up |
6252 | firstWindow->assertNoEvents(); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6253 | secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 6254 | wallpaper1->assertNoEvents(); |
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6255 | wallpaper2->consumeMotionUp(ADISPLAY_ID_DEFAULT, |
Linnan Li | 7235222 | 2024-04-12 18:55:57 +0800 | [diff] [blame] | 6256 | EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Arthur Hung | c539dbb | 2022-12-08 07:45:36 +0000 | [diff] [blame] | 6257 | } |
6258 | |||||
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6259 | // For the cases of single pointer touch and two pointers non-split touch, the api's |
Prabir Pradhan | 367f343 | 2024-02-13 23:05:58 +0000 | [diff] [blame] | 6260 | // 'transferTouchGesture' and 'transferTouchOnDisplay' are equivalent in behaviour. They only differ |
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6261 | // for the case where there are multiple pointers split across several windows. |
Prabir Pradhan | 367f343 | 2024-02-13 23:05:58 +0000 | [diff] [blame] | 6262 | INSTANTIATE_TEST_SUITE_P( |
6263 | InputDispatcherTransferFunctionTests, TransferTouchFixture, | ||||
6264 | ::testing::Values( | ||||
6265 | [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> /*ignored*/, | ||||
6266 | sp<IBinder> destChannelToken) { | ||||
6267 | return dispatcher->transferTouchOnDisplay(destChannelToken, | ||||
6268 | ADISPLAY_ID_DEFAULT); | ||||
6269 | }, | ||||
6270 | [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> from, | ||||
6271 | sp<IBinder> to) { | ||||
6272 | return dispatcher->transferTouchGesture(from, to, | ||||
6273 | /*isDragAndDrop=*/false); | ||||
6274 | })); | ||||
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6275 | |
Prabir Pradhan | 367f343 | 2024-02-13 23:05:58 +0000 | [diff] [blame] | 6276 | TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 6277 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6278 | |
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 6279 | sp<FakeWindowHandle> firstWindow = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6280 | sp<FakeWindowHandle>::make(application, mDispatcher, "First Window", |
6281 | ADISPLAY_ID_DEFAULT); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6282 | firstWindow->setFrame(Rect(0, 0, 600, 400)); |
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6283 | |
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 6284 | sp<FakeWindowHandle> secondWindow = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6285 | sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", |
6286 | ADISPLAY_ID_DEFAULT); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6287 | secondWindow->setFrame(Rect(0, 400, 600, 800)); |
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6288 | |
6289 | // Add the windows to the dispatcher | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6290 | mDispatcher->onWindowInfosChanged( |
6291 | {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0}); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6292 | |
6293 | PointF pointInFirst = {300, 200}; | ||||
6294 | PointF pointInSecond = {300, 600}; | ||||
6295 | |||||
6296 | // Send down to the first window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6297 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
6298 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
6299 | {pointInFirst})); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6300 | // Only the first window should get the down event |
6301 | firstWindow->consumeMotionDown(); | ||||
6302 | secondWindow->assertNoEvents(); | ||||
6303 | |||||
6304 | // Send down to the second window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6305 | mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, |
6306 | ADISPLAY_ID_DEFAULT, | ||||
6307 | {pointInFirst, pointInSecond})); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6308 | // The first window gets a move and the second a down |
6309 | firstWindow->consumeMotionMove(); | ||||
6310 | secondWindow->consumeMotionDown(); | ||||
6311 | |||||
Prabir Pradhan | 367f343 | 2024-02-13 23:05:58 +0000 | [diff] [blame] | 6312 | // Transfer touch to the second window |
6313 | mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken()); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6314 | // The first window gets cancel and the new gets pointer down (it already saw down) |
6315 | firstWindow->consumeMotionCancel(); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6316 | secondWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT, |
6317 | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6318 | |
6319 | // Send pointer up to the second window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6320 | mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, |
6321 | ADISPLAY_ID_DEFAULT, | ||||
6322 | {pointInFirst, pointInSecond})); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6323 | // The first window gets nothing and the second gets pointer up |
6324 | firstWindow->assertNoEvents(); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6325 | secondWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT, |
6326 | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6327 | |
6328 | // Send up event to the second window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6329 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, |
6330 | ADISPLAY_ID_DEFAULT)); | ||||
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6331 | // The first window gets nothing and the second gets up |
6332 | firstWindow->assertNoEvents(); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6333 | secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Svet Ganov | 5d3bc37 | 2020-01-26 23:11:07 -0800 | [diff] [blame] | 6334 | } |
6335 | |||||
Prabir Pradhan | 367f343 | 2024-02-13 23:05:58 +0000 | [diff] [blame] | 6336 | // Same as TransferTouch_TwoPointersSplitTouch, but using 'transferTouchOnDisplay' api. |
6337 | // Unlike 'transferTouchGesture', calling 'transferTouchOnDisplay' when there are two windows | ||||
6338 | // receiving touch is not supported, so the touch should continue on those windows and the | ||||
6339 | // transferred-to window should get nothing. | ||||
6340 | TEST_F(InputDispatcherTest, TransferTouchOnDisplay_TwoPointersSplitTouch) { | ||||
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6341 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
6342 | |||||
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6343 | sp<FakeWindowHandle> firstWindow = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6344 | sp<FakeWindowHandle>::make(application, mDispatcher, "First Window", |
6345 | ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6346 | firstWindow->setFrame(Rect(0, 0, 600, 400)); |
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6347 | |
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6348 | sp<FakeWindowHandle> secondWindow = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6349 | sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", |
6350 | ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6351 | secondWindow->setFrame(Rect(0, 400, 600, 800)); |
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6352 | |
6353 | // Add the windows to the dispatcher | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6354 | mDispatcher->onWindowInfosChanged( |
6355 | {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6356 | |
6357 | PointF pointInFirst = {300, 200}; | ||||
6358 | PointF pointInSecond = {300, 600}; | ||||
6359 | |||||
6360 | // Send down to the first window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6361 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
6362 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
6363 | {pointInFirst})); | ||||
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6364 | // Only the first window should get the down event |
6365 | firstWindow->consumeMotionDown(); | ||||
6366 | secondWindow->assertNoEvents(); | ||||
6367 | |||||
6368 | // Send down to the second window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6369 | mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, |
6370 | ADISPLAY_ID_DEFAULT, | ||||
6371 | {pointInFirst, pointInSecond})); | ||||
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6372 | // The first window gets a move and the second a down |
6373 | firstWindow->consumeMotionMove(); | ||||
6374 | secondWindow->consumeMotionDown(); | ||||
6375 | |||||
6376 | // Transfer touch focus to the second window | ||||
Siarhei Vishniakou | 7ae7afd | 2022-03-31 15:26:13 -0700 | [diff] [blame] | 6377 | const bool transferred = |
Prabir Pradhan | 367f343 | 2024-02-13 23:05:58 +0000 | [diff] [blame] | 6378 | mDispatcher->transferTouchOnDisplay(secondWindow->getToken(), ADISPLAY_ID_DEFAULT); |
6379 | // The 'transferTouchOnDisplay' call should not succeed, because there are 2 touched windows | ||||
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6380 | ASSERT_FALSE(transferred); |
6381 | firstWindow->assertNoEvents(); | ||||
6382 | secondWindow->assertNoEvents(); | ||||
6383 | |||||
6384 | // The rest of the dispatch should proceed as normal | ||||
6385 | // Send pointer up to the second window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6386 | mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, |
6387 | ADISPLAY_ID_DEFAULT, | ||||
6388 | {pointInFirst, pointInSecond})); | ||||
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6389 | // The first window gets MOVE and the second gets pointer up |
6390 | firstWindow->consumeMotionMove(); | ||||
6391 | secondWindow->consumeMotionUp(); | ||||
6392 | |||||
6393 | // Send up event to the first window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6394 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, |
6395 | ADISPLAY_ID_DEFAULT)); | ||||
Siarhei Vishniakou | d0c6bc8 | 2021-03-13 03:14:52 +0000 | [diff] [blame] | 6396 | // The first window gets nothing and the second gets up |
6397 | firstWindow->consumeMotionUp(); | ||||
6398 | secondWindow->assertNoEvents(); | ||||
6399 | } | ||||
6400 | |||||
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6401 | // This case will create two windows and one mirrored window on the default display and mirror |
Prabir Pradhan | 367f343 | 2024-02-13 23:05:58 +0000 | [diff] [blame] | 6402 | // two windows on the second display. It will test if 'transferTouchGesture' works fine if we put |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6403 | // the windows info of second display before default display. |
Prabir Pradhan | 367f343 | 2024-02-13 23:05:58 +0000 | [diff] [blame] | 6404 | TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) { |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6405 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
6406 | sp<FakeWindowHandle> firstWindowInPrimary = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6407 | sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6408 | firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100)); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6409 | sp<FakeWindowHandle> secondWindowInPrimary = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6410 | sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6411 | secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6412 | |
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 6413 | sp<FakeWindowHandle> mirrorWindowInPrimary = firstWindowInPrimary->clone(ADISPLAY_ID_DEFAULT); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6414 | mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200)); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6415 | |
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 6416 | sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6417 | firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100)); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6418 | |
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 6419 | sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6420 | secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6421 | |
6422 | // Update window info, let it find window handle of second display first. | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6423 | mDispatcher->onWindowInfosChanged( |
6424 | {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(), | ||||
6425 | *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(), | ||||
6426 | *secondWindowInPrimary->getInfo()}, | ||||
6427 | {}, | ||||
6428 | 0, | ||||
6429 | 0}); | ||||
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6430 | |
6431 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 6432 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6433 | {50, 50})) |
6434 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
6435 | |||||
6436 | // Window should receive motion event. | ||||
6437 | firstWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
6438 | |||||
Prabir Pradhan | 367f343 | 2024-02-13 23:05:58 +0000 | [diff] [blame] | 6439 | // Transfer touch |
6440 | ASSERT_TRUE(mDispatcher->transferTouchGesture(firstWindowInPrimary->getToken(), | ||||
6441 | secondWindowInPrimary->getToken())); | ||||
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6442 | // The first window gets cancel. |
6443 | firstWindowInPrimary->consumeMotionCancel(); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6444 | secondWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT, |
6445 | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); | ||||
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6446 | |
6447 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 6448 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6449 | ADISPLAY_ID_DEFAULT, {150, 50})) |
6450 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
6451 | firstWindowInPrimary->assertNoEvents(); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6452 | secondWindowInPrimary->consumeMotionMove(ADISPLAY_ID_DEFAULT, |
6453 | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); | ||||
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6454 | |
6455 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 6456 | injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6457 | {150, 50})) |
6458 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
6459 | firstWindowInPrimary->assertNoEvents(); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6460 | secondWindowInPrimary->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6461 | } |
6462 | |||||
Prabir Pradhan | 367f343 | 2024-02-13 23:05:58 +0000 | [diff] [blame] | 6463 | // Same as TransferTouch_CloneSurface, but this touch on the secondary display and use |
6464 | // 'transferTouchOnDisplay' api. | ||||
6465 | TEST_F(InputDispatcherTest, TransferTouchOnDisplay_CloneSurface) { | ||||
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6466 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
6467 | sp<FakeWindowHandle> firstWindowInPrimary = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6468 | sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6469 | firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100)); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6470 | sp<FakeWindowHandle> secondWindowInPrimary = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6471 | sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6472 | secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6473 | |
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 6474 | sp<FakeWindowHandle> mirrorWindowInPrimary = firstWindowInPrimary->clone(ADISPLAY_ID_DEFAULT); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6475 | mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200)); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6476 | |
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 6477 | sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6478 | firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100)); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6479 | |
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 6480 | sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6481 | secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6482 | |
6483 | // Update window info, let it find window handle of second display first. | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6484 | mDispatcher->onWindowInfosChanged( |
6485 | {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(), | ||||
6486 | *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(), | ||||
6487 | *secondWindowInPrimary->getInfo()}, | ||||
6488 | {}, | ||||
6489 | 0, | ||||
6490 | 0}); | ||||
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6491 | |
6492 | // Touch on second display. | ||||
6493 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 6494 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, |
6495 | {50, 50})) | ||||
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6496 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
6497 | |||||
6498 | // Window should receive motion event. | ||||
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 6499 | firstWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6500 | |
6501 | // Transfer touch focus | ||||
Prabir Pradhan | 367f343 | 2024-02-13 23:05:58 +0000 | [diff] [blame] | 6502 | ASSERT_TRUE(mDispatcher->transferTouchOnDisplay(secondWindowInSecondary->getToken(), |
6503 | SECOND_DISPLAY_ID)); | ||||
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6504 | |
6505 | // The first window gets cancel. | ||||
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 6506 | firstWindowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID); |
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6507 | secondWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID, |
6508 | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); | ||||
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6509 | |
6510 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 6511 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6512 | SECOND_DISPLAY_ID, {150, 50})) |
6513 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 6514 | firstWindowInSecondary->assertNoEvents(); |
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6515 | secondWindowInSecondary->consumeMotionMove(SECOND_DISPLAY_ID, |
6516 | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); | ||||
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6517 | |
6518 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 6519 | injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50})) |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6520 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 6521 | firstWindowInSecondary->assertNoEvents(); |
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 6522 | secondWindowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Arthur Hung | abbb9d8 | 2021-09-01 14:52:30 +0000 | [diff] [blame] | 6523 | } |
6524 | |||||
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 6525 | TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) { |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 6526 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6527 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
6528 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 6529 | |
Vishnu Nair | 47074b8 | 2020-08-14 11:54:47 -0700 | [diff] [blame] | 6530 | window->setFocusable(true); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6531 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 6532 | setFocusedWindow(window); |
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 6533 | |
6534 | window->consumeFocusEvent(true); | ||||
6535 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6536 | mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); |
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 6537 | |
6538 | // Window should receive key down event. | ||||
6539 | window->consumeKeyDown(ADISPLAY_ID_DEFAULT); | ||||
Josep del Rio | b398162 | 2023-04-18 15:49:45 +0000 | [diff] [blame] | 6540 | |
6541 | // Should have poked user activity | ||||
Siarhei Vishniakou | 4fd8673 | 2023-05-24 17:33:01 +0000 | [diff] [blame] | 6542 | mDispatcher->waitForIdle(); |
Josep del Rio | b398162 | 2023-04-18 15:49:45 +0000 | [diff] [blame] | 6543 | mFakePolicy->assertUserActivityPoked(); |
6544 | } | ||||
6545 | |||||
6546 | TEST_F(InputDispatcherTest, FocusedWindow_DisableUserActivity) { | ||||
6547 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
6548 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, | ||||
6549 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
6550 | |||||
6551 | window->setDisableUserActivity(true); | ||||
6552 | window->setFocusable(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6553 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Josep del Rio | b398162 | 2023-04-18 15:49:45 +0000 | [diff] [blame] | 6554 | setFocusedWindow(window); |
6555 | |||||
6556 | window->consumeFocusEvent(true); | ||||
6557 | |||||
6558 | mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); | ||||
6559 | |||||
6560 | // Window should receive key down event. | ||||
6561 | window->consumeKeyDown(ADISPLAY_ID_DEFAULT); | ||||
6562 | |||||
6563 | // Should have poked user activity | ||||
Siarhei Vishniakou | 4fd8673 | 2023-05-24 17:33:01 +0000 | [diff] [blame] | 6564 | mDispatcher->waitForIdle(); |
Josep del Rio | b398162 | 2023-04-18 15:49:45 +0000 | [diff] [blame] | 6565 | mFakePolicy->assertUserActivityNotPoked(); |
6566 | } | ||||
6567 | |||||
6568 | TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveSystemShortcut) { | ||||
6569 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
6570 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, | ||||
6571 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
6572 | |||||
6573 | window->setFocusable(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6574 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Josep del Rio | b398162 | 2023-04-18 15:49:45 +0000 | [diff] [blame] | 6575 | setFocusedWindow(window); |
6576 | |||||
6577 | window->consumeFocusEvent(true); | ||||
6578 | |||||
6579 | mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); | ||||
6580 | mDispatcher->waitForIdle(); | ||||
6581 | |||||
6582 | // System key is not passed down | ||||
6583 | window->assertNoEvents(); | ||||
6584 | |||||
6585 | // Should have poked user activity | ||||
6586 | mFakePolicy->assertUserActivityPoked(); | ||||
6587 | } | ||||
6588 | |||||
6589 | TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveAssistantKey) { | ||||
6590 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
6591 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, | ||||
6592 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
6593 | |||||
6594 | window->setFocusable(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6595 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Josep del Rio | b398162 | 2023-04-18 15:49:45 +0000 | [diff] [blame] | 6596 | setFocusedWindow(window); |
6597 | |||||
6598 | window->consumeFocusEvent(true); | ||||
6599 | |||||
6600 | mDispatcher->notifyKey(generateAssistantKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); | ||||
6601 | mDispatcher->waitForIdle(); | ||||
6602 | |||||
6603 | // System key is not passed down | ||||
6604 | window->assertNoEvents(); | ||||
6605 | |||||
6606 | // Should have poked user activity | ||||
6607 | mFakePolicy->assertUserActivityPoked(); | ||||
6608 | } | ||||
6609 | |||||
6610 | TEST_F(InputDispatcherTest, FocusedWindow_SystemKeyIgnoresDisableUserActivity) { | ||||
6611 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
6612 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, | ||||
6613 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
6614 | |||||
6615 | window->setDisableUserActivity(true); | ||||
6616 | window->setFocusable(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6617 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Josep del Rio | b398162 | 2023-04-18 15:49:45 +0000 | [diff] [blame] | 6618 | setFocusedWindow(window); |
6619 | |||||
6620 | window->consumeFocusEvent(true); | ||||
6621 | |||||
6622 | mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); | ||||
6623 | mDispatcher->waitForIdle(); | ||||
6624 | |||||
6625 | // System key is not passed down | ||||
6626 | window->assertNoEvents(); | ||||
6627 | |||||
6628 | // Should have poked user activity | ||||
6629 | mFakePolicy->assertUserActivityPoked(); | ||||
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 6630 | } |
6631 | |||||
Siarhei Vishniakou | 90ee478 | 2023-05-08 11:57:24 -0700 | [diff] [blame] | 6632 | TEST_F(InputDispatcherTest, InjectedTouchesPokeUserActivity) { |
6633 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
6634 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, | ||||
6635 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
6636 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6637 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | 90ee478 | 2023-05-08 11:57:24 -0700 | [diff] [blame] | 6638 | |
6639 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 6640 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, |
Siarhei Vishniakou | 90ee478 | 2023-05-08 11:57:24 -0700 | [diff] [blame] | 6641 | ADISPLAY_ID_DEFAULT, {100, 100})) |
6642 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
6643 | |||||
6644 | window->consumeMotionEvent( | ||||
6645 | AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT))); | ||||
6646 | |||||
6647 | // Should have poked user activity | ||||
Siarhei Vishniakou | 4fd8673 | 2023-05-24 17:33:01 +0000 | [diff] [blame] | 6648 | mDispatcher->waitForIdle(); |
Siarhei Vishniakou | 90ee478 | 2023-05-08 11:57:24 -0700 | [diff] [blame] | 6649 | mFakePolicy->assertUserActivityPoked(); |
6650 | } | ||||
6651 | |||||
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 6652 | TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) { |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 6653 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6654 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
6655 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 6656 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6657 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 6658 | |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6659 | mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); |
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 6660 | mDispatcher->waitForIdle(); |
6661 | |||||
6662 | window->assertNoEvents(); | ||||
6663 | } | ||||
6664 | |||||
6665 | // If a window is touchable, but does not have focus, it should receive motion events, but not keys | ||||
6666 | TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) { | ||||
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 6667 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6668 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
6669 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 6670 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6671 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 6672 | |
6673 | // Send key | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6674 | mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); |
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 6675 | // Send motion |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6676 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
6677 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); | ||||
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 6678 | |
6679 | // Window should receive only the motion event | ||||
6680 | window->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
6681 | window->assertNoEvents(); // Key event or focus event will not be received | ||||
6682 | } | ||||
6683 | |||||
arthurhung | ea3f4fc | 2020-12-21 23:18:53 +0800 | [diff] [blame] | 6684 | TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) { |
6685 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
6686 | |||||
arthurhung | ea3f4fc | 2020-12-21 23:18:53 +0800 | [diff] [blame] | 6687 | sp<FakeWindowHandle> firstWindow = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6688 | sp<FakeWindowHandle>::make(application, mDispatcher, "First Window", |
6689 | ADISPLAY_ID_DEFAULT); | ||||
arthurhung | ea3f4fc | 2020-12-21 23:18:53 +0800 | [diff] [blame] | 6690 | firstWindow->setFrame(Rect(0, 0, 600, 400)); |
arthurhung | ea3f4fc | 2020-12-21 23:18:53 +0800 | [diff] [blame] | 6691 | |
arthurhung | ea3f4fc | 2020-12-21 23:18:53 +0800 | [diff] [blame] | 6692 | sp<FakeWindowHandle> secondWindow = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6693 | sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", |
6694 | ADISPLAY_ID_DEFAULT); | ||||
arthurhung | ea3f4fc | 2020-12-21 23:18:53 +0800 | [diff] [blame] | 6695 | secondWindow->setFrame(Rect(0, 400, 600, 800)); |
arthurhung | ea3f4fc | 2020-12-21 23:18:53 +0800 | [diff] [blame] | 6696 | |
6697 | // Add the windows to the dispatcher | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6698 | mDispatcher->onWindowInfosChanged( |
6699 | {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0}); | ||||
arthurhung | ea3f4fc | 2020-12-21 23:18:53 +0800 | [diff] [blame] | 6700 | |
6701 | PointF pointInFirst = {300, 200}; | ||||
6702 | PointF pointInSecond = {300, 600}; | ||||
6703 | |||||
6704 | // Send down to the first window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6705 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
6706 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
6707 | {pointInFirst})); | ||||
arthurhung | ea3f4fc | 2020-12-21 23:18:53 +0800 | [diff] [blame] | 6708 | // Only the first window should get the down event |
6709 | firstWindow->consumeMotionDown(); | ||||
6710 | secondWindow->assertNoEvents(); | ||||
6711 | |||||
6712 | // Send down to the second window | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6713 | mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, |
6714 | ADISPLAY_ID_DEFAULT, | ||||
6715 | {pointInFirst, pointInSecond})); | ||||
arthurhung | ea3f4fc | 2020-12-21 23:18:53 +0800 | [diff] [blame] | 6716 | // The first window gets a move and the second a down |
6717 | firstWindow->consumeMotionMove(); | ||||
6718 | secondWindow->consumeMotionDown(); | ||||
6719 | |||||
6720 | // Send pointer cancel to the second window | ||||
6721 | NotifyMotionArgs pointerUpMotionArgs = | ||||
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 6722 | generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
arthurhung | ea3f4fc | 2020-12-21 23:18:53 +0800 | [diff] [blame] | 6723 | {pointInFirst, pointInSecond}); |
6724 | pointerUpMotionArgs.flags |= AMOTION_EVENT_FLAG_CANCELED; | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6725 | mDispatcher->notifyMotion(pointerUpMotionArgs); |
arthurhung | ea3f4fc | 2020-12-21 23:18:53 +0800 | [diff] [blame] | 6726 | // The first window gets move and the second gets cancel. |
6727 | firstWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED); | ||||
6728 | secondWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED); | ||||
6729 | |||||
6730 | // Send up event. | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 6731 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, |
6732 | ADISPLAY_ID_DEFAULT)); | ||||
arthurhung | ea3f4fc | 2020-12-21 23:18:53 +0800 | [diff] [blame] | 6733 | // The first window gets up and the second gets nothing. |
6734 | firstWindow->consumeMotionUp(); | ||||
6735 | secondWindow->assertNoEvents(); | ||||
6736 | } | ||||
6737 | |||||
Siarhei Vishniakou | f94ae02 | 2021-02-04 01:23:17 +0000 | [diff] [blame] | 6738 | TEST_F(InputDispatcherTest, SendTimeline_DoesNotCrashDispatcher) { |
6739 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
6740 | |||||
6741 | sp<FakeWindowHandle> window = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6742 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6743 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | f94ae02 | 2021-02-04 01:23:17 +0000 | [diff] [blame] | 6744 | std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline; |
6745 | graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2; | ||||
6746 | graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3; | ||||
6747 | |||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 6748 | window->sendTimeline(/*inputEventId=*/1, graphicsTimeline); |
Siarhei Vishniakou | f94ae02 | 2021-02-04 01:23:17 +0000 | [diff] [blame] | 6749 | window->assertNoEvents(); |
6750 | mDispatcher->waitForIdle(); | ||||
6751 | } | ||||
6752 | |||||
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 6753 | using InputDispatcherMonitorTest = InputDispatcherTest; |
6754 | |||||
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 6755 | /** |
6756 | * Two entities that receive touch: A window, and a global monitor. | ||||
6757 | * The touch goes to the window, and then the window disappears. | ||||
6758 | * The monitor does not get cancel right away. But if more events come in, the touch gets canceled | ||||
6759 | * for the monitor, as well. | ||||
6760 | * 1. foregroundWindow | ||||
6761 | * 2. monitor <-- global monitor (doesn't observe z order, receives all events) | ||||
6762 | */ | ||||
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 6763 | TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDisappears) { |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 6764 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
6765 | sp<FakeWindowHandle> window = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6766 | sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 6767 | |
Prabir Pradhan | fb54907 | 2023-10-05 19:17:36 +0000 | [diff] [blame] | 6768 | FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 6769 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6770 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 6771 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 6772 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 6773 | {100, 200})) |
6774 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
6775 | |||||
6776 | // Both the foreground window and the global monitor should receive the touch down | ||||
6777 | window->consumeMotionDown(); | ||||
6778 | monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
6779 | |||||
6780 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 6781 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 6782 | ADISPLAY_ID_DEFAULT, {110, 200})) |
6783 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
6784 | |||||
6785 | window->consumeMotionMove(); | ||||
6786 | monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT); | ||||
6787 | |||||
6788 | // Now the foreground window goes away | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6789 | mDispatcher->onWindowInfosChanged({{}, {}, 0, 0}); |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 6790 | window->consumeMotionCancel(); |
6791 | monitor.assertNoEvents(); // Global monitor does not get a cancel yet | ||||
6792 | |||||
6793 | // If more events come in, there will be no more foreground window to send them to. This will | ||||
6794 | // cause a cancel for the monitor, as well. | ||||
6795 | ASSERT_EQ(InputEventInjectionResult::FAILED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 6796 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
Siarhei Vishniakou | ca20550 | 2021-07-16 21:31:58 +0000 | [diff] [blame] | 6797 | ADISPLAY_ID_DEFAULT, {120, 200})) |
6798 | << "Injection should fail because the window was removed"; | ||||
6799 | window->assertNoEvents(); | ||||
6800 | // Global monitor now gets the cancel | ||||
6801 | monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT); | ||||
6802 | } | ||||
6803 | |||||
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 6804 | TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) { |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 6805 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6806 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
6807 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6808 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Michael Wright | 3a240c4 | 2019-12-10 20:53:41 +0000 | [diff] [blame] | 6809 | |
Prabir Pradhan | fb54907 | 2023-10-05 19:17:36 +0000 | [diff] [blame] | 6810 | FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); |
Michael Wright | 3a240c4 | 2019-12-10 20:53:41 +0000 | [diff] [blame] | 6811 | |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 6812 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 6813 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 6814 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
Michael Wright | 3a240c4 | 2019-12-10 20:53:41 +0000 | [diff] [blame] | 6815 | window->consumeMotionDown(ADISPLAY_ID_DEFAULT); |
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 6816 | monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); |
Michael Wright | 3a240c4 | 2019-12-10 20:53:41 +0000 | [diff] [blame] | 6817 | } |
6818 | |||||
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 6819 | TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) { |
Prabir Pradhan | fb54907 | 2023-10-05 19:17:36 +0000 | [diff] [blame] | 6820 | FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); |
Michael Wright | 3a240c4 | 2019-12-10 20:53:41 +0000 | [diff] [blame] | 6821 | |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 6822 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6823 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
6824 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6825 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Michael Wright | 3a240c4 | 2019-12-10 20:53:41 +0000 | [diff] [blame] | 6826 | |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 6827 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 6828 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 6829 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 6830 | monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 6831 | window->consumeMotionDown(ADISPLAY_ID_DEFAULT); |
Michael Wright | 3a240c4 | 2019-12-10 20:53:41 +0000 | [diff] [blame] | 6832 | |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 6833 | // Pilfer pointers from the monitor. |
6834 | // This should not do anything and the window should continue to receive events. | ||||
6835 | EXPECT_NE(OK, mDispatcher->pilferPointers(monitor.getToken())); | ||||
Michael Wright | 3a240c4 | 2019-12-10 20:53:41 +0000 | [diff] [blame] | 6836 | |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 6837 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 6838 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 6839 | ADISPLAY_ID_DEFAULT)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 6840 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 6841 | |
6842 | monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT); | ||||
6843 | window->consumeMotionMove(ADISPLAY_ID_DEFAULT); | ||||
Michael Wright | 3a240c4 | 2019-12-10 20:53:41 +0000 | [diff] [blame] | 6844 | } |
6845 | |||||
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 6846 | TEST_F(InputDispatcherMonitorTest, NoWindowTransform) { |
Evan Rosky | 84f07f0 | 2021-04-16 10:42:42 -0700 | [diff] [blame] | 6847 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 6848 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
6849 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 6850 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Evan Rosky | 84f07f0 | 2021-04-16 10:42:42 -0700 | [diff] [blame] | 6851 | window->setWindowOffset(20, 40); |
6852 | window->setWindowTransform(0, 1, -1, 0); | ||||
6853 | |||||
Prabir Pradhan | fb54907 | 2023-10-05 19:17:36 +0000 | [diff] [blame] | 6854 | FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); |
Evan Rosky | 84f07f0 | 2021-04-16 10:42:42 -0700 | [diff] [blame] | 6855 | |
6856 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 6857 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) |
Evan Rosky | 84f07f0 | 2021-04-16 10:42:42 -0700 | [diff] [blame] | 6858 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
6859 | window->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 6860 | std::unique_ptr<MotionEvent> event = monitor.consumeMotion(); |
6861 | ASSERT_NE(nullptr, event); | ||||
Evan Rosky | 84f07f0 | 2021-04-16 10:42:42 -0700 | [diff] [blame] | 6862 | // Even though window has transform, gesture monitor must not. |
6863 | ASSERT_EQ(ui::Transform(), event->getTransform()); | ||||
6864 | } | ||||
6865 | |||||
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 6866 | TEST_F(InputDispatcherMonitorTest, InjectionFailsWithNoWindow) { |
Arthur Hung | b3307ee | 2021-10-14 10:57:37 +0000 | [diff] [blame] | 6867 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Prabir Pradhan | fb54907 | 2023-10-05 19:17:36 +0000 | [diff] [blame] | 6868 | FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); |
Arthur Hung | b3307ee | 2021-10-14 10:57:37 +0000 | [diff] [blame] | 6869 | |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 6870 | ASSERT_EQ(InputEventInjectionResult::FAILED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 6871 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 6872 | << "Injection should fail if there is a monitor, but no touchable window"; |
6873 | monitor.assertNoEvents(); | ||||
Arthur Hung | b3307ee | 2021-10-14 10:57:37 +0000 | [diff] [blame] | 6874 | } |
6875 | |||||
Linnan Li | d815095 | 2024-01-26 18:07:17 +0000 | [diff] [blame] | 6876 | /** |
6877 | * Two displays | ||||
6878 | * The first monitor has a foreground window, a monitor | ||||
6879 | * The second window has only one monitor. | ||||
6880 | * We first inject a Down event into the first display, this injection should succeed and both | ||||
6881 | * the foreground window and monitor should receive a down event, then inject a Down event into | ||||
6882 | * the second display as well, this injection should fail, at this point, the first display | ||||
6883 | * window and monitor should not receive a cancel or any other event. | ||||
6884 | * Continue to inject Move and UP events to the first display, the events should be received | ||||
6885 | * normally by the foreground window and monitor. | ||||
6886 | */ | ||||
6887 | TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCanceledWhenAnotherEmptyDisplayReceiveEvents) { | ||||
6888 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
6889 | sp<FakeWindowHandle> window = | ||||
6890 | sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); | ||||
6891 | |||||
6892 | FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); | ||||
6893 | FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID); | ||||
6894 | |||||
6895 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
6896 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
6897 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
6898 | {100, 200})) | ||||
6899 | << "The down event injected into the first display should succeed"; | ||||
6900 | |||||
6901 | window->consumeMotionDown(); | ||||
6902 | monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
Linnan Li | d815095 | 2024-01-26 18:07:17 +0000 | [diff] [blame] | 6903 | |
6904 | ASSERT_EQ(InputEventInjectionResult::FAILED, | ||||
6905 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, | ||||
6906 | {100, 200})) | ||||
Prabir Pradhan | a0d43d4 | 2024-01-30 00:27:08 +0000 | [diff] [blame] | 6907 | << "The down event injected into the second display should fail since there's no " |
6908 | "touchable window"; | ||||
Linnan Li | d815095 | 2024-01-26 18:07:17 +0000 | [diff] [blame] | 6909 | |
6910 | // Continue to inject event to first display. | ||||
6911 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
6912 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, | ||||
6913 | ADISPLAY_ID_DEFAULT, {110, 220})) | ||||
6914 | << "The move event injected into the first display should succeed"; | ||||
6915 | |||||
6916 | window->consumeMotionMove(); | ||||
6917 | monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT); | ||||
Linnan Li | d815095 | 2024-01-26 18:07:17 +0000 | [diff] [blame] | 6918 | |
6919 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
6920 | injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
6921 | {110, 220})) | ||||
6922 | << "The up event injected into the first display should succeed"; | ||||
6923 | |||||
6924 | window->consumeMotionUp(); | ||||
6925 | monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | a0d43d4 | 2024-01-30 00:27:08 +0000 | [diff] [blame] | 6926 | |
6927 | window->assertNoEvents(); | ||||
6928 | monitor.assertNoEvents(); | ||||
Linnan Li | d815095 | 2024-01-26 18:07:17 +0000 | [diff] [blame] | 6929 | secondMonitor.assertNoEvents(); |
6930 | } | ||||
6931 | |||||
6932 | /** | ||||
6933 | * Two displays | ||||
6934 | * There is a monitor and foreground window on each display. | ||||
6935 | * First, we inject down events into each of the two displays, at this point, the foreground windows | ||||
6936 | * and monitors on both displays should receive down events. | ||||
6937 | * At this point, the foreground window of the second display goes away, the gone window should | ||||
6938 | * receive the cancel event, and the other windows and monitors should not receive any events. | ||||
6939 | * Inject a move event into the second display. At this point, the injection should fail because | ||||
6940 | * the second display no longer has a foreground window. At this point, the monitor on the second | ||||
6941 | * display should receive a cancel event, and any windows or monitors on the first display should | ||||
6942 | * not receive any events, and any subsequent injection of events into the second display should | ||||
6943 | * also fail. | ||||
6944 | * Continue to inject events into the first display, and the events should all be injected | ||||
6945 | * successfully and received normally. | ||||
6946 | */ | ||||
6947 | TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCancelWhenAnotherDisplayMonitorTouchCanceled) { | ||||
6948 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
6949 | sp<FakeWindowHandle> window = | ||||
6950 | sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); | ||||
6951 | sp<FakeWindowHandle> secondWindow = | ||||
6952 | sp<FakeWindowHandle>::make(application, mDispatcher, "SecondForeground", | ||||
6953 | SECOND_DISPLAY_ID); | ||||
6954 | |||||
6955 | FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); | ||||
6956 | FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID); | ||||
6957 | |||||
6958 | // There is a foreground window on both displays. | ||||
6959 | mDispatcher->onWindowInfosChanged({{*window->getInfo(), *secondWindow->getInfo()}, {}, 0, 0}); | ||||
6960 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
6961 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
6962 | {100, 200})) | ||||
6963 | << "The down event injected into the first display should succeed"; | ||||
6964 | |||||
6965 | window->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
6966 | monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
Linnan Li | d815095 | 2024-01-26 18:07:17 +0000 | [diff] [blame] | 6967 | |
6968 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
6969 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, | ||||
6970 | {100, 200})) | ||||
6971 | << "The down event injected into the second display should succeed"; | ||||
6972 | |||||
Linnan Li | d815095 | 2024-01-26 18:07:17 +0000 | [diff] [blame] | 6973 | secondWindow->consumeMotionDown(SECOND_DISPLAY_ID); |
6974 | secondMonitor.consumeMotionDown(SECOND_DISPLAY_ID); | ||||
6975 | |||||
6976 | // Now second window is gone away. | ||||
6977 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
6978 | |||||
6979 | // The gone window should receive a cancel, and the monitor on the second display should not | ||||
6980 | // receive any events. | ||||
Linnan Li | d815095 | 2024-01-26 18:07:17 +0000 | [diff] [blame] | 6981 | secondWindow->consumeMotionCancel(SECOND_DISPLAY_ID); |
6982 | secondMonitor.assertNoEvents(); | ||||
6983 | |||||
6984 | ASSERT_EQ(InputEventInjectionResult::FAILED, | ||||
6985 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, | ||||
6986 | SECOND_DISPLAY_ID, {110, 220})) | ||||
Prabir Pradhan | a0d43d4 | 2024-01-30 00:27:08 +0000 | [diff] [blame] | 6987 | << "The move event injected into the second display should fail because there's no " |
6988 | "touchable window"; | ||||
Linnan Li | d815095 | 2024-01-26 18:07:17 +0000 | [diff] [blame] | 6989 | // Now the monitor on the second display should receive a cancel event. |
6990 | secondMonitor.consumeMotionCancel(SECOND_DISPLAY_ID); | ||||
Linnan Li | d815095 | 2024-01-26 18:07:17 +0000 | [diff] [blame] | 6991 | |
6992 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
6993 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, | ||||
6994 | ADISPLAY_ID_DEFAULT, {110, 200})) | ||||
6995 | << "The move event injected into the first display should succeed"; | ||||
6996 | |||||
6997 | window->consumeMotionMove(); | ||||
6998 | monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT); | ||||
Linnan Li | d815095 | 2024-01-26 18:07:17 +0000 | [diff] [blame] | 6999 | |
7000 | ASSERT_EQ(InputEventInjectionResult::FAILED, | ||||
Prabir Pradhan | a0d43d4 | 2024-01-30 00:27:08 +0000 | [diff] [blame] | 7001 | injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, |
7002 | {110, 220})) | ||||
7003 | << "The up event injected into the second display should fail because there's no " | ||||
7004 | "touchable window"; | ||||
Linnan Li | d815095 | 2024-01-26 18:07:17 +0000 | [diff] [blame] | 7005 | |
7006 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
7007 | injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
7008 | {110, 220})) | ||||
7009 | << "The up event injected into the first display should succeed"; | ||||
7010 | |||||
7011 | window->consumeMotionUp(ADISPLAY_ID_DEFAULT); | ||||
7012 | monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | a0d43d4 | 2024-01-30 00:27:08 +0000 | [diff] [blame] | 7013 | |
Linnan Li | d815095 | 2024-01-26 18:07:17 +0000 | [diff] [blame] | 7014 | window->assertNoEvents(); |
7015 | monitor.assertNoEvents(); | ||||
Prabir Pradhan | a0d43d4 | 2024-01-30 00:27:08 +0000 | [diff] [blame] | 7016 | secondWindow->assertNoEvents(); |
7017 | secondMonitor.assertNoEvents(); | ||||
Linnan Li | d815095 | 2024-01-26 18:07:17 +0000 | [diff] [blame] | 7018 | } |
7019 | |||||
7020 | /** | ||||
7021 | * One display with transform | ||||
7022 | * There is a foreground window and a monitor on the display | ||||
7023 | * Inject down event and move event sequentially, the foreground window and monitor can receive down | ||||
7024 | * event and move event, then let the foreground window go away, the foreground window receives | ||||
7025 | * cancel event, inject move event again, the monitor receives cancel event, all the events received | ||||
7026 | * by the monitor should be with the same transform as the display | ||||
7027 | */ | ||||
7028 | TEST_F(InputDispatcherMonitorTest, MonitorTouchCancelEventWithDisplayTransform) { | ||||
7029 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
7030 | sp<FakeWindowHandle> window = | ||||
7031 | sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); | ||||
7032 | FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); | ||||
7033 | |||||
7034 | ui::Transform transform; | ||||
7035 | transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1}); | ||||
7036 | |||||
7037 | gui::DisplayInfo displayInfo; | ||||
7038 | displayInfo.displayId = ADISPLAY_ID_DEFAULT; | ||||
7039 | displayInfo.transform = transform; | ||||
7040 | |||||
7041 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0}); | ||||
7042 | |||||
7043 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
7044 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
7045 | {100, 200})) | ||||
7046 | << "The down event injected should succeed"; | ||||
7047 | |||||
7048 | window->consumeMotionDown(); | ||||
7049 | std::unique_ptr<MotionEvent> downMotionEvent = monitor.consumeMotion(); | ||||
7050 | EXPECT_EQ(transform, downMotionEvent->getTransform()); | ||||
7051 | EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, downMotionEvent->getAction()); | ||||
7052 | |||||
7053 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
7054 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, | ||||
7055 | ADISPLAY_ID_DEFAULT, {110, 220})) | ||||
7056 | << "The move event injected should succeed"; | ||||
7057 | |||||
7058 | window->consumeMotionMove(); | ||||
7059 | std::unique_ptr<MotionEvent> moveMotionEvent = monitor.consumeMotion(); | ||||
7060 | EXPECT_EQ(transform, moveMotionEvent->getTransform()); | ||||
7061 | EXPECT_EQ(AMOTION_EVENT_ACTION_MOVE, moveMotionEvent->getAction()); | ||||
7062 | |||||
7063 | // Let foreground window gone | ||||
7064 | mDispatcher->onWindowInfosChanged({{}, {displayInfo}, 0, 0}); | ||||
7065 | |||||
Prabir Pradhan | a0d43d4 | 2024-01-30 00:27:08 +0000 | [diff] [blame] | 7066 | // Foreground window should receive a cancel event, but not the monitor. |
Linnan Li | d815095 | 2024-01-26 18:07:17 +0000 | [diff] [blame] | 7067 | window->consumeMotionCancel(); |
Linnan Li | d815095 | 2024-01-26 18:07:17 +0000 | [diff] [blame] | 7068 | |
7069 | ASSERT_EQ(InputEventInjectionResult::FAILED, | ||||
7070 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, | ||||
7071 | ADISPLAY_ID_DEFAULT, {110, 220})) | ||||
7072 | << "The move event injected should failed"; | ||||
7073 | // Now foreground should not receive any events, but monitor should receive a cancel event | ||||
7074 | // with transform that same as display's display. | ||||
Linnan Li | d815095 | 2024-01-26 18:07:17 +0000 | [diff] [blame] | 7075 | std::unique_ptr<MotionEvent> cancelMotionEvent = monitor.consumeMotion(); |
7076 | EXPECT_EQ(transform, cancelMotionEvent->getTransform()); | ||||
7077 | EXPECT_EQ(ADISPLAY_ID_DEFAULT, cancelMotionEvent->getDisplayId()); | ||||
7078 | EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, cancelMotionEvent->getAction()); | ||||
7079 | |||||
7080 | // Other event inject to this display should fail. | ||||
7081 | ASSERT_EQ(InputEventInjectionResult::FAILED, | ||||
7082 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, | ||||
7083 | ADISPLAY_ID_DEFAULT, {110, 220})) | ||||
Prabir Pradhan | a0d43d4 | 2024-01-30 00:27:08 +0000 | [diff] [blame] | 7084 | << "The up event injected should fail because the touched window was removed"; |
Linnan Li | d815095 | 2024-01-26 18:07:17 +0000 | [diff] [blame] | 7085 | window->assertNoEvents(); |
7086 | monitor.assertNoEvents(); | ||||
7087 | } | ||||
7088 | |||||
chaviw | 81e2bb9 | 2019-12-18 15:03:51 -0800 | [diff] [blame] | 7089 | TEST_F(InputDispatcherTest, TestMoveEvent) { |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 7090 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 7091 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
7092 | "Fake Window", ADISPLAY_ID_DEFAULT); | ||||
chaviw | 81e2bb9 | 2019-12-18 15:03:51 -0800 | [diff] [blame] | 7093 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7094 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
chaviw | 81e2bb9 | 2019-12-18 15:03:51 -0800 | [diff] [blame] | 7095 | |
7096 | NotifyMotionArgs motionArgs = | ||||
7097 | generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, | ||||
7098 | ADISPLAY_ID_DEFAULT); | ||||
7099 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 7100 | mDispatcher->notifyMotion(motionArgs); |
chaviw | 81e2bb9 | 2019-12-18 15:03:51 -0800 | [diff] [blame] | 7101 | // Window should receive motion down event. |
7102 | window->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
7103 | |||||
7104 | motionArgs.action = AMOTION_EVENT_ACTION_MOVE; | ||||
Garfield Tan | c51d1ba | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 7105 | motionArgs.id += 1; |
chaviw | 81e2bb9 | 2019-12-18 15:03:51 -0800 | [diff] [blame] | 7106 | motionArgs.eventTime = systemTime(SYSTEM_TIME_MONOTONIC); |
7107 | motionArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, | ||||
7108 | motionArgs.pointerCoords[0].getX() - 10); | ||||
7109 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 7110 | mDispatcher->notifyMotion(motionArgs); |
Prabir Pradhan | 7662a8d | 2023-12-15 01:58:14 +0000 | [diff] [blame] | 7111 | window->consumeMotionMove(ADISPLAY_ID_DEFAULT, /*expectedFlags=*/0); |
chaviw | 81e2bb9 | 2019-12-18 15:03:51 -0800 | [diff] [blame] | 7112 | } |
7113 | |||||
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 7114 | /** |
7115 | * Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to | ||||
7116 | * the device default right away. In the test scenario, we check both the default value, | ||||
7117 | * and the action of enabling / disabling. | ||||
7118 | */ | ||||
7119 | TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) { | ||||
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 7120 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 7121 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
7122 | "Test window", ADISPLAY_ID_DEFAULT); | ||||
Antonio Kantek | ea47acb | 2021-12-23 12:41:25 -0800 | [diff] [blame] | 7123 | const WindowInfo& windowInfo = *window->getInfo(); |
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 7124 | |
7125 | // Set focused application. | ||||
7126 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); | ||||
Vishnu Nair | 47074b8 | 2020-08-14 11:54:47 -0700 | [diff] [blame] | 7127 | window->setFocusable(true); |
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 7128 | |
7129 | SCOPED_TRACE("Check default value of touch mode"); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7130 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7131 | setFocusedWindow(window); |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 7132 | window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true); |
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 7133 | |
7134 | SCOPED_TRACE("Remove the window to trigger focus loss"); | ||||
Vishnu Nair | 47074b8 | 2020-08-14 11:54:47 -0700 | [diff] [blame] | 7135 | window->setFocusable(false); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7136 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 7137 | window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/true); |
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 7138 | |
7139 | SCOPED_TRACE("Disable touch mode"); | ||||
Antonio Kantek | ea47acb | 2021-12-23 12:41:25 -0800 | [diff] [blame] | 7140 | mDispatcher->setInTouchMode(false, windowInfo.ownerPid, windowInfo.ownerUid, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 7141 | /*hasPermission=*/true, ADISPLAY_ID_DEFAULT); |
Antonio Kantek | f16f283 | 2021-09-28 04:39:20 +0000 | [diff] [blame] | 7142 | window->consumeTouchModeEvent(false); |
Vishnu Nair | 47074b8 | 2020-08-14 11:54:47 -0700 | [diff] [blame] | 7143 | window->setFocusable(true); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7144 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7145 | setFocusedWindow(window); |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 7146 | window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/false); |
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 7147 | |
7148 | SCOPED_TRACE("Remove the window to trigger focus loss"); | ||||
Vishnu Nair | 47074b8 | 2020-08-14 11:54:47 -0700 | [diff] [blame] | 7149 | window->setFocusable(false); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7150 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 7151 | window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/false); |
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 7152 | |
7153 | SCOPED_TRACE("Enable touch mode again"); | ||||
Antonio Kantek | ea47acb | 2021-12-23 12:41:25 -0800 | [diff] [blame] | 7154 | mDispatcher->setInTouchMode(true, windowInfo.ownerPid, windowInfo.ownerUid, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 7155 | /*hasPermission=*/true, ADISPLAY_ID_DEFAULT); |
Antonio Kantek | f16f283 | 2021-09-28 04:39:20 +0000 | [diff] [blame] | 7156 | window->consumeTouchModeEvent(true); |
Vishnu Nair | 47074b8 | 2020-08-14 11:54:47 -0700 | [diff] [blame] | 7157 | window->setFocusable(true); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7158 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7159 | setFocusedWindow(window); |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 7160 | window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true); |
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 7161 | |
7162 | window->assertNoEvents(); | ||||
7163 | } | ||||
7164 | |||||
Gang Wang | e908789 | 2020-01-07 12:17:14 -0500 | [diff] [blame] | 7165 | TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) { |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 7166 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 7167 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
7168 | "Test window", ADISPLAY_ID_DEFAULT); | ||||
Gang Wang | e908789 | 2020-01-07 12:17:14 -0500 | [diff] [blame] | 7169 | |
7170 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); | ||||
Vishnu Nair | 47074b8 | 2020-08-14 11:54:47 -0700 | [diff] [blame] | 7171 | window->setFocusable(true); |
Gang Wang | e908789 | 2020-01-07 12:17:14 -0500 | [diff] [blame] | 7172 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7173 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7174 | setFocusedWindow(window); |
7175 | |||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 7176 | window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true); |
Gang Wang | e908789 | 2020-01-07 12:17:14 -0500 | [diff] [blame] | 7177 | |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 7178 | const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN); |
7179 | mDispatcher->notifyKey(keyArgs); | ||||
Gang Wang | e908789 | 2020-01-07 12:17:14 -0500 | [diff] [blame] | 7180 | |
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 7181 | std::unique_ptr<KeyEvent> event = window->consumeKey(); |
7182 | ASSERT_NE(event, nullptr); | ||||
7183 | std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event); | ||||
Gang Wang | e908789 | 2020-01-07 12:17:14 -0500 | [diff] [blame] | 7184 | ASSERT_NE(verified, nullptr); |
7185 | ASSERT_EQ(verified->type, VerifiedInputEvent::Type::KEY); | ||||
7186 | |||||
7187 | ASSERT_EQ(keyArgs.eventTime, verified->eventTimeNanos); | ||||
7188 | ASSERT_EQ(keyArgs.deviceId, verified->deviceId); | ||||
7189 | ASSERT_EQ(keyArgs.source, verified->source); | ||||
7190 | ASSERT_EQ(keyArgs.displayId, verified->displayId); | ||||
7191 | |||||
7192 | const VerifiedKeyEvent& verifiedKey = static_cast<const VerifiedKeyEvent&>(*verified); | ||||
7193 | |||||
7194 | ASSERT_EQ(keyArgs.action, verifiedKey.action); | ||||
Gang Wang | e908789 | 2020-01-07 12:17:14 -0500 | [diff] [blame] | 7195 | ASSERT_EQ(keyArgs.flags & VERIFIED_KEY_EVENT_FLAGS, verifiedKey.flags); |
Siarhei Vishniakou | f355bf9 | 2021-12-09 10:43:21 -0800 | [diff] [blame] | 7196 | ASSERT_EQ(keyArgs.downTime, verifiedKey.downTimeNanos); |
Gang Wang | e908789 | 2020-01-07 12:17:14 -0500 | [diff] [blame] | 7197 | ASSERT_EQ(keyArgs.keyCode, verifiedKey.keyCode); |
7198 | ASSERT_EQ(keyArgs.scanCode, verifiedKey.scanCode); | ||||
7199 | ASSERT_EQ(keyArgs.metaState, verifiedKey.metaState); | ||||
7200 | ASSERT_EQ(0, verifiedKey.repeatCount); | ||||
7201 | } | ||||
7202 | |||||
Siarhei Vishniakou | 47040bf | 2020-02-28 15:03:13 -0800 | [diff] [blame] | 7203 | TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 7204 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 7205 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
7206 | "Test window", ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | 47040bf | 2020-02-28 15:03:13 -0800 | [diff] [blame] | 7207 | |
7208 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); | ||||
7209 | |||||
Prabir Pradhan | b5cb957 | 2021-09-24 06:35:16 -0700 | [diff] [blame] | 7210 | ui::Transform transform; |
7211 | transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1}); | ||||
7212 | |||||
7213 | gui::DisplayInfo displayInfo; | ||||
7214 | displayInfo.displayId = ADISPLAY_ID_DEFAULT; | ||||
7215 | displayInfo.transform = transform; | ||||
7216 | |||||
Patrick Williams | d828f30 | 2023-04-28 17:52:08 -0500 | [diff] [blame] | 7217 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0}); |
Siarhei Vishniakou | 47040bf | 2020-02-28 15:03:13 -0800 | [diff] [blame] | 7218 | |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 7219 | const NotifyMotionArgs motionArgs = |
Siarhei Vishniakou | 47040bf | 2020-02-28 15:03:13 -0800 | [diff] [blame] | 7220 | generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, |
7221 | ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 7222 | mDispatcher->notifyMotion(motionArgs); |
Siarhei Vishniakou | 47040bf | 2020-02-28 15:03:13 -0800 | [diff] [blame] | 7223 | |
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 7224 | std::unique_ptr<MotionEvent> event = window->consumeMotionEvent(); |
7225 | ASSERT_NE(nullptr, event); | ||||
7226 | std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event); | ||||
Siarhei Vishniakou | 47040bf | 2020-02-28 15:03:13 -0800 | [diff] [blame] | 7227 | ASSERT_NE(verified, nullptr); |
7228 | ASSERT_EQ(verified->type, VerifiedInputEvent::Type::MOTION); | ||||
7229 | |||||
7230 | EXPECT_EQ(motionArgs.eventTime, verified->eventTimeNanos); | ||||
7231 | EXPECT_EQ(motionArgs.deviceId, verified->deviceId); | ||||
7232 | EXPECT_EQ(motionArgs.source, verified->source); | ||||
7233 | EXPECT_EQ(motionArgs.displayId, verified->displayId); | ||||
7234 | |||||
7235 | const VerifiedMotionEvent& verifiedMotion = static_cast<const VerifiedMotionEvent&>(*verified); | ||||
7236 | |||||
Prabir Pradhan | b5cb957 | 2021-09-24 06:35:16 -0700 | [diff] [blame] | 7237 | const vec2 rawXY = |
7238 | MotionEvent::calculateTransformedXY(motionArgs.source, transform, | ||||
7239 | motionArgs.pointerCoords[0].getXYValue()); | ||||
7240 | EXPECT_EQ(rawXY.x, verifiedMotion.rawX); | ||||
7241 | EXPECT_EQ(rawXY.y, verifiedMotion.rawY); | ||||
Siarhei Vishniakou | 47040bf | 2020-02-28 15:03:13 -0800 | [diff] [blame] | 7242 | EXPECT_EQ(motionArgs.action & AMOTION_EVENT_ACTION_MASK, verifiedMotion.actionMasked); |
Siarhei Vishniakou | 47040bf | 2020-02-28 15:03:13 -0800 | [diff] [blame] | 7243 | EXPECT_EQ(motionArgs.flags & VERIFIED_MOTION_EVENT_FLAGS, verifiedMotion.flags); |
Siarhei Vishniakou | f355bf9 | 2021-12-09 10:43:21 -0800 | [diff] [blame] | 7244 | EXPECT_EQ(motionArgs.downTime, verifiedMotion.downTimeNanos); |
Siarhei Vishniakou | 47040bf | 2020-02-28 15:03:13 -0800 | [diff] [blame] | 7245 | EXPECT_EQ(motionArgs.metaState, verifiedMotion.metaState); |
7246 | EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState); | ||||
7247 | } | ||||
7248 | |||||
chaviw | 09c8d2d | 2020-08-24 15:48:26 -0700 | [diff] [blame] | 7249 | /** |
7250 | * Ensure that separate calls to sign the same data are generating the same key. | ||||
7251 | * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance | ||||
7252 | * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky | ||||
7253 | * tests. | ||||
7254 | */ | ||||
7255 | TEST_F(InputDispatcherTest, GeneratedHmac_IsConsistent) { | ||||
7256 | KeyEvent event = getTestKeyEvent(); | ||||
7257 | VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event); | ||||
7258 | |||||
7259 | std::array<uint8_t, 32> hmac1 = mDispatcher->sign(verifiedEvent); | ||||
7260 | std::array<uint8_t, 32> hmac2 = mDispatcher->sign(verifiedEvent); | ||||
7261 | ASSERT_EQ(hmac1, hmac2); | ||||
7262 | } | ||||
7263 | |||||
7264 | /** | ||||
7265 | * Ensure that changes in VerifiedKeyEvent produce a different hmac. | ||||
7266 | */ | ||||
7267 | TEST_F(InputDispatcherTest, GeneratedHmac_ChangesWhenFieldsChange) { | ||||
7268 | KeyEvent event = getTestKeyEvent(); | ||||
7269 | VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event); | ||||
7270 | std::array<uint8_t, 32> initialHmac = mDispatcher->sign(verifiedEvent); | ||||
7271 | |||||
7272 | verifiedEvent.deviceId += 1; | ||||
7273 | ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); | ||||
7274 | |||||
7275 | verifiedEvent.source += 1; | ||||
7276 | ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); | ||||
7277 | |||||
7278 | verifiedEvent.eventTimeNanos += 1; | ||||
7279 | ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); | ||||
7280 | |||||
7281 | verifiedEvent.displayId += 1; | ||||
7282 | ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); | ||||
7283 | |||||
7284 | verifiedEvent.action += 1; | ||||
7285 | ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); | ||||
7286 | |||||
7287 | verifiedEvent.downTimeNanos += 1; | ||||
7288 | ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); | ||||
7289 | |||||
7290 | verifiedEvent.flags += 1; | ||||
7291 | ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); | ||||
7292 | |||||
7293 | verifiedEvent.keyCode += 1; | ||||
7294 | ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); | ||||
7295 | |||||
7296 | verifiedEvent.scanCode += 1; | ||||
7297 | ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); | ||||
7298 | |||||
7299 | verifiedEvent.metaState += 1; | ||||
7300 | ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); | ||||
7301 | |||||
7302 | verifiedEvent.repeatCount += 1; | ||||
7303 | ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); | ||||
7304 | } | ||||
7305 | |||||
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7306 | TEST_F(InputDispatcherTest, SetFocusedWindow) { |
7307 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
7308 | sp<FakeWindowHandle> windowTop = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 7309 | sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7310 | sp<FakeWindowHandle> windowSecond = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 7311 | sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7312 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); |
7313 | |||||
7314 | // Top window is also focusable but is not granted focus. | ||||
7315 | windowTop->setFocusable(true); | ||||
7316 | windowSecond->setFocusable(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7317 | mDispatcher->onWindowInfosChanged( |
7318 | {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0}); | ||||
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7319 | setFocusedWindow(windowSecond); |
7320 | |||||
7321 | windowSecond->consumeFocusEvent(true); | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 7322 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 7323 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7324 | |
7325 | // Focused window should receive event. | ||||
7326 | windowSecond->consumeKeyDown(ADISPLAY_ID_NONE); | ||||
7327 | windowTop->assertNoEvents(); | ||||
7328 | } | ||||
7329 | |||||
7330 | TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) { | ||||
7331 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
7332 | sp<FakeWindowHandle> window = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 7333 | sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7334 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); |
7335 | |||||
7336 | window->setFocusable(true); | ||||
7337 | // Release channel for window is no longer valid. | ||||
7338 | window->releaseChannel(); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7339 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7340 | setFocusedWindow(window); |
7341 | |||||
7342 | // Test inject a key down, should timeout. | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 7343 | ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher)); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7344 | |
7345 | // window channel is invalid, so it should not receive any input event. | ||||
7346 | window->assertNoEvents(); | ||||
7347 | } | ||||
7348 | |||||
7349 | TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) { | ||||
7350 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
7351 | sp<FakeWindowHandle> window = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 7352 | sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); |
Prabir Pradhan | 76bdecb | 2022-01-31 11:14:15 -0800 | [diff] [blame] | 7353 | window->setFocusable(false); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7354 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); |
7355 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7356 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7357 | setFocusedWindow(window); |
7358 | |||||
7359 | // Test inject a key down, should timeout. | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 7360 | ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher)); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7361 | |
Prabir Pradhan | 76bdecb | 2022-01-31 11:14:15 -0800 | [diff] [blame] | 7362 | // window is not focusable, so it should not receive any input event. |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7363 | window->assertNoEvents(); |
7364 | } | ||||
7365 | |||||
7366 | TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) { | ||||
7367 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
7368 | sp<FakeWindowHandle> windowTop = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 7369 | sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7370 | sp<FakeWindowHandle> windowSecond = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 7371 | sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7372 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); |
7373 | |||||
7374 | windowTop->setFocusable(true); | ||||
7375 | windowSecond->setFocusable(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7376 | mDispatcher->onWindowInfosChanged( |
7377 | {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0}); | ||||
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7378 | setFocusedWindow(windowTop); |
7379 | windowTop->consumeFocusEvent(true); | ||||
7380 | |||||
Chavi Weingarten | 847e851 | 2023-03-29 00:26:09 +0000 | [diff] [blame] | 7381 | windowTop->editInfo()->focusTransferTarget = windowSecond->getToken(); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7382 | mDispatcher->onWindowInfosChanged( |
7383 | {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0}); | ||||
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7384 | windowSecond->consumeFocusEvent(true); |
7385 | windowTop->consumeFocusEvent(false); | ||||
7386 | |||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 7387 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 7388 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7389 | |
7390 | // Focused window should receive event. | ||||
7391 | windowSecond->consumeKeyDown(ADISPLAY_ID_NONE); | ||||
7392 | } | ||||
7393 | |||||
Chavi Weingarten | 847e851 | 2023-03-29 00:26:09 +0000 | [diff] [blame] | 7394 | TEST_F(InputDispatcherTest, SetFocusedWindow_TransferFocusTokenNotFocusable) { |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7395 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
7396 | sp<FakeWindowHandle> windowTop = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 7397 | sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7398 | sp<FakeWindowHandle> windowSecond = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 7399 | sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7400 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); |
7401 | |||||
7402 | windowTop->setFocusable(true); | ||||
Chavi Weingarten | 847e851 | 2023-03-29 00:26:09 +0000 | [diff] [blame] | 7403 | windowSecond->setFocusable(false); |
7404 | windowTop->editInfo()->focusTransferTarget = windowSecond->getToken(); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7405 | mDispatcher->onWindowInfosChanged( |
7406 | {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0}); | ||||
Chavi Weingarten | 847e851 | 2023-03-29 00:26:09 +0000 | [diff] [blame] | 7407 | setFocusedWindow(windowTop); |
7408 | windowTop->consumeFocusEvent(true); | ||||
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7409 | |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 7410 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) |
Chavi Weingarten | 847e851 | 2023-03-29 00:26:09 +0000 | [diff] [blame] | 7411 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7412 | |
7413 | // Event should be dropped. | ||||
Chavi Weingarten | 847e851 | 2023-03-29 00:26:09 +0000 | [diff] [blame] | 7414 | windowTop->consumeKeyDown(ADISPLAY_ID_NONE); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7415 | windowSecond->assertNoEvents(); |
7416 | } | ||||
7417 | |||||
7418 | TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) { | ||||
7419 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
7420 | sp<FakeWindowHandle> window = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 7421 | sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7422 | sp<FakeWindowHandle> previousFocusedWindow = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 7423 | sp<FakeWindowHandle>::make(application, mDispatcher, "previousFocusedWindow", |
7424 | ADISPLAY_ID_DEFAULT); | ||||
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7425 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); |
7426 | |||||
7427 | window->setFocusable(true); | ||||
7428 | previousFocusedWindow->setFocusable(true); | ||||
7429 | window->setVisible(false); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7430 | mDispatcher->onWindowInfosChanged( |
7431 | {{*window->getInfo(), *previousFocusedWindow->getInfo()}, {}, 0, 0}); | ||||
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7432 | setFocusedWindow(previousFocusedWindow); |
7433 | previousFocusedWindow->consumeFocusEvent(true); | ||||
7434 | |||||
7435 | // Requesting focus on invisible window takes focus from currently focused window. | ||||
7436 | setFocusedWindow(window); | ||||
7437 | previousFocusedWindow->consumeFocusEvent(false); | ||||
7438 | |||||
7439 | // Injected key goes to pending queue. | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 7440 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 7441 | injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, |
7442 | ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE)); | ||||
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7443 | |
7444 | // Window does not get focus event or key down. | ||||
7445 | window->assertNoEvents(); | ||||
7446 | |||||
7447 | // Window becomes visible. | ||||
7448 | window->setVisible(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7449 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 7450 | |
7451 | // Window receives focus event. | ||||
7452 | window->consumeFocusEvent(true); | ||||
7453 | // Focused window receives key down. | ||||
7454 | window->consumeKeyDown(ADISPLAY_ID_DEFAULT); | ||||
7455 | } | ||||
7456 | |||||
Vishnu Nair | 599f141 | 2021-06-21 10:39:58 -0700 | [diff] [blame] | 7457 | TEST_F(InputDispatcherTest, DisplayRemoved) { |
7458 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
7459 | sp<FakeWindowHandle> window = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 7460 | sp<FakeWindowHandle>::make(application, mDispatcher, "window", ADISPLAY_ID_DEFAULT); |
Vishnu Nair | 599f141 | 2021-06-21 10:39:58 -0700 | [diff] [blame] | 7461 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); |
7462 | |||||
7463 | // window is granted focus. | ||||
7464 | window->setFocusable(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7465 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 599f141 | 2021-06-21 10:39:58 -0700 | [diff] [blame] | 7466 | setFocusedWindow(window); |
7467 | window->consumeFocusEvent(true); | ||||
7468 | |||||
7469 | // When a display is removed window loses focus. | ||||
7470 | mDispatcher->displayRemoved(ADISPLAY_ID_DEFAULT); | ||||
7471 | window->consumeFocusEvent(false); | ||||
7472 | } | ||||
7473 | |||||
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 7474 | /** |
7475 | * Launch two windows, with different owners. One window (slipperyExitWindow) has Flag::SLIPPERY, | ||||
7476 | * and overlaps the other window, slipperyEnterWindow. The window 'slipperyExitWindow' is on top | ||||
7477 | * of the 'slipperyEnterWindow'. | ||||
7478 | * | ||||
7479 | * Inject touch down into the top window. Upon receipt of the DOWN event, move the window in such | ||||
7480 | * a way so that the touched location is no longer covered by the top window. | ||||
7481 | * | ||||
7482 | * Next, inject a MOVE event. Because the top window already moved earlier, this event is now | ||||
7483 | * positioned over the bottom (slipperyEnterWindow) only. And because the top window had | ||||
7484 | * Flag::SLIPPERY, this will cause the top window to lose the touch event (it will receive | ||||
7485 | * ACTION_CANCEL instead), and the bottom window will receive a newly generated gesture (starting | ||||
7486 | * with ACTION_DOWN). | ||||
7487 | * Thus, the touch has been transferred from the top window into the bottom window, because the top | ||||
7488 | * window moved itself away from the touched location and had Flag::SLIPPERY. | ||||
7489 | * | ||||
7490 | * Even though the top window moved away from the touched location, it is still obscuring the bottom | ||||
7491 | * window. It's just not obscuring it at the touched location. That means, FLAG_WINDOW_IS_PARTIALLY_ | ||||
7492 | * OBSCURED should be set for the MotionEvent that reaches the bottom window. | ||||
7493 | * | ||||
7494 | * In this test, we ensure that the event received by the bottom window has | ||||
7495 | * FLAG_WINDOW_IS_PARTIALLY_OBSCURED. | ||||
7496 | */ | ||||
7497 | TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) { | ||||
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 7498 | constexpr gui::Pid SLIPPERY_PID{WINDOW_PID.val() + 1}; |
Prabir Pradhan | 8a5c41d | 2023-06-08 19:13:46 +0000 | [diff] [blame] | 7499 | constexpr gui::Uid SLIPPERY_UID{WINDOW_UID.val() + 1}; |
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 7500 | |
7501 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
7502 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); | ||||
7503 | |||||
7504 | sp<FakeWindowHandle> slipperyExitWindow = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 7505 | sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); |
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 7506 | slipperyExitWindow->setSlippery(true); |
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 7507 | // Make sure this one overlaps the bottom window |
7508 | slipperyExitWindow->setFrame(Rect(25, 25, 75, 75)); | ||||
7509 | // Change the owner uid/pid of the window so that it is considered to be occluding the bottom | ||||
7510 | // one. Windows with the same owner are not considered to be occluding each other. | ||||
7511 | slipperyExitWindow->setOwnerInfo(SLIPPERY_PID, SLIPPERY_UID); | ||||
7512 | |||||
7513 | sp<FakeWindowHandle> slipperyEnterWindow = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 7514 | sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); |
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 7515 | slipperyExitWindow->setFrame(Rect(0, 0, 100, 100)); |
7516 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7517 | mDispatcher->onWindowInfosChanged( |
7518 | {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 7519 | |
7520 | // Use notifyMotion instead of injecting to avoid dealing with injection permissions | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 7521 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
7522 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
7523 | {{50, 50}})); | ||||
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 7524 | slipperyExitWindow->consumeMotionDown(); |
7525 | slipperyExitWindow->setFrame(Rect(70, 70, 100, 100)); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7526 | mDispatcher->onWindowInfosChanged( |
7527 | {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 7528 | |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 7529 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_MOVE, |
7530 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
7531 | {{51, 51}})); | ||||
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 7532 | |
7533 | slipperyExitWindow->consumeMotionCancel(); | ||||
7534 | |||||
7535 | slipperyEnterWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, | ||||
7536 | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED); | ||||
7537 | } | ||||
7538 | |||||
Siarhei Vishniakou | afa08cc | 2023-05-08 22:35:50 -0700 | [diff] [blame] | 7539 | /** |
7540 | * Two windows, one on the left and another on the right. The left window is slippery. The right | ||||
7541 | * window isn't eligible to receive touch because it specifies InputConfig::DROP_INPUT. When the | ||||
7542 | * touch moves from the left window into the right window, the gesture should continue to go to the | ||||
7543 | * left window. Touch shouldn't slip because the right window can't receive touches. This test | ||||
7544 | * reproduces a crash. | ||||
7545 | */ | ||||
7546 | TEST_F(InputDispatcherTest, TouchSlippingIntoWindowThatDropsTouches) { | ||||
7547 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
7548 | |||||
7549 | sp<FakeWindowHandle> leftSlipperyWindow = | ||||
7550 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); | ||||
7551 | leftSlipperyWindow->setSlippery(true); | ||||
7552 | leftSlipperyWindow->setFrame(Rect(0, 0, 100, 100)); | ||||
7553 | |||||
7554 | sp<FakeWindowHandle> rightDropTouchesWindow = | ||||
7555 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); | ||||
7556 | rightDropTouchesWindow->setFrame(Rect(100, 0, 200, 100)); | ||||
7557 | rightDropTouchesWindow->setDropInput(true); | ||||
7558 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7559 | mDispatcher->onWindowInfosChanged( |
7560 | {{*leftSlipperyWindow->getInfo(), *rightDropTouchesWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | afa08cc | 2023-05-08 22:35:50 -0700 | [diff] [blame] | 7561 | |
7562 | // Start touch in the left window | ||||
7563 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7564 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
7565 | .build()); | ||||
7566 | leftSlipperyWindow->consumeMotionDown(); | ||||
7567 | |||||
7568 | // And move it into the right window | ||||
7569 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7570 | .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) | ||||
7571 | .build()); | ||||
7572 | |||||
7573 | // Since the right window isn't eligible to receive input, touch does not slip. | ||||
7574 | // The left window continues to receive the gesture. | ||||
7575 | leftSlipperyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); | ||||
7576 | rightDropTouchesWindow->assertNoEvents(); | ||||
7577 | } | ||||
7578 | |||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 7579 | /** |
7580 | * A single window is on screen first. Touch is injected into that window. Next, a second window | ||||
7581 | * appears. Since the first window is slippery, touch will move from the first window to the second. | ||||
7582 | */ | ||||
7583 | TEST_F(InputDispatcherTest, InjectedTouchSlips) { | ||||
7584 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
7585 | sp<FakeWindowHandle> originalWindow = | ||||
7586 | sp<FakeWindowHandle>::make(application, mDispatcher, "Original", ADISPLAY_ID_DEFAULT); | ||||
7587 | originalWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
7588 | originalWindow->setSlippery(true); | ||||
7589 | |||||
7590 | sp<FakeWindowHandle> appearingWindow = | ||||
7591 | sp<FakeWindowHandle>::make(application, mDispatcher, "Appearing", ADISPLAY_ID_DEFAULT); | ||||
7592 | appearingWindow->setFrame(Rect(0, 0, 200, 200)); | ||||
7593 | |||||
7594 | mDispatcher->onWindowInfosChanged({{*originalWindow->getInfo()}, {}, 0, 0}); | ||||
7595 | |||||
7596 | // Touch down on the original window | ||||
7597 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
7598 | injectMotionEvent(*mDispatcher, | ||||
7599 | MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7600 | .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100)) | ||||
7601 | .build())); | ||||
7602 | originalWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); | ||||
7603 | |||||
7604 | // Now, a new window appears. This could be, for example, a notification shade that appears | ||||
7605 | // after user starts to drag down on the launcher window. | ||||
7606 | mDispatcher->onWindowInfosChanged( | ||||
7607 | {{*appearingWindow->getInfo(), *originalWindow->getInfo()}, {}, 0, 0}); | ||||
7608 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
7609 | injectMotionEvent(*mDispatcher, | ||||
7610 | MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7611 | .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(110)) | ||||
7612 | .build())); | ||||
7613 | originalWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); | ||||
7614 | appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); | ||||
7615 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
7616 | injectMotionEvent(*mDispatcher, | ||||
7617 | MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7618 | .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120)) | ||||
7619 | .build())); | ||||
7620 | appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); | ||||
7621 | |||||
7622 | originalWindow->assertNoEvents(); | ||||
7623 | appearingWindow->assertNoEvents(); | ||||
7624 | } | ||||
7625 | |||||
Linnan Li | 49b2b20 | 2024-04-12 12:46:40 +0800 | [diff] [blame] | 7626 | /** |
7627 | * Three windows: | ||||
7628 | * - left window, which has FLAG_SLIPPERY, so it supports slippery exit | ||||
7629 | * - right window | ||||
7630 | * - spy window | ||||
7631 | * The three windows do not overlap. | ||||
7632 | * | ||||
7633 | * We have two devices reporting events: | ||||
7634 | * - Device A reports ACTION_DOWN, which lands in the left window | ||||
7635 | * - Device B reports ACTION_DOWN, which lands in the spy window. | ||||
7636 | * - Now, device B reports ACTION_MOVE events which move to the right window. | ||||
7637 | * | ||||
7638 | * The right window should not receive any events because the spy window is not a foreground window, | ||||
7639 | * and also it does not support slippery touches. | ||||
7640 | */ | ||||
7641 | TEST_F(InputDispatcherTest, MultiDeviceSpyWindowSlipTest) { | ||||
7642 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
7643 | sp<FakeWindowHandle> leftWindow = | ||||
7644 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left window", | ||||
7645 | ADISPLAY_ID_DEFAULT); | ||||
7646 | leftWindow->setFrame(Rect(0, 0, 100, 100)); | ||||
7647 | leftWindow->setSlippery(true); | ||||
7648 | |||||
7649 | sp<FakeWindowHandle> rightWindow = | ||||
7650 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right window", | ||||
7651 | ADISPLAY_ID_DEFAULT); | ||||
7652 | rightWindow->setFrame(Rect(100, 0, 200, 100)); | ||||
7653 | |||||
7654 | sp<FakeWindowHandle> spyWindow = | ||||
7655 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT); | ||||
7656 | spyWindow->setFrame(Rect(200, 0, 300, 100)); | ||||
7657 | spyWindow->setSpy(true); | ||||
7658 | spyWindow->setTrustedOverlay(true); | ||||
7659 | |||||
7660 | mDispatcher->onWindowInfosChanged( | ||||
7661 | {{*leftWindow->getInfo(), *rightWindow->getInfo(), *spyWindow->getInfo()}, {}, 0, 0}); | ||||
7662 | |||||
7663 | const DeviceId deviceA = 9; | ||||
7664 | const DeviceId deviceB = 3; | ||||
7665 | |||||
7666 | // Tap on left window with device A | ||||
7667 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7668 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
7669 | .deviceId(deviceA) | ||||
7670 | .build()); | ||||
7671 | leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA))); | ||||
7672 | |||||
7673 | // Tap on spy window with device B | ||||
7674 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7675 | .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(50)) | ||||
7676 | .deviceId(deviceB) | ||||
7677 | .build()); | ||||
7678 | spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB))); | ||||
7679 | |||||
7680 | // Move to right window with device B. Touches should not slip to the right window, because spy | ||||
7681 | // window is not a foreground window, and it does not have FLAG_SLIPPERY | ||||
7682 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7683 | .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) | ||||
7684 | .deviceId(deviceB) | ||||
7685 | .build()); | ||||
7686 | leftWindow->assertNoEvents(); | ||||
7687 | rightWindow->assertNoEvents(); | ||||
7688 | spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB))); | ||||
7689 | } | ||||
7690 | |||||
7691 | /** | ||||
7692 | * Three windows arranged horizontally and without any overlap. | ||||
7693 | * The left and right windows have FLAG_SLIPPERY. The middle window does not have any special flags. | ||||
7694 | * | ||||
7695 | * We have two devices reporting events: | ||||
7696 | * - Device A reports ACTION_DOWN which lands in the left window | ||||
7697 | * - Device B reports ACTION_DOWN which lands in the right window | ||||
7698 | * - Device B reports ACTION_MOVE that shifts to the middle window. | ||||
7699 | * This should cause touches for Device B to slip from the right window to the middle window. | ||||
7700 | * The right window should receive ACTION_CANCEL for device B and the | ||||
7701 | * middle window should receive down event for Device B. | ||||
7702 | * If device B reports more ACTION_MOVE events, the middle window should receive remaining events. | ||||
7703 | */ | ||||
7704 | TEST_F(InputDispatcherTest, MultiDeviceSlipperyWindowTest) { | ||||
7705 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
7706 | sp<FakeWindowHandle> leftWindow = | ||||
7707 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left window", | ||||
7708 | ADISPLAY_ID_DEFAULT); | ||||
7709 | leftWindow->setFrame(Rect(0, 0, 100, 100)); | ||||
7710 | leftWindow->setSlippery(true); | ||||
7711 | |||||
7712 | sp<FakeWindowHandle> middleWindow = | ||||
7713 | sp<FakeWindowHandle>::make(application, mDispatcher, "middle window", | ||||
7714 | ADISPLAY_ID_DEFAULT); | ||||
7715 | middleWindow->setFrame(Rect(100, 0, 200, 100)); | ||||
7716 | |||||
7717 | sp<FakeWindowHandle> rightWindow = | ||||
7718 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right window", | ||||
7719 | ADISPLAY_ID_DEFAULT); | ||||
7720 | rightWindow->setFrame(Rect(200, 0, 300, 100)); | ||||
7721 | rightWindow->setSlippery(true); | ||||
7722 | |||||
7723 | mDispatcher->onWindowInfosChanged( | ||||
7724 | {{*leftWindow->getInfo(), *middleWindow->getInfo(), *rightWindow->getInfo()}, | ||||
7725 | {}, | ||||
7726 | 0, | ||||
7727 | 0}); | ||||
7728 | |||||
7729 | const DeviceId deviceA = 9; | ||||
7730 | const DeviceId deviceB = 3; | ||||
7731 | |||||
7732 | // Tap on left window with device A | ||||
7733 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7734 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
7735 | .deviceId(deviceA) | ||||
7736 | .build()); | ||||
7737 | leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA))); | ||||
7738 | |||||
7739 | // Tap on right window with device B | ||||
7740 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7741 | .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(50)) | ||||
7742 | .deviceId(deviceB) | ||||
7743 | .build()); | ||||
7744 | rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB))); | ||||
7745 | |||||
7746 | // Move to middle window with device B. Touches should slip to middle window, because right | ||||
7747 | // window is a foreground window that's associated with device B and has FLAG_SLIPPERY. | ||||
7748 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7749 | .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) | ||||
7750 | .deviceId(deviceB) | ||||
7751 | .build()); | ||||
7752 | rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB))); | ||||
7753 | middleWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB))); | ||||
7754 | |||||
7755 | // Move to middle window with device A. Touches should slip to middle window, because left | ||||
7756 | // window is a foreground window that's associated with device A and has FLAG_SLIPPERY. | ||||
7757 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7758 | .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) | ||||
7759 | .deviceId(deviceA) | ||||
7760 | .build()); | ||||
7761 | leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceA))); | ||||
7762 | middleWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA))); | ||||
7763 | |||||
7764 | // Ensure that middle window can receive the remaining move events. | ||||
7765 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7766 | .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51)) | ||||
7767 | .deviceId(deviceB) | ||||
7768 | .build()); | ||||
7769 | leftWindow->assertNoEvents(); | ||||
7770 | middleWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB))); | ||||
7771 | rightWindow->assertNoEvents(); | ||||
7772 | } | ||||
7773 | |||||
Prabir Pradhan | 8ede1d1 | 2023-05-08 19:37:44 +0000 | [diff] [blame] | 7774 | TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithMotions) { |
Prabir Pradhan | 8a5c41d | 2023-06-08 19:13:46 +0000 | [diff] [blame] | 7775 | using Uid = gui::Uid; |
Prabir Pradhan | 8ede1d1 | 2023-05-08 19:37:44 +0000 | [diff] [blame] | 7776 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
7777 | |||||
7778 | sp<FakeWindowHandle> leftWindow = | ||||
7779 | sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); | ||||
7780 | leftWindow->setFrame(Rect(0, 0, 100, 100)); | ||||
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 7781 | leftWindow->setOwnerInfo(gui::Pid{1}, Uid{101}); |
Prabir Pradhan | 8ede1d1 | 2023-05-08 19:37:44 +0000 | [diff] [blame] | 7782 | |
7783 | sp<FakeWindowHandle> rightSpy = | ||||
7784 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right spy", ADISPLAY_ID_DEFAULT); | ||||
7785 | rightSpy->setFrame(Rect(100, 0, 200, 100)); | ||||
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 7786 | rightSpy->setOwnerInfo(gui::Pid{2}, Uid{102}); |
Prabir Pradhan | 8ede1d1 | 2023-05-08 19:37:44 +0000 | [diff] [blame] | 7787 | rightSpy->setSpy(true); |
7788 | rightSpy->setTrustedOverlay(true); | ||||
7789 | |||||
7790 | sp<FakeWindowHandle> rightWindow = | ||||
7791 | sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); | ||||
7792 | rightWindow->setFrame(Rect(100, 0, 200, 100)); | ||||
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 7793 | rightWindow->setOwnerInfo(gui::Pid{3}, Uid{103}); |
Prabir Pradhan | 8ede1d1 | 2023-05-08 19:37:44 +0000 | [diff] [blame] | 7794 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7795 | mDispatcher->onWindowInfosChanged( |
7796 | {{*rightSpy->getInfo(), *rightWindow->getInfo(), *leftWindow->getInfo()}, {}, 0, 0}); | ||||
Prabir Pradhan | 8ede1d1 | 2023-05-08 19:37:44 +0000 | [diff] [blame] | 7797 | |
7798 | // Touch in the left window | ||||
7799 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7800 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
7801 | .build()); | ||||
7802 | ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionDown()); | ||||
7803 | mDispatcher->waitForIdle(); | ||||
Prabir Pradhan | 8a5c41d | 2023-06-08 19:13:46 +0000 | [diff] [blame] | 7804 | ASSERT_NO_FATAL_FAILURE( |
7805 | mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{101}})); | ||||
Prabir Pradhan | 8ede1d1 | 2023-05-08 19:37:44 +0000 | [diff] [blame] | 7806 | |
7807 | // Touch another finger over the right windows | ||||
7808 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7809 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
7810 | .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50)) | ||||
7811 | .build()); | ||||
7812 | ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionDown()); | ||||
7813 | ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionDown()); | ||||
7814 | ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionMove()); | ||||
7815 | mDispatcher->waitForIdle(); | ||||
7816 | ASSERT_NO_FATAL_FAILURE( | ||||
Prabir Pradhan | 8a5c41d | 2023-06-08 19:13:46 +0000 | [diff] [blame] | 7817 | mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, |
7818 | {Uid{101}, Uid{102}, Uid{103}})); | ||||
Prabir Pradhan | 8ede1d1 | 2023-05-08 19:37:44 +0000 | [diff] [blame] | 7819 | |
7820 | // Release finger over left window. The UP actions are not treated as device interaction. | ||||
7821 | // The windows that did not receive the UP pointer will receive MOVE events, but since this | ||||
7822 | // is part of the UP action, we do not treat this as device interaction. | ||||
7823 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7824 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
7825 | .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50)) | ||||
7826 | .build()); | ||||
7827 | ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionUp()); | ||||
7828 | ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove()); | ||||
7829 | ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove()); | ||||
7830 | mDispatcher->waitForIdle(); | ||||
7831 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled()); | ||||
7832 | |||||
7833 | // Move remaining finger | ||||
7834 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7835 | .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50)) | ||||
7836 | .build()); | ||||
7837 | ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove()); | ||||
7838 | ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove()); | ||||
7839 | mDispatcher->waitForIdle(); | ||||
7840 | ASSERT_NO_FATAL_FAILURE( | ||||
Prabir Pradhan | 8a5c41d | 2023-06-08 19:13:46 +0000 | [diff] [blame] | 7841 | mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{102}, Uid{103}})); |
Prabir Pradhan | 8ede1d1 | 2023-05-08 19:37:44 +0000 | [diff] [blame] | 7842 | |
7843 | // Release all fingers | ||||
7844 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7845 | .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50)) | ||||
7846 | .build()); | ||||
7847 | ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionUp()); | ||||
7848 | ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionUp()); | ||||
7849 | mDispatcher->waitForIdle(); | ||||
7850 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled()); | ||||
7851 | } | ||||
7852 | |||||
7853 | TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithKeys) { | ||||
7854 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
7855 | |||||
7856 | sp<FakeWindowHandle> window = | ||||
7857 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
7858 | window->setFrame(Rect(0, 0, 100, 100)); | ||||
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 7859 | window->setOwnerInfo(gui::Pid{1}, gui::Uid{101}); |
Prabir Pradhan | 8ede1d1 | 2023-05-08 19:37:44 +0000 | [diff] [blame] | 7860 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 7861 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | 8ede1d1 | 2023-05-08 19:37:44 +0000 | [diff] [blame] | 7862 | setFocusedWindow(window); |
7863 | ASSERT_NO_FATAL_FAILURE(window->consumeFocusEvent(true)); | ||||
7864 | |||||
7865 | mDispatcher->notifyKey(KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).build()); | ||||
7866 | ASSERT_NO_FATAL_FAILURE(window->consumeKeyDown(ADISPLAY_ID_DEFAULT)); | ||||
7867 | mDispatcher->waitForIdle(); | ||||
Prabir Pradhan | 8a5c41d | 2023-06-08 19:13:46 +0000 | [diff] [blame] | 7868 | ASSERT_NO_FATAL_FAILURE( |
7869 | mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {gui::Uid{101}})); | ||||
Prabir Pradhan | 8ede1d1 | 2023-05-08 19:37:44 +0000 | [diff] [blame] | 7870 | |
7871 | // The UP actions are not treated as device interaction. | ||||
7872 | mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).build()); | ||||
7873 | ASSERT_NO_FATAL_FAILURE(window->consumeKeyUp(ADISPLAY_ID_DEFAULT)); | ||||
7874 | mDispatcher->waitForIdle(); | ||||
7875 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled()); | ||||
7876 | } | ||||
7877 | |||||
Prabir Pradhan | 5893d36 | 2023-11-17 04:30:40 +0000 | [diff] [blame] | 7878 | TEST_F(InputDispatcherTest, HoverEnterExitSynthesisUsesNewEventId) { |
7879 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
7880 | |||||
7881 | sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window", | ||||
7882 | ADISPLAY_ID_DEFAULT); | ||||
7883 | left->setFrame(Rect(0, 0, 100, 100)); | ||||
7884 | sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher, | ||||
7885 | "Right Window", ADISPLAY_ID_DEFAULT); | ||||
7886 | right->setFrame(Rect(100, 0, 200, 100)); | ||||
7887 | sp<FakeWindowHandle> spy = | ||||
7888 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT); | ||||
7889 | spy->setFrame(Rect(0, 0, 200, 100)); | ||||
7890 | spy->setTrustedOverlay(true); | ||||
7891 | spy->setSpy(true); | ||||
7892 | |||||
7893 | mDispatcher->onWindowInfosChanged( | ||||
7894 | {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0}); | ||||
7895 | |||||
7896 | // Send hover move to the left window, and ensure hover enter is synthesized with a new eventId. | ||||
7897 | NotifyMotionArgs notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS, | ||||
7898 | ADISPLAY_ID_DEFAULT, {PointF{50, 50}}); | ||||
7899 | mDispatcher->notifyMotion(notifyArgs); | ||||
7900 | |||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 7901 | std::unique_ptr<MotionEvent> leftEnter = left->consumeMotionEvent( |
Prabir Pradhan | 5893d36 | 2023-11-17 04:30:40 +0000 | [diff] [blame] | 7902 | AllOf(WithMotionAction(ACTION_HOVER_ENTER), Not(WithEventId(notifyArgs.id)), |
7903 | WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER))); | ||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 7904 | ASSERT_NE(nullptr, leftEnter); |
Prabir Pradhan | 5893d36 | 2023-11-17 04:30:40 +0000 | [diff] [blame] | 7905 | spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER), |
7906 | Not(WithEventId(notifyArgs.id)), | ||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 7907 | Not(WithEventId(leftEnter->getId())), |
Prabir Pradhan | 5893d36 | 2023-11-17 04:30:40 +0000 | [diff] [blame] | 7908 | WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER))); |
7909 | |||||
7910 | // Send move to the right window, and ensure hover exit and enter are synthesized with new ids. | ||||
7911 | notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT, | ||||
7912 | {PointF{150, 50}}); | ||||
7913 | mDispatcher->notifyMotion(notifyArgs); | ||||
7914 | |||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 7915 | std::unique_ptr<MotionEvent> leftExit = left->consumeMotionEvent( |
Prabir Pradhan | 5893d36 | 2023-11-17 04:30:40 +0000 | [diff] [blame] | 7916 | AllOf(WithMotionAction(ACTION_HOVER_EXIT), Not(WithEventId(notifyArgs.id)), |
7917 | WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER))); | ||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 7918 | ASSERT_NE(nullptr, leftExit); |
Prabir Pradhan | 5893d36 | 2023-11-17 04:30:40 +0000 | [diff] [blame] | 7919 | right->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER), |
7920 | Not(WithEventId(notifyArgs.id)), | ||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 7921 | Not(WithEventId(leftExit->getId())), |
Prabir Pradhan | 5893d36 | 2023-11-17 04:30:40 +0000 | [diff] [blame] | 7922 | WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER))); |
7923 | |||||
7924 | spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithEventId(notifyArgs.id))); | ||||
7925 | } | ||||
7926 | |||||
Linnan Li | ccf6ce3 | 2024-04-11 20:32:13 +0800 | [diff] [blame] | 7927 | /** |
7928 | * When a device reports a DOWN event, which lands in a window that supports splits, and then the | ||||
7929 | * device then reports a POINTER_DOWN, which lands in the location of a non-existing window, then | ||||
7930 | * the previous window should receive this event and not be dropped. | ||||
7931 | */ | ||||
7932 | TEST_F(InputDispatcherMultiDeviceTest, SingleDevicePointerDownEventRetentionWithoutWindowTarget) { | ||||
7933 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
7934 | sp<FakeWindowHandle> window = | ||||
7935 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
7936 | window->setFrame(Rect(0, 0, 100, 100)); | ||||
7937 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
7938 | |||||
7939 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7940 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
7941 | .build()); | ||||
7942 | |||||
7943 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN))); | ||||
7944 | |||||
7945 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7946 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
7947 | .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200)) | ||||
7948 | .build()); | ||||
7949 | |||||
7950 | window->consumeMotionEvent(AllOf(WithMotionAction(POINTER_1_DOWN))); | ||||
7951 | } | ||||
7952 | |||||
7953 | /** | ||||
7954 | * When deviceA reports a DOWN event, which lands in a window that supports splits, and then deviceB | ||||
7955 | * also reports a DOWN event, which lands in the location of a non-existing window, then the | ||||
7956 | * previous window should receive deviceB's event and it should be dropped. | ||||
7957 | */ | ||||
7958 | TEST_F(InputDispatcherMultiDeviceTest, SecondDeviceDownEventDroppedWithoutWindowTarget) { | ||||
7959 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
7960 | sp<FakeWindowHandle> window = | ||||
7961 | sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
7962 | window->setFrame(Rect(0, 0, 100, 100)); | ||||
7963 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); | ||||
7964 | |||||
7965 | const DeviceId deviceA = 9; | ||||
7966 | const DeviceId deviceB = 3; | ||||
7967 | |||||
7968 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7969 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
7970 | .deviceId(deviceA) | ||||
7971 | .build()); | ||||
7972 | window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA))); | ||||
7973 | |||||
7974 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
7975 | .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200)) | ||||
7976 | .deviceId(deviceB) | ||||
7977 | .build()); | ||||
7978 | window->assertNoEvents(); | ||||
7979 | } | ||||
7980 | |||||
Prabir Pradhan | b0dad3a | 2023-11-02 20:52:47 +0000 | [diff] [blame] | 7981 | class InputDispatcherFallbackKeyTest : public InputDispatcherTest { |
7982 | protected: | ||||
7983 | std::shared_ptr<FakeApplicationHandle> mApp; | ||||
7984 | sp<FakeWindowHandle> mWindow; | ||||
7985 | |||||
7986 | virtual void SetUp() override { | ||||
7987 | InputDispatcherTest::SetUp(); | ||||
7988 | |||||
7989 | mApp = std::make_shared<FakeApplicationHandle>(); | ||||
7990 | |||||
7991 | mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); | ||||
7992 | mWindow->setFrame(Rect(0, 0, 100, 100)); | ||||
7993 | |||||
7994 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); | ||||
7995 | setFocusedWindow(mWindow); | ||||
7996 | ASSERT_NO_FATAL_FAILURE(mWindow->consumeFocusEvent(/*hasFocus=*/true)); | ||||
7997 | } | ||||
7998 | |||||
7999 | void setFallback(int32_t keycode) { | ||||
8000 | mFakePolicy->setUnhandledKeyHandler([keycode](const KeyEvent& event) { | ||||
8001 | return KeyEventBuilder(event).keyCode(keycode).build(); | ||||
8002 | }); | ||||
8003 | } | ||||
8004 | |||||
8005 | void consumeKey(bool handled, const ::testing::Matcher<KeyEvent>& matcher) { | ||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 8006 | std::unique_ptr<KeyEvent> event = mWindow->consumeKey(handled); |
8007 | ASSERT_NE(nullptr, event); | ||||
8008 | ASSERT_THAT(*event, matcher); | ||||
Prabir Pradhan | b0dad3a | 2023-11-02 20:52:47 +0000 | [diff] [blame] | 8009 | } |
8010 | }; | ||||
8011 | |||||
8012 | TEST_F(InputDispatcherFallbackKeyTest, PolicyNotNotifiedForHandledKey) { | ||||
8013 | mDispatcher->notifyKey( | ||||
8014 | KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); | ||||
8015 | consumeKey(/*handled=*/true, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A))); | ||||
8016 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported()); | ||||
8017 | } | ||||
8018 | |||||
8019 | TEST_F(InputDispatcherFallbackKeyTest, PolicyNotifiedForUnhandledKey) { | ||||
8020 | mDispatcher->notifyKey( | ||||
8021 | KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); | ||||
8022 | consumeKey(/*handled=*/false, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A))); | ||||
8023 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); | ||||
8024 | } | ||||
8025 | |||||
8026 | TEST_F(InputDispatcherFallbackKeyTest, NoFallbackRequestedByPolicy) { | ||||
8027 | mDispatcher->notifyKey( | ||||
8028 | KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); | ||||
8029 | |||||
8030 | // Do not handle this key event. | ||||
8031 | consumeKey(/*handled=*/false, | ||||
8032 | AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0))); | ||||
8033 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); | ||||
8034 | |||||
8035 | // Since the policy did not request any fallback to be generated, ensure there are no events. | ||||
8036 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported()); | ||||
8037 | } | ||||
8038 | |||||
8039 | TEST_F(InputDispatcherFallbackKeyTest, FallbackDispatchForUnhandledKey) { | ||||
8040 | setFallback(AKEYCODE_B); | ||||
8041 | mDispatcher->notifyKey( | ||||
8042 | KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); | ||||
8043 | |||||
8044 | // Do not handle this key event. | ||||
8045 | consumeKey(/*handled=*/false, | ||||
8046 | AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0))); | ||||
8047 | |||||
8048 | // Since the key was not handled, ensure the fallback event was dispatched instead. | ||||
8049 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); | ||||
8050 | consumeKey(/*handled=*/true, | ||||
8051 | AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B), | ||||
8052 | WithFlags(AKEY_EVENT_FLAG_FALLBACK))); | ||||
8053 | |||||
8054 | // Release the original key, and ensure the fallback key is also released. | ||||
8055 | mDispatcher->notifyKey( | ||||
8056 | KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); | ||||
8057 | consumeKey(/*handled=*/false, | ||||
8058 | AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0))); | ||||
8059 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); | ||||
8060 | consumeKey(/*handled=*/true, | ||||
8061 | AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B), | ||||
8062 | WithFlags(AKEY_EVENT_FLAG_FALLBACK))); | ||||
8063 | |||||
8064 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported()); | ||||
8065 | mWindow->assertNoEvents(); | ||||
8066 | } | ||||
8067 | |||||
8068 | TEST_F(InputDispatcherFallbackKeyTest, AppHandlesPreviouslyUnhandledKey) { | ||||
8069 | setFallback(AKEYCODE_B); | ||||
8070 | mDispatcher->notifyKey( | ||||
8071 | KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); | ||||
8072 | |||||
8073 | // Do not handle this key event, but handle the fallback. | ||||
8074 | consumeKey(/*handled=*/false, | ||||
8075 | AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0))); | ||||
8076 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); | ||||
8077 | consumeKey(/*handled=*/true, | ||||
8078 | AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B), | ||||
8079 | WithFlags(AKEY_EVENT_FLAG_FALLBACK))); | ||||
8080 | |||||
8081 | // Release the original key, and ensure the fallback key is also released. | ||||
8082 | mDispatcher->notifyKey( | ||||
8083 | KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); | ||||
8084 | // But this time, the app handles the original key. | ||||
8085 | consumeKey(/*handled=*/true, | ||||
8086 | AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0))); | ||||
8087 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); | ||||
8088 | // Ensure the fallback key is canceled. | ||||
8089 | consumeKey(/*handled=*/true, | ||||
8090 | AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B), | ||||
8091 | WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED))); | ||||
8092 | |||||
8093 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported()); | ||||
8094 | mWindow->assertNoEvents(); | ||||
8095 | } | ||||
8096 | |||||
8097 | TEST_F(InputDispatcherFallbackKeyTest, AppDoesNotHandleFallback) { | ||||
8098 | setFallback(AKEYCODE_B); | ||||
8099 | mDispatcher->notifyKey( | ||||
8100 | KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); | ||||
8101 | |||||
8102 | // Do not handle this key event. | ||||
8103 | consumeKey(/*handled=*/false, | ||||
8104 | AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0))); | ||||
8105 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); | ||||
8106 | // App does not handle the fallback either, so ensure another fallback is not generated. | ||||
8107 | setFallback(AKEYCODE_C); | ||||
8108 | consumeKey(/*handled=*/false, | ||||
8109 | AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B), | ||||
8110 | WithFlags(AKEY_EVENT_FLAG_FALLBACK))); | ||||
8111 | |||||
8112 | // Release the original key, and ensure the fallback key is also released. | ||||
8113 | setFallback(AKEYCODE_B); | ||||
8114 | mDispatcher->notifyKey( | ||||
8115 | KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); | ||||
8116 | consumeKey(/*handled=*/false, | ||||
8117 | AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0))); | ||||
8118 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); | ||||
8119 | consumeKey(/*handled=*/false, | ||||
8120 | AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B), | ||||
8121 | WithFlags(AKEY_EVENT_FLAG_FALLBACK))); | ||||
8122 | |||||
8123 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported()); | ||||
8124 | mWindow->assertNoEvents(); | ||||
8125 | } | ||||
8126 | |||||
8127 | TEST_F(InputDispatcherFallbackKeyTest, InconsistentPolicyCancelsFallback) { | ||||
8128 | setFallback(AKEYCODE_B); | ||||
8129 | mDispatcher->notifyKey( | ||||
8130 | KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); | ||||
8131 | |||||
8132 | // Do not handle this key event, so fallback is generated. | ||||
8133 | consumeKey(/*handled=*/false, | ||||
8134 | AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0))); | ||||
8135 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); | ||||
8136 | consumeKey(/*handled=*/true, | ||||
8137 | AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B), | ||||
8138 | WithFlags(AKEY_EVENT_FLAG_FALLBACK))); | ||||
8139 | |||||
8140 | // Release the original key, but assume the policy is misbehaving and it | ||||
8141 | // generates an inconsistent fallback to the one from the DOWN event. | ||||
8142 | setFallback(AKEYCODE_C); | ||||
8143 | mDispatcher->notifyKey( | ||||
8144 | KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); | ||||
8145 | consumeKey(/*handled=*/false, | ||||
8146 | AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0))); | ||||
8147 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); | ||||
8148 | // Ensure the fallback key reported before as DOWN is canceled due to the inconsistency. | ||||
8149 | consumeKey(/*handled=*/true, | ||||
8150 | AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B), | ||||
8151 | WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED))); | ||||
8152 | |||||
8153 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported()); | ||||
8154 | mWindow->assertNoEvents(); | ||||
8155 | } | ||||
8156 | |||||
8157 | TEST_F(InputDispatcherFallbackKeyTest, CanceledKeyCancelsFallback) { | ||||
8158 | setFallback(AKEYCODE_B); | ||||
8159 | mDispatcher->notifyKey( | ||||
8160 | KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); | ||||
8161 | |||||
8162 | // Do not handle this key event, so fallback is generated. | ||||
8163 | consumeKey(/*handled=*/false, | ||||
8164 | AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0))); | ||||
8165 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); | ||||
8166 | consumeKey(/*handled=*/true, | ||||
8167 | AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B), | ||||
8168 | WithFlags(AKEY_EVENT_FLAG_FALLBACK))); | ||||
8169 | |||||
8170 | // The original key is canceled. | ||||
8171 | mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD) | ||||
8172 | .keyCode(AKEYCODE_A) | ||||
8173 | .addFlag(AKEY_EVENT_FLAG_CANCELED) | ||||
8174 | .build()); | ||||
8175 | consumeKey(/*handled=*/false, | ||||
8176 | AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), | ||||
8177 | WithFlags(AKEY_EVENT_FLAG_CANCELED))); | ||||
8178 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); | ||||
8179 | // Ensure the fallback key is also canceled due to the original key being canceled. | ||||
8180 | consumeKey(/*handled=*/true, | ||||
8181 | AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B), | ||||
8182 | WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED))); | ||||
8183 | |||||
8184 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported()); | ||||
8185 | mWindow->assertNoEvents(); | ||||
8186 | } | ||||
8187 | |||||
Prabir Pradhan | fa2c69f | 2024-02-01 20:31:34 +0000 | [diff] [blame] | 8188 | TEST_F(InputDispatcherFallbackKeyTest, InputChannelRemovedDuringPolicyCall) { |
Prabir Pradhan | b13da8f | 2024-01-09 23:10:13 +0000 | [diff] [blame] | 8189 | setFallback(AKEYCODE_B); |
8190 | mDispatcher->notifyKey( | ||||
8191 | KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); | ||||
8192 | |||||
8193 | // Do not handle this key event. | ||||
8194 | consumeKey(/*handled=*/false, | ||||
8195 | AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0))); | ||||
8196 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); | ||||
8197 | consumeKey(/*handled=*/true, | ||||
8198 | AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B), | ||||
8199 | WithFlags(AKEY_EVENT_FLAG_FALLBACK))); | ||||
8200 | |||||
8201 | mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) { | ||||
8202 | // When the unhandled key is reported to the policy next, remove the input channel. | ||||
8203 | mDispatcher->removeInputChannel(mWindow->getToken()); | ||||
8204 | return KeyEventBuilder(event).keyCode(AKEYCODE_B).build(); | ||||
8205 | }); | ||||
8206 | // Release the original key, and let the app now handle the previously unhandled key. | ||||
8207 | // This should result in the previously generated fallback key to be cancelled. | ||||
8208 | // Since the policy was notified of the unhandled DOWN event earlier, it will also be notified | ||||
8209 | // of the UP event for consistency. The Dispatcher calls into the policy from its own thread | ||||
8210 | // without holding the lock, because it need to synchronously fetch the fallback key. While in | ||||
8211 | // the policy call, we will now remove the input channel. Once the policy call returns, the | ||||
8212 | // Dispatcher will no longer have a channel to send cancellation events to. Ensure this does | ||||
8213 | // not cause any crashes. | ||||
8214 | mDispatcher->notifyKey( | ||||
8215 | KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); | ||||
8216 | consumeKey(/*handled=*/true, | ||||
8217 | AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0))); | ||||
8218 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); | ||||
8219 | } | ||||
8220 | |||||
Prabir Pradhan | fa2c69f | 2024-02-01 20:31:34 +0000 | [diff] [blame] | 8221 | TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedDuringPolicyCall) { |
8222 | setFallback(AKEYCODE_B); | ||||
8223 | mDispatcher->notifyKey( | ||||
8224 | KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); | ||||
8225 | |||||
8226 | // Do not handle this key event. | ||||
8227 | consumeKey(/*handled=*/false, | ||||
8228 | AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0))); | ||||
8229 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); | ||||
8230 | consumeKey(/*handled=*/true, | ||||
8231 | AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B), | ||||
8232 | WithFlags(AKEY_EVENT_FLAG_FALLBACK))); | ||||
8233 | |||||
8234 | mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) { | ||||
8235 | // When the unhandled key is reported to the policy next, remove the window. | ||||
8236 | mDispatcher->onWindowInfosChanged({{}, {}, 0, 0}); | ||||
8237 | return KeyEventBuilder(event).keyCode(AKEYCODE_B).build(); | ||||
8238 | }); | ||||
8239 | // Release the original key, which the app will not handle. When this unhandled key is reported | ||||
8240 | // to the policy, the window will be removed. | ||||
8241 | mDispatcher->notifyKey( | ||||
8242 | KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); | ||||
8243 | consumeKey(/*handled=*/false, | ||||
8244 | AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0))); | ||||
8245 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); | ||||
8246 | |||||
8247 | // Since the window was removed, it loses focus, and the channel state will be reset. | ||||
8248 | consumeKey(/*handled=*/true, | ||||
8249 | AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B), | ||||
8250 | WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED))); | ||||
8251 | mWindow->consumeFocusEvent(false); | ||||
8252 | mWindow->assertNoEvents(); | ||||
8253 | } | ||||
8254 | |||||
8255 | TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedWhileAwaitingFinishedSignal) { | ||||
8256 | setFallback(AKEYCODE_B); | ||||
8257 | mDispatcher->notifyKey( | ||||
8258 | KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); | ||||
8259 | |||||
8260 | // Do not handle this key event. | ||||
8261 | consumeKey(/*handled=*/false, | ||||
8262 | AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0))); | ||||
8263 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); | ||||
8264 | const auto [seq, event] = mWindow->receiveEvent(); | ||||
8265 | ASSERT_TRUE(seq.has_value() && event != nullptr) << "Failed to receive fallback event"; | ||||
8266 | ASSERT_EQ(event->getType(), InputEventType::KEY); | ||||
8267 | ASSERT_THAT(static_cast<const KeyEvent&>(*event), | ||||
8268 | AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B), | ||||
8269 | WithFlags(AKEY_EVENT_FLAG_FALLBACK))); | ||||
8270 | |||||
8271 | // Remove the window now, which should generate a cancellations and make the window lose focus. | ||||
8272 | mDispatcher->onWindowInfosChanged({{}, {}, 0, 0}); | ||||
8273 | consumeKey(/*handled=*/true, | ||||
8274 | AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), | ||||
8275 | WithFlags(AKEY_EVENT_FLAG_CANCELED))); | ||||
8276 | consumeKey(/*handled=*/true, | ||||
8277 | AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B), | ||||
8278 | WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED))); | ||||
8279 | mWindow->consumeFocusEvent(false); | ||||
8280 | |||||
8281 | // Finish the event by reporting it as handled. | ||||
8282 | mWindow->finishEvent(*seq); | ||||
8283 | mWindow->assertNoEvents(); | ||||
8284 | } | ||||
8285 | |||||
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8286 | class InputDispatcherKeyRepeatTest : public InputDispatcherTest { |
8287 | protected: | ||||
Siarhei Vishniakou | fa2a049 | 2023-11-14 13:13:18 -0800 | [diff] [blame] | 8288 | static constexpr std::chrono::nanoseconds KEY_REPEAT_TIMEOUT = 40ms; |
8289 | static constexpr std::chrono::nanoseconds KEY_REPEAT_DELAY = 40ms; | ||||
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8290 | |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 8291 | std::shared_ptr<FakeApplicationHandle> mApp; |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8292 | sp<FakeWindowHandle> mWindow; |
8293 | |||||
8294 | virtual void SetUp() override { | ||||
Prabir Pradhan | dae5279 | 2023-12-15 07:36:40 +0000 | [diff] [blame] | 8295 | InputDispatcherTest::SetUp(); |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8296 | |
Prabir Pradhan | dae5279 | 2023-12-15 07:36:40 +0000 | [diff] [blame] | 8297 | mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY); |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8298 | setUpWindow(); |
8299 | } | ||||
8300 | |||||
8301 | void setUpWindow() { | ||||
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 8302 | mApp = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 8303 | mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8304 | |
Vishnu Nair | 47074b8 | 2020-08-14 11:54:47 -0700 | [diff] [blame] | 8305 | mWindow->setFocusable(true); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 8306 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 8307 | setFocusedWindow(mWindow); |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8308 | mWindow->consumeFocusEvent(true); |
8309 | } | ||||
8310 | |||||
Chris Ye | 2ad9539 | 2020-09-01 13:44:44 -0700 | [diff] [blame] | 8311 | void sendAndConsumeKeyDown(int32_t deviceId) { |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8312 | NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); |
Chris Ye | 2ad9539 | 2020-09-01 13:44:44 -0700 | [diff] [blame] | 8313 | keyArgs.deviceId = deviceId; |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8314 | keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Otherwise it won't generate repeat event |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 8315 | mDispatcher->notifyKey(keyArgs); |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8316 | |
8317 | // Window should receive key down event. | ||||
8318 | mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); | ||||
8319 | } | ||||
8320 | |||||
8321 | void expectKeyRepeatOnce(int32_t repeatCount) { | ||||
8322 | SCOPED_TRACE(StringPrintf("Checking event with repeat count %" PRId32, repeatCount)); | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 8323 | mWindow->consumeKeyEvent( |
8324 | AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithRepeatCount(repeatCount))); | ||||
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8325 | } |
8326 | |||||
Chris Ye | 2ad9539 | 2020-09-01 13:44:44 -0700 | [diff] [blame] | 8327 | void sendAndConsumeKeyUp(int32_t deviceId) { |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8328 | NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); |
Chris Ye | 2ad9539 | 2020-09-01 13:44:44 -0700 | [diff] [blame] | 8329 | keyArgs.deviceId = deviceId; |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8330 | keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Unless it won't generate repeat event |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 8331 | mDispatcher->notifyKey(keyArgs); |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8332 | |
8333 | // Window should receive key down event. | ||||
Prabir Pradhan | 7662a8d | 2023-12-15 01:58:14 +0000 | [diff] [blame] | 8334 | mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8335 | /*expectedFlags=*/0); |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8336 | } |
Hu Guo | fe3c8f1 | 2023-09-22 17:20:15 +0800 | [diff] [blame] | 8337 | |
8338 | void injectKeyRepeat(int32_t repeatCount) { | ||||
8339 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
8340 | injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, repeatCount, ADISPLAY_ID_DEFAULT)) | ||||
8341 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; | ||||
8342 | } | ||||
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8343 | }; |
8344 | |||||
8345 | TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeat) { | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8346 | sendAndConsumeKeyDown(/*deviceId=*/1); |
Chris Ye | 2ad9539 | 2020-09-01 13:44:44 -0700 | [diff] [blame] | 8347 | for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) { |
8348 | expectKeyRepeatOnce(repeatCount); | ||||
8349 | } | ||||
8350 | } | ||||
8351 | |||||
8352 | TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeatFromTwoDevices) { | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8353 | sendAndConsumeKeyDown(/*deviceId=*/1); |
Chris Ye | 2ad9539 | 2020-09-01 13:44:44 -0700 | [diff] [blame] | 8354 | for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) { |
8355 | expectKeyRepeatOnce(repeatCount); | ||||
8356 | } | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8357 | sendAndConsumeKeyDown(/*deviceId=*/2); |
Chris Ye | 2ad9539 | 2020-09-01 13:44:44 -0700 | [diff] [blame] | 8358 | /* repeatCount will start from 1 for deviceId 2 */ |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8359 | for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) { |
8360 | expectKeyRepeatOnce(repeatCount); | ||||
8361 | } | ||||
8362 | } | ||||
8363 | |||||
8364 | TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterUp) { | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8365 | sendAndConsumeKeyDown(/*deviceId=*/1); |
8366 | expectKeyRepeatOnce(/*repeatCount=*/1); | ||||
8367 | sendAndConsumeKeyUp(/*deviceId=*/1); | ||||
Chris Ye | 2ad9539 | 2020-09-01 13:44:44 -0700 | [diff] [blame] | 8368 | mWindow->assertNoEvents(); |
8369 | } | ||||
8370 | |||||
8371 | TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatAfterStaleDeviceKeyUp) { | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8372 | sendAndConsumeKeyDown(/*deviceId=*/1); |
8373 | expectKeyRepeatOnce(/*repeatCount=*/1); | ||||
8374 | sendAndConsumeKeyDown(/*deviceId=*/2); | ||||
8375 | expectKeyRepeatOnce(/*repeatCount=*/1); | ||||
Chris Ye | 2ad9539 | 2020-09-01 13:44:44 -0700 | [diff] [blame] | 8376 | // Stale key up from device 1. |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8377 | sendAndConsumeKeyUp(/*deviceId=*/1); |
Chris Ye | 2ad9539 | 2020-09-01 13:44:44 -0700 | [diff] [blame] | 8378 | // Device 2 is still down, keep repeating |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8379 | expectKeyRepeatOnce(/*repeatCount=*/2); |
8380 | expectKeyRepeatOnce(/*repeatCount=*/3); | ||||
Chris Ye | 2ad9539 | 2020-09-01 13:44:44 -0700 | [diff] [blame] | 8381 | // Device 2 key up |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8382 | sendAndConsumeKeyUp(/*deviceId=*/2); |
Chris Ye | 2ad9539 | 2020-09-01 13:44:44 -0700 | [diff] [blame] | 8383 | mWindow->assertNoEvents(); |
8384 | } | ||||
8385 | |||||
8386 | TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatStopsAfterRepeatingKeyUp) { | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8387 | sendAndConsumeKeyDown(/*deviceId=*/1); |
8388 | expectKeyRepeatOnce(/*repeatCount=*/1); | ||||
8389 | sendAndConsumeKeyDown(/*deviceId=*/2); | ||||
8390 | expectKeyRepeatOnce(/*repeatCount=*/1); | ||||
Chris Ye | 2ad9539 | 2020-09-01 13:44:44 -0700 | [diff] [blame] | 8391 | // Device 2 which holds the key repeating goes up, expect the repeating to stop. |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8392 | sendAndConsumeKeyUp(/*deviceId=*/2); |
Chris Ye | 2ad9539 | 2020-09-01 13:44:44 -0700 | [diff] [blame] | 8393 | // Device 1 still holds key down, but the repeating was already stopped |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8394 | mWindow->assertNoEvents(); |
8395 | } | ||||
8396 | |||||
liushenxiang | 4223291 | 2021-05-21 20:24:09 +0800 | [diff] [blame] | 8397 | TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterDisableInputDevice) { |
8398 | sendAndConsumeKeyDown(DEVICE_ID); | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8399 | expectKeyRepeatOnce(/*repeatCount=*/1); |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 8400 | mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID}); |
liushenxiang | 4223291 | 2021-05-21 20:24:09 +0800 | [diff] [blame] | 8401 | mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT, |
8402 | AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_LONG_PRESS); | ||||
8403 | mWindow->assertNoEvents(); | ||||
8404 | } | ||||
8405 | |||||
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8406 | TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFromInputDispatcher) { |
Michael Wright | e1cbbd6 | 2023-02-22 19:32:13 +0000 | [diff] [blame] | 8407 | GTEST_SKIP() << "Flaky test (b/270393106)"; |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8408 | sendAndConsumeKeyDown(/*deviceId=*/1); |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8409 | for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) { |
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 8410 | std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey(); |
8411 | ASSERT_NE(nullptr, repeatEvent); | ||||
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8412 | EXPECT_EQ(IdGenerator::Source::INPUT_DISPATCHER, |
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 8413 | IdGenerator::getSource(repeatEvent->getId())); |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8414 | } |
8415 | } | ||||
8416 | |||||
8417 | TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEventId) { | ||||
Michael Wright | e1cbbd6 | 2023-02-22 19:32:13 +0000 | [diff] [blame] | 8418 | GTEST_SKIP() << "Flaky test (b/270393106)"; |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8419 | sendAndConsumeKeyDown(/*deviceId=*/1); |
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8420 | |
8421 | std::unordered_set<int32_t> idSet; | ||||
8422 | for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) { | ||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 8423 | std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey(); |
8424 | ASSERT_NE(nullptr, repeatEvent); | ||||
8425 | int32_t id = repeatEvent->getId(); | ||||
Garfield Tan | 1c7bc86 | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 8426 | EXPECT_EQ(idSet.end(), idSet.find(id)); |
8427 | idSet.insert(id); | ||||
8428 | } | ||||
8429 | } | ||||
8430 | |||||
Hu Guo | fe3c8f1 | 2023-09-22 17:20:15 +0800 | [diff] [blame] | 8431 | TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_CorrectRepeatCountWhenInjectKeyRepeat) { |
8432 | injectKeyRepeat(0); | ||||
8433 | mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); | ||||
8434 | for (int32_t repeatCount = 1; repeatCount <= 2; ++repeatCount) { | ||||
8435 | expectKeyRepeatOnce(repeatCount); | ||||
8436 | } | ||||
8437 | injectKeyRepeat(1); | ||||
8438 | // Expect repeatCount to be 3 instead of 1 | ||||
8439 | expectKeyRepeatOnce(3); | ||||
8440 | } | ||||
8441 | |||||
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8442 | /* Test InputDispatcher for MultiDisplay */ |
8443 | class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest { | ||||
8444 | public: | ||||
Prabir Pradhan | 3608aad | 2019-10-02 17:08:26 -0700 | [diff] [blame] | 8445 | virtual void SetUp() override { |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8446 | InputDispatcherTest::SetUp(); |
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 8447 | |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 8448 | application1 = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 8449 | windowInPrimary = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 8450 | sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1", ADISPLAY_ID_DEFAULT); |
Siarhei Vishniakou | b9b1535 | 2019-11-26 13:19:26 -0800 | [diff] [blame] | 8451 | |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8452 | // Set focus window for primary display, but focused display would be second one. |
8453 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1); | ||||
Vishnu Nair | 47074b8 | 2020-08-14 11:54:47 -0700 | [diff] [blame] | 8454 | windowInPrimary->setFocusable(true); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 8455 | mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0}); |
8456 | |||||
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 8457 | setFocusedWindow(windowInPrimary); |
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 8458 | windowInPrimary->consumeFocusEvent(true); |
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 8459 | |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 8460 | application2 = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 8461 | windowInSecondary = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 8462 | sp<FakeWindowHandle>::make(application2, mDispatcher, "D_2", SECOND_DISPLAY_ID); |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8463 | // Set focus to second display window. |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8464 | // Set focus display to second one. |
8465 | mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID); | ||||
8466 | // Set focus window for second display. | ||||
8467 | mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2); | ||||
Vishnu Nair | 47074b8 | 2020-08-14 11:54:47 -0700 | [diff] [blame] | 8468 | windowInSecondary->setFocusable(true); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 8469 | mDispatcher->onWindowInfosChanged( |
8470 | {{*windowInPrimary->getInfo(), *windowInSecondary->getInfo()}, {}, 0, 0}); | ||||
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 8471 | setFocusedWindow(windowInSecondary); |
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 8472 | windowInSecondary->consumeFocusEvent(true); |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8473 | } |
8474 | |||||
Prabir Pradhan | 3608aad | 2019-10-02 17:08:26 -0700 | [diff] [blame] | 8475 | virtual void TearDown() override { |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8476 | InputDispatcherTest::TearDown(); |
8477 | |||||
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 8478 | application1.reset(); |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8479 | windowInPrimary.clear(); |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 8480 | application2.reset(); |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8481 | windowInSecondary.clear(); |
8482 | } | ||||
8483 | |||||
8484 | protected: | ||||
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 8485 | std::shared_ptr<FakeApplicationHandle> application1; |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8486 | sp<FakeWindowHandle> windowInPrimary; |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 8487 | std::shared_ptr<FakeApplicationHandle> application2; |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8488 | sp<FakeWindowHandle> windowInSecondary; |
8489 | }; | ||||
8490 | |||||
8491 | TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayTouch) { | ||||
8492 | // Test touch down on primary display. | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 8493 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 8494 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 8495 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
Siarhei Vishniakou | c5ca85c | 2019-11-15 17:20:00 -0800 | [diff] [blame] | 8496 | windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT); |
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 8497 | windowInSecondary->assertNoEvents(); |
8498 | |||||
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8499 | // Test touch down on second display. |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 8500 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 8501 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 8502 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 8503 | windowInPrimary->assertNoEvents(); |
Siarhei Vishniakou | c5ca85c | 2019-11-15 17:20:00 -0800 | [diff] [blame] | 8504 | windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID); |
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 8505 | } |
8506 | |||||
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8507 | TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) { |
Tiger Huang | 721e26f | 2018-07-24 22:26:19 +0800 | [diff] [blame] | 8508 | // Test inject a key down with display id specified. |
Prabir Pradhan | 93f342c | 2021-03-11 15:05:30 -0800 | [diff] [blame] | 8509 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 8510 | injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 8511 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Siarhei Vishniakou | c5ca85c | 2019-11-15 17:20:00 -0800 | [diff] [blame] | 8512 | windowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT); |
Tiger Huang | 721e26f | 2018-07-24 22:26:19 +0800 | [diff] [blame] | 8513 | windowInSecondary->assertNoEvents(); |
8514 | |||||
8515 | // Test inject a key down without display id specified. | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 8516 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 8517 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 8518 | windowInPrimary->assertNoEvents(); |
Siarhei Vishniakou | c5ca85c | 2019-11-15 17:20:00 -0800 | [diff] [blame] | 8519 | windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE); |
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 8520 | |
Siarhei Vishniakou | b9b1535 | 2019-11-26 13:19:26 -0800 | [diff] [blame] | 8521 | // Remove all windows in secondary display. |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 8522 | mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0}); |
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 8523 | |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 8524 | // Old focus should receive a cancel event. |
Prabir Pradhan | 7662a8d | 2023-12-15 01:58:14 +0000 | [diff] [blame] | 8525 | windowInSecondary->consumeKeyUp(ADISPLAY_ID_NONE, AKEY_EVENT_FLAG_CANCELED); |
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 8526 | |
8527 | // Test inject a key down, should timeout because of no target window. | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 8528 | ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher)); |
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 8529 | windowInPrimary->assertNoEvents(); |
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 8530 | windowInSecondary->consumeFocusEvent(false); |
Arthur Hung | b92218b | 2018-08-14 12:00:21 +0800 | [diff] [blame] | 8531 | windowInSecondary->assertNoEvents(); |
8532 | } | ||||
8533 | |||||
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8534 | // Test per-display input monitors for motion event. |
8535 | TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) { | ||||
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 8536 | FakeMonitorReceiver monitorInPrimary = |
Prabir Pradhan | fb54907 | 2023-10-05 19:17:36 +0000 | [diff] [blame] | 8537 | FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); |
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 8538 | FakeMonitorReceiver monitorInSecondary = |
Prabir Pradhan | fb54907 | 2023-10-05 19:17:36 +0000 | [diff] [blame] | 8539 | FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID); |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8540 | |
8541 | // Test touch down on primary display. | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 8542 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 8543 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 8544 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
Siarhei Vishniakou | c5ca85c | 2019-11-15 17:20:00 -0800 | [diff] [blame] | 8545 | windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT); |
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 8546 | monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT); |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8547 | windowInSecondary->assertNoEvents(); |
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 8548 | monitorInSecondary.assertNoEvents(); |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8549 | |
8550 | // Test touch down on second display. | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 8551 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 8552 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 8553 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8554 | windowInPrimary->assertNoEvents(); |
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 8555 | monitorInPrimary.assertNoEvents(); |
Siarhei Vishniakou | c5ca85c | 2019-11-15 17:20:00 -0800 | [diff] [blame] | 8556 | windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID); |
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 8557 | monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID); |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8558 | |
Siarhei Vishniakou | 92c8fd5 | 2023-01-29 14:57:43 -0800 | [diff] [blame] | 8559 | // Lift up the touch from the second display |
8560 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 8561 | injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) |
Siarhei Vishniakou | 92c8fd5 | 2023-01-29 14:57:43 -0800 | [diff] [blame] | 8562 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
8563 | windowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID); | ||||
8564 | monitorInSecondary.consumeMotionUp(SECOND_DISPLAY_ID); | ||||
8565 | |||||
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8566 | // Test inject a non-pointer motion event. |
8567 | // If specific a display, it will dispatch to the focused window of particular display, | ||||
8568 | // or it will dispatch to the focused window of focused display. | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 8569 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 8570 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_NONE)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 8571 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8572 | windowInPrimary->assertNoEvents(); |
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 8573 | monitorInPrimary.assertNoEvents(); |
Siarhei Vishniakou | c5ca85c | 2019-11-15 17:20:00 -0800 | [diff] [blame] | 8574 | windowInSecondary->consumeMotionDown(ADISPLAY_ID_NONE); |
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 8575 | monitorInSecondary.consumeMotionDown(ADISPLAY_ID_NONE); |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8576 | } |
8577 | |||||
8578 | // Test per-display input monitors for key event. | ||||
8579 | TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) { | ||||
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 8580 | // Input monitor per display. |
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 8581 | FakeMonitorReceiver monitorInPrimary = |
Prabir Pradhan | fb54907 | 2023-10-05 19:17:36 +0000 | [diff] [blame] | 8582 | FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); |
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 8583 | FakeMonitorReceiver monitorInSecondary = |
Prabir Pradhan | fb54907 | 2023-10-05 19:17:36 +0000 | [diff] [blame] | 8584 | FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID); |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8585 | |
8586 | // Test inject a key down. | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 8587 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 8588 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8589 | windowInPrimary->assertNoEvents(); |
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 8590 | monitorInPrimary.assertNoEvents(); |
Siarhei Vishniakou | c5ca85c | 2019-11-15 17:20:00 -0800 | [diff] [blame] | 8591 | windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE); |
chaviw | d1c2318 | 2019-12-20 18:44:56 -0800 | [diff] [blame] | 8592 | monitorInSecondary.consumeKeyDown(ADISPLAY_ID_NONE); |
Arthur Hung | 2fbf37f | 2018-09-13 18:16:41 +0800 | [diff] [blame] | 8593 | } |
8594 | |||||
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 8595 | TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) { |
8596 | sp<FakeWindowHandle> secondWindowInPrimary = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 8597 | sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 8598 | secondWindowInPrimary->setFocusable(true); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 8599 | mDispatcher->onWindowInfosChanged( |
8600 | {{*windowInPrimary->getInfo(), *secondWindowInPrimary->getInfo(), | ||||
8601 | *windowInSecondary->getInfo()}, | ||||
8602 | {}, | ||||
8603 | 0, | ||||
8604 | 0}); | ||||
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 8605 | setFocusedWindow(secondWindowInPrimary); |
8606 | windowInPrimary->consumeFocusEvent(false); | ||||
8607 | secondWindowInPrimary->consumeFocusEvent(true); | ||||
8608 | |||||
8609 | // Test inject a key down. | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 8610 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
8611 | injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT)) | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 8612 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 8613 | windowInPrimary->assertNoEvents(); |
8614 | windowInSecondary->assertNoEvents(); | ||||
8615 | secondWindowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT); | ||||
8616 | } | ||||
8617 | |||||
Arthur Hung | dfd528e | 2021-12-08 13:23:04 +0000 | [diff] [blame] | 8618 | TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CancelTouch_MultiDisplay) { |
8619 | FakeMonitorReceiver monitorInPrimary = | ||||
Prabir Pradhan | fb54907 | 2023-10-05 19:17:36 +0000 | [diff] [blame] | 8620 | FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); |
Arthur Hung | dfd528e | 2021-12-08 13:23:04 +0000 | [diff] [blame] | 8621 | FakeMonitorReceiver monitorInSecondary = |
Prabir Pradhan | fb54907 | 2023-10-05 19:17:36 +0000 | [diff] [blame] | 8622 | FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID); |
Arthur Hung | dfd528e | 2021-12-08 13:23:04 +0000 | [diff] [blame] | 8623 | |
8624 | // Test touch down on primary display. | ||||
8625 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 8626 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) |
Arthur Hung | dfd528e | 2021-12-08 13:23:04 +0000 | [diff] [blame] | 8627 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
8628 | windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
8629 | monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
8630 | |||||
8631 | // Test touch down on second display. | ||||
8632 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 8633 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) |
Arthur Hung | dfd528e | 2021-12-08 13:23:04 +0000 | [diff] [blame] | 8634 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
8635 | windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID); | ||||
8636 | monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID); | ||||
8637 | |||||
8638 | // Trigger cancel touch. | ||||
8639 | mDispatcher->cancelCurrentTouch(); | ||||
8640 | windowInPrimary->consumeMotionCancel(ADISPLAY_ID_DEFAULT); | ||||
8641 | monitorInPrimary.consumeMotionCancel(ADISPLAY_ID_DEFAULT); | ||||
8642 | windowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID); | ||||
8643 | monitorInSecondary.consumeMotionCancel(SECOND_DISPLAY_ID); | ||||
8644 | |||||
8645 | // Test inject a move motion event, no window/monitor should receive the event. | ||||
8646 | ASSERT_EQ(InputEventInjectionResult::FAILED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 8647 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
Arthur Hung | dfd528e | 2021-12-08 13:23:04 +0000 | [diff] [blame] | 8648 | ADISPLAY_ID_DEFAULT, {110, 200})) |
8649 | << "Inject motion event should return InputEventInjectionResult::FAILED"; | ||||
8650 | windowInPrimary->assertNoEvents(); | ||||
8651 | monitorInPrimary.assertNoEvents(); | ||||
8652 | |||||
8653 | ASSERT_EQ(InputEventInjectionResult::FAILED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 8654 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
Arthur Hung | dfd528e | 2021-12-08 13:23:04 +0000 | [diff] [blame] | 8655 | SECOND_DISPLAY_ID, {110, 200})) |
8656 | << "Inject motion event should return InputEventInjectionResult::FAILED"; | ||||
8657 | windowInSecondary->assertNoEvents(); | ||||
8658 | monitorInSecondary.assertNoEvents(); | ||||
8659 | } | ||||
8660 | |||||
Hu Guo | cb134f1 | 2023-12-23 13:42:44 +0000 | [diff] [blame] | 8661 | /** |
8662 | * Send a key to the primary display and to the secondary display. | ||||
8663 | * Then cause the key on the primary display to be canceled by sending in a stale key. | ||||
8664 | * Ensure that the key on the primary display is canceled, and that the key on the secondary display | ||||
8665 | * does not get canceled. | ||||
8666 | */ | ||||
8667 | TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture) { | ||||
8668 | // Send a key down on primary display | ||||
8669 | mDispatcher->notifyKey( | ||||
8670 | KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD) | ||||
8671 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
8672 | .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT) | ||||
8673 | .build()); | ||||
8674 | windowInPrimary->consumeKeyEvent( | ||||
8675 | AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT))); | ||||
8676 | windowInSecondary->assertNoEvents(); | ||||
8677 | |||||
8678 | // Send a key down on second display | ||||
8679 | mDispatcher->notifyKey( | ||||
8680 | KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD) | ||||
8681 | .displayId(SECOND_DISPLAY_ID) | ||||
8682 | .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT) | ||||
8683 | .build()); | ||||
8684 | windowInSecondary->consumeKeyEvent( | ||||
8685 | AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID))); | ||||
8686 | windowInPrimary->assertNoEvents(); | ||||
8687 | |||||
8688 | // Send a valid key up event on primary display that will be dropped because it is stale | ||||
8689 | NotifyKeyArgs staleKeyUp = | ||||
8690 | KeyArgsBuilder(AKEY_EVENT_ACTION_UP, AINPUT_SOURCE_KEYBOARD) | ||||
8691 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
8692 | .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT) | ||||
8693 | .build(); | ||||
8694 | static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms; | ||||
8695 | mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT); | ||||
8696 | std::this_thread::sleep_for(STALE_EVENT_TIMEOUT); | ||||
8697 | mDispatcher->notifyKey(staleKeyUp); | ||||
8698 | |||||
8699 | // Only the key gesture corresponding to the dropped event should receive the cancel event. | ||||
8700 | // Therefore, windowInPrimary should get the cancel event and windowInSecondary should not | ||||
8701 | // receive any events. | ||||
8702 | windowInPrimary->consumeKeyEvent(AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP), | ||||
8703 | WithDisplayId(ADISPLAY_ID_DEFAULT), | ||||
8704 | WithFlags(AKEY_EVENT_FLAG_CANCELED))); | ||||
8705 | windowInSecondary->assertNoEvents(); | ||||
8706 | } | ||||
8707 | |||||
8708 | /** | ||||
8709 | * Similar to 'WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture' but for motion events. | ||||
8710 | */ | ||||
8711 | TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropMotionEvent_OnlyCancelCorrespondingGesture) { | ||||
8712 | // Send touch down on primary display. | ||||
8713 | mDispatcher->notifyMotion( | ||||
8714 | MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
8715 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200)) | ||||
8716 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
8717 | .build()); | ||||
8718 | windowInPrimary->consumeMotionEvent( | ||||
8719 | AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT))); | ||||
8720 | windowInSecondary->assertNoEvents(); | ||||
8721 | |||||
8722 | // Send touch down on second display. | ||||
8723 | mDispatcher->notifyMotion( | ||||
8724 | MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
8725 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200)) | ||||
8726 | .displayId(SECOND_DISPLAY_ID) | ||||
8727 | .build()); | ||||
8728 | windowInPrimary->assertNoEvents(); | ||||
8729 | windowInSecondary->consumeMotionEvent( | ||||
8730 | AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID))); | ||||
8731 | |||||
8732 | // inject a valid MotionEvent on primary display that will be stale when it arrives. | ||||
8733 | NotifyMotionArgs staleMotionUp = | ||||
8734 | MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
8735 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
8736 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200)) | ||||
8737 | .build(); | ||||
8738 | static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms; | ||||
8739 | mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT); | ||||
8740 | std::this_thread::sleep_for(STALE_EVENT_TIMEOUT); | ||||
8741 | mDispatcher->notifyMotion(staleMotionUp); | ||||
8742 | |||||
8743 | // For stale motion events, we let the gesture to complete. This behaviour is different from key | ||||
8744 | // events, where we would cancel the current keys instead. | ||||
8745 | windowInPrimary->consumeMotionEvent(WithMotionAction(ACTION_UP)); | ||||
8746 | windowInSecondary->assertNoEvents(); | ||||
8747 | } | ||||
8748 | |||||
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 8749 | class InputFilterTest : public InputDispatcherTest { |
8750 | protected: | ||||
Prabir Pradhan | 81420cc | 2021-09-06 10:28:50 -0700 | [diff] [blame] | 8751 | void testNotifyMotion(int32_t displayId, bool expectToBeFiltered, |
8752 | const ui::Transform& transform = ui::Transform()) { | ||||
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 8753 | NotifyMotionArgs motionArgs; |
8754 | |||||
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 8755 | motionArgs = |
8756 | generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId); | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 8757 | mDispatcher->notifyMotion(motionArgs); |
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 8758 | motionArgs = |
8759 | generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId); | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 8760 | mDispatcher->notifyMotion(motionArgs); |
Siarhei Vishniakou | 2bfa905 | 2019-11-21 18:10:54 -0800 | [diff] [blame] | 8761 | ASSERT_TRUE(mDispatcher->waitForIdle()); |
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 8762 | if (expectToBeFiltered) { |
Siarhei Vishniakou | 3218fc0 | 2023-06-15 20:41:02 -0700 | [diff] [blame] | 8763 | const auto xy = transform.transform(motionArgs.pointerCoords[0].getXYValue()); |
Prabir Pradhan | 81420cc | 2021-09-06 10:28:50 -0700 | [diff] [blame] | 8764 | mFakePolicy->assertFilterInputEventWasCalled(motionArgs, xy); |
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 8765 | } else { |
8766 | mFakePolicy->assertFilterInputEventWasNotCalled(); | ||||
8767 | } | ||||
8768 | } | ||||
8769 | |||||
8770 | void testNotifyKey(bool expectToBeFiltered) { | ||||
8771 | NotifyKeyArgs keyArgs; | ||||
8772 | |||||
8773 | keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN); | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 8774 | mDispatcher->notifyKey(keyArgs); |
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 8775 | keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP); |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 8776 | mDispatcher->notifyKey(keyArgs); |
Siarhei Vishniakou | 2bfa905 | 2019-11-21 18:10:54 -0800 | [diff] [blame] | 8777 | ASSERT_TRUE(mDispatcher->waitForIdle()); |
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 8778 | |
8779 | if (expectToBeFiltered) { | ||||
Siarhei Vishniakou | 8935a80 | 2019-11-15 16:41:44 -0800 | [diff] [blame] | 8780 | mFakePolicy->assertFilterInputEventWasCalled(keyArgs); |
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 8781 | } else { |
8782 | mFakePolicy->assertFilterInputEventWasNotCalled(); | ||||
8783 | } | ||||
8784 | } | ||||
8785 | }; | ||||
8786 | |||||
8787 | // Test InputFilter for MotionEvent | ||||
8788 | TEST_F(InputFilterTest, MotionEvent_InputFilter) { | ||||
8789 | // Since the InputFilter is disabled by default, check if touch events aren't filtered. | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 8790 | testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false); |
8791 | testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false); | ||||
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 8792 | |
8793 | // Enable InputFilter | ||||
8794 | mDispatcher->setInputFilterEnabled(true); | ||||
8795 | // Test touch on both primary and second display, and check if both events are filtered. | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 8796 | testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true); |
8797 | testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true); | ||||
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 8798 | |
8799 | // Disable InputFilter | ||||
8800 | mDispatcher->setInputFilterEnabled(false); | ||||
8801 | // Test touch on both primary and second display, and check if both events aren't filtered. | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 8802 | testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false); |
8803 | testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false); | ||||
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 8804 | } |
8805 | |||||
8806 | // Test InputFilter for KeyEvent | ||||
8807 | TEST_F(InputFilterTest, KeyEvent_InputFilter) { | ||||
8808 | // Since the InputFilter is disabled by default, check if key event aren't filtered. | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 8809 | testNotifyKey(/*expectToBeFiltered=*/false); |
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 8810 | |
8811 | // Enable InputFilter | ||||
8812 | mDispatcher->setInputFilterEnabled(true); | ||||
8813 | // Send a key event, and check if it is filtered. | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 8814 | testNotifyKey(/*expectToBeFiltered=*/true); |
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 8815 | |
8816 | // Disable InputFilter | ||||
8817 | mDispatcher->setInputFilterEnabled(false); | ||||
8818 | // Send a key event, and check if it isn't filtered. | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 8819 | testNotifyKey(/*expectToBeFiltered=*/false); |
Jackal Guo | f969668 | 2018-10-05 12:23:23 +0800 | [diff] [blame] | 8820 | } |
8821 | |||||
Prabir Pradhan | 81420cc | 2021-09-06 10:28:50 -0700 | [diff] [blame] | 8822 | // Ensure that MotionEvents sent to the InputFilter through InputListener are converted to the |
8823 | // logical display coordinate space. | ||||
8824 | TEST_F(InputFilterTest, MotionEvent_UsesLogicalDisplayCoordinates_notifyMotion) { | ||||
8825 | ui::Transform firstDisplayTransform; | ||||
8826 | firstDisplayTransform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1}); | ||||
8827 | ui::Transform secondDisplayTransform; | ||||
8828 | secondDisplayTransform.set({-6.6, -5.5, -4.4, -3.3, -2.2, -1.1, 0, 0, 1}); | ||||
8829 | |||||
8830 | std::vector<gui::DisplayInfo> displayInfos(2); | ||||
8831 | displayInfos[0].displayId = ADISPLAY_ID_DEFAULT; | ||||
8832 | displayInfos[0].transform = firstDisplayTransform; | ||||
8833 | displayInfos[1].displayId = SECOND_DISPLAY_ID; | ||||
8834 | displayInfos[1].transform = secondDisplayTransform; | ||||
8835 | |||||
Patrick Williams | d828f30 | 2023-04-28 17:52:08 -0500 | [diff] [blame] | 8836 | mDispatcher->onWindowInfosChanged({{}, displayInfos, 0, 0}); |
Prabir Pradhan | 81420cc | 2021-09-06 10:28:50 -0700 | [diff] [blame] | 8837 | |
8838 | // Enable InputFilter | ||||
8839 | mDispatcher->setInputFilterEnabled(true); | ||||
8840 | |||||
8841 | // Ensure the correct transforms are used for the displays. | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 8842 | testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true, firstDisplayTransform); |
8843 | testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true, secondDisplayTransform); | ||||
Prabir Pradhan | 81420cc | 2021-09-06 10:28:50 -0700 | [diff] [blame] | 8844 | } |
8845 | |||||
Siarhei Vishniakou | 5d552c4 | 2021-05-21 05:02:22 +0000 | [diff] [blame] | 8846 | class InputFilterInjectionPolicyTest : public InputDispatcherTest { |
8847 | protected: | ||||
8848 | virtual void SetUp() override { | ||||
8849 | InputDispatcherTest::SetUp(); | ||||
8850 | |||||
8851 | /** | ||||
8852 | * We don't need to enable input filter to test the injected event policy, but we enabled it | ||||
8853 | * here to make the tests more realistic, since this policy only matters when inputfilter is | ||||
8854 | * on. | ||||
8855 | */ | ||||
8856 | mDispatcher->setInputFilterEnabled(true); | ||||
8857 | |||||
8858 | std::shared_ptr<InputApplicationHandle> application = | ||||
8859 | std::make_shared<FakeApplicationHandle>(); | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 8860 | mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Test Window", |
8861 | ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | 5d552c4 | 2021-05-21 05:02:22 +0000 | [diff] [blame] | 8862 | |
8863 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); | ||||
8864 | mWindow->setFocusable(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 8865 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | 5d552c4 | 2021-05-21 05:02:22 +0000 | [diff] [blame] | 8866 | setFocusedWindow(mWindow); |
8867 | mWindow->consumeFocusEvent(true); | ||||
8868 | } | ||||
8869 | |||||
Siarhei Vishniakou | f00a4ec | 2021-06-16 03:55:32 +0000 | [diff] [blame] | 8870 | void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId, |
8871 | int32_t flags) { | ||||
Siarhei Vishniakou | 5d552c4 | 2021-05-21 05:02:22 +0000 | [diff] [blame] | 8872 | KeyEvent event; |
8873 | |||||
8874 | const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC); | ||||
8875 | event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_KEYBOARD, | ||||
8876 | ADISPLAY_ID_NONE, INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A, | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8877 | KEY_A, AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime); |
Siarhei Vishniakou | 5d552c4 | 2021-05-21 05:02:22 +0000 | [diff] [blame] | 8878 | const int32_t additionalPolicyFlags = |
8879 | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT; | ||||
8880 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8881 | mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, |
Siarhei Vishniakou | 4648fea | 2023-06-27 01:00:12 +0000 | [diff] [blame] | 8882 | InputEventInjectionSync::WAIT_FOR_RESULT, 100ms, |
Siarhei Vishniakou | 5d552c4 | 2021-05-21 05:02:22 +0000 | [diff] [blame] | 8883 | policyFlags | additionalPolicyFlags)); |
8884 | |||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 8885 | mWindow->consumeKeyEvent(AllOf(WithDeviceId(resolvedDeviceId), WithFlags(flags))); |
Siarhei Vishniakou | f00a4ec | 2021-06-16 03:55:32 +0000 | [diff] [blame] | 8886 | } |
8887 | |||||
8888 | void testInjectedMotion(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId, | ||||
8889 | int32_t flags) { | ||||
8890 | MotionEvent event; | ||||
8891 | PointerProperties pointerProperties[1]; | ||||
8892 | PointerCoords pointerCoords[1]; | ||||
8893 | pointerProperties[0].clear(); | ||||
8894 | pointerProperties[0].id = 0; | ||||
8895 | pointerCoords[0].clear(); | ||||
8896 | pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 300); | ||||
8897 | pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 400); | ||||
8898 | |||||
8899 | ui::Transform identityTransform; | ||||
8900 | const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC); | ||||
8901 | event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_TOUCHSCREEN, | ||||
8902 | DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, | ||||
8903 | AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE, | ||||
8904 | identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, | ||||
Prabir Pradhan | b9b1850 | 2021-08-26 12:30:32 -0700 | [diff] [blame] | 8905 | AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, eventTime, |
Evan Rosky | 0957669 | 2021-07-01 12:22:09 -0700 | [diff] [blame] | 8906 | eventTime, |
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 8907 | /*pointerCount=*/1, pointerProperties, pointerCoords); |
Siarhei Vishniakou | f00a4ec | 2021-06-16 03:55:32 +0000 | [diff] [blame] | 8908 | |
8909 | const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER; | ||||
8910 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8911 | mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, |
Siarhei Vishniakou | 4648fea | 2023-06-27 01:00:12 +0000 | [diff] [blame] | 8912 | InputEventInjectionSync::WAIT_FOR_RESULT, 100ms, |
Siarhei Vishniakou | f00a4ec | 2021-06-16 03:55:32 +0000 | [diff] [blame] | 8913 | policyFlags | additionalPolicyFlags)); |
8914 | |||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 8915 | mWindow->consumeMotionEvent(AllOf(WithFlags(flags), WithDeviceId(resolvedDeviceId))); |
Siarhei Vishniakou | 5d552c4 | 2021-05-21 05:02:22 +0000 | [diff] [blame] | 8916 | } |
8917 | |||||
8918 | private: | ||||
8919 | sp<FakeWindowHandle> mWindow; | ||||
8920 | }; | ||||
8921 | |||||
8922 | TEST_F(InputFilterInjectionPolicyTest, TrustedFilteredEvents_KeepOriginalDeviceId) { | ||||
Siarhei Vishniakou | f00a4ec | 2021-06-16 03:55:32 +0000 | [diff] [blame] | 8923 | // Must have POLICY_FLAG_FILTERED here to indicate that the event has gone through the input |
8924 | // filter. Without it, the event will no different from a regularly injected event, and the | ||||
8925 | // injected device id will be overwritten. | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8926 | testInjectedKey(POLICY_FLAG_FILTERED, /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3, |
8927 | /*flags=*/0); | ||||
Siarhei Vishniakou | 5d552c4 | 2021-05-21 05:02:22 +0000 | [diff] [blame] | 8928 | } |
8929 | |||||
Siarhei Vishniakou | f00a4ec | 2021-06-16 03:55:32 +0000 | [diff] [blame] | 8930 | TEST_F(InputFilterInjectionPolicyTest, KeyEventsInjectedFromAccessibility_HaveAccessibilityFlag) { |
Siarhei Vishniakou | 5d552c4 | 2021-05-21 05:02:22 +0000 | [diff] [blame] | 8931 | testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8932 | /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3, |
Siarhei Vishniakou | f00a4ec | 2021-06-16 03:55:32 +0000 | [diff] [blame] | 8933 | AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT); |
8934 | } | ||||
8935 | |||||
8936 | TEST_F(InputFilterInjectionPolicyTest, | ||||
8937 | MotionEventsInjectedFromAccessibility_HaveAccessibilityFlag) { | ||||
8938 | testInjectedMotion(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY, | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8939 | /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3, |
Siarhei Vishniakou | f00a4ec | 2021-06-16 03:55:32 +0000 | [diff] [blame] | 8940 | AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT); |
Siarhei Vishniakou | 5d552c4 | 2021-05-21 05:02:22 +0000 | [diff] [blame] | 8941 | } |
8942 | |||||
8943 | TEST_F(InputFilterInjectionPolicyTest, RegularInjectedEvents_ReceiveVirtualDeviceId) { | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 8944 | testInjectedKey(/*policyFlags=*/0, /*injectedDeviceId=*/3, |
8945 | /*resolvedDeviceId=*/VIRTUAL_KEYBOARD_ID, /*flags=*/0); | ||||
Siarhei Vishniakou | 5d552c4 | 2021-05-21 05:02:22 +0000 | [diff] [blame] | 8946 | } |
8947 | |||||
Yeabkal Wubshit | b8aadfa | 2024-01-17 17:03:42 -0800 | [diff] [blame] | 8948 | class InputDispatcherUserActivityPokeTests : public InputDispatcherTest { |
8949 | protected: | ||||
8950 | virtual void SetUp() override { | ||||
8951 | InputDispatcherTest::SetUp(); | ||||
8952 | |||||
8953 | std::shared_ptr<FakeApplicationHandle> application = | ||||
8954 | std::make_shared<FakeApplicationHandle>(); | ||||
8955 | application->setDispatchingTimeout(100ms); | ||||
8956 | mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", | ||||
8957 | ADISPLAY_ID_DEFAULT); | ||||
Yeabkal Wubshit | 222d83d | 2024-01-24 18:00:09 +0000 | [diff] [blame] | 8958 | mWindow->setFrame(Rect(0, 0, 100, 100)); |
Yeabkal Wubshit | b8aadfa | 2024-01-17 17:03:42 -0800 | [diff] [blame] | 8959 | mWindow->setDispatchingTimeout(100ms); |
8960 | mWindow->setFocusable(true); | ||||
8961 | |||||
8962 | // Set focused application. | ||||
8963 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); | ||||
8964 | |||||
8965 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); | ||||
8966 | setFocusedWindow(mWindow); | ||||
8967 | mWindow->consumeFocusEvent(true); | ||||
8968 | } | ||||
8969 | |||||
8970 | void notifyAndConsumeMotion(int32_t action, uint32_t source, int32_t displayId, | ||||
8971 | nsecs_t eventTime) { | ||||
8972 | mDispatcher->notifyMotion(MotionArgsBuilder(action, source) | ||||
8973 | .displayId(displayId) | ||||
8974 | .eventTime(eventTime) | ||||
8975 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
8976 | .build()); | ||||
8977 | mWindow->consumeMotionEvent(WithMotionAction(action)); | ||||
8978 | } | ||||
8979 | |||||
8980 | private: | ||||
8981 | sp<FakeWindowHandle> mWindow; | ||||
8982 | }; | ||||
8983 | |||||
8984 | TEST_F_WITH_FLAGS( | ||||
8985 | InputDispatcherUserActivityPokeTests, MinPokeTimeObserved, | ||||
8986 | REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, | ||||
8987 | rate_limit_user_activity_poke_in_dispatcher))) { | ||||
8988 | mDispatcher->setMinTimeBetweenUserActivityPokes(50ms); | ||||
8989 | |||||
8990 | // First event of type TOUCH. Should poke. | ||||
8991 | notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
8992 | milliseconds_to_nanoseconds(50)); | ||||
8993 | mFakePolicy->assertUserActivityPoked( | ||||
8994 | {{milliseconds_to_nanoseconds(50), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}}); | ||||
8995 | |||||
8996 | // 80ns > 50ns has passed since previous TOUCH event. Should poke. | ||||
8997 | notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
8998 | milliseconds_to_nanoseconds(130)); | ||||
8999 | mFakePolicy->assertUserActivityPoked( | ||||
9000 | {{milliseconds_to_nanoseconds(130), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}}); | ||||
9001 | |||||
9002 | // First event of type OTHER. Should poke (despite being within 50ns of previous TOUCH event). | ||||
9003 | notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT, | ||||
9004 | milliseconds_to_nanoseconds(135)); | ||||
9005 | mFakePolicy->assertUserActivityPoked( | ||||
9006 | {{milliseconds_to_nanoseconds(135), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}}); | ||||
9007 | |||||
9008 | // Within 50ns of previous TOUCH event. Should NOT poke. | ||||
9009 | notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
9010 | milliseconds_to_nanoseconds(140)); | ||||
9011 | mFakePolicy->assertUserActivityNotPoked(); | ||||
9012 | |||||
9013 | // Within 50ns of previous OTHER event. Should NOT poke. | ||||
9014 | notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT, | ||||
9015 | milliseconds_to_nanoseconds(150)); | ||||
9016 | mFakePolicy->assertUserActivityNotPoked(); | ||||
9017 | |||||
9018 | // Within 50ns of previous TOUCH event (which was at time 130). Should NOT poke. | ||||
9019 | // Note that STYLUS is mapped to TOUCH user activity, since it's a pointer-type source. | ||||
9020 | notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT, | ||||
9021 | milliseconds_to_nanoseconds(160)); | ||||
9022 | mFakePolicy->assertUserActivityNotPoked(); | ||||
9023 | |||||
9024 | // 65ns > 50ns has passed since previous OTHER event. Should poke. | ||||
9025 | notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT, | ||||
9026 | milliseconds_to_nanoseconds(200)); | ||||
9027 | mFakePolicy->assertUserActivityPoked( | ||||
9028 | {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}}); | ||||
9029 | |||||
9030 | // 170ns > 50ns has passed since previous TOUCH event. Should poke. | ||||
9031 | notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT, | ||||
9032 | milliseconds_to_nanoseconds(300)); | ||||
9033 | mFakePolicy->assertUserActivityPoked( | ||||
9034 | {{milliseconds_to_nanoseconds(300), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}}); | ||||
9035 | |||||
9036 | // Assert that there's no more user activity poke event. | ||||
9037 | mFakePolicy->assertUserActivityNotPoked(); | ||||
9038 | } | ||||
9039 | |||||
9040 | TEST_F_WITH_FLAGS( | ||||
9041 | InputDispatcherUserActivityPokeTests, DefaultMinPokeTimeOf100MsUsed, | ||||
9042 | REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, | ||||
9043 | rate_limit_user_activity_poke_in_dispatcher))) { | ||||
9044 | notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
9045 | milliseconds_to_nanoseconds(200)); | ||||
9046 | mFakePolicy->assertUserActivityPoked( | ||||
9047 | {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}}); | ||||
9048 | |||||
9049 | notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
9050 | milliseconds_to_nanoseconds(280)); | ||||
9051 | mFakePolicy->assertUserActivityNotPoked(); | ||||
9052 | |||||
9053 | notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
9054 | milliseconds_to_nanoseconds(340)); | ||||
9055 | mFakePolicy->assertUserActivityPoked( | ||||
9056 | {{milliseconds_to_nanoseconds(340), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}}); | ||||
9057 | } | ||||
9058 | |||||
9059 | TEST_F_WITH_FLAGS( | ||||
9060 | InputDispatcherUserActivityPokeTests, ZeroMinPokeTimeDisablesRateLimiting, | ||||
9061 | REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, | ||||
9062 | rate_limit_user_activity_poke_in_dispatcher))) { | ||||
9063 | mDispatcher->setMinTimeBetweenUserActivityPokes(0ms); | ||||
9064 | |||||
9065 | notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 20); | ||||
9066 | mFakePolicy->assertUserActivityPoked(); | ||||
9067 | |||||
9068 | notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 30); | ||||
9069 | mFakePolicy->assertUserActivityPoked(); | ||||
9070 | } | ||||
9071 | |||||
chaviw | fd6d351 | 2019-03-25 13:23:49 -0700 | [diff] [blame] | 9072 | class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest { |
Prabir Pradhan | 3608aad | 2019-10-02 17:08:26 -0700 | [diff] [blame] | 9073 | virtual void SetUp() override { |
chaviw | fd6d351 | 2019-03-25 13:23:49 -0700 | [diff] [blame] | 9074 | InputDispatcherTest::SetUp(); |
9075 | |||||
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 9076 | std::shared_ptr<FakeApplicationHandle> application = |
9077 | std::make_shared<FakeApplicationHandle>(); | ||||
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 9078 | mUnfocusedWindow = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 9079 | sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); |
chaviw | fd6d351 | 2019-03-25 13:23:49 -0700 | [diff] [blame] | 9080 | mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); |
chaviw | fd6d351 | 2019-03-25 13:23:49 -0700 | [diff] [blame] | 9081 | |
Siarhei Vishniakou | b9b1535 | 2019-11-26 13:19:26 -0800 | [diff] [blame] | 9082 | mFocusedWindow = |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 9083 | sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); |
Siarhei Vishniakou | b9b1535 | 2019-11-26 13:19:26 -0800 | [diff] [blame] | 9084 | mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); |
chaviw | fd6d351 | 2019-03-25 13:23:49 -0700 | [diff] [blame] | 9085 | |
9086 | // Set focused application. | ||||
9087 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); | ||||
Vishnu Nair | 47074b8 | 2020-08-14 11:54:47 -0700 | [diff] [blame] | 9088 | mFocusedWindow->setFocusable(true); |
chaviw | fd6d351 | 2019-03-25 13:23:49 -0700 | [diff] [blame] | 9089 | |
9090 | // Expect one focus window exist in display. | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9091 | mDispatcher->onWindowInfosChanged( |
9092 | {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0}); | ||||
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 9093 | setFocusedWindow(mFocusedWindow); |
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 9094 | mFocusedWindow->consumeFocusEvent(true); |
chaviw | fd6d351 | 2019-03-25 13:23:49 -0700 | [diff] [blame] | 9095 | } |
9096 | |||||
Prabir Pradhan | 3608aad | 2019-10-02 17:08:26 -0700 | [diff] [blame] | 9097 | virtual void TearDown() override { |
chaviw | fd6d351 | 2019-03-25 13:23:49 -0700 | [diff] [blame] | 9098 | InputDispatcherTest::TearDown(); |
9099 | |||||
9100 | mUnfocusedWindow.clear(); | ||||
Siarhei Vishniakou | b9b1535 | 2019-11-26 13:19:26 -0800 | [diff] [blame] | 9101 | mFocusedWindow.clear(); |
chaviw | fd6d351 | 2019-03-25 13:23:49 -0700 | [diff] [blame] | 9102 | } |
9103 | |||||
9104 | protected: | ||||
9105 | sp<FakeWindowHandle> mUnfocusedWindow; | ||||
Siarhei Vishniakou | b9b1535 | 2019-11-26 13:19:26 -0800 | [diff] [blame] | 9106 | sp<FakeWindowHandle> mFocusedWindow; |
Siarhei Vishniakou | fb9fcda | 2020-05-04 14:59:19 -0700 | [diff] [blame] | 9107 | static constexpr PointF FOCUSED_WINDOW_TOUCH_POINT = {60, 60}; |
chaviw | fd6d351 | 2019-03-25 13:23:49 -0700 | [diff] [blame] | 9108 | }; |
9109 | |||||
9110 | // Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action | ||||
9111 | // DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received | ||||
9112 | // the onPointerDownOutsideFocus callback. | ||||
9113 | TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) { | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 9114 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9115 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | fb9fcda | 2020-05-04 14:59:19 -0700 | [diff] [blame] | 9116 | {20, 20})) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 9117 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
Siarhei Vishniakou | 03aee2a | 2020-04-13 20:44:54 -0700 | [diff] [blame] | 9118 | mUnfocusedWindow->consumeMotionDown(); |
chaviw | fd6d351 | 2019-03-25 13:23:49 -0700 | [diff] [blame] | 9119 | |
Siarhei Vishniakou | 2bfa905 | 2019-11-21 18:10:54 -0800 | [diff] [blame] | 9120 | ASSERT_TRUE(mDispatcher->waitForIdle()); |
chaviw | fd6d351 | 2019-03-25 13:23:49 -0700 | [diff] [blame] | 9121 | mFakePolicy->assertOnPointerDownEquals(mUnfocusedWindow->getToken()); |
9122 | } | ||||
9123 | |||||
9124 | // Have two windows, one with focus. Inject MotionEvent with source TRACKBALL and action | ||||
9125 | // DOWN on the window that doesn't have focus. Ensure no window received the | ||||
9126 | // onPointerDownOutsideFocus callback. | ||||
9127 | TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) { | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 9128 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9129 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT, |
9130 | {20, 20})) | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 9131 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
Siarhei Vishniakou | 03aee2a | 2020-04-13 20:44:54 -0700 | [diff] [blame] | 9132 | mFocusedWindow->consumeMotionDown(); |
chaviw | fd6d351 | 2019-03-25 13:23:49 -0700 | [diff] [blame] | 9133 | |
Siarhei Vishniakou | 2bfa905 | 2019-11-21 18:10:54 -0800 | [diff] [blame] | 9134 | ASSERT_TRUE(mDispatcher->waitForIdle()); |
9135 | mFakePolicy->assertOnPointerDownWasNotCalled(); | ||||
chaviw | fd6d351 | 2019-03-25 13:23:49 -0700 | [diff] [blame] | 9136 | } |
9137 | |||||
9138 | // Have two windows, one with focus. Inject KeyEvent with action DOWN on the window that doesn't | ||||
9139 | // have focus. Ensure no window received the onPointerDownOutsideFocus callback. | ||||
9140 | TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) { | ||||
Prabir Pradhan | 93f342c | 2021-03-11 15:05:30 -0800 | [diff] [blame] | 9141 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9142 | injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 9143 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Siarhei Vishniakou | 03aee2a | 2020-04-13 20:44:54 -0700 | [diff] [blame] | 9144 | mFocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); |
chaviw | fd6d351 | 2019-03-25 13:23:49 -0700 | [diff] [blame] | 9145 | |
Siarhei Vishniakou | 2bfa905 | 2019-11-21 18:10:54 -0800 | [diff] [blame] | 9146 | ASSERT_TRUE(mDispatcher->waitForIdle()); |
9147 | mFakePolicy->assertOnPointerDownWasNotCalled(); | ||||
chaviw | fd6d351 | 2019-03-25 13:23:49 -0700 | [diff] [blame] | 9148 | } |
9149 | |||||
9150 | // Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action | ||||
9151 | // DOWN on the window that already has focus. Ensure no window received the | ||||
9152 | // onPointerDownOutsideFocus callback. | ||||
Siarhei Vishniakou | 870ecec | 2020-12-09 08:07:46 -1000 | [diff] [blame] | 9153 | TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) { |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 9154 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9155 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | fb9fcda | 2020-05-04 14:59:19 -0700 | [diff] [blame] | 9156 | FOCUSED_WINDOW_TOUCH_POINT)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 9157 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
Siarhei Vishniakou | 03aee2a | 2020-04-13 20:44:54 -0700 | [diff] [blame] | 9158 | mFocusedWindow->consumeMotionDown(); |
chaviw | fd6d351 | 2019-03-25 13:23:49 -0700 | [diff] [blame] | 9159 | |
Siarhei Vishniakou | 2bfa905 | 2019-11-21 18:10:54 -0800 | [diff] [blame] | 9160 | ASSERT_TRUE(mDispatcher->waitForIdle()); |
9161 | mFakePolicy->assertOnPointerDownWasNotCalled(); | ||||
chaviw | fd6d351 | 2019-03-25 13:23:49 -0700 | [diff] [blame] | 9162 | } |
9163 | |||||
Prabir Pradhan | 47cf0a0 | 2021-03-11 20:30:57 -0800 | [diff] [blame] | 9164 | // Have two windows, one with focus. Injecting a trusted DOWN MotionEvent with the flag |
9165 | // NO_FOCUS_CHANGE on the unfocused window should not call the onPointerDownOutsideFocus callback. | ||||
9166 | TEST_F(InputDispatcherOnPointerDownOutsideFocus, NoFocusChangeFlag) { | ||||
9167 | const MotionEvent event = | ||||
9168 | MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) | ||||
9169 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 9170 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(20).y(20)) |
Prabir Pradhan | 47cf0a0 | 2021-03-11 20:30:57 -0800 | [diff] [blame] | 9171 | .addFlag(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE) |
9172 | .build(); | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9173 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, event)) |
Prabir Pradhan | 47cf0a0 | 2021-03-11 20:30:57 -0800 | [diff] [blame] | 9174 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
9175 | mUnfocusedWindow->consumeAnyMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); | ||||
9176 | |||||
9177 | ASSERT_TRUE(mDispatcher->waitForIdle()); | ||||
9178 | mFakePolicy->assertOnPointerDownWasNotCalled(); | ||||
9179 | // Ensure that the unfocused window did not receive any FOCUS events. | ||||
9180 | mUnfocusedWindow->assertNoEvents(); | ||||
9181 | } | ||||
9182 | |||||
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9183 | // These tests ensures we can send touch events to a single client when there are multiple input |
9184 | // windows that point to the same client token. | ||||
9185 | class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest { | ||||
9186 | virtual void SetUp() override { | ||||
9187 | InputDispatcherTest::SetUp(); | ||||
9188 | |||||
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 9189 | std::shared_ptr<FakeApplicationHandle> application = |
9190 | std::make_shared<FakeApplicationHandle>(); | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 9191 | mWindow1 = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window 1", |
9192 | ADISPLAY_ID_DEFAULT); | ||||
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9193 | mWindow1->setFrame(Rect(0, 0, 100, 100)); |
9194 | |||||
Prabir Pradhan | e7cc69c | 2024-01-05 21:35:28 +0000 | [diff] [blame] | 9195 | mWindow2 = mWindow1->clone(ADISPLAY_ID_DEFAULT); |
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9196 | mWindow2->setFrame(Rect(100, 100, 200, 200)); |
9197 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9198 | mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); |
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9199 | } |
9200 | |||||
9201 | protected: | ||||
9202 | sp<FakeWindowHandle> mWindow1; | ||||
9203 | sp<FakeWindowHandle> mWindow2; | ||||
9204 | |||||
9205 | // Helper function to convert the point from screen coordinates into the window's space | ||||
chaviw | 3277faf | 2021-05-19 16:45:23 -0500 | [diff] [blame] | 9206 | static PointF getPointInWindow(const WindowInfo* windowInfo, const PointF& point) { |
chaviw | 1ff3d1e | 2020-07-01 15:53:47 -0700 | [diff] [blame] | 9207 | vec2 vals = windowInfo->transform.transform(point.x, point.y); |
9208 | return {vals.x, vals.y}; | ||||
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9209 | } |
9210 | |||||
9211 | void consumeMotionEvent(const sp<FakeWindowHandle>& window, int32_t expectedAction, | ||||
9212 | const std::vector<PointF>& points) { | ||||
Siarhei Vishniakou | f1035d4 | 2019-09-20 16:32:01 +0100 | [diff] [blame] | 9213 | const std::string name = window->getName(); |
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 9214 | std::unique_ptr<MotionEvent> motionEvent = |
Prabir Pradhan | 7662a8d | 2023-12-15 01:58:14 +0000 | [diff] [blame] | 9215 | window->consumeMotionEvent(WithMotionAction(expectedAction)); |
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 9216 | ASSERT_NE(nullptr, motionEvent); |
9217 | ASSERT_EQ(points.size(), motionEvent->getPointerCount()); | ||||
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9218 | |
9219 | for (size_t i = 0; i < points.size(); i++) { | ||||
9220 | float expectedX = points[i].x; | ||||
9221 | float expectedY = points[i].y; | ||||
9222 | |||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 9223 | EXPECT_EQ(expectedX, motionEvent->getX(i)) |
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9224 | << "expected " << expectedX << " for x[" << i << "] coord of " << name.c_str() |
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 9225 | << ", got " << motionEvent->getX(i); |
9226 | EXPECT_EQ(expectedY, motionEvent->getY(i)) | ||||
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9227 | << "expected " << expectedY << " for y[" << i << "] coord of " << name.c_str() |
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 9228 | << ", got " << motionEvent->getY(i); |
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9229 | } |
9230 | } | ||||
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9231 | |
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9232 | void touchAndAssertPositions(sp<FakeWindowHandle> touchedWindow, int32_t action, |
9233 | const std::vector<PointF>& touchedPoints, | ||||
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9234 | std::vector<PointF> expectedPoints) { |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 9235 | mDispatcher->notifyMotion(generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN, |
9236 | ADISPLAY_ID_DEFAULT, touchedPoints)); | ||||
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9237 | |
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9238 | consumeMotionEvent(touchedWindow, action, expectedPoints); |
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9239 | } |
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9240 | }; |
9241 | |||||
9242 | TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchSameScale) { | ||||
9243 | // Touch Window 1 | ||||
9244 | PointF touchedPoint = {10, 10}; | ||||
9245 | PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint); | ||||
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9246 | touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint}); |
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9247 | |
9248 | // Release touch on Window 1 | ||||
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9249 | touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint}); |
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9250 | |
9251 | // Touch Window 2 | ||||
9252 | touchedPoint = {150, 150}; | ||||
9253 | expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint); | ||||
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9254 | touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint}); |
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9255 | } |
9256 | |||||
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9257 | TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchDifferentTransform) { |
9258 | // Set scale value for window2 | ||||
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9259 | mWindow2->setWindowScale(0.5f, 0.5f); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9260 | mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); |
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9261 | |
9262 | // Touch Window 1 | ||||
9263 | PointF touchedPoint = {10, 10}; | ||||
9264 | PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint); | ||||
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9265 | touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint}); |
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9266 | // Release touch on Window 1 |
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9267 | touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint}); |
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9268 | |
9269 | // Touch Window 2 | ||||
9270 | touchedPoint = {150, 150}; | ||||
9271 | expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint); | ||||
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9272 | touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint}); |
9273 | touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint}); | ||||
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9274 | |
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9275 | // Update the transform so rotation is set |
9276 | mWindow2->setWindowTransform(0, -1, 1, 0); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9277 | mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); |
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9278 | expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint); |
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9279 | touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint}); |
chaviw | af87b3e | 2019-10-01 16:59:28 -0700 | [diff] [blame] | 9280 | } |
9281 | |||||
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9282 | TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchDifferentTransform) { |
Chavi Weingarten | 65f98b8 | 2020-01-16 18:56:50 +0000 | [diff] [blame] | 9283 | mWindow2->setWindowScale(0.5f, 0.5f); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9284 | mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); |
Chavi Weingarten | 65f98b8 | 2020-01-16 18:56:50 +0000 | [diff] [blame] | 9285 | |
9286 | // Touch Window 1 | ||||
9287 | std::vector<PointF> touchedPoints = {PointF{10, 10}}; | ||||
9288 | std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])}; | ||||
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9289 | touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints); |
Chavi Weingarten | 65f98b8 | 2020-01-16 18:56:50 +0000 | [diff] [blame] | 9290 | |
9291 | // Touch Window 2 | ||||
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9292 | // Since this is part of the same touch gesture that has already been dispatched to Window 1, |
9293 | // the touch stream from Window 2 will be merged with the stream in Window 1. The merged stream | ||||
9294 | // will continue to be dispatched through Window 1. | ||||
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9295 | touchedPoints.push_back(PointF{150, 150}); |
9296 | expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1])); | ||||
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9297 | touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints); |
Chavi Weingarten | 65f98b8 | 2020-01-16 18:56:50 +0000 | [diff] [blame] | 9298 | |
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9299 | // Release Window 2 |
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9300 | touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints); |
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9301 | expectedPoints.pop_back(); |
Chavi Weingarten | 65f98b8 | 2020-01-16 18:56:50 +0000 | [diff] [blame] | 9302 | |
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9303 | // Update the transform so rotation is set for Window 2 |
9304 | mWindow2->setWindowTransform(0, -1, 1, 0); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9305 | mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); |
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9306 | expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1])); |
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9307 | touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints); |
Chavi Weingarten | 65f98b8 | 2020-01-16 18:56:50 +0000 | [diff] [blame] | 9308 | } |
9309 | |||||
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9310 | TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchMoveDifferentTransform) { |
Chavi Weingarten | 65f98b8 | 2020-01-16 18:56:50 +0000 | [diff] [blame] | 9311 | mWindow2->setWindowScale(0.5f, 0.5f); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9312 | mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); |
Chavi Weingarten | 65f98b8 | 2020-01-16 18:56:50 +0000 | [diff] [blame] | 9313 | |
9314 | // Touch Window 1 | ||||
9315 | std::vector<PointF> touchedPoints = {PointF{10, 10}}; | ||||
9316 | std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])}; | ||||
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9317 | touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints); |
Chavi Weingarten | 65f98b8 | 2020-01-16 18:56:50 +0000 | [diff] [blame] | 9318 | |
9319 | // Touch Window 2 | ||||
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9320 | touchedPoints.push_back(PointF{150, 150}); |
9321 | expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1])); | ||||
Chavi Weingarten | 65f98b8 | 2020-01-16 18:56:50 +0000 | [diff] [blame] | 9322 | |
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9323 | touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints); |
Chavi Weingarten | 65f98b8 | 2020-01-16 18:56:50 +0000 | [diff] [blame] | 9324 | |
9325 | // Move both windows | ||||
9326 | touchedPoints = {{20, 20}, {175, 175}}; | ||||
9327 | expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]), | ||||
9328 | getPointInWindow(mWindow2->getInfo(), touchedPoints[1])}; | ||||
9329 | |||||
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9330 | touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints); |
Chavi Weingarten | 65f98b8 | 2020-01-16 18:56:50 +0000 | [diff] [blame] | 9331 | |
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9332 | // Release Window 2 |
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9333 | touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints); |
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9334 | expectedPoints.pop_back(); |
9335 | |||||
9336 | // Touch Window 2 | ||||
9337 | mWindow2->setWindowTransform(0, -1, 1, 0); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9338 | mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); |
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9339 | expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1])); |
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9340 | touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints); |
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9341 | |
9342 | // Move both windows | ||||
9343 | touchedPoints = {{20, 20}, {175, 175}}; | ||||
9344 | expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]), | ||||
9345 | getPointInWindow(mWindow2->getInfo(), touchedPoints[1])}; | ||||
9346 | |||||
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9347 | touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints); |
Chavi Weingarten | 65f98b8 | 2020-01-16 18:56:50 +0000 | [diff] [blame] | 9348 | } |
9349 | |||||
9350 | TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleWindowsFirstTouchWithScale) { | ||||
9351 | mWindow1->setWindowScale(0.5f, 0.5f); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9352 | mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); |
Chavi Weingarten | 65f98b8 | 2020-01-16 18:56:50 +0000 | [diff] [blame] | 9353 | |
9354 | // Touch Window 1 | ||||
9355 | std::vector<PointF> touchedPoints = {PointF{10, 10}}; | ||||
9356 | std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])}; | ||||
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9357 | touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints); |
Chavi Weingarten | 65f98b8 | 2020-01-16 18:56:50 +0000 | [diff] [blame] | 9358 | |
9359 | // Touch Window 2 | ||||
chaviw | 9eaa22c | 2020-07-01 16:21:27 -0700 | [diff] [blame] | 9360 | touchedPoints.push_back(PointF{150, 150}); |
9361 | expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1])); | ||||
Chavi Weingarten | 65f98b8 | 2020-01-16 18:56:50 +0000 | [diff] [blame] | 9362 | |
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9363 | touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints); |
Chavi Weingarten | 65f98b8 | 2020-01-16 18:56:50 +0000 | [diff] [blame] | 9364 | |
9365 | // Move both windows | ||||
9366 | touchedPoints = {{20, 20}, {175, 175}}; | ||||
9367 | expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]), | ||||
9368 | getPointInWindow(mWindow2->getInfo(), touchedPoints[1])}; | ||||
9369 | |||||
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9370 | touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints); |
Chavi Weingarten | 65f98b8 | 2020-01-16 18:56:50 +0000 | [diff] [blame] | 9371 | } |
9372 | |||||
Siarhei Vishniakou | 0f6558d | 2023-04-21 12:05:13 -0700 | [diff] [blame] | 9373 | /** |
9374 | * When one of the windows is slippery, the touch should not slip into the other window with the | ||||
9375 | * same input channel. | ||||
9376 | */ | ||||
9377 | TEST_F(InputDispatcherMultiWindowSameTokenTests, TouchDoesNotSlipEvenIfSlippery) { | ||||
9378 | mWindow1->setSlippery(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9379 | mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | 0f6558d | 2023-04-21 12:05:13 -0700 | [diff] [blame] | 9380 | |
9381 | // Touch down in window 1 | ||||
9382 | mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, | ||||
9383 | ADISPLAY_ID_DEFAULT, {{50, 50}})); | ||||
9384 | consumeMotionEvent(mWindow1, ACTION_DOWN, {{50, 50}}); | ||||
9385 | |||||
9386 | // Move touch to be above window 2. Even though window 1 is slippery, touch should not slip. | ||||
9387 | // That means the gesture should continue normally, without any ACTION_CANCEL or ACTION_DOWN | ||||
9388 | // getting generated. | ||||
9389 | mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, | ||||
9390 | ADISPLAY_ID_DEFAULT, {{150, 150}})); | ||||
9391 | |||||
9392 | consumeMotionEvent(mWindow1, ACTION_MOVE, {{150, 150}}); | ||||
9393 | } | ||||
9394 | |||||
Siarhei Vishniakou | d5876ba | 2023-05-15 17:58:34 -0700 | [diff] [blame] | 9395 | /** |
9396 | * When hover starts in one window and continues into the other, there should be a HOVER_EXIT and | ||||
9397 | * a HOVER_ENTER generated, even if the windows have the same token. This is because the new window | ||||
9398 | * that the pointer is hovering over may have a different transform. | ||||
9399 | */ | ||||
9400 | TEST_F(InputDispatcherMultiWindowSameTokenTests, HoverIntoClone) { | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9401 | mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | d5876ba | 2023-05-15 17:58:34 -0700 | [diff] [blame] | 9402 | |
9403 | // Start hover in window 1 | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 9404 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_TOUCHSCREEN) |
9405 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
9406 | .build()); | ||||
Siarhei Vishniakou | d5876ba | 2023-05-15 17:58:34 -0700 | [diff] [blame] | 9407 | consumeMotionEvent(mWindow1, ACTION_HOVER_ENTER, |
9408 | {getPointInWindow(mWindow1->getInfo(), PointF{50, 50})}); | ||||
Siarhei Vishniakou | d5876ba | 2023-05-15 17:58:34 -0700 | [diff] [blame] | 9409 | // Move hover to window 2. |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 9410 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_TOUCHSCREEN) |
9411 | .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150)) | ||||
9412 | .build()); | ||||
Siarhei Vishniakou | d5876ba | 2023-05-15 17:58:34 -0700 | [diff] [blame] | 9413 | consumeMotionEvent(mWindow1, ACTION_HOVER_EXIT, {{50, 50}}); |
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 9414 | consumeMotionEvent(mWindow2, ACTION_HOVER_ENTER, |
Siarhei Vishniakou | d5876ba | 2023-05-15 17:58:34 -0700 | [diff] [blame] | 9415 | {getPointInWindow(mWindow2->getInfo(), PointF{150, 150})}); |
9416 | } | ||||
9417 | |||||
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 9418 | class InputDispatcherSingleWindowAnr : public InputDispatcherTest { |
9419 | virtual void SetUp() override { | ||||
9420 | InputDispatcherTest::SetUp(); | ||||
9421 | |||||
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 9422 | mApplication = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | f83c693 | 2023-07-07 17:48:10 -0700 | [diff] [blame] | 9423 | mApplication->setDispatchingTimeout(100ms); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 9424 | mWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "TestWindow", |
9425 | ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 9426 | mWindow->setFrame(Rect(0, 0, 30, 30)); |
Siarhei Vishniakou | f83c693 | 2023-07-07 17:48:10 -0700 | [diff] [blame] | 9427 | mWindow->setDispatchingTimeout(100ms); |
Vishnu Nair | 47074b8 | 2020-08-14 11:54:47 -0700 | [diff] [blame] | 9428 | mWindow->setFocusable(true); |
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 9429 | |
9430 | // Set focused application. | ||||
9431 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); | ||||
9432 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9433 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 9434 | setFocusedWindow(mWindow); |
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 9435 | mWindow->consumeFocusEvent(true); |
9436 | } | ||||
9437 | |||||
9438 | virtual void TearDown() override { | ||||
9439 | InputDispatcherTest::TearDown(); | ||||
9440 | mWindow.clear(); | ||||
9441 | } | ||||
9442 | |||||
9443 | protected: | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9444 | static constexpr std::chrono::duration SPY_TIMEOUT = 200ms; |
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 9445 | std::shared_ptr<FakeApplicationHandle> mApplication; |
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 9446 | sp<FakeWindowHandle> mWindow; |
9447 | static constexpr PointF WINDOW_LOCATION = {20, 20}; | ||||
9448 | |||||
9449 | void tapOnWindow() { | ||||
Siarhei Vishniakou | 67bf216 | 2023-11-16 13:29:50 -0800 | [diff] [blame] | 9450 | const auto touchingPointer = PointerBuilder(/*id=*/0, ToolType::FINGER) |
9451 | .x(WINDOW_LOCATION.x) | ||||
9452 | .y(WINDOW_LOCATION.y); | ||||
9453 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
9454 | .pointer(touchingPointer) | ||||
9455 | .build()); | ||||
9456 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
9457 | .pointer(touchingPointer) | ||||
9458 | .build()); | ||||
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 9459 | } |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9460 | |
9461 | sp<FakeWindowHandle> addSpyWindow() { | ||||
9462 | sp<FakeWindowHandle> spy = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 9463 | sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9464 | spy->setTrustedOverlay(true); |
9465 | spy->setFocusable(false); | ||||
Prabir Pradhan | 51e7db0 | 2022-02-07 06:02:57 -0800 | [diff] [blame] | 9466 | spy->setSpy(true); |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9467 | spy->setDispatchingTimeout(SPY_TIMEOUT); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9468 | mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *mWindow->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9469 | return spy; |
9470 | } | ||||
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 9471 | }; |
9472 | |||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9473 | // Send a tap and respond, which should not cause an ANR. |
9474 | TEST_F(InputDispatcherSingleWindowAnr, WhenTouchIsConsumed_NoAnr) { | ||||
9475 | tapOnWindow(); | ||||
9476 | mWindow->consumeMotionDown(); | ||||
9477 | mWindow->consumeMotionUp(); | ||||
9478 | ASSERT_TRUE(mDispatcher->waitForIdle()); | ||||
9479 | mFakePolicy->assertNotifyAnrWasNotCalled(); | ||||
9480 | } | ||||
9481 | |||||
9482 | // Send a regular key and respond, which should not cause an ANR. | ||||
9483 | TEST_F(InputDispatcherSingleWindowAnr, WhenKeyIsConsumed_NoAnr) { | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9484 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher)); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9485 | mWindow->consumeKeyDown(ADISPLAY_ID_NONE); |
9486 | ASSERT_TRUE(mDispatcher->waitForIdle()); | ||||
9487 | mFakePolicy->assertNotifyAnrWasNotCalled(); | ||||
9488 | } | ||||
9489 | |||||
Siarhei Vishniakou | e41c451 | 2020-09-08 19:35:58 -0500 | [diff] [blame] | 9490 | TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) { |
9491 | mWindow->setFocusable(false); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9492 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | e41c451 | 2020-09-08 19:35:58 -0500 | [diff] [blame] | 9493 | mWindow->consumeFocusEvent(false); |
9494 | |||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 9495 | InputEventInjectionResult result = |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9496 | injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, |
9497 | InputEventInjectionSync::NONE, CONSUME_TIMEOUT_EVENT_EXPECTED, | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 9498 | /*allowKeyRepeat=*/false); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 9499 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result); |
Siarhei Vishniakou | e41c451 | 2020-09-08 19:35:58 -0500 | [diff] [blame] | 9500 | // Key will not go to window because we have no focused window. |
9501 | // The 'no focused window' ANR timer should start instead. | ||||
9502 | |||||
9503 | // Now, the focused application goes away. | ||||
9504 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, nullptr); | ||||
9505 | // The key should get dropped and there should be no ANR. | ||||
9506 | |||||
9507 | ASSERT_TRUE(mDispatcher->waitForIdle()); | ||||
9508 | mFakePolicy->assertNotifyAnrWasNotCalled(); | ||||
9509 | } | ||||
9510 | |||||
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 9511 | // Send an event to the app and have the app not respond right away. |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9512 | // When ANR is raised, policy will tell the dispatcher to cancel the events for that window. |
9513 | // So InputDispatcher will enqueue ACTION_CANCEL event as well. | ||||
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 9514 | TEST_F(InputDispatcherSingleWindowAnr, OnPointerDown_BasicAnr) { |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 9515 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9516 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 9517 | WINDOW_LOCATION)); |
9518 | |||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 9519 | const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN |
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 9520 | ASSERT_TRUE(sequenceNum); |
9521 | const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); | ||||
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 9522 | mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9523 | |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9524 | mWindow->finishEvent(*sequenceNum); |
Siarhei Vishniakou | 1ae72f1 | 2023-01-29 12:55:30 -0800 | [diff] [blame] | 9525 | mWindow->consumeMotionEvent( |
9526 | AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT))); | ||||
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 9527 | ASSERT_TRUE(mDispatcher->waitForIdle()); |
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 9528 | mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid()); |
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 9529 | } |
9530 | |||||
9531 | // Send a key to the app and have the app not respond right away. | ||||
9532 | TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) { | ||||
9533 | // Inject a key, and don't respond - expect that ANR is called. | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9534 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher)); |
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 9535 | const auto [sequenceNum, _] = mWindow->receiveEvent(); |
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 9536 | ASSERT_TRUE(sequenceNum); |
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 9537 | const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); |
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 9538 | mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow); |
Siarhei Vishniakou | 4cb50ca | 2020-05-26 21:43:02 -0700 | [diff] [blame] | 9539 | ASSERT_TRUE(mDispatcher->waitForIdle()); |
9540 | } | ||||
9541 | |||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9542 | // We have a focused application, but no focused window |
9543 | TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) { | ||||
Vishnu Nair | 47074b8 | 2020-08-14 11:54:47 -0700 | [diff] [blame] | 9544 | mWindow->setFocusable(false); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9545 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9546 | mWindow->consumeFocusEvent(false); |
9547 | |||||
9548 | // taps on the window work as normal | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 9549 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9550 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9551 | WINDOW_LOCATION)); |
9552 | ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown()); | ||||
9553 | mDispatcher->waitForIdle(); | ||||
9554 | mFakePolicy->assertNotifyAnrWasNotCalled(); | ||||
9555 | |||||
9556 | // Once a focused event arrives, we get an ANR for this application | ||||
9557 | // We specify the injection timeout to be smaller than the application timeout, to ensure that | ||||
9558 | // injection times out (instead of failing). | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 9559 | const InputEventInjectionResult result = |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9560 | injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | f83c693 | 2023-07-07 17:48:10 -0700 | [diff] [blame] | 9561 | InputEventInjectionSync::WAIT_FOR_RESULT, 50ms, /*allowKeyRepeat=*/false); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 9562 | ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9563 | const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT); |
Vishnu Nair | e4df875 | 2022-09-08 09:17:55 -0700 | [diff] [blame] | 9564 | mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9565 | ASSERT_TRUE(mDispatcher->waitForIdle()); |
9566 | } | ||||
9567 | |||||
Siarhei Vishniakou | 289e924 | 2022-02-15 14:50:16 -0800 | [diff] [blame] | 9568 | /** |
9569 | * Make sure the stale key is dropped before causing an ANR. So even if there's no focused window, | ||||
9570 | * there will not be an ANR. | ||||
9571 | */ | ||||
9572 | TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) { | ||||
9573 | mWindow->setFocusable(false); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9574 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | 289e924 | 2022-02-15 14:50:16 -0800 | [diff] [blame] | 9575 | mWindow->consumeFocusEvent(false); |
9576 | |||||
9577 | KeyEvent event; | ||||
Siarhei Vishniakou | a733311 | 2023-10-27 13:33:29 -0700 | [diff] [blame] | 9578 | static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms; |
9579 | mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT); | ||||
Siarhei Vishniakou | 289e924 | 2022-02-15 14:50:16 -0800 | [diff] [blame] | 9580 | const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC) - |
9581 | std::chrono::nanoseconds(STALE_EVENT_TIMEOUT).count(); | ||||
9582 | |||||
9583 | // Define a valid key down event that is stale (too old). | ||||
9584 | event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 9585 | INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /*flags=*/0, AKEYCODE_A, KEY_A, |
Hu Guo | fe3c8f1 | 2023-09-22 17:20:15 +0800 | [diff] [blame] | 9586 | AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime); |
Siarhei Vishniakou | 289e924 | 2022-02-15 14:50:16 -0800 | [diff] [blame] | 9587 | |
Hu Guo | fe3c8f1 | 2023-09-22 17:20:15 +0800 | [diff] [blame] | 9588 | const int32_t policyFlags = |
9589 | POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT; | ||||
Siarhei Vishniakou | 289e924 | 2022-02-15 14:50:16 -0800 | [diff] [blame] | 9590 | |
9591 | InputEventInjectionResult result = | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 9592 | mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, |
Siarhei Vishniakou | 289e924 | 2022-02-15 14:50:16 -0800 | [diff] [blame] | 9593 | InputEventInjectionSync::WAIT_FOR_RESULT, |
9594 | INJECT_EVENT_TIMEOUT, policyFlags); | ||||
9595 | ASSERT_EQ(InputEventInjectionResult::FAILED, result) | ||||
9596 | << "Injection should fail because the event is stale"; | ||||
9597 | |||||
9598 | ASSERT_TRUE(mDispatcher->waitForIdle()); | ||||
9599 | mFakePolicy->assertNotifyAnrWasNotCalled(); | ||||
9600 | mWindow->assertNoEvents(); | ||||
9601 | } | ||||
9602 | |||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9603 | // We have a focused application, but no focused window |
Siarhei Vishniakou | 234129c | 2020-10-22 22:28:12 -0500 | [diff] [blame] | 9604 | // Make sure that we don't notify policy twice about the same ANR. |
9605 | TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) { | ||||
Siarhei Vishniakou | 06405fc | 2023-09-22 13:40:51 -0700 | [diff] [blame] | 9606 | const std::chrono::duration appTimeout = 400ms; |
9607 | mApplication->setDispatchingTimeout(appTimeout); | ||||
9608 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); | ||||
9609 | |||||
Vishnu Nair | 47074b8 | 2020-08-14 11:54:47 -0700 | [diff] [blame] | 9610 | mWindow->setFocusable(false); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9611 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9612 | mWindow->consumeFocusEvent(false); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9613 | |
9614 | // Once a focused event arrives, we get an ANR for this application | ||||
9615 | // We specify the injection timeout to be smaller than the application timeout, to ensure that | ||||
9616 | // injection times out (instead of failing). | ||||
Siarhei Vishniakou | 06405fc | 2023-09-22 13:40:51 -0700 | [diff] [blame] | 9617 | const std::chrono::duration eventInjectionTimeout = 100ms; |
9618 | ASSERT_LT(eventInjectionTimeout, appTimeout); | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 9619 | const InputEventInjectionResult result = |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9620 | injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | 06405fc | 2023-09-22 13:40:51 -0700 | [diff] [blame] | 9621 | InputEventInjectionSync::WAIT_FOR_RESULT, eventInjectionTimeout, |
9622 | /*allowKeyRepeat=*/false); | ||||
9623 | ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result) | ||||
9624 | << "result=" << ftl::enum_string(result); | ||||
9625 | // We already waited for 'eventInjectionTimeout`, because the countdown started when the event | ||||
9626 | // was first injected. So now we have (appTimeout - eventInjectionTimeout) left to wait. | ||||
9627 | std::chrono::duration remainingWaitTime = appTimeout - eventInjectionTimeout; | ||||
9628 | mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(remainingWaitTime, mApplication); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9629 | |
Vishnu Nair | e4df875 | 2022-09-08 09:17:55 -0700 | [diff] [blame] | 9630 | std::this_thread::sleep_for(appTimeout); |
Siarhei Vishniakou | 234129c | 2020-10-22 22:28:12 -0500 | [diff] [blame] | 9631 | // ANR should not be raised again. It is up to policy to do that if it desires. |
9632 | mFakePolicy->assertNotifyAnrWasNotCalled(); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9633 | |
Siarhei Vishniakou | 234129c | 2020-10-22 22:28:12 -0500 | [diff] [blame] | 9634 | // If we now get a focused window, the ANR should stop, but the policy handles that via |
9635 | // 'notifyFocusChanged' callback. This is implemented in the policy so we can't test it here. | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9636 | ASSERT_TRUE(mDispatcher->waitForIdle()); |
9637 | } | ||||
9638 | |||||
9639 | // We have a focused application, but no focused window | ||||
9640 | TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) { | ||||
Vishnu Nair | 47074b8 | 2020-08-14 11:54:47 -0700 | [diff] [blame] | 9641 | mWindow->setFocusable(false); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9642 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9643 | mWindow->consumeFocusEvent(false); |
9644 | |||||
9645 | // Once a focused event arrives, we get an ANR for this application | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9646 | ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher)); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9647 | |
Vishnu Nair | e4df875 | 2022-09-08 09:17:55 -0700 | [diff] [blame] | 9648 | const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT); |
9649 | mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9650 | |
9651 | // Future focused events get dropped right away | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9652 | ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(*mDispatcher)); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9653 | ASSERT_TRUE(mDispatcher->waitForIdle()); |
9654 | mWindow->assertNoEvents(); | ||||
9655 | } | ||||
9656 | |||||
9657 | /** | ||||
9658 | * Ensure that the implementation is valid. Since we are using multiset to keep track of the | ||||
9659 | * ANR timeouts, we are allowing entries with identical timestamps in the same connection. | ||||
9660 | * If we process 1 of the events, but ANR on the second event with the same timestamp, | ||||
9661 | * the ANR mechanism should still work. | ||||
9662 | * | ||||
9663 | * In this test, we are injecting DOWN and UP events with the same timestamps, and acknowledging the | ||||
9664 | * DOWN event, while not responding on the second one. | ||||
9665 | */ | ||||
9666 | TEST_F(InputDispatcherSingleWindowAnr, Anr_HandlesEventsWithIdenticalTimestamps) { | ||||
9667 | nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9668 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9669 | ADISPLAY_ID_DEFAULT, WINDOW_LOCATION, |
9670 | {AMOTION_EVENT_INVALID_CURSOR_POSITION, | ||||
9671 | AMOTION_EVENT_INVALID_CURSOR_POSITION}, | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 9672 | 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9673 | |
9674 | // Now send ACTION_UP, with identical timestamp | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9675 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9676 | ADISPLAY_ID_DEFAULT, WINDOW_LOCATION, |
9677 | {AMOTION_EVENT_INVALID_CURSOR_POSITION, | ||||
9678 | AMOTION_EVENT_INVALID_CURSOR_POSITION}, | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 9679 | 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9680 | |
9681 | // We have now sent down and up. Let's consume first event and then ANR on the second. | ||||
9682 | mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
9683 | const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); | ||||
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 9684 | mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9685 | } |
9686 | |||||
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9687 | // A spy window can receive an ANR |
9688 | TEST_F(InputDispatcherSingleWindowAnr, SpyWindowAnr) { | ||||
9689 | sp<FakeWindowHandle> spy = addSpyWindow(); | ||||
9690 | |||||
9691 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9692 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9693 | WINDOW_LOCATION)); |
9694 | mWindow->consumeMotionDown(); | ||||
9695 | |||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 9696 | const auto [sequenceNum, _] = spy->receiveEvent(); // ACTION_DOWN |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9697 | ASSERT_TRUE(sequenceNum); |
9698 | const std::chrono::duration timeout = spy->getDispatchingTimeout(DISPATCHING_TIMEOUT); | ||||
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 9699 | mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy); |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9700 | |
9701 | spy->finishEvent(*sequenceNum); | ||||
Siarhei Vishniakou | 1ae72f1 | 2023-01-29 12:55:30 -0800 | [diff] [blame] | 9702 | spy->consumeMotionEvent( |
9703 | AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT))); | ||||
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9704 | ASSERT_TRUE(mDispatcher->waitForIdle()); |
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 9705 | mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken(), mWindow->getPid()); |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9706 | } |
9707 | |||||
9708 | // If an app is not responding to a key event, spy windows should continue to receive | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9709 | // new motion events |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9710 | TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnKey) { |
9711 | sp<FakeWindowHandle> spy = addSpyWindow(); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9712 | |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 9713 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9714 | injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT)); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9715 | mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9716 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher, ADISPLAY_ID_DEFAULT)); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9717 | |
9718 | // Stuck on the ACTION_UP | ||||
9719 | const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); | ||||
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 9720 | mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9721 | |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9722 | // New tap will go to the spy window, but not to the window |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9723 | tapOnWindow(); |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9724 | spy->consumeMotionDown(ADISPLAY_ID_DEFAULT); |
9725 | spy->consumeMotionUp(ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9726 | |
9727 | mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT); // still the previous motion | ||||
9728 | mDispatcher->waitForIdle(); | ||||
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 9729 | mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid()); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9730 | mWindow->assertNoEvents(); |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9731 | spy->assertNoEvents(); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9732 | } |
9733 | |||||
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9734 | // If an app is not responding to a motion event, spy windows should continue to receive |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9735 | // new motion events |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9736 | TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnMotion) { |
9737 | sp<FakeWindowHandle> spy = addSpyWindow(); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9738 | |
9739 | tapOnWindow(); | ||||
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9740 | spy->consumeMotionDown(ADISPLAY_ID_DEFAULT); |
9741 | spy->consumeMotionUp(ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9742 | |
9743 | mWindow->consumeMotionDown(); | ||||
9744 | // Stuck on the ACTION_UP | ||||
9745 | const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); | ||||
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 9746 | mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9747 | |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9748 | // New tap will go to the spy window, but not to the window |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9749 | tapOnWindow(); |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9750 | spy->consumeMotionDown(ADISPLAY_ID_DEFAULT); |
9751 | spy->consumeMotionUp(ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9752 | |
9753 | mWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); // still the previous motion | ||||
9754 | mDispatcher->waitForIdle(); | ||||
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 9755 | mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid()); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9756 | mWindow->assertNoEvents(); |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9757 | spy->assertNoEvents(); |
9758 | } | ||||
9759 | |||||
9760 | TEST_F(InputDispatcherSingleWindowAnr, UnresponsiveMonitorAnr) { | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9761 | mDispatcher->setMonitorDispatchingTimeoutForTest(SPY_TIMEOUT); |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9762 | |
Prabir Pradhan | fb54907 | 2023-10-05 19:17:36 +0000 | [diff] [blame] | 9763 | FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9764 | |
9765 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9766 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9767 | WINDOW_LOCATION)); |
9768 | |||||
9769 | mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
9770 | const std::optional<uint32_t> consumeSeq = monitor.receiveEvent(); | ||||
9771 | ASSERT_TRUE(consumeSeq); | ||||
9772 | |||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9773 | mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(SPY_TIMEOUT, monitor.getToken(), |
9774 | MONITOR_PID); | ||||
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 9775 | |
9776 | monitor.finishEvent(*consumeSeq); | ||||
9777 | monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT); | ||||
9778 | |||||
9779 | ASSERT_TRUE(mDispatcher->waitForIdle()); | ||||
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 9780 | mFakePolicy->assertNotifyWindowResponsiveWasCalled(monitor.getToken(), MONITOR_PID); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9781 | } |
9782 | |||||
9783 | // If a window is unresponsive, then you get anr. if the window later catches up and starts to | ||||
9784 | // process events, you don't get an anr. When the window later becomes unresponsive again, you | ||||
9785 | // get an ANR again. | ||||
9786 | // 1. tap -> block on ACTION_UP -> receive ANR | ||||
9787 | // 2. consume all pending events (= queue becomes healthy again) | ||||
9788 | // 3. tap again -> block on ACTION_UP again -> receive ANR second time | ||||
9789 | TEST_F(InputDispatcherSingleWindowAnr, SameWindow_CanReceiveAnrTwice) { | ||||
9790 | tapOnWindow(); | ||||
9791 | |||||
9792 | mWindow->consumeMotionDown(); | ||||
9793 | // Block on ACTION_UP | ||||
9794 | const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); | ||||
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 9795 | mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9796 | mWindow->consumeMotionUp(); // Now the connection should be healthy again |
9797 | mDispatcher->waitForIdle(); | ||||
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 9798 | mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid()); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9799 | mWindow->assertNoEvents(); |
9800 | |||||
9801 | tapOnWindow(); | ||||
9802 | mWindow->consumeMotionDown(); | ||||
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 9803 | mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9804 | mWindow->consumeMotionUp(); |
9805 | |||||
9806 | mDispatcher->waitForIdle(); | ||||
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 9807 | mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid()); |
Siarhei Vishniakou | 234129c | 2020-10-22 22:28:12 -0500 | [diff] [blame] | 9808 | mFakePolicy->assertNotifyAnrWasNotCalled(); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9809 | mWindow->assertNoEvents(); |
9810 | } | ||||
9811 | |||||
Siarhei Vishniakou | 234129c | 2020-10-22 22:28:12 -0500 | [diff] [blame] | 9812 | // If a connection remains unresponsive for a while, make sure policy is only notified once about |
9813 | // it. | ||||
9814 | TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) { | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 9815 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9816 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9817 | WINDOW_LOCATION)); |
9818 | |||||
9819 | const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); | ||||
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 9820 | mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(windowTimeout, mWindow); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9821 | std::this_thread::sleep_for(windowTimeout); |
Siarhei Vishniakou | 234129c | 2020-10-22 22:28:12 -0500 | [diff] [blame] | 9822 | // 'notifyConnectionUnresponsive' should only be called once per connection |
9823 | mFakePolicy->assertNotifyAnrWasNotCalled(); | ||||
9824 | // When the ANR happened, dispatcher should abort the current event stream via ACTION_CANCEL | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9825 | mWindow->consumeMotionDown(); |
Siarhei Vishniakou | 1ae72f1 | 2023-01-29 12:55:30 -0800 | [diff] [blame] | 9826 | mWindow->consumeMotionEvent( |
9827 | AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT))); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9828 | mWindow->assertNoEvents(); |
Siarhei Vishniakou | 234129c | 2020-10-22 22:28:12 -0500 | [diff] [blame] | 9829 | mDispatcher->waitForIdle(); |
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 9830 | mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid()); |
Siarhei Vishniakou | 234129c | 2020-10-22 22:28:12 -0500 | [diff] [blame] | 9831 | mFakePolicy->assertNotifyAnrWasNotCalled(); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9832 | } |
9833 | |||||
9834 | /** | ||||
9835 | * If a window is processing a motion event, and then a key event comes in, the key event should | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9836 | * not get delivered to the focused window until the motion is processed. |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9837 | */ |
9838 | TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) { | ||||
Siarhei Vishniakou | ef2b450 | 2023-12-28 11:51:47 -0800 | [diff] [blame] | 9839 | // The timeouts in this test are established by relying on the fact that the "key waiting for |
9840 | // events timeout" is equal to 500ms. | ||||
9841 | ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9842 | mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9843 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9844 | |
9845 | tapOnWindow(); | ||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 9846 | const auto& [downSequenceNum, downEvent] = mWindow->receiveEvent(); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9847 | ASSERT_TRUE(downSequenceNum); |
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 9848 | const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent(); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9849 | ASSERT_TRUE(upSequenceNum); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9850 | |
Siarhei Vishniakou | ef2b450 | 2023-12-28 11:51:47 -0800 | [diff] [blame] | 9851 | // Don't finish the events yet, and send a key |
9852 | mDispatcher->notifyKey( | ||||
9853 | KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD) | ||||
9854 | .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT) | ||||
9855 | .build()); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9856 | // Key will not be sent to the window, yet, because the window is still processing events |
9857 | // and the key remains pending, waiting for the touch events to be processed | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 9858 | // Make sure that `assertNoEvents` doesn't wait too long, because it could cause an ANR. |
Siarhei Vishniakou | ef2b450 | 2023-12-28 11:51:47 -0800 | [diff] [blame] | 9859 | mWindow->assertNoEvents(100ms); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9860 | |
Siarhei Vishniakou | ef2b450 | 2023-12-28 11:51:47 -0800 | [diff] [blame] | 9861 | std::this_thread::sleep_for(400ms); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9862 | // if we wait long enough though, dispatcher will give up, and still send the key |
9863 | // to the focused window, even though we have not yet finished the motion event | ||||
9864 | mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); | ||||
9865 | mWindow->finishEvent(*downSequenceNum); | ||||
9866 | mWindow->finishEvent(*upSequenceNum); | ||||
9867 | } | ||||
9868 | |||||
9869 | /** | ||||
9870 | * If a window is processing a motion event, and then a key event comes in, the key event should | ||||
9871 | * not go to the focused window until the motion is processed. | ||||
9872 | * If then a new motion comes in, then the pending key event should be going to the currently | ||||
9873 | * focused window right away. | ||||
9874 | */ | ||||
9875 | TEST_F(InputDispatcherSingleWindowAnr, | ||||
Siarhei Vishniakou | ef2b450 | 2023-12-28 11:51:47 -0800 | [diff] [blame] | 9876 | PendingKey_IsDeliveredWhileMotionIsProcessingAndNewTouchComesIn) { |
9877 | // The timeouts in this test are established by relying on the fact that the "key waiting for | ||||
9878 | // events timeout" is equal to 500ms. | ||||
9879 | ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9880 | mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 9881 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9882 | |
9883 | tapOnWindow(); | ||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 9884 | const auto& [downSequenceNum, _] = mWindow->receiveEvent(); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9885 | ASSERT_TRUE(downSequenceNum); |
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 9886 | const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent(); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9887 | ASSERT_TRUE(upSequenceNum); |
9888 | // Don't finish the events yet, and send a key | ||||
Siarhei Vishniakou | 67bf216 | 2023-11-16 13:29:50 -0800 | [diff] [blame] | 9889 | mDispatcher->notifyKey( |
9890 | KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD) | ||||
9891 | .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT) | ||||
9892 | .build()); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9893 | // At this point, key is still pending, and should not be sent to the application yet. |
Siarhei Vishniakou | ef2b450 | 2023-12-28 11:51:47 -0800 | [diff] [blame] | 9894 | mWindow->assertNoEvents(100ms); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9895 | |
9896 | // Now tap down again. It should cause the pending key to go to the focused window right away. | ||||
9897 | tapOnWindow(); | ||||
Siarhei Vishniakou | ef2b450 | 2023-12-28 11:51:47 -0800 | [diff] [blame] | 9898 | // Now that we tapped, we should receive the key immediately. |
9899 | // Since there's still room for slowness, we use 200ms, which is much less than | ||||
9900 | // the "key waiting for events' timeout of 500ms minus the already waited 100ms duration. | ||||
9901 | std::unique_ptr<InputEvent> keyEvent = mWindow->consume(200ms); | ||||
9902 | ASSERT_NE(nullptr, keyEvent); | ||||
9903 | ASSERT_EQ(InputEventType::KEY, keyEvent->getType()); | ||||
9904 | ASSERT_THAT(static_cast<KeyEvent&>(*keyEvent), WithKeyAction(AKEY_EVENT_ACTION_DOWN)); | ||||
9905 | // it doesn't matter that we haven't ack'd the other events yet. We can finish events in any | ||||
9906 | // order. | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9907 | mWindow->finishEvent(*downSequenceNum); // first tap's ACTION_DOWN |
9908 | mWindow->finishEvent(*upSequenceNum); // first tap's ACTION_UP | ||||
Siarhei Vishniakou | 67bf216 | 2023-11-16 13:29:50 -0800 | [diff] [blame] | 9909 | mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); |
9910 | mWindow->consumeMotionEvent(WithMotionAction(ACTION_UP)); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 9911 | mWindow->assertNoEvents(); |
9912 | } | ||||
9913 | |||||
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 9914 | /** |
9915 | * Send an event to the app and have the app not respond right away. | ||||
9916 | * When ANR is raised, policy will tell the dispatcher to cancel the events for that window. | ||||
9917 | * So InputDispatcher will enqueue ACTION_CANCEL event as well. | ||||
9918 | * At some point, the window becomes responsive again. | ||||
9919 | * Ensure that subsequent events get dropped, and the next gesture is delivered. | ||||
9920 | */ | ||||
9921 | TEST_F(InputDispatcherSingleWindowAnr, TwoGesturesWithAnr) { | ||||
9922 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
9923 | .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10)) | ||||
9924 | .build()); | ||||
9925 | |||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 9926 | const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN |
Siarhei Vishniakou | adb9fc9 | 2023-05-26 10:46:09 -0700 | [diff] [blame] | 9927 | ASSERT_TRUE(sequenceNum); |
9928 | const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); | ||||
9929 | mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow); | ||||
9930 | |||||
9931 | mWindow->finishEvent(*sequenceNum); | ||||
9932 | mWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); | ||||
9933 | ASSERT_TRUE(mDispatcher->waitForIdle()); | ||||
9934 | mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid()); | ||||
9935 | |||||
9936 | // Now that the window is responsive, let's continue the gesture. | ||||
9937 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
9938 | .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11)) | ||||
9939 | .build()); | ||||
9940 | |||||
9941 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
9942 | .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11)) | ||||
9943 | .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3)) | ||||
9944 | .build()); | ||||
9945 | |||||
9946 | mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
9947 | .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11)) | ||||
9948 | .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3)) | ||||
9949 | .build()); | ||||
9950 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
9951 | .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11)) | ||||
9952 | .build()); | ||||
9953 | // We already canceled this pointer, so the window shouldn't get any new events. | ||||
9954 | mWindow->assertNoEvents(); | ||||
9955 | |||||
9956 | // Start another one. | ||||
9957 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
9958 | .pointer(PointerBuilder(0, ToolType::FINGER).x(15).y(15)) | ||||
9959 | .build()); | ||||
9960 | mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); | ||||
9961 | } | ||||
9962 | |||||
Prabir Pradhan | fc36472 | 2024-02-08 17:51:20 +0000 | [diff] [blame] | 9963 | // Send an event to the app and have the app not respond right away. Then remove the app window. |
9964 | // When the window is removed, the dispatcher will cancel the events for that window. | ||||
9965 | // So InputDispatcher will enqueue ACTION_CANCEL event as well. | ||||
9966 | TEST_F(InputDispatcherSingleWindowAnr, AnrAfterWindowRemoval) { | ||||
9967 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, | ||||
9968 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
9969 | {WINDOW_LOCATION})); | ||||
9970 | |||||
9971 | const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN | ||||
9972 | ASSERT_TRUE(sequenceNum); | ||||
9973 | |||||
9974 | // Remove the window, but the input channel should remain alive. | ||||
9975 | mDispatcher->onWindowInfosChanged({{}, {}, 0, 0}); | ||||
9976 | |||||
9977 | const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); | ||||
9978 | // Since the window was removed, Dispatcher does not know the PID associated with the window | ||||
9979 | // anymore, so the policy is notified without the PID. | ||||
9980 | mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken(), | ||||
9981 | /*pid=*/std::nullopt); | ||||
9982 | |||||
9983 | mWindow->finishEvent(*sequenceNum); | ||||
9984 | // The cancellation was generated when the window was removed, along with the focus event. | ||||
9985 | mWindow->consumeMotionEvent( | ||||
9986 | AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT))); | ||||
9987 | mWindow->consumeFocusEvent(false); | ||||
9988 | ASSERT_TRUE(mDispatcher->waitForIdle()); | ||||
9989 | mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt); | ||||
9990 | } | ||||
9991 | |||||
9992 | // Send an event to the app and have the app not respond right away. Wait for the policy to be | ||||
9993 | // notified of the unresponsive window, then remove the app window. | ||||
9994 | TEST_F(InputDispatcherSingleWindowAnr, AnrFollowedByWindowRemoval) { | ||||
9995 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, | ||||
9996 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
9997 | {WINDOW_LOCATION})); | ||||
9998 | |||||
9999 | const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN | ||||
10000 | ASSERT_TRUE(sequenceNum); | ||||
10001 | const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); | ||||
10002 | mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow); | ||||
10003 | |||||
10004 | // Remove the window, but the input channel should remain alive. | ||||
10005 | mDispatcher->onWindowInfosChanged({{}, {}, 0, 0}); | ||||
10006 | |||||
10007 | mWindow->finishEvent(*sequenceNum); | ||||
10008 | // The cancellation was generated during the ANR, and the window lost focus when it was removed. | ||||
10009 | mWindow->consumeMotionEvent( | ||||
10010 | AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT))); | ||||
10011 | mWindow->consumeFocusEvent(false); | ||||
10012 | ASSERT_TRUE(mDispatcher->waitForIdle()); | ||||
10013 | // Since the window was removed, Dispatcher does not know the PID associated with the window | ||||
10014 | // becoming responsive, so the policy is notified without the PID. | ||||
10015 | mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt); | ||||
10016 | } | ||||
10017 | |||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10018 | class InputDispatcherMultiWindowAnr : public InputDispatcherTest { |
10019 | virtual void SetUp() override { | ||||
10020 | InputDispatcherTest::SetUp(); | ||||
10021 | |||||
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 10022 | mApplication = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | f83c693 | 2023-07-07 17:48:10 -0700 | [diff] [blame] | 10023 | mApplication->setDispatchingTimeout(100ms); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 10024 | mUnfocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Unfocused", |
10025 | ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10026 | mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10027 | // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped |
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 10028 | mUnfocusedWindow->setWatchOutsideTouch(true); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10029 | |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 10030 | mFocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Focused", |
10031 | ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | f83c693 | 2023-07-07 17:48:10 -0700 | [diff] [blame] | 10032 | mFocusedWindow->setDispatchingTimeout(100ms); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10033 | mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10034 | |
10035 | // Set focused application. | ||||
10036 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); | ||||
Vishnu Nair | 47074b8 | 2020-08-14 11:54:47 -0700 | [diff] [blame] | 10037 | mFocusedWindow->setFocusable(true); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10038 | |
10039 | // Expect one focus window exist in display. | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10040 | mDispatcher->onWindowInfosChanged( |
10041 | {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0}); | ||||
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10042 | setFocusedWindow(mFocusedWindow); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10043 | mFocusedWindow->consumeFocusEvent(true); |
10044 | } | ||||
10045 | |||||
10046 | virtual void TearDown() override { | ||||
10047 | InputDispatcherTest::TearDown(); | ||||
10048 | |||||
10049 | mUnfocusedWindow.clear(); | ||||
10050 | mFocusedWindow.clear(); | ||||
10051 | } | ||||
10052 | |||||
10053 | protected: | ||||
Chris Ye | a209fde | 2020-07-22 13:54:51 -0700 | [diff] [blame] | 10054 | std::shared_ptr<FakeApplicationHandle> mApplication; |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10055 | sp<FakeWindowHandle> mUnfocusedWindow; |
10056 | sp<FakeWindowHandle> mFocusedWindow; | ||||
10057 | static constexpr PointF UNFOCUSED_WINDOW_LOCATION = {20, 20}; | ||||
10058 | static constexpr PointF FOCUSED_WINDOW_LOCATION = {75, 75}; | ||||
10059 | static constexpr PointF LOCATION_OUTSIDE_ALL_WINDOWS = {40, 40}; | ||||
10060 | |||||
10061 | void tapOnFocusedWindow() { tap(FOCUSED_WINDOW_LOCATION); } | ||||
10062 | |||||
10063 | void tapOnUnfocusedWindow() { tap(UNFOCUSED_WINDOW_LOCATION); } | ||||
10064 | |||||
10065 | private: | ||||
10066 | void tap(const PointF& location) { | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10067 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10068 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10069 | location)); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10070 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10071 | injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10072 | location)); |
10073 | } | ||||
10074 | }; | ||||
10075 | |||||
10076 | // If we have 2 windows that are both unresponsive, the one with the shortest timeout | ||||
10077 | // should be ANR'd first. | ||||
10078 | TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) { | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10079 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 10080 | injectMotionEvent(*mDispatcher, |
10081 | MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, | ||||
10082 | AINPUT_SOURCE_TOUCHSCREEN) | ||||
10083 | .pointer(PointerBuilder(0, ToolType::FINGER) | ||||
10084 | .x(FOCUSED_WINDOW_LOCATION.x) | ||||
10085 | .y(FOCUSED_WINDOW_LOCATION.y)) | ||||
10086 | .build())); | ||||
10087 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
10088 | injectMotionEvent(*mDispatcher, | ||||
10089 | MotionEventBuilder(AMOTION_EVENT_ACTION_UP, | ||||
10090 | AINPUT_SOURCE_TOUCHSCREEN) | ||||
10091 | .pointer(PointerBuilder(0, ToolType::FINGER) | ||||
10092 | .x(FOCUSED_WINDOW_LOCATION.x) | ||||
10093 | .y(FOCUSED_WINDOW_LOCATION.y)) | ||||
10094 | .build())); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10095 | mFocusedWindow->consumeMotionDown(); |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 10096 | mFocusedWindow->consumeMotionUp(); |
Prabir Pradhan | 7662a8d | 2023-12-15 01:58:14 +0000 | [diff] [blame] | 10097 | mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10098 | // We consumed all events, so no ANR |
10099 | ASSERT_TRUE(mDispatcher->waitForIdle()); | ||||
10100 | mFakePolicy->assertNotifyAnrWasNotCalled(); | ||||
10101 | |||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10102 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 10103 | injectMotionEvent(*mDispatcher, |
10104 | MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, | ||||
10105 | AINPUT_SOURCE_TOUCHSCREEN) | ||||
10106 | .pointer(PointerBuilder(0, ToolType::FINGER) | ||||
10107 | .x(FOCUSED_WINDOW_LOCATION.x) | ||||
10108 | .y(FOCUSED_WINDOW_LOCATION.y)) | ||||
10109 | .build())); | ||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 10110 | const auto [unfocusedSequenceNum, _] = mUnfocusedWindow->receiveEvent(); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10111 | ASSERT_TRUE(unfocusedSequenceNum); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10112 | |
10113 | const std::chrono::duration timeout = | ||||
10114 | mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); | ||||
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 10115 | mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow); |
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 10116 | |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10117 | mUnfocusedWindow->finishEvent(*unfocusedSequenceNum); |
Siarhei Vishniakou | 234129c | 2020-10-22 22:28:12 -0500 | [diff] [blame] | 10118 | mFocusedWindow->consumeMotionDown(); |
10119 | // This cancel is generated because the connection was unresponsive | ||||
10120 | mFocusedWindow->consumeMotionCancel(); | ||||
10121 | mFocusedWindow->assertNoEvents(); | ||||
10122 | mUnfocusedWindow->assertNoEvents(); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10123 | ASSERT_TRUE(mDispatcher->waitForIdle()); |
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 10124 | mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(), |
10125 | mFocusedWindow->getPid()); | ||||
Siarhei Vishniakou | 234129c | 2020-10-22 22:28:12 -0500 | [diff] [blame] | 10126 | mFakePolicy->assertNotifyAnrWasNotCalled(); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10127 | } |
10128 | |||||
10129 | // If we have 2 windows with identical timeouts that are both unresponsive, | ||||
10130 | // it doesn't matter which order they should have ANR. | ||||
10131 | // But we should receive ANR for both. | ||||
10132 | TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout) { | ||||
10133 | // Set the timeout for unfocused window to match the focused window | ||||
Siarhei Vishniakou | f83c693 | 2023-07-07 17:48:10 -0700 | [diff] [blame] | 10134 | mUnfocusedWindow->setDispatchingTimeout( |
10135 | mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT)); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10136 | mDispatcher->onWindowInfosChanged( |
10137 | {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10138 | |
10139 | tapOnFocusedWindow(); | ||||
10140 | // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10141 | // We don't know which window will ANR first. But both of them should happen eventually. |
Siarhei Vishniakou | f83c693 | 2023-07-07 17:48:10 -0700 | [diff] [blame] | 10142 | std::array<sp<IBinder>, 2> anrConnectionTokens = {mFakePolicy->getUnresponsiveWindowToken( |
10143 | mFocusedWindow->getDispatchingTimeout( | ||||
10144 | DISPATCHING_TIMEOUT)), | ||||
10145 | mFakePolicy->getUnresponsiveWindowToken(0ms)}; | ||||
10146 | |||||
10147 | ASSERT_THAT(anrConnectionTokens, | ||||
10148 | ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()), | ||||
10149 | testing::Eq(mUnfocusedWindow->getToken()))); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10150 | |
10151 | ASSERT_TRUE(mDispatcher->waitForIdle()); | ||||
10152 | mFakePolicy->assertNotifyAnrWasNotCalled(); | ||||
Siarhei Vishniakou | 234129c | 2020-10-22 22:28:12 -0500 | [diff] [blame] | 10153 | |
10154 | mFocusedWindow->consumeMotionDown(); | ||||
10155 | mFocusedWindow->consumeMotionUp(); | ||||
10156 | mUnfocusedWindow->consumeMotionOutside(); | ||||
10157 | |||||
Siarhei Vishniakou | f83c693 | 2023-07-07 17:48:10 -0700 | [diff] [blame] | 10158 | std::array<sp<IBinder>, 2> responsiveTokens = {mFakePolicy->getResponsiveWindowToken(), |
10159 | mFakePolicy->getResponsiveWindowToken()}; | ||||
Siarhei Vishniakou | 234129c | 2020-10-22 22:28:12 -0500 | [diff] [blame] | 10160 | |
10161 | // Both applications should be marked as responsive, in any order | ||||
Siarhei Vishniakou | f83c693 | 2023-07-07 17:48:10 -0700 | [diff] [blame] | 10162 | ASSERT_THAT(responsiveTokens, |
10163 | ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()), | ||||
10164 | testing::Eq(mUnfocusedWindow->getToken()))); | ||||
Siarhei Vishniakou | 234129c | 2020-10-22 22:28:12 -0500 | [diff] [blame] | 10165 | mFakePolicy->assertNotifyAnrWasNotCalled(); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10166 | } |
10167 | |||||
10168 | // If a window is already not responding, the second tap on the same window should be ignored. | ||||
10169 | // We should also log an error to account for the dropped event (not tested here). | ||||
10170 | // At the same time, FLAG_WATCH_OUTSIDE_TOUCH targets should not receive any events. | ||||
10171 | TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) { | ||||
10172 | tapOnFocusedWindow(); | ||||
Prabir Pradhan | 7662a8d | 2023-12-15 01:58:14 +0000 | [diff] [blame] | 10173 | mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10174 | // Receive the events, but don't respond |
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 10175 | const auto [downEventSequenceNum, downEvent] = mFocusedWindow->receiveEvent(); // ACTION_DOWN |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10176 | ASSERT_TRUE(downEventSequenceNum); |
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 10177 | const auto [upEventSequenceNum, upEvent] = mFocusedWindow->receiveEvent(); // ACTION_UP |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10178 | ASSERT_TRUE(upEventSequenceNum); |
10179 | const std::chrono::duration timeout = | ||||
10180 | mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); | ||||
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 10181 | mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10182 | |
10183 | // Tap once again | ||||
10184 | // We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10185 | ASSERT_EQ(InputEventInjectionResult::FAILED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10186 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10187 | FOCUSED_WINDOW_LOCATION)); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10188 | ASSERT_EQ(InputEventInjectionResult::FAILED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10189 | injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10190 | FOCUSED_WINDOW_LOCATION)); |
10191 | // Unfocused window does not receive ACTION_OUTSIDE because the tapped window is not a | ||||
10192 | // valid touch target | ||||
10193 | mUnfocusedWindow->assertNoEvents(); | ||||
10194 | |||||
10195 | // Consume the first tap | ||||
10196 | mFocusedWindow->finishEvent(*downEventSequenceNum); | ||||
10197 | mFocusedWindow->finishEvent(*upEventSequenceNum); | ||||
10198 | ASSERT_TRUE(mDispatcher->waitForIdle()); | ||||
10199 | // The second tap did not go to the focused window | ||||
10200 | mFocusedWindow->assertNoEvents(); | ||||
Siarhei Vishniakou | 234129c | 2020-10-22 22:28:12 -0500 | [diff] [blame] | 10201 | // Since all events are finished, connection should be deemed healthy again |
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 10202 | mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(), |
10203 | mFocusedWindow->getPid()); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10204 | mFakePolicy->assertNotifyAnrWasNotCalled(); |
10205 | } | ||||
10206 | |||||
10207 | // If you tap outside of all windows, there will not be ANR | ||||
10208 | TEST_F(InputDispatcherMultiWindowAnr, TapOutsideAllWindows_DoesNotAnr) { | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10209 | ASSERT_EQ(InputEventInjectionResult::FAILED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10210 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10211 | LOCATION_OUTSIDE_ALL_WINDOWS)); |
10212 | ASSERT_TRUE(mDispatcher->waitForIdle()); | ||||
10213 | mFakePolicy->assertNotifyAnrWasNotCalled(); | ||||
10214 | } | ||||
10215 | |||||
10216 | // Since the focused window is paused, tapping on it should not produce any events | ||||
10217 | TEST_F(InputDispatcherMultiWindowAnr, Window_CanBePaused) { | ||||
10218 | mFocusedWindow->setPaused(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10219 | mDispatcher->onWindowInfosChanged( |
10220 | {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10221 | |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10222 | ASSERT_EQ(InputEventInjectionResult::FAILED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10223 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10224 | FOCUSED_WINDOW_LOCATION)); |
10225 | |||||
10226 | std::this_thread::sleep_for(mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT)); | ||||
10227 | ASSERT_TRUE(mDispatcher->waitForIdle()); | ||||
10228 | // Should not ANR because the window is paused, and touches shouldn't go to it | ||||
10229 | mFakePolicy->assertNotifyAnrWasNotCalled(); | ||||
10230 | |||||
10231 | mFocusedWindow->assertNoEvents(); | ||||
10232 | mUnfocusedWindow->assertNoEvents(); | ||||
10233 | } | ||||
10234 | |||||
10235 | /** | ||||
10236 | * If a window is processing a motion event, and then a key event comes in, the key event should | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10237 | * not get delivered to the focused window until the motion is processed. |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10238 | * If a different window becomes focused at this time, the key should go to that window instead. |
10239 | * | ||||
10240 | * Warning!!! | ||||
10241 | * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT | ||||
10242 | * and the injection timeout that we specify when injecting the key. | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10243 | * We must have the injection timeout (100ms) be smaller than |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10244 | * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms). |
10245 | * | ||||
10246 | * If that value changes, this test should also change. | ||||
10247 | */ | ||||
10248 | TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) { | ||||
10249 | // Set a long ANR timeout to prevent it from triggering | ||||
10250 | mFocusedWindow->setDispatchingTimeout(2s); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10251 | mDispatcher->onWindowInfosChanged( |
10252 | {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10253 | |
10254 | tapOnUnfocusedWindow(); | ||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 10255 | const auto [downSequenceNum, downEvent] = mUnfocusedWindow->receiveEvent(); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10256 | ASSERT_TRUE(downSequenceNum); |
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 10257 | const auto [upSequenceNum, upEvent] = mUnfocusedWindow->receiveEvent(); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10258 | ASSERT_TRUE(upSequenceNum); |
10259 | // Don't finish the events yet, and send a key | ||||
10260 | // Injection will succeed because we will eventually give up and send the key to the focused | ||||
10261 | // window even if motions are still being processed. | ||||
10262 | |||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10263 | InputEventInjectionResult result = |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10264 | injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, |
10265 | InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms); | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10266 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10267 | // Key will not be sent to the window, yet, because the window is still processing events |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10268 | // and the key remains pending, waiting for the touch events to be processed. |
10269 | // Make sure `assertNoEvents` doesn't take too long. It uses CONSUME_TIMEOUT_NO_EVENT_EXPECTED | ||||
10270 | // under the hood. | ||||
10271 | static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms); | ||||
10272 | mFocusedWindow->assertNoEvents(); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10273 | |
10274 | // Switch the focus to the "unfocused" window that we tapped. Expect the key to go there | ||||
Vishnu Nair | 47074b8 | 2020-08-14 11:54:47 -0700 | [diff] [blame] | 10275 | mFocusedWindow->setFocusable(false); |
10276 | mUnfocusedWindow->setFocusable(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10277 | mDispatcher->onWindowInfosChanged( |
10278 | {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0}); | ||||
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10279 | setFocusedWindow(mUnfocusedWindow); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10280 | |
10281 | // Focus events should precede the key events | ||||
10282 | mUnfocusedWindow->consumeFocusEvent(true); | ||||
10283 | mFocusedWindow->consumeFocusEvent(false); | ||||
10284 | |||||
10285 | // Finish the tap events, which should unblock dispatcher | ||||
10286 | mUnfocusedWindow->finishEvent(*downSequenceNum); | ||||
10287 | mUnfocusedWindow->finishEvent(*upSequenceNum); | ||||
10288 | |||||
10289 | // Now that all queues are cleared and no backlog in the connections, the key event | ||||
10290 | // can finally go to the newly focused "mUnfocusedWindow". | ||||
10291 | mUnfocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); | ||||
10292 | mFocusedWindow->assertNoEvents(); | ||||
10293 | mUnfocusedWindow->assertNoEvents(); | ||||
Siarhei Vishniakou | 234129c | 2020-10-22 22:28:12 -0500 | [diff] [blame] | 10294 | mFakePolicy->assertNotifyAnrWasNotCalled(); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10295 | } |
10296 | |||||
10297 | // When the touch stream is split across 2 windows, and one of them does not respond, | ||||
10298 | // then ANR should be raised and the touch should be canceled for the unresponsive window. | ||||
10299 | // The other window should not be affected by that. | ||||
10300 | TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) { | ||||
10301 | // Touch Window 1 | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 10302 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
10303 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
10304 | {FOCUSED_WINDOW_LOCATION})); | ||||
Prabir Pradhan | 7662a8d | 2023-12-15 01:58:14 +0000 | [diff] [blame] | 10305 | mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10306 | |
10307 | // Touch Window 2 | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 10308 | mDispatcher->notifyMotion( |
10309 | generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
10310 | {FOCUSED_WINDOW_LOCATION, UNFOCUSED_WINDOW_LOCATION})); | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10311 | |
10312 | const std::chrono::duration timeout = | ||||
10313 | mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); | ||||
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 10314 | mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10315 | |
10316 | mUnfocusedWindow->consumeMotionDown(); | ||||
10317 | mFocusedWindow->consumeMotionDown(); | ||||
10318 | // Focused window may or may not receive ACTION_MOVE | ||||
10319 | // But it should definitely receive ACTION_CANCEL due to the ANR | ||||
Siarhei Vishniakou | d3061ab | 2023-12-18 20:41:08 -0800 | [diff] [blame] | 10320 | const auto [moveOrCancelSequenceNum, event] = mFocusedWindow->receiveEvent(); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10321 | ASSERT_TRUE(moveOrCancelSequenceNum); |
10322 | mFocusedWindow->finishEvent(*moveOrCancelSequenceNum); | ||||
10323 | ASSERT_NE(nullptr, event); | ||||
Siarhei Vishniakou | 63b6361 | 2023-04-12 11:00:23 -0700 | [diff] [blame] | 10324 | ASSERT_EQ(event->getType(), InputEventType::MOTION); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10325 | MotionEvent& motionEvent = static_cast<MotionEvent&>(*event); |
10326 | if (motionEvent.getAction() == AMOTION_EVENT_ACTION_MOVE) { | ||||
10327 | mFocusedWindow->consumeMotionCancel(); | ||||
10328 | } else { | ||||
10329 | ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionEvent.getAction()); | ||||
10330 | } | ||||
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10331 | ASSERT_TRUE(mDispatcher->waitForIdle()); |
Prabir Pradhan | edd9640 | 2022-02-15 01:46:16 -0800 | [diff] [blame] | 10332 | mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(), |
10333 | mFocusedWindow->getPid()); | ||||
Siarhei Vishniakou | 234129c | 2020-10-22 22:28:12 -0500 | [diff] [blame] | 10334 | |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10335 | mUnfocusedWindow->assertNoEvents(); |
10336 | mFocusedWindow->assertNoEvents(); | ||||
Siarhei Vishniakou | 234129c | 2020-10-22 22:28:12 -0500 | [diff] [blame] | 10337 | mFakePolicy->assertNotifyAnrWasNotCalled(); |
Siarhei Vishniakou | d44dddf | 2020-03-25 16:16:40 -0700 | [diff] [blame] | 10338 | } |
10339 | |||||
Siarhei Vishniakou | f56b269 | 2020-09-08 19:43:33 -0500 | [diff] [blame] | 10340 | /** |
10341 | * If we have no focused window, and a key comes in, we start the ANR timer. | ||||
10342 | * The focused application should add a focused window before the timer runs out to prevent ANR. | ||||
10343 | * | ||||
10344 | * If the user touches another application during this time, the key should be dropped. | ||||
10345 | * Next, if a new focused window comes in, without toggling the focused application, | ||||
10346 | * then no ANR should occur. | ||||
10347 | * | ||||
10348 | * Normally, we would expect the new focused window to be accompanied by 'setFocusedApplication', | ||||
10349 | * but in some cases the policy may not update the focused application. | ||||
10350 | */ | ||||
10351 | TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) { | ||||
10352 | std::shared_ptr<FakeApplicationHandle> focusedApplication = | ||||
10353 | std::make_shared<FakeApplicationHandle>(); | ||||
Siarhei Vishniakou | c033dfb | 2023-10-03 10:45:16 -0700 | [diff] [blame] | 10354 | focusedApplication->setDispatchingTimeout(300ms); |
Siarhei Vishniakou | f56b269 | 2020-09-08 19:43:33 -0500 | [diff] [blame] | 10355 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, focusedApplication); |
10356 | // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused. | ||||
10357 | mFocusedWindow->setFocusable(false); | ||||
10358 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10359 | mDispatcher->onWindowInfosChanged( |
10360 | {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | f56b269 | 2020-09-08 19:43:33 -0500 | [diff] [blame] | 10361 | mFocusedWindow->consumeFocusEvent(false); |
10362 | |||||
10363 | // Send a key. The ANR timer should start because there is no focused window. | ||||
10364 | // 'focusedApplication' will get blamed if this timer completes. | ||||
10365 | // Key will not be sent anywhere because we have no focused window. It will remain pending. | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10366 | InputEventInjectionResult result = |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10367 | injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, |
10368 | InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms, | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 10369 | /*allowKeyRepeat=*/false); |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10370 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result); |
Siarhei Vishniakou | f56b269 | 2020-09-08 19:43:33 -0500 | [diff] [blame] | 10371 | |
10372 | // Wait until dispatcher starts the "no focused window" timer. If we don't wait here, | ||||
10373 | // then the injected touches won't cause the focused event to get dropped. | ||||
10374 | // The dispatcher only checks for whether the queue should be pruned upon queueing. | ||||
10375 | // If we inject the touch right away and the ANR timer hasn't started, the touch event would | ||||
10376 | // simply be added to the queue without 'shouldPruneInboundQueueLocked' returning 'true'. | ||||
10377 | // For this test, it means that the key would get delivered to the window once it becomes | ||||
10378 | // focused. | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10379 | std::this_thread::sleep_for(100ms); |
Siarhei Vishniakou | f56b269 | 2020-09-08 19:43:33 -0500 | [diff] [blame] | 10380 | |
10381 | // Touch unfocused window. This should force the pending key to get dropped. | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 10382 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
10383 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
10384 | {UNFOCUSED_WINDOW_LOCATION})); | ||||
Siarhei Vishniakou | f56b269 | 2020-09-08 19:43:33 -0500 | [diff] [blame] | 10385 | |
10386 | // We do not consume the motion right away, because that would require dispatcher to first | ||||
10387 | // process (== drop) the key event, and by that time, ANR will be raised. | ||||
10388 | // Set the focused window first. | ||||
10389 | mFocusedWindow->setFocusable(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10390 | mDispatcher->onWindowInfosChanged( |
10391 | {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | f56b269 | 2020-09-08 19:43:33 -0500 | [diff] [blame] | 10392 | setFocusedWindow(mFocusedWindow); |
10393 | mFocusedWindow->consumeFocusEvent(true); | ||||
10394 | // We do not call "setFocusedApplication" here, even though the newly focused window belongs | ||||
10395 | // to another application. This could be a bug / behaviour in the policy. | ||||
10396 | |||||
10397 | mUnfocusedWindow->consumeMotionDown(); | ||||
10398 | |||||
10399 | ASSERT_TRUE(mDispatcher->waitForIdle()); | ||||
10400 | // Should not ANR because we actually have a focused window. It was just added too slowly. | ||||
10401 | ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyAnrWasNotCalled()); | ||||
10402 | } | ||||
10403 | |||||
Siarhei Vishniakou | 99e407b | 2023-12-26 18:09:32 -0800 | [diff] [blame] | 10404 | /** |
10405 | * If we are pruning input queue, we should never drop pointer events. Otherwise, we risk having | ||||
10406 | * an inconsistent event stream inside the dispatcher. In this test, we make sure that the | ||||
10407 | * dispatcher doesn't prune pointer events incorrectly. | ||||
10408 | * | ||||
10409 | * This test reproduces a crash in InputDispatcher. | ||||
10410 | * To reproduce the crash, we need to simulate the conditions for "pruning input queue" to occur. | ||||
10411 | * | ||||
10412 | * Keep the currently focused application (mApplication), and have no focused window. | ||||
10413 | * We set up two additional windows: | ||||
10414 | * 1) The navigation bar window. This simulates the system "NavigationBar", which is used in the | ||||
10415 | * 3-button navigation mode. This window injects a BACK button when it's touched. 2) The application | ||||
10416 | * window. This window is not focusable, but is touchable. | ||||
10417 | * | ||||
10418 | * We first touch the navigation bar, which causes it to inject a key. Since there's no focused | ||||
10419 | * window, the dispatcher doesn't process this key, and all other events inside dispatcher are now | ||||
10420 | * blocked. The dispatcher is waiting for 'mApplication' to add a focused window. | ||||
10421 | * | ||||
10422 | * Now, we touch "Another window". This window is owned by a different application than | ||||
10423 | * 'mApplication'. This causes the dispatcher to stop waiting for 'mApplication' to add a focused | ||||
10424 | * window. Now, the "pruning input queue" behaviour should kick in, and the dispatcher should start | ||||
10425 | * dropping the events from its queue. Ensure that no crash occurs. | ||||
10426 | * | ||||
10427 | * In this test, we are setting long timeouts to prevent ANRs and events dropped due to being stale. | ||||
10428 | * This does not affect the test running time. | ||||
10429 | */ | ||||
10430 | TEST_F(InputDispatcherMultiWindowAnr, PruningInputQueueShouldNotDropPointerEvents) { | ||||
10431 | std::shared_ptr<FakeApplicationHandle> systemUiApplication = | ||||
10432 | std::make_shared<FakeApplicationHandle>(); | ||||
10433 | systemUiApplication->setDispatchingTimeout(3000ms); | ||||
10434 | mFakePolicy->setStaleEventTimeout(3000ms); | ||||
10435 | sp<FakeWindowHandle> navigationBar = | ||||
10436 | sp<FakeWindowHandle>::make(systemUiApplication, mDispatcher, "NavigationBar", | ||||
10437 | ADISPLAY_ID_DEFAULT); | ||||
10438 | navigationBar->setFocusable(false); | ||||
10439 | navigationBar->setWatchOutsideTouch(true); | ||||
10440 | navigationBar->setFrame(Rect(0, 0, 100, 100)); | ||||
10441 | |||||
10442 | mApplication->setDispatchingTimeout(3000ms); | ||||
10443 | // 'mApplication' is already focused, but we call it again here to make it explicit. | ||||
10444 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); | ||||
10445 | |||||
10446 | std::shared_ptr<FakeApplicationHandle> anotherApplication = | ||||
10447 | std::make_shared<FakeApplicationHandle>(); | ||||
10448 | sp<FakeWindowHandle> appWindow = | ||||
10449 | sp<FakeWindowHandle>::make(anotherApplication, mDispatcher, "Another window", | ||||
10450 | ADISPLAY_ID_DEFAULT); | ||||
10451 | appWindow->setFocusable(false); | ||||
10452 | appWindow->setFrame(Rect(100, 100, 200, 200)); | ||||
10453 | |||||
10454 | mDispatcher->onWindowInfosChanged( | ||||
10455 | {{*navigationBar->getInfo(), *appWindow->getInfo()}, {}, 0, 0}); | ||||
10456 | // 'mFocusedWindow' is no longer in the dispatcher window list, and therefore loses focus | ||||
10457 | mFocusedWindow->consumeFocusEvent(false); | ||||
10458 | |||||
10459 | // Touch down the navigation bar. It consumes the touch and injects a key into the dispatcher | ||||
10460 | // in response. | ||||
10461 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
10462 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
10463 | .build()); | ||||
10464 | navigationBar->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); | ||||
10465 | |||||
10466 | // Key will not be sent anywhere because we have no focused window. It will remain pending. | ||||
10467 | // Pretend we are injecting KEYCODE_BACK, but it doesn't actually matter what key it is. | ||||
10468 | InputEventInjectionResult result = | ||||
10469 | injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, | ||||
10470 | InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms, | ||||
10471 | /*allowKeyRepeat=*/false); | ||||
10472 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result); | ||||
10473 | |||||
10474 | // Finish the gesture - lift up finger and inject ACTION_UP key event | ||||
10475 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
10476 | .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) | ||||
10477 | .build()); | ||||
10478 | result = injectKey(*mDispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, | ||||
10479 | InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms, | ||||
10480 | /*allowKeyRepeat=*/false); | ||||
10481 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result); | ||||
10482 | // The key that was injected is blocking the dispatcher, so the navigation bar shouldn't be | ||||
10483 | // getting any events yet. | ||||
10484 | navigationBar->assertNoEvents(); | ||||
10485 | |||||
10486 | // Now touch "Another window". This touch is going to a different application than the one we | ||||
10487 | // are waiting for (which is 'mApplication'). | ||||
10488 | // This should cause the dispatcher to drop the pending focus-dispatched events (like the key | ||||
10489 | // trying to be injected) and to continue processing the rest of the events in the original | ||||
10490 | // order. | ||||
10491 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
10492 | .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150)) | ||||
10493 | .build()); | ||||
10494 | navigationBar->consumeMotionEvent(WithMotionAction(ACTION_UP)); | ||||
10495 | navigationBar->consumeMotionEvent(WithMotionAction(ACTION_OUTSIDE)); | ||||
10496 | appWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); | ||||
10497 | |||||
10498 | appWindow->assertNoEvents(); | ||||
10499 | navigationBar->assertNoEvents(); | ||||
10500 | } | ||||
10501 | |||||
Siarhei Vishniakou | a2862a0 | 2020-07-20 16:36:46 -0500 | [diff] [blame] | 10502 | // These tests ensure we cannot send touch events to a window that's positioned behind a window |
10503 | // that has feature NO_INPUT_CHANNEL. | ||||
10504 | // Layout: | ||||
10505 | // Top (closest to user) | ||||
10506 | // mNoInputWindow (above all windows) | ||||
10507 | // mBottomWindow | ||||
10508 | // Bottom (furthest from user) | ||||
10509 | class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest { | ||||
10510 | virtual void SetUp() override { | ||||
10511 | InputDispatcherTest::SetUp(); | ||||
10512 | |||||
10513 | mApplication = std::make_shared<FakeApplicationHandle>(); | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 10514 | mNoInputWindow = |
10515 | sp<FakeWindowHandle>::make(mApplication, mDispatcher, | ||||
10516 | "Window without input channel", ADISPLAY_ID_DEFAULT, | ||||
Prabir Pradhan | e7cc69c | 2024-01-05 21:35:28 +0000 | [diff] [blame] | 10517 | /*createInputChannel=*/false); |
Prabir Pradhan | 51e7db0 | 2022-02-07 06:02:57 -0800 | [diff] [blame] | 10518 | mNoInputWindow->setNoInputChannel(true); |
Siarhei Vishniakou | a2862a0 | 2020-07-20 16:36:46 -0500 | [diff] [blame] | 10519 | mNoInputWindow->setFrame(Rect(0, 0, 100, 100)); |
10520 | // It's perfectly valid for this window to not have an associated input channel | ||||
10521 | |||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 10522 | mBottomWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Bottom window", |
10523 | ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | a2862a0 | 2020-07-20 16:36:46 -0500 | [diff] [blame] | 10524 | mBottomWindow->setFrame(Rect(0, 0, 100, 100)); |
10525 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10526 | mDispatcher->onWindowInfosChanged( |
10527 | {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | a2862a0 | 2020-07-20 16:36:46 -0500 | [diff] [blame] | 10528 | } |
10529 | |||||
10530 | protected: | ||||
10531 | std::shared_ptr<FakeApplicationHandle> mApplication; | ||||
10532 | sp<FakeWindowHandle> mNoInputWindow; | ||||
10533 | sp<FakeWindowHandle> mBottomWindow; | ||||
10534 | }; | ||||
10535 | |||||
10536 | TEST_F(InputDispatcherMultiWindowOcclusionTests, NoInputChannelFeature_DropsTouches) { | ||||
10537 | PointF touchedPoint = {10, 10}; | ||||
10538 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 10539 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
10540 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
10541 | {touchedPoint})); | ||||
Siarhei Vishniakou | a2862a0 | 2020-07-20 16:36:46 -0500 | [diff] [blame] | 10542 | |
10543 | mNoInputWindow->assertNoEvents(); | ||||
10544 | // Even though the window 'mNoInputWindow' positioned above 'mBottomWindow' does not have | ||||
10545 | // an input channel, it is not marked as FLAG_NOT_TOUCHABLE, | ||||
10546 | // and therefore should prevent mBottomWindow from receiving touches | ||||
10547 | mBottomWindow->assertNoEvents(); | ||||
10548 | } | ||||
10549 | |||||
10550 | /** | ||||
10551 | * If a window has feature NO_INPUT_CHANNEL, and somehow (by mistake) still has an input channel, | ||||
10552 | * ensure that this window does not receive any touches, and blocks touches to windows underneath. | ||||
10553 | */ | ||||
10554 | TEST_F(InputDispatcherMultiWindowOcclusionTests, | ||||
10555 | NoInputChannelFeature_DropsTouchesWithValidChannel) { | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 10556 | mNoInputWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, |
10557 | "Window with input channel and NO_INPUT_CHANNEL", | ||||
10558 | ADISPLAY_ID_DEFAULT); | ||||
Siarhei Vishniakou | a2862a0 | 2020-07-20 16:36:46 -0500 | [diff] [blame] | 10559 | |
Prabir Pradhan | 51e7db0 | 2022-02-07 06:02:57 -0800 | [diff] [blame] | 10560 | mNoInputWindow->setNoInputChannel(true); |
Siarhei Vishniakou | a2862a0 | 2020-07-20 16:36:46 -0500 | [diff] [blame] | 10561 | mNoInputWindow->setFrame(Rect(0, 0, 100, 100)); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10562 | mDispatcher->onWindowInfosChanged( |
10563 | {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0}); | ||||
Siarhei Vishniakou | a2862a0 | 2020-07-20 16:36:46 -0500 | [diff] [blame] | 10564 | |
10565 | PointF touchedPoint = {10, 10}; | ||||
10566 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 10567 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
10568 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
10569 | {touchedPoint})); | ||||
Siarhei Vishniakou | a2862a0 | 2020-07-20 16:36:46 -0500 | [diff] [blame] | 10570 | |
10571 | mNoInputWindow->assertNoEvents(); | ||||
10572 | mBottomWindow->assertNoEvents(); | ||||
10573 | } | ||||
10574 | |||||
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10575 | class InputDispatcherMirrorWindowFocusTests : public InputDispatcherTest { |
10576 | protected: | ||||
10577 | std::shared_ptr<FakeApplicationHandle> mApp; | ||||
10578 | sp<FakeWindowHandle> mWindow; | ||||
10579 | sp<FakeWindowHandle> mMirror; | ||||
10580 | |||||
10581 | virtual void SetUp() override { | ||||
10582 | InputDispatcherTest::SetUp(); | ||||
10583 | mApp = std::make_shared<FakeApplicationHandle>(); | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 10584 | mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); |
Prabir Pradhan | e7cc69c | 2024-01-05 21:35:28 +0000 | [diff] [blame] | 10585 | mMirror = mWindow->clone(ADISPLAY_ID_DEFAULT); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10586 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); |
10587 | mWindow->setFocusable(true); | ||||
10588 | mMirror->setFocusable(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10589 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10590 | } |
10591 | }; | ||||
10592 | |||||
10593 | TEST_F(InputDispatcherMirrorWindowFocusTests, CanGetFocus) { | ||||
10594 | // Request focus on a mirrored window | ||||
10595 | setFocusedWindow(mMirror); | ||||
10596 | |||||
10597 | // window gets focused | ||||
10598 | mWindow->consumeFocusEvent(true); | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10599 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10600 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10601 | mWindow->consumeKeyDown(ADISPLAY_ID_NONE); |
10602 | } | ||||
10603 | |||||
10604 | // A focused & mirrored window remains focused only if the window and its mirror are both | ||||
10605 | // focusable. | ||||
10606 | TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAllWindowsFocusable) { | ||||
10607 | setFocusedWindow(mMirror); | ||||
10608 | |||||
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 10609 | // window gets focused because it is above the mirror |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10610 | mWindow->consumeFocusEvent(true); |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10611 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10612 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10613 | mWindow->consumeKeyDown(ADISPLAY_ID_NONE); |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10614 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10615 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10616 | mWindow->consumeKeyUp(ADISPLAY_ID_NONE); |
10617 | |||||
10618 | mMirror->setFocusable(false); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10619 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10620 | |
10621 | // window loses focus since one of the windows associated with the token in not focusable | ||||
10622 | mWindow->consumeFocusEvent(false); | ||||
10623 | |||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10624 | ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10625 | << "Inject key event should return InputEventInjectionResult::TIMED_OUT"; |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10626 | mWindow->assertNoEvents(); |
10627 | } | ||||
10628 | |||||
10629 | // A focused & mirrored window remains focused until the window and its mirror both become | ||||
10630 | // invisible. | ||||
10631 | TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAnyWindowVisible) { | ||||
10632 | setFocusedWindow(mMirror); | ||||
10633 | |||||
10634 | // window gets focused | ||||
10635 | mWindow->consumeFocusEvent(true); | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10636 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10637 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10638 | mWindow->consumeKeyDown(ADISPLAY_ID_NONE); |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10639 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10640 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10641 | mWindow->consumeKeyUp(ADISPLAY_ID_NONE); |
10642 | |||||
10643 | mMirror->setVisible(false); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10644 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10645 | |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10646 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10647 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10648 | mWindow->consumeKeyDown(ADISPLAY_ID_NONE); |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10649 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10650 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10651 | mWindow->consumeKeyUp(ADISPLAY_ID_NONE); |
10652 | |||||
10653 | mWindow->setVisible(false); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10654 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10655 | |
10656 | // window loses focus only after all windows associated with the token become invisible. | ||||
10657 | mWindow->consumeFocusEvent(false); | ||||
10658 | |||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10659 | ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10660 | << "Inject key event should return InputEventInjectionResult::TIMED_OUT"; |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10661 | mWindow->assertNoEvents(); |
10662 | } | ||||
10663 | |||||
10664 | // A focused & mirrored window remains focused until both windows are removed. | ||||
10665 | TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedWhileWindowsAlive) { | ||||
10666 | setFocusedWindow(mMirror); | ||||
10667 | |||||
10668 | // window gets focused | ||||
10669 | mWindow->consumeFocusEvent(true); | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10670 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10671 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10672 | mWindow->consumeKeyDown(ADISPLAY_ID_NONE); |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10673 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10674 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10675 | mWindow->consumeKeyUp(ADISPLAY_ID_NONE); |
10676 | |||||
10677 | // single window is removed but the window token remains focused | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10678 | mDispatcher->onWindowInfosChanged({{*mMirror->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10679 | |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10680 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10681 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 10682 | mMirror->consumeKeyDown(ADISPLAY_ID_NONE); |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10683 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10684 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
Prabir Pradhan | bb3f1c0 | 2024-01-04 20:17:14 +0000 | [diff] [blame] | 10685 | mMirror->consumeKeyUp(ADISPLAY_ID_NONE); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10686 | |
10687 | // Both windows are removed | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10688 | mDispatcher->onWindowInfosChanged({{}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10689 | mWindow->consumeFocusEvent(false); |
10690 | |||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10691 | ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher)) |
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10692 | << "Inject key event should return InputEventInjectionResult::TIMED_OUT"; |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10693 | mWindow->assertNoEvents(); |
10694 | } | ||||
10695 | |||||
10696 | // Focus request can be pending until one window becomes visible. | ||||
10697 | TEST_F(InputDispatcherMirrorWindowFocusTests, DeferFocusWhenInvisible) { | ||||
10698 | // Request focus on an invisible mirror. | ||||
10699 | mWindow->setVisible(false); | ||||
10700 | mMirror->setVisible(false); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10701 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10702 | setFocusedWindow(mMirror); |
10703 | |||||
10704 | // Injected key goes to pending queue. | ||||
Siarhei Vishniakou | ae6229e | 2019-12-30 16:23:19 -0800 | [diff] [blame] | 10705 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 10706 | injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, |
10707 | ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE)); | ||||
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10708 | |
10709 | mMirror->setVisible(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10710 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 958da93 | 2020-08-21 17:12:37 -0700 | [diff] [blame] | 10711 | |
10712 | // window gets focused | ||||
10713 | mWindow->consumeFocusEvent(true); | ||||
10714 | // window gets the pending key event | ||||
10715 | mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); | ||||
10716 | } | ||||
Prabir Pradhan | 9998771 | 2020-11-10 18:43:05 -0800 | [diff] [blame] | 10717 | |
10718 | class InputDispatcherPointerCaptureTests : public InputDispatcherTest { | ||||
10719 | protected: | ||||
10720 | std::shared_ptr<FakeApplicationHandle> mApp; | ||||
10721 | sp<FakeWindowHandle> mWindow; | ||||
10722 | sp<FakeWindowHandle> mSecondWindow; | ||||
10723 | |||||
10724 | void SetUp() override { | ||||
10725 | InputDispatcherTest::SetUp(); | ||||
10726 | mApp = std::make_shared<FakeApplicationHandle>(); | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 10727 | mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); |
Prabir Pradhan | 9998771 | 2020-11-10 18:43:05 -0800 | [diff] [blame] | 10728 | mWindow->setFocusable(true); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 10729 | mSecondWindow = |
10730 | sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | 9998771 | 2020-11-10 18:43:05 -0800 | [diff] [blame] | 10731 | mSecondWindow->setFocusable(true); |
10732 | |||||
10733 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10734 | mDispatcher->onWindowInfosChanged( |
10735 | {{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0}); | ||||
Prabir Pradhan | 9998771 | 2020-11-10 18:43:05 -0800 | [diff] [blame] | 10736 | |
10737 | setFocusedWindow(mWindow); | ||||
10738 | mWindow->consumeFocusEvent(true); | ||||
10739 | } | ||||
10740 | |||||
Prabir Pradhan | 5cc1a69 | 2021-08-06 14:01:18 +0000 | [diff] [blame] | 10741 | void notifyPointerCaptureChanged(const PointerCaptureRequest& request) { |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 10742 | mDispatcher->notifyPointerCaptureChanged(generatePointerCaptureChangedArgs(request)); |
Prabir Pradhan | 9998771 | 2020-11-10 18:43:05 -0800 | [diff] [blame] | 10743 | } |
10744 | |||||
Prabir Pradhan | 5cc1a69 | 2021-08-06 14:01:18 +0000 | [diff] [blame] | 10745 | PointerCaptureRequest requestAndVerifyPointerCapture(const sp<FakeWindowHandle>& window, |
10746 | bool enabled) { | ||||
Prabir Pradhan | 9998771 | 2020-11-10 18:43:05 -0800 | [diff] [blame] | 10747 | mDispatcher->requestPointerCapture(window->getToken(), enabled); |
Hiroki Sato | 2504023 | 2024-02-22 17:21:22 +0900 | [diff] [blame] | 10748 | auto request = mFakePolicy->assertSetPointerCaptureCalled(window, enabled); |
Prabir Pradhan | 5cc1a69 | 2021-08-06 14:01:18 +0000 | [diff] [blame] | 10749 | notifyPointerCaptureChanged(request); |
Prabir Pradhan | 9998771 | 2020-11-10 18:43:05 -0800 | [diff] [blame] | 10750 | window->consumeCaptureEvent(enabled); |
Prabir Pradhan | 5cc1a69 | 2021-08-06 14:01:18 +0000 | [diff] [blame] | 10751 | return request; |
Prabir Pradhan | 9998771 | 2020-11-10 18:43:05 -0800 | [diff] [blame] | 10752 | } |
10753 | }; | ||||
10754 | |||||
10755 | TEST_F(InputDispatcherPointerCaptureTests, EnablePointerCaptureWhenFocused) { | ||||
10756 | // Ensure that capture cannot be obtained for unfocused windows. | ||||
10757 | mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true); | ||||
10758 | mFakePolicy->assertSetPointerCaptureNotCalled(); | ||||
10759 | mSecondWindow->assertNoEvents(); | ||||
10760 | |||||
10761 | // Ensure that capture can be enabled from the focus window. | ||||
10762 | requestAndVerifyPointerCapture(mWindow, true); | ||||
10763 | |||||
10764 | // Ensure that capture cannot be disabled from a window that does not have capture. | ||||
10765 | mDispatcher->requestPointerCapture(mSecondWindow->getToken(), false); | ||||
10766 | mFakePolicy->assertSetPointerCaptureNotCalled(); | ||||
10767 | |||||
10768 | // Ensure that capture can be disabled from the window with capture. | ||||
10769 | requestAndVerifyPointerCapture(mWindow, false); | ||||
10770 | } | ||||
10771 | |||||
10772 | TEST_F(InputDispatcherPointerCaptureTests, DisablesPointerCaptureAfterWindowLosesFocus) { | ||||
Prabir Pradhan | 5cc1a69 | 2021-08-06 14:01:18 +0000 | [diff] [blame] | 10773 | auto request = requestAndVerifyPointerCapture(mWindow, true); |
Prabir Pradhan | 9998771 | 2020-11-10 18:43:05 -0800 | [diff] [blame] | 10774 | |
10775 | setFocusedWindow(mSecondWindow); | ||||
10776 | |||||
10777 | // Ensure that the capture disabled event was sent first. | ||||
10778 | mWindow->consumeCaptureEvent(false); | ||||
10779 | mWindow->consumeFocusEvent(false); | ||||
10780 | mSecondWindow->consumeFocusEvent(true); | ||||
Hiroki Sato | 2504023 | 2024-02-22 17:21:22 +0900 | [diff] [blame] | 10781 | mFakePolicy->assertSetPointerCaptureCalled(mWindow, false); |
Prabir Pradhan | 9998771 | 2020-11-10 18:43:05 -0800 | [diff] [blame] | 10782 | |
10783 | // Ensure that additional state changes from InputReader are not sent to the window. | ||||
Prabir Pradhan | 5cc1a69 | 2021-08-06 14:01:18 +0000 | [diff] [blame] | 10784 | notifyPointerCaptureChanged({}); |
10785 | notifyPointerCaptureChanged(request); | ||||
10786 | notifyPointerCaptureChanged({}); | ||||
Prabir Pradhan | 9998771 | 2020-11-10 18:43:05 -0800 | [diff] [blame] | 10787 | mWindow->assertNoEvents(); |
10788 | mSecondWindow->assertNoEvents(); | ||||
10789 | mFakePolicy->assertSetPointerCaptureNotCalled(); | ||||
10790 | } | ||||
10791 | |||||
10792 | TEST_F(InputDispatcherPointerCaptureTests, UnexpectedStateChangeDisablesPointerCapture) { | ||||
Prabir Pradhan | 5cc1a69 | 2021-08-06 14:01:18 +0000 | [diff] [blame] | 10793 | auto request = requestAndVerifyPointerCapture(mWindow, true); |
Prabir Pradhan | 9998771 | 2020-11-10 18:43:05 -0800 | [diff] [blame] | 10794 | |
10795 | // InputReader unexpectedly disables and enables pointer capture. | ||||
Prabir Pradhan | 5cc1a69 | 2021-08-06 14:01:18 +0000 | [diff] [blame] | 10796 | notifyPointerCaptureChanged({}); |
10797 | notifyPointerCaptureChanged(request); | ||||
Prabir Pradhan | 9998771 | 2020-11-10 18:43:05 -0800 | [diff] [blame] | 10798 | |
10799 | // Ensure that Pointer Capture is disabled. | ||||
Hiroki Sato | 2504023 | 2024-02-22 17:21:22 +0900 | [diff] [blame] | 10800 | mFakePolicy->assertSetPointerCaptureCalled(mWindow, false); |
Prabir Pradhan | 9998771 | 2020-11-10 18:43:05 -0800 | [diff] [blame] | 10801 | mWindow->consumeCaptureEvent(false); |
10802 | mWindow->assertNoEvents(); | ||||
10803 | } | ||||
10804 | |||||
Prabir Pradhan | 167e6d9 | 2021-02-04 16:18:17 -0800 | [diff] [blame] | 10805 | TEST_F(InputDispatcherPointerCaptureTests, OutOfOrderRequests) { |
10806 | requestAndVerifyPointerCapture(mWindow, true); | ||||
10807 | |||||
10808 | // The first window loses focus. | ||||
10809 | setFocusedWindow(mSecondWindow); | ||||
Hiroki Sato | 2504023 | 2024-02-22 17:21:22 +0900 | [diff] [blame] | 10810 | mFakePolicy->assertSetPointerCaptureCalled(mWindow, false); |
Prabir Pradhan | 167e6d9 | 2021-02-04 16:18:17 -0800 | [diff] [blame] | 10811 | mWindow->consumeCaptureEvent(false); |
10812 | |||||
10813 | // Request Pointer Capture from the second window before the notification from InputReader | ||||
10814 | // arrives. | ||||
10815 | mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true); | ||||
Hiroki Sato | 2504023 | 2024-02-22 17:21:22 +0900 | [diff] [blame] | 10816 | auto request = mFakePolicy->assertSetPointerCaptureCalled(mSecondWindow, true); |
Prabir Pradhan | 167e6d9 | 2021-02-04 16:18:17 -0800 | [diff] [blame] | 10817 | |
10818 | // InputReader notifies Pointer Capture was disabled (because of the focus change). | ||||
Prabir Pradhan | 5cc1a69 | 2021-08-06 14:01:18 +0000 | [diff] [blame] | 10819 | notifyPointerCaptureChanged({}); |
Prabir Pradhan | 167e6d9 | 2021-02-04 16:18:17 -0800 | [diff] [blame] | 10820 | |
10821 | // InputReader notifies Pointer Capture was enabled (because of mSecondWindow's request). | ||||
Prabir Pradhan | 5cc1a69 | 2021-08-06 14:01:18 +0000 | [diff] [blame] | 10822 | notifyPointerCaptureChanged(request); |
Prabir Pradhan | 167e6d9 | 2021-02-04 16:18:17 -0800 | [diff] [blame] | 10823 | |
10824 | mSecondWindow->consumeFocusEvent(true); | ||||
10825 | mSecondWindow->consumeCaptureEvent(true); | ||||
10826 | } | ||||
10827 | |||||
Prabir Pradhan | 5cc1a69 | 2021-08-06 14:01:18 +0000 | [diff] [blame] | 10828 | TEST_F(InputDispatcherPointerCaptureTests, EnableRequestFollowsSequenceNumbers) { |
10829 | // App repeatedly enables and disables capture. | ||||
10830 | mDispatcher->requestPointerCapture(mWindow->getToken(), true); | ||||
Hiroki Sato | 2504023 | 2024-02-22 17:21:22 +0900 | [diff] [blame] | 10831 | auto firstRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true); |
Prabir Pradhan | 5cc1a69 | 2021-08-06 14:01:18 +0000 | [diff] [blame] | 10832 | mDispatcher->requestPointerCapture(mWindow->getToken(), false); |
Hiroki Sato | 2504023 | 2024-02-22 17:21:22 +0900 | [diff] [blame] | 10833 | mFakePolicy->assertSetPointerCaptureCalled(mWindow, false); |
Prabir Pradhan | 5cc1a69 | 2021-08-06 14:01:18 +0000 | [diff] [blame] | 10834 | mDispatcher->requestPointerCapture(mWindow->getToken(), true); |
Hiroki Sato | 2504023 | 2024-02-22 17:21:22 +0900 | [diff] [blame] | 10835 | auto secondRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true); |
Prabir Pradhan | 5cc1a69 | 2021-08-06 14:01:18 +0000 | [diff] [blame] | 10836 | |
10837 | // InputReader notifies that PointerCapture has been enabled for the first request. Since the | ||||
10838 | // first request is now stale, this should do nothing. | ||||
10839 | notifyPointerCaptureChanged(firstRequest); | ||||
10840 | mWindow->assertNoEvents(); | ||||
10841 | |||||
10842 | // InputReader notifies that the second request was enabled. | ||||
10843 | notifyPointerCaptureChanged(secondRequest); | ||||
10844 | mWindow->consumeCaptureEvent(true); | ||||
10845 | } | ||||
10846 | |||||
Prabir Pradhan | 7092e26 | 2022-05-03 16:51:09 +0000 | [diff] [blame] | 10847 | TEST_F(InputDispatcherPointerCaptureTests, RapidToggleRequests) { |
10848 | requestAndVerifyPointerCapture(mWindow, true); | ||||
10849 | |||||
10850 | // App toggles pointer capture off and on. | ||||
10851 | mDispatcher->requestPointerCapture(mWindow->getToken(), false); | ||||
Hiroki Sato | 2504023 | 2024-02-22 17:21:22 +0900 | [diff] [blame] | 10852 | mFakePolicy->assertSetPointerCaptureCalled(mWindow, false); |
Prabir Pradhan | 7092e26 | 2022-05-03 16:51:09 +0000 | [diff] [blame] | 10853 | |
10854 | mDispatcher->requestPointerCapture(mWindow->getToken(), true); | ||||
Hiroki Sato | 2504023 | 2024-02-22 17:21:22 +0900 | [diff] [blame] | 10855 | auto enableRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true); |
Prabir Pradhan | 7092e26 | 2022-05-03 16:51:09 +0000 | [diff] [blame] | 10856 | |
10857 | // InputReader notifies that the latest "enable" request was processed, while skipping over the | ||||
10858 | // preceding "disable" request. | ||||
10859 | notifyPointerCaptureChanged(enableRequest); | ||||
10860 | |||||
10861 | // Since pointer capture was never disabled during the rapid toggle, the window does not receive | ||||
10862 | // any notifications. | ||||
10863 | mWindow->assertNoEvents(); | ||||
10864 | } | ||||
10865 | |||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 10866 | /** |
10867 | * One window. Hover mouse in the window, and then start capture. Make sure that the relative | ||||
10868 | * mouse movements don't affect the previous mouse hovering state. | ||||
10869 | * When pointer capture is enabled, the incoming events are always ACTION_MOVE (there are no | ||||
10870 | * HOVER_MOVE events). | ||||
10871 | */ | ||||
10872 | TEST_F(InputDispatcherPointerCaptureTests, MouseHoverAndPointerCapture) { | ||||
10873 | // Mouse hover on the window | ||||
10874 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) | ||||
10875 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110)) | ||||
10876 | .build()); | ||||
10877 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) | ||||
10878 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110)) | ||||
10879 | .build()); | ||||
10880 | |||||
10881 | mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER))); | ||||
10882 | mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE))); | ||||
10883 | |||||
10884 | // Start pointer capture | ||||
10885 | requestAndVerifyPointerCapture(mWindow, true); | ||||
10886 | |||||
10887 | // Send some relative mouse movements and receive them in the window. | ||||
10888 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE_RELATIVE) | ||||
10889 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(11)) | ||||
10890 | .build()); | ||||
10891 | mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithCoords(10, 11), | ||||
10892 | WithSource(AINPUT_SOURCE_MOUSE_RELATIVE))); | ||||
10893 | |||||
10894 | // Stop pointer capture | ||||
10895 | requestAndVerifyPointerCapture(mWindow, false); | ||||
10896 | |||||
10897 | // Continue hovering on the window | ||||
10898 | mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) | ||||
10899 | .pointer(PointerBuilder(0, ToolType::MOUSE).x(105).y(115)) | ||||
10900 | .build()); | ||||
10901 | mWindow->consumeMotionEvent( | ||||
10902 | AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE))); | ||||
10903 | |||||
10904 | mWindow->assertNoEvents(); | ||||
10905 | } | ||||
10906 | |||||
Hiroki Sato | 2504023 | 2024-02-22 17:21:22 +0900 | [diff] [blame] | 10907 | using InputDispatcherPointerCaptureDeathTest = InputDispatcherPointerCaptureTests; |
10908 | |||||
10909 | TEST_F(InputDispatcherPointerCaptureDeathTest, | ||||
10910 | NotifyPointerCaptureChangedWithWrongTokenAbortsDispatcher) { | ||||
10911 | testing::GTEST_FLAG(death_test_style) = "threadsafe"; | ||||
10912 | ScopedSilentDeath _silentDeath; | ||||
10913 | |||||
10914 | mDispatcher->requestPointerCapture(mWindow->getToken(), true); | ||||
10915 | auto request = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true); | ||||
10916 | |||||
10917 | // Dispatch a pointer changed event with a wrong token. | ||||
10918 | request.window = mSecondWindow->getToken(); | ||||
10919 | ASSERT_DEATH( | ||||
10920 | { | ||||
10921 | notifyPointerCaptureChanged(request); | ||||
10922 | mSecondWindow->consumeCaptureEvent(true); | ||||
10923 | }, | ||||
10924 | "Unexpected requested window for Pointer Capture."); | ||||
10925 | } | ||||
10926 | |||||
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 10927 | class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest { |
10928 | protected: | ||||
10929 | constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8; | ||||
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 10930 | |
10931 | constexpr static const float OPACITY_ABOVE_THRESHOLD = 0.9; | ||||
10932 | static_assert(OPACITY_ABOVE_THRESHOLD > MAXIMUM_OBSCURING_OPACITY); | ||||
10933 | |||||
10934 | constexpr static const float OPACITY_BELOW_THRESHOLD = 0.7; | ||||
10935 | static_assert(OPACITY_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY); | ||||
10936 | |||||
10937 | // When combined twice, ie 1 - (1 - 0.5)*(1 - 0.5) = 0.75 < 8, is still below the threshold | ||||
10938 | constexpr static const float OPACITY_FAR_BELOW_THRESHOLD = 0.5; | ||||
10939 | static_assert(OPACITY_FAR_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY); | ||||
10940 | static_assert(1 - (1 - OPACITY_FAR_BELOW_THRESHOLD) * (1 - OPACITY_FAR_BELOW_THRESHOLD) < | ||||
10941 | MAXIMUM_OBSCURING_OPACITY); | ||||
10942 | |||||
Prabir Pradhan | 8a5c41d | 2023-06-08 19:13:46 +0000 | [diff] [blame] | 10943 | static constexpr gui::Uid TOUCHED_APP_UID{10001}; |
10944 | static constexpr gui::Uid APP_B_UID{10002}; | ||||
10945 | static constexpr gui::Uid APP_C_UID{10003}; | ||||
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 10946 | |
10947 | sp<FakeWindowHandle> mTouchWindow; | ||||
10948 | |||||
10949 | virtual void SetUp() override { | ||||
10950 | InputDispatcherTest::SetUp(); | ||||
Bernardo Rufino | 6d52e54 | 2021-02-15 18:38:10 +0000 | [diff] [blame] | 10951 | mTouchWindow = getWindow(TOUCHED_APP_UID, "Touched"); |
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 10952 | mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY); |
10953 | } | ||||
10954 | |||||
10955 | virtual void TearDown() override { | ||||
10956 | InputDispatcherTest::TearDown(); | ||||
10957 | mTouchWindow.clear(); | ||||
10958 | } | ||||
10959 | |||||
Prabir Pradhan | 8a5c41d | 2023-06-08 19:13:46 +0000 | [diff] [blame] | 10960 | sp<FakeWindowHandle> getOccludingWindow(gui::Uid uid, std::string name, TouchOcclusionMode mode, |
chaviw | 3277faf | 2021-05-19 16:45:23 -0500 | [diff] [blame] | 10961 | float alpha = 1.0f) { |
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 10962 | sp<FakeWindowHandle> window = getWindow(uid, name); |
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 10963 | window->setTouchable(false); |
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 10964 | window->setTouchOcclusionMode(mode); |
Bernardo Rufino | 1d0d1f2 | 2021-02-12 15:08:43 +0000 | [diff] [blame] | 10965 | window->setAlpha(alpha); |
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 10966 | return window; |
10967 | } | ||||
10968 | |||||
Prabir Pradhan | 8a5c41d | 2023-06-08 19:13:46 +0000 | [diff] [blame] | 10969 | sp<FakeWindowHandle> getWindow(gui::Uid uid, std::string name) { |
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 10970 | std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>(); |
10971 | sp<FakeWindowHandle> window = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 10972 | sp<FakeWindowHandle>::make(app, mDispatcher, name, ADISPLAY_ID_DEFAULT); |
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 10973 | // Generate an arbitrary PID based on the UID |
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 10974 | window->setOwnerInfo(gui::Pid{static_cast<pid_t>(1777 + (uid.val() % 10000))}, uid); |
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 10975 | return window; |
10976 | } | ||||
10977 | |||||
10978 | void touch(const std::vector<PointF>& points = {PointF{100, 200}}) { | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 10979 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
10980 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
10981 | points)); | ||||
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 10982 | } |
10983 | }; | ||||
10984 | |||||
10985 | TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionMode_BlocksTouch) { | ||||
Bernardo Rufino | 1d0d1f2 | 2021-02-12 15:08:43 +0000 | [diff] [blame] | 10986 | const sp<FakeWindowHandle>& w = |
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 10987 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10988 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 10989 | |
10990 | touch(); | ||||
10991 | |||||
10992 | mTouchWindow->assertNoEvents(); | ||||
10993 | } | ||||
10994 | |||||
Bernardo Rufino | a43a5a4 | 2021-02-17 12:21:14 +0000 | [diff] [blame] | 10995 | TEST_F(InputDispatcherUntrustedTouchesTest, |
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 10996 | WindowWithBlockUntrustedOcclusionModeWithOpacityBelowThreshold_BlocksTouch) { |
10997 | const sp<FakeWindowHandle>& w = | ||||
10998 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.7f); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 10999 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11000 | |
11001 | touch(); | ||||
11002 | |||||
11003 | mTouchWindow->assertNoEvents(); | ||||
11004 | } | ||||
11005 | |||||
11006 | TEST_F(InputDispatcherUntrustedTouchesTest, | ||||
Bernardo Rufino | a43a5a4 | 2021-02-17 12:21:14 +0000 | [diff] [blame] | 11007 | WindowWithBlockUntrustedOcclusionMode_DoesNotReceiveTouch) { |
11008 | const sp<FakeWindowHandle>& w = | ||||
11009 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11010 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | a43a5a4 | 2021-02-17 12:21:14 +0000 | [diff] [blame] | 11011 | |
11012 | touch(); | ||||
11013 | |||||
11014 | w->assertNoEvents(); | ||||
11015 | } | ||||
11016 | |||||
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 11017 | TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithAllowOcclusionMode_AllowsTouch) { |
Bernardo Rufino | 1d0d1f2 | 2021-02-12 15:08:43 +0000 | [diff] [blame] | 11018 | const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::ALLOW); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11019 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 11020 | |
11021 | touch(); | ||||
11022 | |||||
11023 | mTouchWindow->consumeAnyMotionDown(); | ||||
11024 | } | ||||
11025 | |||||
11026 | TEST_F(InputDispatcherUntrustedTouchesTest, TouchOutsideOccludingWindow_AllowsTouch) { | ||||
Bernardo Rufino | 1d0d1f2 | 2021-02-12 15:08:43 +0000 | [diff] [blame] | 11027 | const sp<FakeWindowHandle>& w = |
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 11028 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED); |
Bernardo Rufino | 1d0d1f2 | 2021-02-12 15:08:43 +0000 | [diff] [blame] | 11029 | w->setFrame(Rect(0, 0, 50, 50)); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11030 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 11031 | |
11032 | touch({PointF{100, 100}}); | ||||
11033 | |||||
11034 | mTouchWindow->consumeAnyMotionDown(); | ||||
11035 | } | ||||
11036 | |||||
11037 | TEST_F(InputDispatcherUntrustedTouchesTest, WindowFromSameUid_AllowsTouch) { | ||||
Bernardo Rufino | 1d0d1f2 | 2021-02-12 15:08:43 +0000 | [diff] [blame] | 11038 | const sp<FakeWindowHandle>& w = |
Bernardo Rufino | 6d52e54 | 2021-02-15 18:38:10 +0000 | [diff] [blame] | 11039 | getOccludingWindow(TOUCHED_APP_UID, "A", TouchOcclusionMode::BLOCK_UNTRUSTED); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11040 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | 1d0d1f2 | 2021-02-12 15:08:43 +0000 | [diff] [blame] | 11041 | |
11042 | touch(); | ||||
11043 | |||||
11044 | mTouchWindow->consumeAnyMotionDown(); | ||||
11045 | } | ||||
11046 | |||||
11047 | TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_AllowsTouch) { | ||||
11048 | const sp<FakeWindowHandle>& w = | ||||
11049 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11050 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 11051 | |
11052 | touch(); | ||||
11053 | |||||
11054 | mTouchWindow->consumeAnyMotionDown(); | ||||
11055 | } | ||||
11056 | |||||
Bernardo Rufino | a43a5a4 | 2021-02-17 12:21:14 +0000 | [diff] [blame] | 11057 | TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_DoesNotReceiveTouch) { |
11058 | const sp<FakeWindowHandle>& w = | ||||
11059 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11060 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | a43a5a4 | 2021-02-17 12:21:14 +0000 | [diff] [blame] | 11061 | |
11062 | touch(); | ||||
11063 | |||||
11064 | w->assertNoEvents(); | ||||
11065 | } | ||||
11066 | |||||
11067 | /** | ||||
11068 | * This is important to make sure apps can't indirectly learn the position of touches (outside vs | ||||
11069 | * inside) while letting them pass-through. Note that even though touch passes through the occluding | ||||
11070 | * window, the occluding window will still receive ACTION_OUTSIDE event. | ||||
11071 | */ | ||||
11072 | TEST_F(InputDispatcherUntrustedTouchesTest, | ||||
11073 | WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) { | ||||
11074 | const sp<FakeWindowHandle>& w = | ||||
11075 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f); | ||||
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 11076 | w->setWatchOutsideTouch(true); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11077 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | a43a5a4 | 2021-02-17 12:21:14 +0000 | [diff] [blame] | 11078 | |
11079 | touch(); | ||||
11080 | |||||
11081 | w->consumeMotionOutside(); | ||||
11082 | } | ||||
11083 | |||||
11084 | TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) { | ||||
11085 | const sp<FakeWindowHandle>& w = | ||||
11086 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f); | ||||
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 11087 | w->setWatchOutsideTouch(true); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11088 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | a43a5a4 | 2021-02-17 12:21:14 +0000 | [diff] [blame] | 11089 | |
11090 | touch(); | ||||
11091 | |||||
Prabir Pradhan | dfabf8a | 2022-01-21 08:19:30 -0800 | [diff] [blame] | 11092 | w->consumeMotionOutsideWithZeroedCoords(); |
Bernardo Rufino | a43a5a4 | 2021-02-17 12:21:14 +0000 | [diff] [blame] | 11093 | } |
11094 | |||||
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 11095 | TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) { |
Bernardo Rufino | 1d0d1f2 | 2021-02-12 15:08:43 +0000 | [diff] [blame] | 11096 | const sp<FakeWindowHandle>& w = |
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11097 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, |
11098 | OPACITY_BELOW_THRESHOLD); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11099 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | 1d0d1f2 | 2021-02-12 15:08:43 +0000 | [diff] [blame] | 11100 | |
11101 | touch(); | ||||
11102 | |||||
11103 | mTouchWindow->consumeAnyMotionDown(); | ||||
11104 | } | ||||
11105 | |||||
11106 | TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAtThreshold_AllowsTouch) { | ||||
11107 | const sp<FakeWindowHandle>& w = | ||||
11108 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, | ||||
11109 | MAXIMUM_OBSCURING_OPACITY); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11110 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 11111 | |
11112 | touch(); | ||||
11113 | |||||
11114 | mTouchWindow->consumeAnyMotionDown(); | ||||
11115 | } | ||||
11116 | |||||
11117 | TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAboveThreshold_BlocksTouch) { | ||||
Bernardo Rufino | 1d0d1f2 | 2021-02-12 15:08:43 +0000 | [diff] [blame] | 11118 | const sp<FakeWindowHandle>& w = |
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11119 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, |
11120 | OPACITY_ABOVE_THRESHOLD); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11121 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | 1d0d1f2 | 2021-02-12 15:08:43 +0000 | [diff] [blame] | 11122 | |
11123 | touch(); | ||||
11124 | |||||
11125 | mTouchWindow->assertNoEvents(); | ||||
11126 | } | ||||
11127 | |||||
11128 | TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityAboveThreshold_BlocksTouch) { | ||||
11129 | // Resulting opacity = 1 - (1 - 0.7)*(1 - 0.7) = .91 | ||||
11130 | const sp<FakeWindowHandle>& w1 = | ||||
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11131 | getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY, |
11132 | OPACITY_BELOW_THRESHOLD); | ||||
Bernardo Rufino | 1d0d1f2 | 2021-02-12 15:08:43 +0000 | [diff] [blame] | 11133 | const sp<FakeWindowHandle>& w2 = |
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11134 | getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY, |
11135 | OPACITY_BELOW_THRESHOLD); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11136 | mDispatcher->onWindowInfosChanged( |
11137 | {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); | ||||
Bernardo Rufino | 1d0d1f2 | 2021-02-12 15:08:43 +0000 | [diff] [blame] | 11138 | |
11139 | touch(); | ||||
11140 | |||||
11141 | mTouchWindow->assertNoEvents(); | ||||
11142 | } | ||||
11143 | |||||
11144 | TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityBelowThreshold_AllowsTouch) { | ||||
11145 | // Resulting opacity = 1 - (1 - 0.5)*(1 - 0.5) = .75 | ||||
11146 | const sp<FakeWindowHandle>& w1 = | ||||
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11147 | getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY, |
11148 | OPACITY_FAR_BELOW_THRESHOLD); | ||||
Bernardo Rufino | 1d0d1f2 | 2021-02-12 15:08:43 +0000 | [diff] [blame] | 11149 | const sp<FakeWindowHandle>& w2 = |
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11150 | getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY, |
11151 | OPACITY_FAR_BELOW_THRESHOLD); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11152 | mDispatcher->onWindowInfosChanged( |
11153 | {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); | ||||
Bernardo Rufino | 1d0d1f2 | 2021-02-12 15:08:43 +0000 | [diff] [blame] | 11154 | |
11155 | touch(); | ||||
11156 | |||||
11157 | mTouchWindow->consumeAnyMotionDown(); | ||||
11158 | } | ||||
11159 | |||||
11160 | TEST_F(InputDispatcherUntrustedTouchesTest, | ||||
11161 | WindowsFromDifferentAppsEachBelowThreshold_AllowsTouch) { | ||||
11162 | const sp<FakeWindowHandle>& wB = | ||||
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11163 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, |
11164 | OPACITY_BELOW_THRESHOLD); | ||||
Bernardo Rufino | 1d0d1f2 | 2021-02-12 15:08:43 +0000 | [diff] [blame] | 11165 | const sp<FakeWindowHandle>& wC = |
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11166 | getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY, |
11167 | OPACITY_BELOW_THRESHOLD); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11168 | mDispatcher->onWindowInfosChanged( |
11169 | {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); | ||||
Bernardo Rufino | 1d0d1f2 | 2021-02-12 15:08:43 +0000 | [diff] [blame] | 11170 | |
11171 | touch(); | ||||
11172 | |||||
11173 | mTouchWindow->consumeAnyMotionDown(); | ||||
11174 | } | ||||
11175 | |||||
11176 | TEST_F(InputDispatcherUntrustedTouchesTest, WindowsFromDifferentAppsOneAboveThreshold_BlocksTouch) { | ||||
11177 | const sp<FakeWindowHandle>& wB = | ||||
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11178 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, |
11179 | OPACITY_BELOW_THRESHOLD); | ||||
Bernardo Rufino | 1d0d1f2 | 2021-02-12 15:08:43 +0000 | [diff] [blame] | 11180 | const sp<FakeWindowHandle>& wC = |
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11181 | getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY, |
11182 | OPACITY_ABOVE_THRESHOLD); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11183 | mDispatcher->onWindowInfosChanged( |
11184 | {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); | ||||
Bernardo Rufino | c3b7b8c | 2021-01-29 17:38:07 +0000 | [diff] [blame] | 11185 | |
11186 | touch(); | ||||
11187 | |||||
11188 | mTouchWindow->assertNoEvents(); | ||||
11189 | } | ||||
11190 | |||||
Bernardo Rufino | 6d52e54 | 2021-02-15 18:38:10 +0000 | [diff] [blame] | 11191 | TEST_F(InputDispatcherUntrustedTouchesTest, |
11192 | WindowWithOpacityAboveThresholdAndSelfWindow_BlocksTouch) { | ||||
11193 | const sp<FakeWindowHandle>& wA = | ||||
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11194 | getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY, |
11195 | OPACITY_BELOW_THRESHOLD); | ||||
Bernardo Rufino | 6d52e54 | 2021-02-15 18:38:10 +0000 | [diff] [blame] | 11196 | const sp<FakeWindowHandle>& wB = |
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11197 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, |
11198 | OPACITY_ABOVE_THRESHOLD); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11199 | mDispatcher->onWindowInfosChanged( |
11200 | {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); | ||||
Bernardo Rufino | 6d52e54 | 2021-02-15 18:38:10 +0000 | [diff] [blame] | 11201 | |
11202 | touch(); | ||||
11203 | |||||
11204 | mTouchWindow->assertNoEvents(); | ||||
11205 | } | ||||
11206 | |||||
11207 | TEST_F(InputDispatcherUntrustedTouchesTest, | ||||
11208 | WindowWithOpacityBelowThresholdAndSelfWindow_AllowsTouch) { | ||||
11209 | const sp<FakeWindowHandle>& wA = | ||||
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11210 | getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY, |
11211 | OPACITY_ABOVE_THRESHOLD); | ||||
Bernardo Rufino | 6d52e54 | 2021-02-15 18:38:10 +0000 | [diff] [blame] | 11212 | const sp<FakeWindowHandle>& wB = |
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11213 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, |
11214 | OPACITY_BELOW_THRESHOLD); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11215 | mDispatcher->onWindowInfosChanged( |
11216 | {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); | ||||
Bernardo Rufino | 6d52e54 | 2021-02-15 18:38:10 +0000 | [diff] [blame] | 11217 | |
11218 | touch(); | ||||
11219 | |||||
11220 | mTouchWindow->consumeAnyMotionDown(); | ||||
11221 | } | ||||
11222 | |||||
11223 | TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithOpacityAboveThreshold_AllowsTouch) { | ||||
11224 | const sp<FakeWindowHandle>& w = | ||||
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11225 | getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY, |
11226 | OPACITY_ABOVE_THRESHOLD); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11227 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | 6d52e54 | 2021-02-15 18:38:10 +0000 | [diff] [blame] | 11228 | |
11229 | touch(); | ||||
11230 | |||||
11231 | mTouchWindow->consumeAnyMotionDown(); | ||||
11232 | } | ||||
11233 | |||||
11234 | TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithBlockUntrustedMode_AllowsTouch) { | ||||
11235 | const sp<FakeWindowHandle>& w = | ||||
11236 | getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::BLOCK_UNTRUSTED); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11237 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | 6d52e54 | 2021-02-15 18:38:10 +0000 | [diff] [blame] | 11238 | |
11239 | touch(); | ||||
11240 | |||||
11241 | mTouchWindow->consumeAnyMotionDown(); | ||||
11242 | } | ||||
11243 | |||||
Bernardo Rufino | ccd3dd6 | 2021-02-15 18:47:42 +0000 | [diff] [blame] | 11244 | TEST_F(InputDispatcherUntrustedTouchesTest, |
11245 | OpacityThresholdIs0AndWindowAboveThreshold_BlocksTouch) { | ||||
11246 | mDispatcher->setMaximumObscuringOpacityForTouch(0.0f); | ||||
11247 | const sp<FakeWindowHandle>& w = | ||||
11248 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.1f); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11249 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | ccd3dd6 | 2021-02-15 18:47:42 +0000 | [diff] [blame] | 11250 | |
11251 | touch(); | ||||
11252 | |||||
11253 | mTouchWindow->assertNoEvents(); | ||||
11254 | } | ||||
11255 | |||||
11256 | TEST_F(InputDispatcherUntrustedTouchesTest, OpacityThresholdIs0AndWindowAtThreshold_AllowsTouch) { | ||||
11257 | mDispatcher->setMaximumObscuringOpacityForTouch(0.0f); | ||||
11258 | const sp<FakeWindowHandle>& w = | ||||
11259 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.0f); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11260 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | ccd3dd6 | 2021-02-15 18:47:42 +0000 | [diff] [blame] | 11261 | |
11262 | touch(); | ||||
11263 | |||||
11264 | mTouchWindow->consumeAnyMotionDown(); | ||||
11265 | } | ||||
11266 | |||||
11267 | TEST_F(InputDispatcherUntrustedTouchesTest, | ||||
11268 | OpacityThresholdIs1AndWindowBelowThreshold_AllowsTouch) { | ||||
11269 | mDispatcher->setMaximumObscuringOpacityForTouch(1.0f); | ||||
11270 | const sp<FakeWindowHandle>& w = | ||||
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11271 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, |
11272 | OPACITY_ABOVE_THRESHOLD); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11273 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11274 | |
11275 | touch(); | ||||
11276 | |||||
11277 | mTouchWindow->consumeAnyMotionDown(); | ||||
11278 | } | ||||
11279 | |||||
11280 | TEST_F(InputDispatcherUntrustedTouchesTest, | ||||
11281 | WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromSameApp_BlocksTouch) { | ||||
11282 | const sp<FakeWindowHandle>& w1 = | ||||
11283 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, | ||||
11284 | OPACITY_BELOW_THRESHOLD); | ||||
11285 | const sp<FakeWindowHandle>& w2 = | ||||
11286 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, | ||||
11287 | OPACITY_BELOW_THRESHOLD); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11288 | mDispatcher->onWindowInfosChanged( |
11289 | {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); | ||||
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11290 | |
11291 | touch(); | ||||
11292 | |||||
11293 | mTouchWindow->assertNoEvents(); | ||||
11294 | } | ||||
11295 | |||||
11296 | /** | ||||
11297 | * Window B of BLOCK_UNTRUSTED occlusion mode is enough to block the touch, we're testing that the | ||||
11298 | * addition of another window (C) of USE_OPACITY occlusion mode and opacity below the threshold | ||||
11299 | * (which alone would result in allowing touches) does not affect the blocking behavior. | ||||
11300 | */ | ||||
11301 | TEST_F(InputDispatcherUntrustedTouchesTest, | ||||
11302 | WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromDifferentApps_BlocksTouch) { | ||||
11303 | const sp<FakeWindowHandle>& wB = | ||||
11304 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, | ||||
11305 | OPACITY_BELOW_THRESHOLD); | ||||
11306 | const sp<FakeWindowHandle>& wC = | ||||
11307 | getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY, | ||||
11308 | OPACITY_BELOW_THRESHOLD); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11309 | mDispatcher->onWindowInfosChanged( |
11310 | {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); | ||||
Bernardo Rufino | 7393d17 | 2021-02-26 13:56:11 +0000 | [diff] [blame] | 11311 | |
11312 | touch(); | ||||
11313 | |||||
11314 | mTouchWindow->assertNoEvents(); | ||||
11315 | } | ||||
11316 | |||||
11317 | /** | ||||
11318 | * This test is testing that a window from a different UID but with same application token doesn't | ||||
11319 | * block the touch. Apps can share the application token for close UI collaboration for example. | ||||
11320 | */ | ||||
11321 | TEST_F(InputDispatcherUntrustedTouchesTest, | ||||
11322 | WindowWithSameApplicationTokenFromDifferentApp_AllowsTouch) { | ||||
11323 | const sp<FakeWindowHandle>& w = | ||||
11324 | getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED); | ||||
11325 | w->setApplicationToken(mTouchWindow->getApplicationToken()); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11326 | mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); |
Bernardo Rufino | ccd3dd6 | 2021-02-15 18:47:42 +0000 | [diff] [blame] | 11327 | |
11328 | touch(); | ||||
11329 | |||||
11330 | mTouchWindow->consumeAnyMotionDown(); | ||||
11331 | } | ||||
11332 | |||||
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11333 | class InputDispatcherDragTests : public InputDispatcherTest { |
11334 | protected: | ||||
11335 | std::shared_ptr<FakeApplicationHandle> mApp; | ||||
11336 | sp<FakeWindowHandle> mWindow; | ||||
11337 | sp<FakeWindowHandle> mSecondWindow; | ||||
11338 | sp<FakeWindowHandle> mDragWindow; | ||||
Vaibhav Devmurari | 6abcf8f | 2022-06-06 10:08:05 +0000 | [diff] [blame] | 11339 | sp<FakeWindowHandle> mSpyWindow; |
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11340 | // Mouse would force no-split, set the id as non-zero to verify if drag state could track it. |
11341 | static constexpr int32_t MOUSE_POINTER_ID = 1; | ||||
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11342 | |
11343 | void SetUp() override { | ||||
11344 | InputDispatcherTest::SetUp(); | ||||
11345 | mApp = std::make_shared<FakeApplicationHandle>(); | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 11346 | mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); |
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11347 | mWindow->setFrame(Rect(0, 0, 100, 100)); |
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11348 | |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 11349 | mSecondWindow = |
11350 | sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT); | ||||
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11351 | mSecondWindow->setFrame(Rect(100, 0, 200, 100)); |
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11352 | |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 11353 | mSpyWindow = |
11354 | sp<FakeWindowHandle>::make(mApp, mDispatcher, "SpyWindow", ADISPLAY_ID_DEFAULT); | ||||
Vaibhav Devmurari | 6abcf8f | 2022-06-06 10:08:05 +0000 | [diff] [blame] | 11355 | mSpyWindow->setSpy(true); |
11356 | mSpyWindow->setTrustedOverlay(true); | ||||
11357 | mSpyWindow->setFrame(Rect(0, 0, 200, 100)); | ||||
11358 | |||||
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11359 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11360 | mDispatcher->onWindowInfosChanged( |
11361 | {{*mSpyWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()}, | ||||
11362 | {}, | ||||
11363 | 0, | ||||
11364 | 0}); | ||||
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11365 | } |
11366 | |||||
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11367 | void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) { |
11368 | switch (fromSource) { | ||||
11369 | case AINPUT_SOURCE_TOUCHSCREEN: | ||||
11370 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11371 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, |
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11372 | ADISPLAY_ID_DEFAULT, {50, 50})) |
11373 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
11374 | break; | ||||
11375 | case AINPUT_SOURCE_STYLUS: | ||||
11376 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11377 | injectMotionEvent(*mDispatcher, |
11378 | MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, | ||||
11379 | AINPUT_SOURCE_STYLUS) | ||||
11380 | .buttonState( | ||||
11381 | AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) | ||||
11382 | .pointer(PointerBuilder(0, ToolType::STYLUS) | ||||
11383 | .x(50) | ||||
11384 | .y(50)) | ||||
11385 | .build())); | ||||
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11386 | break; |
11387 | case AINPUT_SOURCE_MOUSE: | ||||
11388 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11389 | injectMotionEvent(*mDispatcher, |
11390 | MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, | ||||
11391 | AINPUT_SOURCE_MOUSE) | ||||
11392 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
11393 | .pointer(PointerBuilder(MOUSE_POINTER_ID, | ||||
11394 | ToolType::MOUSE) | ||||
11395 | .x(50) | ||||
11396 | .y(50)) | ||||
11397 | .build())); | ||||
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11398 | break; |
11399 | default: | ||||
11400 | FAIL() << "Source " << fromSource << " doesn't support drag and drop"; | ||||
11401 | } | ||||
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11402 | |
11403 | // Window should receive motion event. | ||||
11404 | mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
Vaibhav Devmurari | 6abcf8f | 2022-06-06 10:08:05 +0000 | [diff] [blame] | 11405 | // Spy window should also receive motion event |
11406 | mSpyWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11407 | } |
11408 | |||||
11409 | // Start performing drag, we will create a drag window and transfer touch to it. | ||||
11410 | // @param sendDown : if true, send a motion down on first window before perform drag and drop. | ||||
11411 | // Returns true on success. | ||||
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11412 | bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) { |
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11413 | if (sendDown) { |
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11414 | injectDown(fromSource); |
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11415 | } |
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11416 | |
11417 | // The drag window covers the entire display | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 11418 | mDragWindow = |
11419 | sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT); | ||||
Vaibhav Devmurari | 6abcf8f | 2022-06-06 10:08:05 +0000 | [diff] [blame] | 11420 | mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}}); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11421 | mDispatcher->onWindowInfosChanged({{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), |
11422 | *mWindow->getInfo(), *mSecondWindow->getInfo()}, | ||||
11423 | {}, | ||||
11424 | 0, | ||||
11425 | 0}); | ||||
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11426 | |
11427 | // Transfer touch focus to the drag window | ||||
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11428 | bool transferred = |
Prabir Pradhan | 367f343 | 2024-02-13 23:05:58 +0000 | [diff] [blame] | 11429 | mDispatcher->transferTouchGesture(mWindow->getToken(), mDragWindow->getToken(), |
11430 | /*isDragDrop=*/true); | ||||
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11431 | if (transferred) { |
11432 | mWindow->consumeMotionCancel(); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11433 | mDragWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11434 | } |
11435 | return transferred; | ||||
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11436 | } |
11437 | }; | ||||
11438 | |||||
11439 | TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) { | ||||
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11440 | startDrag(); |
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11441 | |
11442 | // Move on window. | ||||
11443 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11444 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11445 | ADISPLAY_ID_DEFAULT, {50, 50})) |
11446 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11447 | mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11448 | mWindow->consumeDragEvent(false, 50, 50); |
11449 | mSecondWindow->assertNoEvents(); | ||||
11450 | |||||
11451 | // Move to another window. | ||||
11452 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11453 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11454 | ADISPLAY_ID_DEFAULT, {150, 50})) |
11455 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11456 | mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11457 | mWindow->consumeDragEvent(true, 150, 50); |
11458 | mSecondWindow->consumeDragEvent(false, 50, 50); | ||||
11459 | |||||
11460 | // Move back to original window. | ||||
11461 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11462 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11463 | ADISPLAY_ID_DEFAULT, {50, 50})) |
11464 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11465 | mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11466 | mWindow->consumeDragEvent(false, 50, 50); |
11467 | mSecondWindow->consumeDragEvent(true, -50, 50); | ||||
11468 | |||||
11469 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11470 | injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
11471 | {50, 50})) | ||||
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11472 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11473 | mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
arthurhung | b89ccb0 | 2020-12-30 16:19:01 +0800 | [diff] [blame] | 11474 | mWindow->assertNoEvents(); |
11475 | mSecondWindow->assertNoEvents(); | ||||
11476 | } | ||||
11477 | |||||
Vaibhav Devmurari | 6abcf8f | 2022-06-06 10:08:05 +0000 | [diff] [blame] | 11478 | TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) { |
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11479 | startDrag(); |
Vaibhav Devmurari | 6abcf8f | 2022-06-06 10:08:05 +0000 | [diff] [blame] | 11480 | |
11481 | // No cancel event after drag start | ||||
11482 | mSpyWindow->assertNoEvents(); | ||||
11483 | |||||
11484 | const MotionEvent secondFingerDownEvent = | ||||
11485 | MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
11486 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 11487 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) |
11488 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60)) | ||||
Vaibhav Devmurari | 6abcf8f | 2022-06-06 10:08:05 +0000 | [diff] [blame] | 11489 | .build(); |
11490 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11491 | injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, |
Vaibhav Devmurari | 6abcf8f | 2022-06-06 10:08:05 +0000 | [diff] [blame] | 11492 | InputEventInjectionSync::WAIT_FOR_RESULT)) |
11493 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
11494 | |||||
11495 | // Receives cancel for first pointer after next pointer down | ||||
11496 | mSpyWindow->consumeMotionCancel(); | ||||
11497 | mSpyWindow->consumeMotionDown(); | ||||
11498 | |||||
11499 | mSpyWindow->assertNoEvents(); | ||||
11500 | } | ||||
11501 | |||||
arthurhung | f452d0b | 2021-01-06 00:19:52 +0800 | [diff] [blame] | 11502 | TEST_F(InputDispatcherDragTests, DragAndDrop) { |
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11503 | startDrag(); |
arthurhung | f452d0b | 2021-01-06 00:19:52 +0800 | [diff] [blame] | 11504 | |
11505 | // Move on window. | ||||
11506 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11507 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
arthurhung | f452d0b | 2021-01-06 00:19:52 +0800 | [diff] [blame] | 11508 | ADISPLAY_ID_DEFAULT, {50, 50})) |
11509 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11510 | mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
arthurhung | f452d0b | 2021-01-06 00:19:52 +0800 | [diff] [blame] | 11511 | mWindow->consumeDragEvent(false, 50, 50); |
11512 | mSecondWindow->assertNoEvents(); | ||||
11513 | |||||
11514 | // Move to another window. | ||||
11515 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11516 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
arthurhung | f452d0b | 2021-01-06 00:19:52 +0800 | [diff] [blame] | 11517 | ADISPLAY_ID_DEFAULT, {150, 50})) |
11518 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11519 | mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
arthurhung | f452d0b | 2021-01-06 00:19:52 +0800 | [diff] [blame] | 11520 | mWindow->consumeDragEvent(true, 150, 50); |
11521 | mSecondWindow->consumeDragEvent(false, 50, 50); | ||||
11522 | |||||
11523 | // drop to another window. | ||||
11524 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11525 | injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
arthurhung | f452d0b | 2021-01-06 00:19:52 +0800 | [diff] [blame] | 11526 | {150, 50})) |
11527 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11528 | mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Siarhei Vishniakou | a66d65e | 2023-06-16 10:32:51 -0700 | [diff] [blame] | 11529 | mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken()); |
arthurhung | f452d0b | 2021-01-06 00:19:52 +0800 | [diff] [blame] | 11530 | mWindow->assertNoEvents(); |
11531 | mSecondWindow->assertNoEvents(); | ||||
11532 | } | ||||
11533 | |||||
Vaibhav Devmurari | 110ba32 | 2023-11-17 10:47:16 +0000 | [diff] [blame] | 11534 | TEST_F(InputDispatcherDragTests, DragAndDropNotCancelledIfSomeOtherPointerIsPilfered) { |
11535 | startDrag(); | ||||
11536 | |||||
11537 | // No cancel event after drag start | ||||
11538 | mSpyWindow->assertNoEvents(); | ||||
11539 | |||||
11540 | const MotionEvent secondFingerDownEvent = | ||||
11541 | MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
11542 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
11543 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) | ||||
11544 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60)) | ||||
11545 | .build(); | ||||
11546 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
11547 | injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, | ||||
11548 | InputEventInjectionSync::WAIT_FOR_RESULT)) | ||||
11549 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
11550 | |||||
11551 | // Receives cancel for first pointer after next pointer down | ||||
11552 | mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); | ||||
Siarhei Vishniakou | 1ff00cc | 2023-12-13 16:12:13 -0800 | [diff] [blame] | 11553 | mSpyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithPointerIds({1}))); |
Vaibhav Devmurari | 110ba32 | 2023-11-17 10:47:16 +0000 | [diff] [blame] | 11554 | mDragWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); |
11555 | |||||
11556 | mSpyWindow->assertNoEvents(); | ||||
11557 | |||||
11558 | // Spy window calls pilfer pointers | ||||
11559 | EXPECT_EQ(OK, mDispatcher->pilferPointers(mSpyWindow->getToken())); | ||||
11560 | mDragWindow->assertNoEvents(); | ||||
11561 | |||||
11562 | const MotionEvent firstFingerMoveEvent = | ||||
Siarhei Vishniakou | 96a1557 | 2023-12-18 10:47:52 -0800 | [diff] [blame] | 11563 | MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) |
Vaibhav Devmurari | 110ba32 | 2023-11-17 10:47:16 +0000 | [diff] [blame] | 11564 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) |
11565 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(60).y(60)) | ||||
11566 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60)) | ||||
11567 | .build(); | ||||
11568 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | 96a1557 | 2023-12-18 10:47:52 -0800 | [diff] [blame] | 11569 | injectMotionEvent(*mDispatcher, firstFingerMoveEvent, INJECT_EVENT_TIMEOUT, |
Vaibhav Devmurari | 110ba32 | 2023-11-17 10:47:16 +0000 | [diff] [blame] | 11570 | InputEventInjectionSync::WAIT_FOR_RESULT)) |
11571 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
11572 | |||||
11573 | // Drag window should still receive the new event | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11574 | mDragWindow->consumeMotionEvent( |
11575 | AllOf(WithMotionAction(ACTION_MOVE), WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))); | ||||
Vaibhav Devmurari | 110ba32 | 2023-11-17 10:47:16 +0000 | [diff] [blame] | 11576 | mDragWindow->assertNoEvents(); |
11577 | } | ||||
11578 | |||||
arthurhung | 6d4bed9 | 2021-03-17 11:59:33 +0800 | [diff] [blame] | 11579 | TEST_F(InputDispatcherDragTests, StylusDragAndDrop) { |
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11580 | startDrag(true, AINPUT_SOURCE_STYLUS); |
arthurhung | 6d4bed9 | 2021-03-17 11:59:33 +0800 | [diff] [blame] | 11581 | |
11582 | // Move on window and keep button pressed. | ||||
11583 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11584 | injectMotionEvent(*mDispatcher, |
arthurhung | 6d4bed9 | 2021-03-17 11:59:33 +0800 | [diff] [blame] | 11585 | MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS) |
11586 | .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 11587 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) |
arthurhung | 6d4bed9 | 2021-03-17 11:59:33 +0800 | [diff] [blame] | 11588 | .build())) |
11589 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11590 | mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
arthurhung | 6d4bed9 | 2021-03-17 11:59:33 +0800 | [diff] [blame] | 11591 | mWindow->consumeDragEvent(false, 50, 50); |
11592 | mSecondWindow->assertNoEvents(); | ||||
11593 | |||||
11594 | // Move to another window and release button, expect to drop item. | ||||
11595 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11596 | injectMotionEvent(*mDispatcher, |
arthurhung | 6d4bed9 | 2021-03-17 11:59:33 +0800 | [diff] [blame] | 11597 | MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS) |
11598 | .buttonState(0) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 11599 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50)) |
arthurhung | 6d4bed9 | 2021-03-17 11:59:33 +0800 | [diff] [blame] | 11600 | .build())) |
11601 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11602 | mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
arthurhung | 6d4bed9 | 2021-03-17 11:59:33 +0800 | [diff] [blame] | 11603 | mWindow->assertNoEvents(); |
11604 | mSecondWindow->assertNoEvents(); | ||||
Siarhei Vishniakou | a66d65e | 2023-06-16 10:32:51 -0700 | [diff] [blame] | 11605 | mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken()); |
arthurhung | 6d4bed9 | 2021-03-17 11:59:33 +0800 | [diff] [blame] | 11606 | |
11607 | // nothing to the window. | ||||
11608 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11609 | injectMotionEvent(*mDispatcher, |
arthurhung | 6d4bed9 | 2021-03-17 11:59:33 +0800 | [diff] [blame] | 11610 | MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_STYLUS) |
11611 | .buttonState(0) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 11612 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50)) |
arthurhung | 6d4bed9 | 2021-03-17 11:59:33 +0800 | [diff] [blame] | 11613 | .build())) |
11614 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11615 | mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
arthurhung | 6d4bed9 | 2021-03-17 11:59:33 +0800 | [diff] [blame] | 11616 | mWindow->assertNoEvents(); |
11617 | mSecondWindow->assertNoEvents(); | ||||
11618 | } | ||||
11619 | |||||
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11620 | TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) { |
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11621 | startDrag(); |
Arthur Hung | 6d0571e | 2021-04-09 20:18:16 +0800 | [diff] [blame] | 11622 | |
11623 | // Set second window invisible. | ||||
11624 | mSecondWindow->setVisible(false); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11625 | mDispatcher->onWindowInfosChanged( |
11626 | {{*mDragWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0}); | ||||
Arthur Hung | 6d0571e | 2021-04-09 20:18:16 +0800 | [diff] [blame] | 11627 | |
11628 | // Move on window. | ||||
11629 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11630 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
Arthur Hung | 6d0571e | 2021-04-09 20:18:16 +0800 | [diff] [blame] | 11631 | ADISPLAY_ID_DEFAULT, {50, 50})) |
11632 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11633 | mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Arthur Hung | 6d0571e | 2021-04-09 20:18:16 +0800 | [diff] [blame] | 11634 | mWindow->consumeDragEvent(false, 50, 50); |
11635 | mSecondWindow->assertNoEvents(); | ||||
11636 | |||||
11637 | // Move to another window. | ||||
11638 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11639 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
Arthur Hung | 6d0571e | 2021-04-09 20:18:16 +0800 | [diff] [blame] | 11640 | ADISPLAY_ID_DEFAULT, {150, 50})) |
11641 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11642 | mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Arthur Hung | 6d0571e | 2021-04-09 20:18:16 +0800 | [diff] [blame] | 11643 | mWindow->consumeDragEvent(true, 150, 50); |
11644 | mSecondWindow->assertNoEvents(); | ||||
11645 | |||||
11646 | // drop to another window. | ||||
11647 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11648 | injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Arthur Hung | 6d0571e | 2021-04-09 20:18:16 +0800 | [diff] [blame] | 11649 | {150, 50})) |
11650 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11651 | mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Siarhei Vishniakou | a66d65e | 2023-06-16 10:32:51 -0700 | [diff] [blame] | 11652 | mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr); |
Arthur Hung | 6d0571e | 2021-04-09 20:18:16 +0800 | [diff] [blame] | 11653 | mWindow->assertNoEvents(); |
11654 | mSecondWindow->assertNoEvents(); | ||||
11655 | } | ||||
11656 | |||||
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11657 | TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) { |
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11658 | // Ensure window could track pointerIds if it didn't support split touch. |
11659 | mWindow->setPreventSplitting(true); | ||||
11660 | |||||
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11661 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11662 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11663 | {50, 50})) |
11664 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
11665 | mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
11666 | |||||
11667 | const MotionEvent secondFingerDownEvent = | ||||
11668 | MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
11669 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
11670 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 11671 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) |
11672 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(75).y(50)) | ||||
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11673 | .build(); |
11674 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11675 | injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, |
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11676 | InputEventInjectionSync::WAIT_FOR_RESULT)) |
11677 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 11678 | mWindow->consumeMotionPointerDown(/*pointerIndex=*/1); |
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11679 | |
11680 | // Should not perform drag and drop when window has multi fingers. | ||||
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11681 | ASSERT_FALSE(startDrag(false)); |
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11682 | } |
11683 | |||||
11684 | TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) { | ||||
11685 | // First down on second window. | ||||
11686 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11687 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11688 | {150, 50})) |
11689 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
11690 | |||||
11691 | mSecondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
11692 | |||||
11693 | // Second down on first window. | ||||
11694 | const MotionEvent secondFingerDownEvent = | ||||
11695 | MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
11696 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
11697 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 11698 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50)) |
11699 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) | ||||
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11700 | .build(); |
11701 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11702 | injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, |
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11703 | InputEventInjectionSync::WAIT_FOR_RESULT)) |
11704 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
11705 | mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | 9d5f9ce | 2024-01-24 00:03:41 +0000 | [diff] [blame] | 11706 | mSecondWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); |
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11707 | |
11708 | // Perform drag and drop from first window. | ||||
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11709 | ASSERT_TRUE(startDrag(false)); |
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11710 | |
11711 | // Move on window. | ||||
11712 | const MotionEvent secondFingerMoveEvent = | ||||
11713 | MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
11714 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 11715 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50)) |
11716 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) | ||||
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11717 | .build(); |
11718 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11719 | injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT, |
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11720 | InputEventInjectionSync::WAIT_FOR_RESULT)); |
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11721 | mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11722 | mWindow->consumeDragEvent(false, 50, 50); |
11723 | mSecondWindow->consumeMotionMove(); | ||||
11724 | |||||
11725 | // Release the drag pointer should perform drop. | ||||
11726 | const MotionEvent secondFingerUpEvent = | ||||
11727 | MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
11728 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 11729 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50)) |
11730 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) | ||||
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11731 | .build(); |
11732 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11733 | injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, |
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11734 | InputEventInjectionSync::WAIT_FOR_RESULT)); |
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11735 | mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Siarhei Vishniakou | a66d65e | 2023-06-16 10:32:51 -0700 | [diff] [blame] | 11736 | mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken()); |
Arthur Hung | 5474565 | 2022-04-20 07:17:41 +0000 | [diff] [blame] | 11737 | mWindow->assertNoEvents(); |
11738 | mSecondWindow->consumeMotionMove(); | ||||
11739 | } | ||||
11740 | |||||
Arthur Hung | 3915c1f | 2022-05-31 07:17:17 +0000 | [diff] [blame] | 11741 | TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) { |
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11742 | startDrag(); |
Arthur Hung | 3915c1f | 2022-05-31 07:17:17 +0000 | [diff] [blame] | 11743 | |
11744 | // Update window of second display. | ||||
11745 | sp<FakeWindowHandle> windowInSecondary = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 11746 | sp<FakeWindowHandle>::make(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11747 | mDispatcher->onWindowInfosChanged( |
11748 | {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(), | ||||
11749 | *mSecondWindow->getInfo(), *windowInSecondary->getInfo()}, | ||||
11750 | {}, | ||||
11751 | 0, | ||||
11752 | 0}); | ||||
Arthur Hung | 3915c1f | 2022-05-31 07:17:17 +0000 | [diff] [blame] | 11753 | |
11754 | // Let second display has a touch state. | ||||
11755 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11756 | injectMotionEvent(*mDispatcher, |
Arthur Hung | 3915c1f | 2022-05-31 07:17:17 +0000 | [diff] [blame] | 11757 | MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, |
11758 | AINPUT_SOURCE_TOUCHSCREEN) | ||||
11759 | .displayId(SECOND_DISPLAY_ID) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 11760 | .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) |
Arthur Hung | 3915c1f | 2022-05-31 07:17:17 +0000 | [diff] [blame] | 11761 | .build())); |
Prabir Pradhan | 7662a8d | 2023-12-15 01:58:14 +0000 | [diff] [blame] | 11762 | windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID, /*expectedFlag=*/0); |
Arthur Hung | 3915c1f | 2022-05-31 07:17:17 +0000 | [diff] [blame] | 11763 | // Update window again. |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11764 | mDispatcher->onWindowInfosChanged( |
11765 | {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(), | ||||
11766 | *mSecondWindow->getInfo(), *windowInSecondary->getInfo()}, | ||||
11767 | {}, | ||||
11768 | 0, | ||||
11769 | 0}); | ||||
Arthur Hung | 3915c1f | 2022-05-31 07:17:17 +0000 | [diff] [blame] | 11770 | |
11771 | // Move on window. | ||||
11772 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11773 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
Arthur Hung | 3915c1f | 2022-05-31 07:17:17 +0000 | [diff] [blame] | 11774 | ADISPLAY_ID_DEFAULT, {50, 50})) |
11775 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11776 | mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Arthur Hung | 3915c1f | 2022-05-31 07:17:17 +0000 | [diff] [blame] | 11777 | mWindow->consumeDragEvent(false, 50, 50); |
11778 | mSecondWindow->assertNoEvents(); | ||||
11779 | |||||
11780 | // Move to another window. | ||||
11781 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11782 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
Arthur Hung | 3915c1f | 2022-05-31 07:17:17 +0000 | [diff] [blame] | 11783 | ADISPLAY_ID_DEFAULT, {150, 50})) |
11784 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11785 | mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Arthur Hung | 3915c1f | 2022-05-31 07:17:17 +0000 | [diff] [blame] | 11786 | mWindow->consumeDragEvent(true, 150, 50); |
11787 | mSecondWindow->consumeDragEvent(false, 50, 50); | ||||
11788 | |||||
11789 | // drop to another window. | ||||
11790 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11791 | injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Arthur Hung | 3915c1f | 2022-05-31 07:17:17 +0000 | [diff] [blame] | 11792 | {150, 50})) |
11793 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11794 | mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Siarhei Vishniakou | a66d65e | 2023-06-16 10:32:51 -0700 | [diff] [blame] | 11795 | mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken()); |
Arthur Hung | 3915c1f | 2022-05-31 07:17:17 +0000 | [diff] [blame] | 11796 | mWindow->assertNoEvents(); |
11797 | mSecondWindow->assertNoEvents(); | ||||
11798 | } | ||||
11799 | |||||
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11800 | TEST_F(InputDispatcherDragTests, MouseDragAndDrop) { |
11801 | startDrag(true, AINPUT_SOURCE_MOUSE); | ||||
11802 | // Move on window. | ||||
11803 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11804 | injectMotionEvent(*mDispatcher, |
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11805 | MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE) |
11806 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11807 | .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE) |
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11808 | .x(50) |
11809 | .y(50)) | ||||
11810 | .build())) | ||||
11811 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11812 | mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11813 | mWindow->consumeDragEvent(false, 50, 50); |
11814 | mSecondWindow->assertNoEvents(); | ||||
11815 | |||||
11816 | // Move to another window. | ||||
11817 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11818 | injectMotionEvent(*mDispatcher, |
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11819 | MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE) |
11820 | .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11821 | .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE) |
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11822 | .x(150) |
11823 | .y(50)) | ||||
11824 | .build())) | ||||
11825 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11826 | mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11827 | mWindow->consumeDragEvent(true, 150, 50); |
11828 | mSecondWindow->consumeDragEvent(false, 50, 50); | ||||
11829 | |||||
11830 | // drop to another window. | ||||
11831 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11832 | injectMotionEvent(*mDispatcher, |
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11833 | MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE) |
11834 | .buttonState(0) | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 11835 | .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE) |
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11836 | .x(150) |
11837 | .y(50)) | ||||
11838 | .build())) | ||||
11839 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11840 | mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); |
Siarhei Vishniakou | a66d65e | 2023-06-16 10:32:51 -0700 | [diff] [blame] | 11841 | mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken()); |
Arthur Hung | b75c2aa | 2022-07-15 09:35:36 +0000 | [diff] [blame] | 11842 | mWindow->assertNoEvents(); |
11843 | mSecondWindow->assertNoEvents(); | ||||
11844 | } | ||||
11845 | |||||
Linnan Li | 5af92f9 | 2023-07-14 14:36:22 +0800 | [diff] [blame] | 11846 | /** |
11847 | * Start drag and drop with a pointer whose id is not 0, cancel the current touch, and ensure drag | ||||
11848 | * and drop is also canceled. Then inject a simple gesture, and ensure dispatcher does not crash. | ||||
11849 | */ | ||||
11850 | TEST_F(InputDispatcherDragTests, DragAndDropFinishedWhenCancelCurrentTouch) { | ||||
11851 | // Down on second window | ||||
11852 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
11853 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
11854 | {150, 50})) | ||||
11855 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
11856 | |||||
11857 | ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionDown()); | ||||
11858 | ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionDown()); | ||||
11859 | |||||
11860 | // Down on first window | ||||
11861 | const MotionEvent secondFingerDownEvent = | ||||
11862 | MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
11863 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
11864 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50)) | ||||
11865 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) | ||||
11866 | .build(); | ||||
11867 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
11868 | injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, | ||||
11869 | InputEventInjectionSync::WAIT_FOR_RESULT)) | ||||
11870 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
11871 | ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown()); | ||||
11872 | ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionMove()); | ||||
11873 | ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionPointerDown(1)); | ||||
11874 | |||||
11875 | // Start drag on first window | ||||
11876 | ASSERT_TRUE(startDrag(/*sendDown=*/false, AINPUT_SOURCE_TOUCHSCREEN)); | ||||
11877 | |||||
11878 | // Trigger cancel | ||||
11879 | mDispatcher->cancelCurrentTouch(); | ||||
11880 | ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionCancel()); | ||||
Prabir Pradhan | 65455c7 | 2024-02-13 21:46:41 +0000 | [diff] [blame] | 11881 | ASSERT_NO_FATAL_FAILURE(mDragWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, |
11882 | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)); | ||||
Linnan Li | 5af92f9 | 2023-07-14 14:36:22 +0800 | [diff] [blame] | 11883 | ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionCancel()); |
11884 | |||||
11885 | ASSERT_TRUE(mDispatcher->waitForIdle()); | ||||
11886 | // The D&D finished with nullptr | ||||
11887 | mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr); | ||||
11888 | |||||
11889 | // Remove drag window | ||||
11890 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0}); | ||||
11891 | |||||
11892 | // Inject a simple gesture, ensure dispatcher not crashed | ||||
11893 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
11894 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
11895 | PointF{50, 50})) | ||||
11896 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
11897 | ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown()); | ||||
11898 | |||||
11899 | const MotionEvent moveEvent = | ||||
11900 | MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
11901 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
11902 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) | ||||
11903 | .build(); | ||||
11904 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
11905 | injectMotionEvent(*mDispatcher, moveEvent, INJECT_EVENT_TIMEOUT, | ||||
11906 | InputEventInjectionSync::WAIT_FOR_RESULT)) | ||||
11907 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
11908 | ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionMove()); | ||||
11909 | |||||
11910 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
11911 | injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, | ||||
11912 | {50, 50})) | ||||
11913 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
11914 | ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionUp()); | ||||
11915 | } | ||||
11916 | |||||
Prabir Pradhan | 9cd9eb6 | 2023-11-22 17:58:06 +0000 | [diff] [blame] | 11917 | TEST_F(InputDispatcherDragTests, NoDragAndDropWithHoveringPointer) { |
11918 | // Start hovering over the window. | ||||
11919 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
11920 | injectMotionEvent(*mDispatcher, ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE, | ||||
11921 | ADISPLAY_ID_DEFAULT, {50, 50})); | ||||
11922 | |||||
11923 | ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER))); | ||||
11924 | ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER))); | ||||
11925 | |||||
11926 | ASSERT_FALSE(startDrag(/*sendDown=*/false)) | ||||
11927 | << "Drag and drop should not work with a hovering pointer"; | ||||
11928 | } | ||||
11929 | |||||
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 11930 | class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {}; |
11931 | |||||
11932 | TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) { | ||||
11933 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 11934 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
11935 | "Test window", ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | 51e7db0 | 2022-02-07 06:02:57 -0800 | [diff] [blame] | 11936 | window->setDropInput(true); |
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 11937 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); |
11938 | window->setFocusable(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11939 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 11940 | setFocusedWindow(window); |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 11941 | window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true); |
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 11942 | |
11943 | // With the flag set, window should not get any input | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 11944 | mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); |
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 11945 | window->assertNoEvents(); |
11946 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 11947 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
11948 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); | ||||
Siarhei Vishniakou | 5c02a71 | 2023-05-15 15:45:02 -0700 | [diff] [blame] | 11949 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, |
11950 | ADISPLAY_ID_DEFAULT)); | ||||
Siarhei Vishniakou | d908f5a | 2023-11-16 10:25:12 -0800 | [diff] [blame] | 11951 | mDispatcher->waitForIdle(); |
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 11952 | window->assertNoEvents(); |
11953 | |||||
11954 | // With the flag cleared, the window should get input | ||||
Prabir Pradhan | 51e7db0 | 2022-02-07 06:02:57 -0800 | [diff] [blame] | 11955 | window->setDropInput(false); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11956 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 11957 | |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 11958 | mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT)); |
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 11959 | window->consumeKeyUp(ADISPLAY_ID_DEFAULT); |
11960 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 11961 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
11962 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); | ||||
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 11963 | window->consumeMotionDown(ADISPLAY_ID_DEFAULT); |
11964 | window->assertNoEvents(); | ||||
11965 | } | ||||
11966 | |||||
11967 | TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) { | ||||
11968 | std::shared_ptr<FakeApplicationHandle> obscuringApplication = | ||||
11969 | std::make_shared<FakeApplicationHandle>(); | ||||
11970 | sp<FakeWindowHandle> obscuringWindow = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 11971 | sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow", |
11972 | ADISPLAY_ID_DEFAULT); | ||||
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 11973 | obscuringWindow->setFrame(Rect(0, 0, 50, 50)); |
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 11974 | obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111}); |
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 11975 | obscuringWindow->setTouchable(false); |
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 11976 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 11977 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
11978 | "Test window", ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | 51e7db0 | 2022-02-07 06:02:57 -0800 | [diff] [blame] | 11979 | window->setDropInputIfObscured(true); |
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 11980 | window->setOwnerInfo(gui::Pid{222}, gui::Uid{222}); |
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 11981 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); |
11982 | window->setFocusable(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 11983 | mDispatcher->onWindowInfosChanged( |
11984 | {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); | ||||
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 11985 | setFocusedWindow(window); |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 11986 | window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true); |
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 11987 | |
11988 | // With the flag set, window should not get any input | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 11989 | mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); |
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 11990 | window->assertNoEvents(); |
11991 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 11992 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
11993 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); | ||||
Siarhei Vishniakou | 5c02a71 | 2023-05-15 15:45:02 -0700 | [diff] [blame] | 11994 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, |
11995 | ADISPLAY_ID_DEFAULT)); | ||||
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 11996 | window->assertNoEvents(); |
11997 | |||||
11998 | // With the flag cleared, the window should get input | ||||
Prabir Pradhan | 51e7db0 | 2022-02-07 06:02:57 -0800 | [diff] [blame] | 11999 | window->setDropInputIfObscured(false); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12000 | mDispatcher->onWindowInfosChanged( |
12001 | {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); | ||||
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 12002 | |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 12003 | mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT)); |
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 12004 | window->consumeKeyUp(ADISPLAY_ID_DEFAULT); |
12005 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 12006 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
12007 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); | ||||
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 12008 | window->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED); |
12009 | window->assertNoEvents(); | ||||
12010 | } | ||||
12011 | |||||
12012 | TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) { | ||||
12013 | std::shared_ptr<FakeApplicationHandle> obscuringApplication = | ||||
12014 | std::make_shared<FakeApplicationHandle>(); | ||||
12015 | sp<FakeWindowHandle> obscuringWindow = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 12016 | sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow", |
12017 | ADISPLAY_ID_DEFAULT); | ||||
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 12018 | obscuringWindow->setFrame(Rect(0, 0, 50, 50)); |
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 12019 | obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111}); |
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 12020 | obscuringWindow->setTouchable(false); |
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 12021 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 12022 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, |
12023 | "Test window", ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | 51e7db0 | 2022-02-07 06:02:57 -0800 | [diff] [blame] | 12024 | window->setDropInputIfObscured(true); |
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 12025 | window->setOwnerInfo(gui::Pid{222}, gui::Uid{222}); |
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 12026 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); |
12027 | window->setFocusable(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12028 | mDispatcher->onWindowInfosChanged( |
12029 | {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); | ||||
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 12030 | setFocusedWindow(window); |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 12031 | window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true); |
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 12032 | |
12033 | // With the flag set, window should not get any input | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 12034 | mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); |
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 12035 | window->assertNoEvents(); |
12036 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 12037 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
12038 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); | ||||
Siarhei Vishniakou | 5c02a71 | 2023-05-15 15:45:02 -0700 | [diff] [blame] | 12039 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, |
12040 | ADISPLAY_ID_DEFAULT)); | ||||
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 12041 | window->assertNoEvents(); |
12042 | |||||
12043 | // When the window is no longer obscured because it went on top, it should get input | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12044 | mDispatcher->onWindowInfosChanged( |
12045 | {{*window->getInfo(), *obscuringWindow->getInfo()}, {}, 0, 0}); | ||||
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 12046 | |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 12047 | mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT)); |
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 12048 | window->consumeKeyUp(ADISPLAY_ID_DEFAULT); |
12049 | |||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 12050 | mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, |
12051 | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); | ||||
Vishnu Nair | 062a867 | 2021-09-03 16:07:44 -0700 | [diff] [blame] | 12052 | window->consumeMotionDown(ADISPLAY_ID_DEFAULT); |
12053 | window->assertNoEvents(); | ||||
12054 | } | ||||
12055 | |||||
Antonio Kantek | f16f283 | 2021-09-28 04:39:20 +0000 | [diff] [blame] | 12056 | class InputDispatcherTouchModeChangedTests : public InputDispatcherTest { |
12057 | protected: | ||||
12058 | std::shared_ptr<FakeApplicationHandle> mApp; | ||||
Antonio Kantek | 15beb51 | 2022-06-13 22:35:41 +0000 | [diff] [blame] | 12059 | std::shared_ptr<FakeApplicationHandle> mSecondaryApp; |
Antonio Kantek | f16f283 | 2021-09-28 04:39:20 +0000 | [diff] [blame] | 12060 | sp<FakeWindowHandle> mWindow; |
12061 | sp<FakeWindowHandle> mSecondWindow; | ||||
Antonio Kantek | 15beb51 | 2022-06-13 22:35:41 +0000 | [diff] [blame] | 12062 | sp<FakeWindowHandle> mThirdWindow; |
Antonio Kantek | f16f283 | 2021-09-28 04:39:20 +0000 | [diff] [blame] | 12063 | |
12064 | void SetUp() override { | ||||
12065 | InputDispatcherTest::SetUp(); | ||||
12066 | |||||
12067 | mApp = std::make_shared<FakeApplicationHandle>(); | ||||
Antonio Kantek | 15beb51 | 2022-06-13 22:35:41 +0000 | [diff] [blame] | 12068 | mSecondaryApp = std::make_shared<FakeApplicationHandle>(); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 12069 | mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); |
Antonio Kantek | f16f283 | 2021-09-28 04:39:20 +0000 | [diff] [blame] | 12070 | mWindow->setFocusable(true); |
Antonio Kantek | 26defcf | 2022-02-08 01:12:27 +0000 | [diff] [blame] | 12071 | setFocusedWindow(mWindow); |
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 12072 | mSecondWindow = |
12073 | sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT); | ||||
Antonio Kantek | f16f283 | 2021-09-28 04:39:20 +0000 | [diff] [blame] | 12074 | mSecondWindow->setFocusable(true); |
Antonio Kantek | 15beb51 | 2022-06-13 22:35:41 +0000 | [diff] [blame] | 12075 | mThirdWindow = |
12076 | sp<FakeWindowHandle>::make(mSecondaryApp, mDispatcher, | ||||
12077 | "TestWindow3_SecondaryDisplay", SECOND_DISPLAY_ID); | ||||
12078 | mThirdWindow->setFocusable(true); | ||||
Antonio Kantek | f16f283 | 2021-09-28 04:39:20 +0000 | [diff] [blame] | 12079 | |
12080 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12081 | mDispatcher->onWindowInfosChanged( |
12082 | {{*mWindow->getInfo(), *mSecondWindow->getInfo(), *mThirdWindow->getInfo()}, | ||||
12083 | {}, | ||||
12084 | 0, | ||||
12085 | 0}); | ||||
Antonio Kantek | 15beb51 | 2022-06-13 22:35:41 +0000 | [diff] [blame] | 12086 | mThirdWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID); |
Antonio Kantek | f16f283 | 2021-09-28 04:39:20 +0000 | [diff] [blame] | 12087 | mWindow->consumeFocusEvent(true); |
Antonio Kantek | 26defcf | 2022-02-08 01:12:27 +0000 | [diff] [blame] | 12088 | |
Antonio Kantek | 15beb51 | 2022-06-13 22:35:41 +0000 | [diff] [blame] | 12089 | // Set main display initial touch mode to InputDispatcher::kDefaultInTouchMode. |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 12090 | if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 12091 | WINDOW_UID, /*hasPermission=*/true, ADISPLAY_ID_DEFAULT)) { |
Antonio Kantek | 48710e4 | 2022-03-24 14:19:30 -0700 | [diff] [blame] | 12092 | mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode); |
12093 | mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode); | ||||
Antonio Kantek | 15beb51 | 2022-06-13 22:35:41 +0000 | [diff] [blame] | 12094 | mThirdWindow->assertNoEvents(); |
12095 | } | ||||
12096 | |||||
12097 | // Set secondary display initial touch mode to InputDispatcher::kDefaultInTouchMode. | ||||
12098 | if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, SECONDARY_WINDOW_PID, | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 12099 | SECONDARY_WINDOW_UID, /*hasPermission=*/true, |
Antonio Kantek | 15beb51 | 2022-06-13 22:35:41 +0000 | [diff] [blame] | 12100 | SECOND_DISPLAY_ID)) { |
12101 | mWindow->assertNoEvents(); | ||||
12102 | mSecondWindow->assertNoEvents(); | ||||
12103 | mThirdWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode); | ||||
Antonio Kantek | 48710e4 | 2022-03-24 14:19:30 -0700 | [diff] [blame] | 12104 | } |
Antonio Kantek | f16f283 | 2021-09-28 04:39:20 +0000 | [diff] [blame] | 12105 | } |
12106 | |||||
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 12107 | void changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode, gui::Pid pid, gui::Uid uid, |
Antonio Kantek | 15beb51 | 2022-06-13 22:35:41 +0000 | [diff] [blame] | 12108 | bool hasPermission) { |
Antonio Kantek | a042c02 | 2022-07-06 16:51:07 -0700 | [diff] [blame] | 12109 | ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission, |
12110 | ADISPLAY_ID_DEFAULT)); | ||||
Antonio Kantek | f16f283 | 2021-09-28 04:39:20 +0000 | [diff] [blame] | 12111 | mWindow->consumeTouchModeEvent(inTouchMode); |
12112 | mSecondWindow->consumeTouchModeEvent(inTouchMode); | ||||
Antonio Kantek | 15beb51 | 2022-06-13 22:35:41 +0000 | [diff] [blame] | 12113 | mThirdWindow->assertNoEvents(); |
Antonio Kantek | f16f283 | 2021-09-28 04:39:20 +0000 | [diff] [blame] | 12114 | } |
12115 | }; | ||||
12116 | |||||
Antonio Kantek | 26defcf | 2022-02-08 01:12:27 +0000 | [diff] [blame] | 12117 | TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) { |
Antonio Kantek | ea47acb | 2021-12-23 12:41:25 -0800 | [diff] [blame] | 12118 | const WindowInfo& windowInfo = *mWindow->getInfo(); |
Antonio Kantek | 15beb51 | 2022-06-13 22:35:41 +0000 | [diff] [blame] | 12119 | changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode, |
12120 | windowInfo.ownerPid, windowInfo.ownerUid, | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 12121 | /* hasPermission=*/false); |
Antonio Kantek | f16f283 | 2021-09-28 04:39:20 +0000 | [diff] [blame] | 12122 | } |
12123 | |||||
Antonio Kantek | 26defcf | 2022-02-08 01:12:27 +0000 | [diff] [blame] | 12124 | TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) { |
12125 | const WindowInfo& windowInfo = *mWindow->getInfo(); | ||||
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 12126 | gui::Pid ownerPid = windowInfo.ownerPid; |
Prabir Pradhan | 8a5c41d | 2023-06-08 19:13:46 +0000 | [diff] [blame] | 12127 | gui::Uid ownerUid = windowInfo.ownerUid; |
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 12128 | mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID); |
Antonio Kantek | 26defcf | 2022-02-08 01:12:27 +0000 | [diff] [blame] | 12129 | ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, ownerPid, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 12130 | ownerUid, /*hasPermission=*/false, |
Antonio Kantek | a042c02 | 2022-07-06 16:51:07 -0700 | [diff] [blame] | 12131 | ADISPLAY_ID_DEFAULT)); |
Antonio Kantek | 26defcf | 2022-02-08 01:12:27 +0000 | [diff] [blame] | 12132 | mWindow->assertNoEvents(); |
12133 | mSecondWindow->assertNoEvents(); | ||||
12134 | } | ||||
12135 | |||||
12136 | TEST_F(InputDispatcherTouchModeChangedTests, NonWindowOwnerMayChangeTouchModeOnPermissionGranted) { | ||||
12137 | const WindowInfo& windowInfo = *mWindow->getInfo(); | ||||
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 12138 | gui::Pid ownerPid = windowInfo.ownerPid; |
Prabir Pradhan | 8a5c41d | 2023-06-08 19:13:46 +0000 | [diff] [blame] | 12139 | gui::Uid ownerUid = windowInfo.ownerUid; |
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 12140 | mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID); |
Antonio Kantek | 15beb51 | 2022-06-13 22:35:41 +0000 | [diff] [blame] | 12141 | changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode, ownerPid, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 12142 | ownerUid, /*hasPermission=*/true); |
Antonio Kantek | 26defcf | 2022-02-08 01:12:27 +0000 | [diff] [blame] | 12143 | } |
12144 | |||||
Antonio Kantek | f16f283 | 2021-09-28 04:39:20 +0000 | [diff] [blame] | 12145 | TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) { |
Antonio Kantek | ea47acb | 2021-12-23 12:41:25 -0800 | [diff] [blame] | 12146 | const WindowInfo& windowInfo = *mWindow->getInfo(); |
Antonio Kantek | 26defcf | 2022-02-08 01:12:27 +0000 | [diff] [blame] | 12147 | ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, |
12148 | windowInfo.ownerPid, windowInfo.ownerUid, | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 12149 | /*hasPermission=*/true, ADISPLAY_ID_DEFAULT)); |
Antonio Kantek | f16f283 | 2021-09-28 04:39:20 +0000 | [diff] [blame] | 12150 | mWindow->assertNoEvents(); |
12151 | mSecondWindow->assertNoEvents(); | ||||
12152 | } | ||||
12153 | |||||
Antonio Kantek | 15beb51 | 2022-06-13 22:35:41 +0000 | [diff] [blame] | 12154 | TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchOnSecondaryDisplayOnly) { |
12155 | const WindowInfo& windowInfo = *mThirdWindow->getInfo(); | ||||
12156 | ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode, | ||||
12157 | windowInfo.ownerPid, windowInfo.ownerUid, | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 12158 | /*hasPermission=*/true, SECOND_DISPLAY_ID)); |
Antonio Kantek | 15beb51 | 2022-06-13 22:35:41 +0000 | [diff] [blame] | 12159 | mWindow->assertNoEvents(); |
12160 | mSecondWindow->assertNoEvents(); | ||||
12161 | mThirdWindow->consumeTouchModeEvent(!InputDispatcher::kDefaultInTouchMode); | ||||
12162 | } | ||||
12163 | |||||
Antonio Kantek | 48710e4 | 2022-03-24 14:19:30 -0700 | [diff] [blame] | 12164 | TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) { |
12165 | // Interact with the window first. | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12166 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, |
12167 | injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT)) | ||||
Antonio Kantek | 48710e4 | 2022-03-24 14:19:30 -0700 | [diff] [blame] | 12168 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
12169 | mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); | ||||
12170 | |||||
12171 | // Then remove focus. | ||||
12172 | mWindow->setFocusable(false); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12173 | mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); |
Antonio Kantek | 48710e4 | 2022-03-24 14:19:30 -0700 | [diff] [blame] | 12174 | |
12175 | // Assert that caller can switch touch mode by owning one of the last interacted window. | ||||
12176 | const WindowInfo& windowInfo = *mWindow->getInfo(); | ||||
12177 | ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode, | ||||
12178 | windowInfo.ownerPid, windowInfo.ownerUid, | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 12179 | /*hasPermission=*/false, ADISPLAY_ID_DEFAULT)); |
Antonio Kantek | 48710e4 | 2022-03-24 14:19:30 -0700 | [diff] [blame] | 12180 | } |
12181 | |||||
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12182 | class InputDispatcherSpyWindowTest : public InputDispatcherTest { |
12183 | public: | ||||
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 12184 | sp<FakeWindowHandle> createSpy() { |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12185 | std::shared_ptr<FakeApplicationHandle> application = |
12186 | std::make_shared<FakeApplicationHandle>(); | ||||
12187 | std::string name = "Fake Spy "; | ||||
12188 | name += std::to_string(mSpyCount++); | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 12189 | sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(application, mDispatcher, |
12190 | name.c_str(), ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | 51e7db0 | 2022-02-07 06:02:57 -0800 | [diff] [blame] | 12191 | spy->setSpy(true); |
Prabir Pradhan | 5c85e05 | 2021-12-22 02:27:12 -0800 | [diff] [blame] | 12192 | spy->setTrustedOverlay(true); |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12193 | return spy; |
12194 | } | ||||
12195 | |||||
12196 | sp<FakeWindowHandle> createForeground() { | ||||
12197 | std::shared_ptr<FakeApplicationHandle> application = | ||||
12198 | std::make_shared<FakeApplicationHandle>(); | ||||
12199 | sp<FakeWindowHandle> window = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 12200 | sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window", |
12201 | ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 12202 | window->setFocusable(true); |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12203 | return window; |
12204 | } | ||||
12205 | |||||
12206 | private: | ||||
12207 | int mSpyCount{0}; | ||||
12208 | }; | ||||
12209 | |||||
Prabir Pradhan | a3ab87a | 2022-01-27 10:00:21 -0800 | [diff] [blame] | 12210 | using InputDispatcherSpyWindowDeathTest = InputDispatcherSpyWindowTest; |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12211 | /** |
Prabir Pradhan | 5c85e05 | 2021-12-22 02:27:12 -0800 | [diff] [blame] | 12212 | * Adding a spy window that is not a trusted overlay causes Dispatcher to abort. |
12213 | */ | ||||
Prabir Pradhan | a3ab87a | 2022-01-27 10:00:21 -0800 | [diff] [blame] | 12214 | TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) { |
Siarhei Vishniakou | 21f77bd | 2023-07-18 17:51:35 -0700 | [diff] [blame] | 12215 | testing::GTEST_FLAG(death_test_style) = "threadsafe"; |
Prabir Pradhan | a3ab87a | 2022-01-27 10:00:21 -0800 | [diff] [blame] | 12216 | ScopedSilentDeath _silentDeath; |
12217 | |||||
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 12218 | auto spy = createSpy(); |
Prabir Pradhan | 5c85e05 | 2021-12-22 02:27:12 -0800 | [diff] [blame] | 12219 | spy->setTrustedOverlay(false); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12220 | ASSERT_DEATH(mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0}), |
Prabir Pradhan | 5c85e05 | 2021-12-22 02:27:12 -0800 | [diff] [blame] | 12221 | ".* not a trusted overlay"); |
12222 | } | ||||
12223 | |||||
12224 | /** | ||||
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12225 | * Input injection into a display with a spy window but no foreground windows should succeed. |
12226 | */ | ||||
12227 | TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) { | ||||
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 12228 | auto spy = createSpy(); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12229 | mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12230 | |
12231 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12232 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12233 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
12234 | spy->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
12235 | } | ||||
12236 | |||||
12237 | /** | ||||
12238 | * Verify the order in which different input windows receive events. The touched foreground window | ||||
12239 | * (if there is one) should always receive the event first. When there are multiple spy windows, the | ||||
12240 | * spy windows will receive the event according to their Z-order, where the top-most spy window will | ||||
12241 | * receive events before ones belows it. | ||||
12242 | * | ||||
12243 | * Here, we set up a scenario with four windows in the following Z order from the top: | ||||
12244 | * spy1, spy2, window, spy3. | ||||
12245 | * We then inject an event and verify that the foreground "window" receives it first, followed by | ||||
12246 | * "spy1" and "spy2". The "spy3" does not receive the event because it is underneath the foreground | ||||
12247 | * window. | ||||
12248 | */ | ||||
12249 | TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) { | ||||
12250 | auto window = createForeground(); | ||||
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 12251 | auto spy1 = createSpy(); |
12252 | auto spy2 = createSpy(); | ||||
12253 | auto spy3 = createSpy(); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12254 | mDispatcher->onWindowInfosChanged( |
12255 | {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo(), *spy3->getInfo()}, {}, 0, 0}); | ||||
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12256 | const std::vector<sp<FakeWindowHandle>> channels{spy1, spy2, window, spy3}; |
12257 | const size_t numChannels = channels.size(); | ||||
12258 | |||||
Michael Wright | 8e9a856 | 2022-02-09 13:44:29 +0000 | [diff] [blame] | 12259 | base::unique_fd epollFd(epoll_create1(EPOLL_CLOEXEC)); |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12260 | if (!epollFd.ok()) { |
12261 | FAIL() << "Failed to create epoll fd"; | ||||
12262 | } | ||||
12263 | |||||
12264 | for (size_t i = 0; i < numChannels; i++) { | ||||
12265 | struct epoll_event event = {.events = EPOLLIN, .data.u64 = i}; | ||||
12266 | if (epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, channels[i]->getChannelFd(), &event) < 0) { | ||||
12267 | FAIL() << "Failed to add fd to epoll"; | ||||
12268 | } | ||||
12269 | } | ||||
12270 | |||||
12271 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12272 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12273 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
12274 | |||||
12275 | std::vector<size_t> eventOrder; | ||||
12276 | std::vector<struct epoll_event> events(numChannels); | ||||
12277 | for (;;) { | ||||
12278 | const int nFds = epoll_wait(epollFd.get(), events.data(), static_cast<int>(numChannels), | ||||
12279 | (100ms).count()); | ||||
12280 | if (nFds < 0) { | ||||
12281 | FAIL() << "Failed to call epoll_wait"; | ||||
12282 | } | ||||
12283 | if (nFds == 0) { | ||||
12284 | break; // epoll_wait timed out | ||||
12285 | } | ||||
12286 | for (int i = 0; i < nFds; i++) { | ||||
Colin Cross | 5b79930 | 2022-10-18 21:52:41 -0700 | [diff] [blame] | 12287 | ASSERT_EQ(static_cast<uint32_t>(EPOLLIN), events[i].events); |
Siarhei Vishniakou | 3197718 | 2022-09-30 08:51:23 -0700 | [diff] [blame] | 12288 | eventOrder.push_back(static_cast<size_t>(events[i].data.u64)); |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12289 | channels[i]->consumeMotionDown(); |
12290 | } | ||||
12291 | } | ||||
12292 | |||||
12293 | // Verify the order in which the events were received. | ||||
12294 | EXPECT_EQ(3u, eventOrder.size()); | ||||
12295 | EXPECT_EQ(2u, eventOrder[0]); // index 2: window | ||||
12296 | EXPECT_EQ(0u, eventOrder[1]); // index 0: spy1 | ||||
12297 | EXPECT_EQ(1u, eventOrder[2]); // index 1: spy2 | ||||
12298 | } | ||||
12299 | |||||
12300 | /** | ||||
12301 | * A spy window using the NOT_TOUCHABLE flag does not receive events. | ||||
12302 | */ | ||||
12303 | TEST_F(InputDispatcherSpyWindowTest, NotTouchable) { | ||||
12304 | auto window = createForeground(); | ||||
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 12305 | auto spy = createSpy(); |
12306 | spy->setTouchable(false); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12307 | mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12308 | |
12309 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12310 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12311 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
12312 | window->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
12313 | spy->assertNoEvents(); | ||||
12314 | } | ||||
12315 | |||||
12316 | /** | ||||
12317 | * A spy window will only receive gestures that originate within its touchable region. Gestures that | ||||
12318 | * have their ACTION_DOWN outside of the touchable region of the spy window will not be dispatched | ||||
12319 | * to the window. | ||||
12320 | */ | ||||
12321 | TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) { | ||||
12322 | auto window = createForeground(); | ||||
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 12323 | auto spy = createSpy(); |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12324 | spy->setTouchableRegion(Region{{0, 0, 20, 20}}); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12325 | mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12326 | |
12327 | // Inject an event outside the spy window's touchable region. | ||||
12328 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12329 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12330 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
12331 | window->consumeMotionDown(); | ||||
12332 | spy->assertNoEvents(); | ||||
12333 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12334 | injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12335 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
12336 | window->consumeMotionUp(); | ||||
12337 | spy->assertNoEvents(); | ||||
12338 | |||||
12339 | // Inject an event inside the spy window's touchable region. | ||||
12340 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12341 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12342 | {5, 10})) |
12343 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
12344 | window->consumeMotionDown(); | ||||
12345 | spy->consumeMotionDown(); | ||||
12346 | } | ||||
12347 | |||||
12348 | /** | ||||
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12349 | * A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES |
Prabir Pradhan | dfabf8a | 2022-01-21 08:19:30 -0800 | [diff] [blame] | 12350 | * flag, but it will get zero-ed out coordinates if the foreground has a different owner. |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12351 | */ |
12352 | TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) { | ||||
12353 | auto window = createForeground(); | ||||
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 12354 | window->setOwnerInfo(gui::Pid{12}, gui::Uid{34}); |
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 12355 | auto spy = createSpy(); |
12356 | spy->setWatchOutsideTouch(true); | ||||
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 12357 | spy->setOwnerInfo(gui::Pid{56}, gui::Uid{78}); |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12358 | spy->setFrame(Rect{0, 0, 20, 20}); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12359 | mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12360 | |
12361 | // Inject an event outside the spy window's frame and touchable region. | ||||
12362 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12363 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Prabir Pradhan | dfabf8a | 2022-01-21 08:19:30 -0800 | [diff] [blame] | 12364 | {100, 200})) |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12365 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
12366 | window->consumeMotionDown(); | ||||
Prabir Pradhan | dfabf8a | 2022-01-21 08:19:30 -0800 | [diff] [blame] | 12367 | spy->consumeMotionOutsideWithZeroedCoords(); |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12368 | } |
12369 | |||||
12370 | /** | ||||
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12371 | * Even when a spy window spans over multiple foreground windows, the spy should receive all |
12372 | * pointers that are down within its bounds. | ||||
12373 | */ | ||||
12374 | TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) { | ||||
12375 | auto windowLeft = createForeground(); | ||||
12376 | windowLeft->setFrame({0, 0, 100, 200}); | ||||
12377 | auto windowRight = createForeground(); | ||||
12378 | windowRight->setFrame({100, 0, 200, 200}); | ||||
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 12379 | auto spy = createSpy(); |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12380 | spy->setFrame({0, 0, 200, 200}); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12381 | mDispatcher->onWindowInfosChanged( |
12382 | {{*spy->getInfo(), *windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0}); | ||||
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12383 | |
12384 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12385 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12386 | {50, 50})) |
12387 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
12388 | windowLeft->consumeMotionDown(); | ||||
12389 | spy->consumeMotionDown(); | ||||
12390 | |||||
12391 | const MotionEvent secondFingerDownEvent = | ||||
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 12392 | MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12393 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) |
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 12394 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) |
12395 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50)) | ||||
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12396 | .build(); |
12397 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12398 | injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12399 | InputEventInjectionSync::WAIT_FOR_RESULT)) |
12400 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
12401 | windowRight->consumeMotionDown(); | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 12402 | spy->consumeMotionPointerDown(/*pointerIndex=*/1); |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12403 | } |
12404 | |||||
12405 | /** | ||||
12406 | * When the first pointer lands outside the spy window and the second pointer lands inside it, the | ||||
12407 | * the spy should receive the second pointer with ACTION_DOWN. | ||||
12408 | */ | ||||
12409 | TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { | ||||
12410 | auto window = createForeground(); | ||||
12411 | window->setFrame({0, 0, 200, 200}); | ||||
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 12412 | auto spyRight = createSpy(); |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12413 | spyRight->setFrame({100, 0, 200, 200}); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12414 | mDispatcher->onWindowInfosChanged({{*spyRight->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12415 | |
12416 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12417 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12418 | {50, 50})) |
12419 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
12420 | window->consumeMotionDown(); | ||||
12421 | spyRight->assertNoEvents(); | ||||
12422 | |||||
12423 | const MotionEvent secondFingerDownEvent = | ||||
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 12424 | MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12425 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) |
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 12426 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) |
12427 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50)) | ||||
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12428 | .build(); |
12429 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12430 | injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12431 | InputEventInjectionSync::WAIT_FOR_RESULT)) |
12432 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 12433 | window->consumeMotionPointerDown(/*pointerIndex=*/1); |
Prabir Pradhan | 07e05b6 | 2021-11-19 03:57:24 -0800 | [diff] [blame] | 12434 | spyRight->consumeMotionDown(); |
12435 | } | ||||
12436 | |||||
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 12437 | /** |
12438 | * The spy window should not be able to affect whether or not touches are split. Only the foreground | ||||
12439 | * windows should be allowed to control split touch. | ||||
12440 | */ | ||||
12441 | TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { | ||||
Prabir Pradhan | 76bdecb | 2022-01-31 11:14:15 -0800 | [diff] [blame] | 12442 | // This spy window prevents touch splitting. However, we still expect to split touches |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 12443 | // because a foreground window has not disabled splitting. |
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 12444 | auto spy = createSpy(); |
Prabir Pradhan | 76bdecb | 2022-01-31 11:14:15 -0800 | [diff] [blame] | 12445 | spy->setPreventSplitting(true); |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 12446 | |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 12447 | auto window = createForeground(); |
12448 | window->setFrame(Rect(0, 0, 100, 100)); | ||||
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 12449 | |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12450 | mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 12451 | |
12452 | // First finger down, no window touched. | ||||
12453 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12454 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 12455 | {100, 200})) |
12456 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
12457 | spy->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
12458 | window->assertNoEvents(); | ||||
12459 | |||||
12460 | // Second finger down on window, the window should receive touch down. | ||||
12461 | const MotionEvent secondFingerDownEvent = | ||||
Siarhei Vishniakou | a16e3a2 | 2022-03-02 15:26:40 -0800 | [diff] [blame] | 12462 | MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 12463 | .displayId(ADISPLAY_ID_DEFAULT) |
12464 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 12465 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200)) |
12466 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) | ||||
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 12467 | .build(); |
12468 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12469 | injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 12470 | InputEventInjectionSync::WAIT_FOR_RESULT)) |
12471 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
12472 | |||||
12473 | window->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 12474 | spy->consumeMotionPointerDown(/*pointerIndex=*/1); |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 12475 | } |
12476 | |||||
12477 | /** | ||||
12478 | * A spy window will usually be implemented as an un-focusable window. Verify that these windows | ||||
12479 | * do not receive key events. | ||||
12480 | */ | ||||
12481 | TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) { | ||||
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 12482 | auto spy = createSpy(); |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 12483 | spy->setFocusable(false); |
12484 | |||||
12485 | auto window = createForeground(); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12486 | mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 12487 | setFocusedWindow(window); |
12488 | window->consumeFocusEvent(true); | ||||
12489 | |||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12490 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 12491 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
12492 | window->consumeKeyDown(ADISPLAY_ID_NONE); | ||||
12493 | |||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12494 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher)) |
Prabir Pradhan | 1376fcd | 2022-01-21 09:56:35 -0800 | [diff] [blame] | 12495 | << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; |
12496 | window->consumeKeyUp(ADISPLAY_ID_NONE); | ||||
12497 | |||||
12498 | spy->assertNoEvents(); | ||||
12499 | } | ||||
12500 | |||||
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12501 | using InputDispatcherPilferPointersTest = InputDispatcherSpyWindowTest; |
12502 | |||||
12503 | /** | ||||
12504 | * A spy window can pilfer pointers. When this happens, touch gestures used by the spy window that | ||||
12505 | * are currently sent to any other windows - including other spy windows - will also be cancelled. | ||||
12506 | */ | ||||
12507 | TEST_F(InputDispatcherPilferPointersTest, PilferPointers) { | ||||
12508 | auto window = createForeground(); | ||||
12509 | auto spy1 = createSpy(); | ||||
12510 | auto spy2 = createSpy(); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12511 | mDispatcher->onWindowInfosChanged( |
12512 | {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo()}, {}, 0, 0}); | ||||
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12513 | |
12514 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12515 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12516 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
12517 | window->consumeMotionDown(); | ||||
12518 | spy1->consumeMotionDown(); | ||||
12519 | spy2->consumeMotionDown(); | ||||
12520 | |||||
12521 | // Pilfer pointers from the second spy window. | ||||
12522 | EXPECT_EQ(OK, mDispatcher->pilferPointers(spy2->getToken())); | ||||
12523 | spy2->assertNoEvents(); | ||||
12524 | spy1->consumeMotionCancel(); | ||||
12525 | window->consumeMotionCancel(); | ||||
12526 | |||||
12527 | // The rest of the gesture should only be sent to the second spy window. | ||||
12528 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12529 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12530 | ADISPLAY_ID_DEFAULT)) |
12531 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
12532 | spy2->consumeMotionMove(); | ||||
12533 | spy1->assertNoEvents(); | ||||
12534 | window->assertNoEvents(); | ||||
12535 | } | ||||
12536 | |||||
12537 | /** | ||||
12538 | * A spy window can pilfer pointers for a gesture even after the foreground window has been removed | ||||
12539 | * in the middle of the gesture. | ||||
12540 | */ | ||||
12541 | TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream) { | ||||
12542 | auto window = createForeground(); | ||||
12543 | auto spy = createSpy(); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12544 | mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12545 | |
12546 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12547 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12548 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
12549 | window->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
12550 | spy->consumeMotionDown(ADISPLAY_ID_DEFAULT); | ||||
12551 | |||||
12552 | window->releaseChannel(); | ||||
12553 | |||||
12554 | EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken())); | ||||
12555 | |||||
12556 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12557 | injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12558 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; |
12559 | spy->consumeMotionUp(ADISPLAY_ID_DEFAULT); | ||||
12560 | } | ||||
12561 | |||||
12562 | /** | ||||
12563 | * After a spy window pilfers pointers, new pointers that go down in its bounds should be sent to | ||||
12564 | * the spy, but not to any other windows. | ||||
12565 | */ | ||||
12566 | TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) { | ||||
12567 | auto spy = createSpy(); | ||||
12568 | auto window = createForeground(); | ||||
12569 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12570 | mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12571 | |
12572 | // First finger down on the window and the spy. | ||||
12573 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12574 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12575 | {100, 200})) |
12576 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
12577 | spy->consumeMotionDown(); | ||||
12578 | window->consumeMotionDown(); | ||||
12579 | |||||
12580 | // Spy window pilfers the pointers. | ||||
12581 | EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken())); | ||||
12582 | window->consumeMotionCancel(); | ||||
12583 | |||||
12584 | // Second finger down on the window and spy, but the window should not receive the pointer down. | ||||
12585 | const MotionEvent secondFingerDownEvent = | ||||
12586 | MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
12587 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
12588 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 12589 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200)) |
12590 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) | ||||
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12591 | .build(); |
12592 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12593 | injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12594 | InputEventInjectionSync::WAIT_FOR_RESULT)) |
12595 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
12596 | |||||
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 12597 | spy->consumeMotionPointerDown(/*pointerIndex=*/1); |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12598 | |
12599 | // Third finger goes down outside all windows, so injection should fail. | ||||
12600 | const MotionEvent thirdFingerDownEvent = | ||||
12601 | MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
12602 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
12603 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 12604 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200)) |
12605 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) | ||||
12606 | .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(-5).y(-5)) | ||||
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12607 | .build(); |
12608 | ASSERT_EQ(InputEventInjectionResult::FAILED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12609 | injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT, |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12610 | InputEventInjectionSync::WAIT_FOR_RESULT)) |
Siarhei Vishniakou | 1ae72f1 | 2023-01-29 12:55:30 -0800 | [diff] [blame] | 12611 | << "Inject motion event should return InputEventInjectionResult::FAILED"; |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12612 | |
12613 | spy->assertNoEvents(); | ||||
12614 | window->assertNoEvents(); | ||||
12615 | } | ||||
12616 | |||||
12617 | /** | ||||
12618 | * After a spy window pilfers pointers, only the pointers used by the spy should be canceled | ||||
12619 | */ | ||||
12620 | TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) { | ||||
12621 | auto spy = createSpy(); | ||||
12622 | spy->setFrame(Rect(0, 0, 100, 100)); | ||||
12623 | auto window = createForeground(); | ||||
12624 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
12625 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12626 | mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12627 | |
12628 | // First finger down on the window only | ||||
12629 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12630 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12631 | {150, 150})) |
12632 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
12633 | window->consumeMotionDown(); | ||||
12634 | |||||
12635 | // Second finger down on the spy and window | ||||
12636 | const MotionEvent secondFingerDownEvent = | ||||
12637 | MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
12638 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
12639 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 12640 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150)) |
12641 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10)) | ||||
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12642 | .build(); |
12643 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12644 | injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12645 | InputEventInjectionSync::WAIT_FOR_RESULT)) |
12646 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
12647 | spy->consumeMotionDown(); | ||||
12648 | window->consumeMotionPointerDown(1); | ||||
12649 | |||||
12650 | // Third finger down on the spy and window | ||||
12651 | const MotionEvent thirdFingerDownEvent = | ||||
12652 | MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
12653 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
12654 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 12655 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150)) |
12656 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10)) | ||||
12657 | .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(50).y(50)) | ||||
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12658 | .build(); |
12659 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12660 | injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT, |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12661 | InputEventInjectionSync::WAIT_FOR_RESULT)) |
12662 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
12663 | spy->consumeMotionPointerDown(1); | ||||
12664 | window->consumeMotionPointerDown(2); | ||||
12665 | |||||
12666 | // Spy window pilfers the pointers. | ||||
12667 | EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken())); | ||||
Harry Cutts | 101ee9b | 2023-07-06 18:04:14 +0000 | [diff] [blame] | 12668 | window->consumeMotionPointerUp(/*idx=*/2, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED); |
12669 | window->consumeMotionPointerUp(/*idx=*/1, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED); | ||||
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12670 | |
12671 | spy->assertNoEvents(); | ||||
12672 | window->assertNoEvents(); | ||||
12673 | } | ||||
12674 | |||||
12675 | /** | ||||
12676 | * After a spy window pilfers pointers, all pilfered pointers that have already been dispatched to | ||||
12677 | * other windows should be canceled. If this results in the cancellation of all pointers for some | ||||
12678 | * window, then that window should receive ACTION_CANCEL. | ||||
12679 | */ | ||||
12680 | TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) { | ||||
12681 | auto spy = createSpy(); | ||||
12682 | spy->setFrame(Rect(0, 0, 100, 100)); | ||||
12683 | auto window = createForeground(); | ||||
12684 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
12685 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12686 | mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12687 | |
12688 | // First finger down on both spy and window | ||||
12689 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12690 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12691 | {10, 10})) |
12692 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
12693 | window->consumeMotionDown(); | ||||
12694 | spy->consumeMotionDown(); | ||||
12695 | |||||
12696 | // Second finger down on the spy and window | ||||
12697 | const MotionEvent secondFingerDownEvent = | ||||
12698 | MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
12699 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
12700 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 12701 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10)) |
12702 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) | ||||
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12703 | .build(); |
12704 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12705 | injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12706 | InputEventInjectionSync::WAIT_FOR_RESULT)) |
12707 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
12708 | spy->consumeMotionPointerDown(1); | ||||
12709 | window->consumeMotionPointerDown(1); | ||||
12710 | |||||
12711 | // Spy window pilfers the pointers. | ||||
12712 | EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken())); | ||||
12713 | window->consumeMotionCancel(); | ||||
12714 | |||||
12715 | spy->assertNoEvents(); | ||||
12716 | window->assertNoEvents(); | ||||
12717 | } | ||||
12718 | |||||
12719 | /** | ||||
12720 | * After a spy window pilfers pointers, new pointers that are not touching the spy window can still | ||||
12721 | * be sent to other windows | ||||
12722 | */ | ||||
12723 | TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) { | ||||
12724 | auto spy = createSpy(); | ||||
12725 | spy->setFrame(Rect(0, 0, 100, 100)); | ||||
12726 | auto window = createForeground(); | ||||
12727 | window->setFrame(Rect(0, 0, 200, 200)); | ||||
12728 | |||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12729 | mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12730 | |
12731 | // First finger down on both window and spy | ||||
12732 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12733 | injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12734 | {10, 10})) |
12735 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
12736 | window->consumeMotionDown(); | ||||
12737 | spy->consumeMotionDown(); | ||||
12738 | |||||
12739 | // Spy window pilfers the pointers. | ||||
12740 | EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken())); | ||||
12741 | window->consumeMotionCancel(); | ||||
12742 | |||||
12743 | // Second finger down on the window only | ||||
12744 | const MotionEvent secondFingerDownEvent = | ||||
12745 | MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
12746 | .displayId(ADISPLAY_ID_DEFAULT) | ||||
12747 | .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 12748 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10)) |
12749 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150)) | ||||
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12750 | .build(); |
12751 | ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 12752 | injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, |
Vaibhav Devmurari | ff798f3 | 2022-05-09 23:45:04 +0000 | [diff] [blame] | 12753 | InputEventInjectionSync::WAIT_FOR_RESULT)) |
12754 | << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; | ||||
12755 | window->consumeMotionDown(); | ||||
12756 | window->assertNoEvents(); | ||||
12757 | |||||
12758 | // TODO(b/232530217): do not send the unnecessary MOVE event and delete the next line | ||||
12759 | spy->consumeMotionMove(); | ||||
12760 | spy->assertNoEvents(); | ||||
12761 | } | ||||
12762 | |||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 12763 | /** |
12764 | * A window on the left and a window on the right. Also, a spy window that's above all of the | ||||
12765 | * windows, and spanning both left and right windows. | ||||
12766 | * Send simultaneous motion streams from two different devices, one to the left window, and another | ||||
12767 | * to the right window. | ||||
12768 | * Pilfer from spy window. | ||||
12769 | * Check that the pilfering only affects the pointers that are actually being received by the spy. | ||||
12770 | */ | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 12771 | TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer_legacy) { |
12772 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 12773 | sp<FakeWindowHandle> spy = createSpy(); |
12774 | spy->setFrame(Rect(0, 0, 200, 200)); | ||||
12775 | sp<FakeWindowHandle> leftWindow = createForeground(); | ||||
12776 | leftWindow->setFrame(Rect(0, 0, 100, 100)); | ||||
12777 | |||||
12778 | sp<FakeWindowHandle> rightWindow = createForeground(); | ||||
12779 | rightWindow->setFrame(Rect(100, 0, 200, 100)); | ||||
12780 | |||||
12781 | constexpr int32_t stylusDeviceId = 1; | ||||
12782 | constexpr int32_t touchDeviceId = 2; | ||||
12783 | |||||
12784 | mDispatcher->onWindowInfosChanged( | ||||
12785 | {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); | ||||
12786 | |||||
12787 | // Stylus down on left window and spy | ||||
12788 | mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS) | ||||
12789 | .deviceId(stylusDeviceId) | ||||
12790 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) | ||||
12791 | .build()); | ||||
12792 | leftWindow->consumeMotionEvent( | ||||
12793 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); | ||||
12794 | spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); | ||||
12795 | |||||
12796 | // Finger down on right window and spy - but spy already has stylus | ||||
12797 | mDispatcher->notifyMotion( | ||||
12798 | MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
12799 | .deviceId(touchDeviceId) | ||||
12800 | .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) | ||||
12801 | .build()); | ||||
12802 | rightWindow->consumeMotionEvent( | ||||
12803 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 12804 | spy->assertNoEvents(); |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 12805 | |
12806 | // Act: pilfer from spy. Spy is currently receiving touch events. | ||||
12807 | EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken())); | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 12808 | leftWindow->consumeMotionEvent( |
12809 | AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId))); | ||||
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 12810 | rightWindow->consumeMotionEvent( |
12811 | AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId))); | ||||
12812 | |||||
12813 | // Continue movements from both stylus and touch. Touch will be delivered to spy, but not stylus | ||||
12814 | mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS) | ||||
12815 | .deviceId(stylusDeviceId) | ||||
12816 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52)) | ||||
12817 | .build()); | ||||
12818 | mDispatcher->notifyMotion( | ||||
12819 | MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
12820 | .deviceId(touchDeviceId) | ||||
12821 | .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52)) | ||||
12822 | .build()); | ||||
Siarhei Vishniakou | 2899c55 | 2023-07-10 18:20:46 -0700 | [diff] [blame] | 12823 | spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId))); |
Siarhei Vishniakou | 0b251a3 | 2023-09-20 16:24:42 -0700 | [diff] [blame] | 12824 | |
12825 | spy->assertNoEvents(); | ||||
12826 | leftWindow->assertNoEvents(); | ||||
12827 | rightWindow->assertNoEvents(); | ||||
12828 | } | ||||
12829 | |||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 12830 | /** |
12831 | * A window on the left and a window on the right. Also, a spy window that's above all of the | ||||
12832 | * windows, and spanning both left and right windows. | ||||
12833 | * Send simultaneous motion streams from two different devices, one to the left window, and another | ||||
12834 | * to the right window. | ||||
12835 | * Pilfer from spy window. | ||||
12836 | * Check that the pilfering affects all of the pointers that are actually being received by the spy. | ||||
12837 | * The spy should receive both the touch and the stylus events after pilfer. | ||||
12838 | */ | ||||
12839 | TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer) { | ||||
12840 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
12841 | sp<FakeWindowHandle> spy = createSpy(); | ||||
12842 | spy->setFrame(Rect(0, 0, 200, 200)); | ||||
12843 | sp<FakeWindowHandle> leftWindow = createForeground(); | ||||
12844 | leftWindow->setFrame(Rect(0, 0, 100, 100)); | ||||
12845 | |||||
12846 | sp<FakeWindowHandle> rightWindow = createForeground(); | ||||
12847 | rightWindow->setFrame(Rect(100, 0, 200, 100)); | ||||
12848 | |||||
12849 | constexpr int32_t stylusDeviceId = 1; | ||||
12850 | constexpr int32_t touchDeviceId = 2; | ||||
12851 | |||||
12852 | mDispatcher->onWindowInfosChanged( | ||||
12853 | {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); | ||||
12854 | |||||
12855 | // Stylus down on left window and spy | ||||
12856 | mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS) | ||||
12857 | .deviceId(stylusDeviceId) | ||||
12858 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) | ||||
12859 | .build()); | ||||
12860 | leftWindow->consumeMotionEvent( | ||||
12861 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); | ||||
12862 | spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); | ||||
12863 | |||||
12864 | // Finger down on right window and spy | ||||
12865 | mDispatcher->notifyMotion( | ||||
12866 | MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
12867 | .deviceId(touchDeviceId) | ||||
12868 | .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) | ||||
12869 | .build()); | ||||
12870 | rightWindow->consumeMotionEvent( | ||||
12871 | AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
12872 | spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); | ||||
12873 | |||||
12874 | // Act: pilfer from spy. Spy is currently receiving touch events. | ||||
12875 | EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken())); | ||||
12876 | leftWindow->consumeMotionEvent( | ||||
12877 | AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId))); | ||||
12878 | rightWindow->consumeMotionEvent( | ||||
12879 | AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId))); | ||||
12880 | |||||
12881 | // Continue movements from both stylus and touch. Touch and stylus will be delivered to spy | ||||
Siarhei Vishniakou | 92bca1c | 2024-04-01 14:06:59 -0700 | [diff] [blame] | 12882 | // Instead of sending the two MOVE events for each input device together, and then receiving |
12883 | // them both, process them one at at time. InputConsumer is always in the batching mode, which | ||||
12884 | // means that the two MOVE events will be initially put into a batch. Once the events are | ||||
12885 | // batched, the 'consume' call may result in any of the MOVE events to be sent first (depending | ||||
12886 | // on the implementation of InputConsumer), which would mean that the order of the received | ||||
12887 | // events could be different depending on whether there are 1 or 2 events pending in the | ||||
12888 | // InputChannel at the time the test calls 'consume'. To make assertions simpler here, and to | ||||
12889 | // avoid this confusing behaviour, send and receive each MOVE event separately. | ||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 12890 | mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS) |
12891 | .deviceId(stylusDeviceId) | ||||
12892 | .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52)) | ||||
12893 | .build()); | ||||
Siarhei Vishniakou | 92bca1c | 2024-04-01 14:06:59 -0700 | [diff] [blame] | 12894 | spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId))); |
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 12895 | mDispatcher->notifyMotion( |
12896 | MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) | ||||
12897 | .deviceId(touchDeviceId) | ||||
12898 | .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52)) | ||||
12899 | .build()); | ||||
Siarhei Vishniakou | 92bca1c | 2024-04-01 14:06:59 -0700 | [diff] [blame] | 12900 | spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); |
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 12901 | |
12902 | spy->assertNoEvents(); | ||||
12903 | leftWindow->assertNoEvents(); | ||||
12904 | rightWindow->assertNoEvents(); | ||||
12905 | } | ||||
12906 | |||||
Prabir Pradhan | 9cd9eb6 | 2023-11-22 17:58:06 +0000 | [diff] [blame] | 12907 | TEST_F(InputDispatcherPilferPointersTest, NoPilferingWithHoveringPointers) { |
12908 | auto window = createForeground(); | ||||
12909 | auto spy = createSpy(); | ||||
12910 | mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); | ||||
12911 | |||||
12912 | mDispatcher->notifyMotion( | ||||
12913 | MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) | ||||
12914 | .deviceId(1) | ||||
12915 | .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(100).y(200)) | ||||
12916 | .build()); | ||||
12917 | window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
12918 | spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
12919 | |||||
12920 | // Pilfer pointers from the spy window should fail. | ||||
12921 | EXPECT_NE(OK, mDispatcher->pilferPointers(spy->getToken())); | ||||
12922 | spy->assertNoEvents(); | ||||
12923 | window->assertNoEvents(); | ||||
12924 | } | ||||
12925 | |||||
Prabir Pradhan | d65552b | 2021-10-07 11:23:50 -0700 | [diff] [blame] | 12926 | class InputDispatcherStylusInterceptorTest : public InputDispatcherTest { |
12927 | public: | ||||
12928 | std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupStylusOverlayScenario() { | ||||
12929 | std::shared_ptr<FakeApplicationHandle> overlayApplication = | ||||
12930 | std::make_shared<FakeApplicationHandle>(); | ||||
12931 | sp<FakeWindowHandle> overlay = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 12932 | sp<FakeWindowHandle>::make(overlayApplication, mDispatcher, |
12933 | "Stylus interceptor window", ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | d65552b | 2021-10-07 11:23:50 -0700 | [diff] [blame] | 12934 | overlay->setFocusable(false); |
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 12935 | overlay->setOwnerInfo(gui::Pid{111}, gui::Uid{111}); |
Prabir Pradhan | 4d5c52f | 2022-01-31 08:52:10 -0800 | [diff] [blame] | 12936 | overlay->setTouchable(false); |
Prabir Pradhan | 51e7db0 | 2022-02-07 06:02:57 -0800 | [diff] [blame] | 12937 | overlay->setInterceptsStylus(true); |
Prabir Pradhan | d65552b | 2021-10-07 11:23:50 -0700 | [diff] [blame] | 12938 | overlay->setTrustedOverlay(true); |
12939 | |||||
12940 | std::shared_ptr<FakeApplicationHandle> application = | ||||
12941 | std::make_shared<FakeApplicationHandle>(); | ||||
12942 | sp<FakeWindowHandle> window = | ||||
Siarhei Vishniakou | aed7ad0 | 2022-08-03 15:04:33 -0700 | [diff] [blame] | 12943 | sp<FakeWindowHandle>::make(application, mDispatcher, "Application window", |
12944 | ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | d65552b | 2021-10-07 11:23:50 -0700 | [diff] [blame] | 12945 | window->setFocusable(true); |
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 12946 | window->setOwnerInfo(gui::Pid{222}, gui::Uid{222}); |
Prabir Pradhan | d65552b | 2021-10-07 11:23:50 -0700 | [diff] [blame] | 12947 | |
12948 | mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12949 | mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | d65552b | 2021-10-07 11:23:50 -0700 | [diff] [blame] | 12950 | setFocusedWindow(window); |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 12951 | window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true); |
Prabir Pradhan | d65552b | 2021-10-07 11:23:50 -0700 | [diff] [blame] | 12952 | return {std::move(overlay), std::move(window)}; |
12953 | } | ||||
12954 | |||||
12955 | void sendFingerEvent(int32_t action) { | ||||
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 12956 | mDispatcher->notifyMotion( |
Prabir Pradhan | d65552b | 2021-10-07 11:23:50 -0700 | [diff] [blame] | 12957 | generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS, |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 12958 | ADISPLAY_ID_DEFAULT, {PointF{20, 20}})); |
Prabir Pradhan | d65552b | 2021-10-07 11:23:50 -0700 | [diff] [blame] | 12959 | } |
12960 | |||||
12961 | void sendStylusEvent(int32_t action) { | ||||
12962 | NotifyMotionArgs motionArgs = | ||||
12963 | generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS, | ||||
12964 | ADISPLAY_ID_DEFAULT, {PointF{30, 40}}); | ||||
Siarhei Vishniakou | 6d73f83 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 12965 | motionArgs.pointerProperties[0].toolType = ToolType::STYLUS; |
Prabir Pradhan | 678438e | 2023-04-13 19:32:51 +0000 | [diff] [blame] | 12966 | mDispatcher->notifyMotion(motionArgs); |
Prabir Pradhan | d65552b | 2021-10-07 11:23:50 -0700 | [diff] [blame] | 12967 | } |
12968 | }; | ||||
12969 | |||||
Prabir Pradhan | a3ab87a | 2022-01-27 10:00:21 -0800 | [diff] [blame] | 12970 | using InputDispatcherStylusInterceptorDeathTest = InputDispatcherStylusInterceptorTest; |
12971 | |||||
12972 | TEST_F(InputDispatcherStylusInterceptorDeathTest, UntrustedOverlay_AbortsDispatcher) { | ||||
Siarhei Vishniakou | ad3b682 | 2023-06-22 14:17:35 -0700 | [diff] [blame] | 12973 | testing::GTEST_FLAG(death_test_style) = "threadsafe"; |
Prabir Pradhan | a3ab87a | 2022-01-27 10:00:21 -0800 | [diff] [blame] | 12974 | ScopedSilentDeath _silentDeath; |
12975 | |||||
Prabir Pradhan | d65552b | 2021-10-07 11:23:50 -0700 | [diff] [blame] | 12976 | auto [overlay, window] = setupStylusOverlayScenario(); |
12977 | overlay->setTrustedOverlay(false); | ||||
12978 | // Configuring an untrusted overlay as a stylus interceptor should cause Dispatcher to abort. | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12979 | ASSERT_DEATH(mDispatcher->onWindowInfosChanged( |
12980 | {{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}), | ||||
Prabir Pradhan | d65552b | 2021-10-07 11:23:50 -0700 | [diff] [blame] | 12981 | ".* not a trusted overlay"); |
12982 | } | ||||
12983 | |||||
12984 | TEST_F(InputDispatcherStylusInterceptorTest, ConsmesOnlyStylusEvents) { | ||||
12985 | auto [overlay, window] = setupStylusOverlayScenario(); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 12986 | mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | d65552b | 2021-10-07 11:23:50 -0700 | [diff] [blame] | 12987 | |
12988 | sendStylusEvent(AMOTION_EVENT_ACTION_DOWN); | ||||
12989 | overlay->consumeMotionDown(); | ||||
12990 | sendStylusEvent(AMOTION_EVENT_ACTION_UP); | ||||
12991 | overlay->consumeMotionUp(); | ||||
12992 | |||||
12993 | sendFingerEvent(AMOTION_EVENT_ACTION_DOWN); | ||||
12994 | window->consumeMotionDown(); | ||||
12995 | sendFingerEvent(AMOTION_EVENT_ACTION_UP); | ||||
12996 | window->consumeMotionUp(); | ||||
12997 | |||||
12998 | overlay->assertNoEvents(); | ||||
12999 | window->assertNoEvents(); | ||||
13000 | } | ||||
13001 | |||||
13002 | TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) { | ||||
13003 | auto [overlay, window] = setupStylusOverlayScenario(); | ||||
Prabir Pradhan | 51e7db0 | 2022-02-07 06:02:57 -0800 | [diff] [blame] | 13004 | overlay->setSpy(true); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 13005 | mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | d65552b | 2021-10-07 11:23:50 -0700 | [diff] [blame] | 13006 | |
13007 | sendStylusEvent(AMOTION_EVENT_ACTION_DOWN); | ||||
13008 | overlay->consumeMotionDown(); | ||||
13009 | window->consumeMotionDown(); | ||||
13010 | sendStylusEvent(AMOTION_EVENT_ACTION_UP); | ||||
13011 | overlay->consumeMotionUp(); | ||||
13012 | window->consumeMotionUp(); | ||||
13013 | |||||
13014 | sendFingerEvent(AMOTION_EVENT_ACTION_DOWN); | ||||
13015 | window->consumeMotionDown(); | ||||
13016 | sendFingerEvent(AMOTION_EVENT_ACTION_UP); | ||||
13017 | window->consumeMotionUp(); | ||||
13018 | |||||
13019 | overlay->assertNoEvents(); | ||||
13020 | window->assertNoEvents(); | ||||
13021 | } | ||||
13022 | |||||
Prabir Pradhan | 6dfbf26 | 2022-03-14 15:24:30 +0000 | [diff] [blame] | 13023 | /** |
13024 | * Set up a scenario to test the behavior used by the stylus handwriting detection feature. | ||||
13025 | * The scenario is as follows: | ||||
13026 | * - The stylus interceptor overlay is configured as a spy window. | ||||
13027 | * - The stylus interceptor spy receives the start of a new stylus gesture. | ||||
13028 | * - It pilfers pointers and then configures itself to no longer be a spy. | ||||
13029 | * - The stylus interceptor continues to receive the rest of the gesture. | ||||
13030 | */ | ||||
13031 | TEST_F(InputDispatcherStylusInterceptorTest, StylusHandwritingScenario) { | ||||
13032 | auto [overlay, window] = setupStylusOverlayScenario(); | ||||
13033 | overlay->setSpy(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 13034 | mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | 6dfbf26 | 2022-03-14 15:24:30 +0000 | [diff] [blame] | 13035 | |
13036 | sendStylusEvent(AMOTION_EVENT_ACTION_DOWN); | ||||
13037 | overlay->consumeMotionDown(); | ||||
13038 | window->consumeMotionDown(); | ||||
13039 | |||||
13040 | // The interceptor pilfers the pointers. | ||||
13041 | EXPECT_EQ(OK, mDispatcher->pilferPointers(overlay->getToken())); | ||||
13042 | window->consumeMotionCancel(); | ||||
13043 | |||||
13044 | // The interceptor configures itself so that it is no longer a spy. | ||||
13045 | overlay->setSpy(false); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 13046 | mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | 6dfbf26 | 2022-03-14 15:24:30 +0000 | [diff] [blame] | 13047 | |
13048 | // It continues to receive the rest of the stylus gesture. | ||||
13049 | sendStylusEvent(AMOTION_EVENT_ACTION_MOVE); | ||||
13050 | overlay->consumeMotionMove(); | ||||
13051 | sendStylusEvent(AMOTION_EVENT_ACTION_UP); | ||||
13052 | overlay->consumeMotionUp(); | ||||
13053 | |||||
13054 | window->assertNoEvents(); | ||||
13055 | } | ||||
13056 | |||||
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13057 | struct User { |
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 13058 | gui::Pid mPid; |
Prabir Pradhan | 8a5c41d | 2023-06-08 19:13:46 +0000 | [diff] [blame] | 13059 | gui::Uid mUid; |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13060 | uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS}; |
13061 | std::unique_ptr<InputDispatcher>& mDispatcher; | ||||
13062 | |||||
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 13063 | User(std::unique_ptr<InputDispatcher>& dispatcher, gui::Pid pid, gui::Uid uid) |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13064 | : mPid(pid), mUid(uid), mDispatcher(dispatcher) {} |
13065 | |||||
13066 | InputEventInjectionResult injectTargetedMotion(int32_t action) const { | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 13067 | return injectMotionEvent(*mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13068 | ADISPLAY_ID_DEFAULT, {100, 200}, |
13069 | {AMOTION_EVENT_INVALID_CURSOR_POSITION, | ||||
13070 | AMOTION_EVENT_INVALID_CURSOR_POSITION}, | ||||
13071 | INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT, | ||||
13072 | systemTime(SYSTEM_TIME_MONOTONIC), {mUid}, mPolicyFlags); | ||||
13073 | } | ||||
13074 | |||||
13075 | InputEventInjectionResult injectTargetedKey(int32_t action) const { | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 13076 | return inputdispatcher::injectKey(*mDispatcher, action, /*repeatCount=*/0, ADISPLAY_ID_NONE, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13077 | InputEventInjectionSync::WAIT_FOR_RESULT, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 13078 | INJECT_EVENT_TIMEOUT, /*allowKeyRepeat=*/false, {mUid}, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13079 | mPolicyFlags); |
13080 | } | ||||
13081 | |||||
Siarhei Vishniakou | e3ce412 | 2023-08-23 10:26:46 -0700 | [diff] [blame] | 13082 | sp<FakeWindowHandle> createWindow(const char* name) const { |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13083 | std::shared_ptr<FakeApplicationHandle> overlayApplication = |
13084 | std::make_shared<FakeApplicationHandle>(); | ||||
Siarhei Vishniakou | e3ce412 | 2023-08-23 10:26:46 -0700 | [diff] [blame] | 13085 | sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(overlayApplication, mDispatcher, |
13086 | name, ADISPLAY_ID_DEFAULT); | ||||
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13087 | window->setOwnerInfo(mPid, mUid); |
13088 | return window; | ||||
13089 | } | ||||
13090 | }; | ||||
13091 | |||||
13092 | using InputDispatcherTargetedInjectionTest = InputDispatcherTest; | ||||
13093 | |||||
13094 | TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) { | ||||
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 13095 | auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11}); |
Siarhei Vishniakou | e3ce412 | 2023-08-23 10:26:46 -0700 | [diff] [blame] | 13096 | auto window = owner.createWindow("Owned window"); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 13097 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13098 | |
13099 | EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
13100 | owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN)); | ||||
13101 | window->consumeMotionDown(); | ||||
13102 | |||||
13103 | setFocusedWindow(window); | ||||
13104 | window->consumeFocusEvent(true); | ||||
13105 | |||||
13106 | EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
13107 | owner.injectTargetedKey(AKEY_EVENT_ACTION_DOWN)); | ||||
13108 | window->consumeKeyDown(ADISPLAY_ID_NONE); | ||||
13109 | } | ||||
13110 | |||||
13111 | TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) { | ||||
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 13112 | auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11}); |
Siarhei Vishniakou | e3ce412 | 2023-08-23 10:26:46 -0700 | [diff] [blame] | 13113 | auto window = owner.createWindow("Owned window"); |
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 13114 | mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13115 | |
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 13116 | auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21}); |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13117 | EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH, |
13118 | rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN)); | ||||
13119 | |||||
13120 | setFocusedWindow(window); | ||||
13121 | window->consumeFocusEvent(true); | ||||
13122 | |||||
13123 | EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH, | ||||
13124 | rando.injectTargetedKey(AKEY_EVENT_ACTION_DOWN)); | ||||
13125 | window->assertNoEvents(); | ||||
13126 | } | ||||
13127 | |||||
13128 | TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) { | ||||
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 13129 | auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11}); |
Siarhei Vishniakou | e3ce412 | 2023-08-23 10:26:46 -0700 | [diff] [blame] | 13130 | auto window = owner.createWindow("Owned window"); |
13131 | auto spy = owner.createWindow("Owned spy"); | ||||
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13132 | spy->setSpy(true); |
13133 | spy->setTrustedOverlay(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 13134 | mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13135 | |
13136 | EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
13137 | owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN)); | ||||
13138 | spy->consumeMotionDown(); | ||||
13139 | window->consumeMotionDown(); | ||||
13140 | } | ||||
13141 | |||||
13142 | TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) { | ||||
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 13143 | auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11}); |
Siarhei Vishniakou | e3ce412 | 2023-08-23 10:26:46 -0700 | [diff] [blame] | 13144 | auto window = owner.createWindow("Owned window"); |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13145 | |
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 13146 | auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21}); |
Siarhei Vishniakou | e3ce412 | 2023-08-23 10:26:46 -0700 | [diff] [blame] | 13147 | auto randosSpy = rando.createWindow("Rando's spy"); |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13148 | randosSpy->setSpy(true); |
13149 | randosSpy->setTrustedOverlay(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 13150 | mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13151 | |
13152 | // The event is targeted at owner's window, so injection should succeed, but the spy should | ||||
13153 | // not receive the event. | ||||
13154 | EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
13155 | owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN)); | ||||
13156 | randosSpy->assertNoEvents(); | ||||
13157 | window->consumeMotionDown(); | ||||
13158 | } | ||||
13159 | |||||
13160 | TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) { | ||||
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 13161 | auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11}); |
Siarhei Vishniakou | e3ce412 | 2023-08-23 10:26:46 -0700 | [diff] [blame] | 13162 | auto window = owner.createWindow("Owned window"); |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13163 | |
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 13164 | auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21}); |
Siarhei Vishniakou | e3ce412 | 2023-08-23 10:26:46 -0700 | [diff] [blame] | 13165 | auto randosSpy = rando.createWindow("Rando's spy"); |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13166 | randosSpy->setSpy(true); |
13167 | randosSpy->setTrustedOverlay(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 13168 | mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13169 | |
13170 | // A user that has injection permission can inject into any window. | ||||
13171 | EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, | ||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 13172 | injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13173 | ADISPLAY_ID_DEFAULT)); |
13174 | randosSpy->consumeMotionDown(); | ||||
13175 | window->consumeMotionDown(); | ||||
13176 | |||||
13177 | setFocusedWindow(randosSpy); | ||||
13178 | randosSpy->consumeFocusEvent(true); | ||||
13179 | |||||
Siarhei Vishniakou | b237f9e | 2023-07-21 16:42:23 -0700 | [diff] [blame] | 13180 | EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)); |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13181 | randosSpy->consumeKeyDown(ADISPLAY_ID_NONE); |
13182 | window->assertNoEvents(); | ||||
13183 | } | ||||
13184 | |||||
Siarhei Vishniakou | 580fb3a | 2023-05-05 15:02:20 -0700 | [diff] [blame] | 13185 | TEST_F(InputDispatcherTargetedInjectionTest, CannotGenerateActionOutsideToOtherUids) { |
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 13186 | auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11}); |
Siarhei Vishniakou | e3ce412 | 2023-08-23 10:26:46 -0700 | [diff] [blame] | 13187 | auto window = owner.createWindow("Owned window"); |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13188 | |
Prabir Pradhan | aeebeb4 | 2023-06-13 19:53:03 +0000 | [diff] [blame] | 13189 | auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21}); |
Siarhei Vishniakou | e3ce412 | 2023-08-23 10:26:46 -0700 | [diff] [blame] | 13190 | auto randosWindow = rando.createWindow("Rando's window"); |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13191 | randosWindow->setFrame(Rect{-10, -10, -5, -5}); |
13192 | randosWindow->setWatchOutsideTouch(true); | ||||
Siarhei Vishniakou | c41de37 | 2023-07-20 13:14:26 -0700 | [diff] [blame] | 13193 | mDispatcher->onWindowInfosChanged({{*randosWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13194 | |
Siarhei Vishniakou | 580fb3a | 2023-05-05 15:02:20 -0700 | [diff] [blame] | 13195 | // Do not allow generation of ACTION_OUTSIDE events into windows owned by different uids. |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13196 | EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, |
13197 | owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN)); | ||||
13198 | window->consumeMotionDown(); | ||||
Siarhei Vishniakou | 580fb3a | 2023-05-05 15:02:20 -0700 | [diff] [blame] | 13199 | randosWindow->assertNoEvents(); |
Prabir Pradhan | 5735a32 | 2022-04-11 17:23:34 +0000 | [diff] [blame] | 13200 | } |
13201 | |||||
Prabir Pradhan | 64f21d2 | 2023-11-28 21:19:42 +0000 | [diff] [blame] | 13202 | using InputDispatcherPointerInWindowTest = InputDispatcherTest; |
13203 | |||||
13204 | TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWhenHovering) { | ||||
13205 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
13206 | |||||
13207 | sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window", | ||||
13208 | ADISPLAY_ID_DEFAULT); | ||||
13209 | left->setFrame(Rect(0, 0, 100, 100)); | ||||
13210 | sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher, | ||||
13211 | "Right Window", ADISPLAY_ID_DEFAULT); | ||||
13212 | right->setFrame(Rect(100, 0, 200, 100)); | ||||
13213 | sp<FakeWindowHandle> spy = | ||||
13214 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT); | ||||
13215 | spy->setFrame(Rect(0, 0, 200, 100)); | ||||
13216 | spy->setTrustedOverlay(true); | ||||
13217 | spy->setSpy(true); | ||||
13218 | |||||
13219 | mDispatcher->onWindowInfosChanged( | ||||
13220 | {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0}); | ||||
13221 | |||||
13222 | // Hover into the left window. | ||||
13223 | mDispatcher->notifyMotion( | ||||
13224 | MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) | ||||
13225 | .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(50).y(50)) | ||||
13226 | .build()); | ||||
13227 | |||||
13228 | left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
13229 | spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
13230 | |||||
13231 | ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13232 | /*pointerId=*/0)); | ||||
13233 | ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13234 | /*pointerId=*/0)); | ||||
13235 | ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13236 | /*pointerId=*/0)); | ||||
13237 | |||||
13238 | // Hover move to the right window. | ||||
13239 | mDispatcher->notifyMotion( | ||||
13240 | MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) | ||||
13241 | .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50)) | ||||
13242 | .build()); | ||||
13243 | |||||
13244 | left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); | ||||
13245 | right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
13246 | spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE)); | ||||
13247 | |||||
13248 | ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13249 | /*pointerId=*/0)); | ||||
13250 | ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13251 | /*pointerId=*/0)); | ||||
13252 | ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13253 | /*pointerId=*/0)); | ||||
13254 | |||||
13255 | // Stop hovering. | ||||
13256 | mDispatcher->notifyMotion( | ||||
13257 | MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) | ||||
13258 | .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50)) | ||||
13259 | .build()); | ||||
13260 | |||||
13261 | right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); | ||||
13262 | spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); | ||||
13263 | |||||
13264 | ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13265 | /*pointerId=*/0)); | ||||
13266 | ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13267 | /*pointerId=*/0)); | ||||
13268 | ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13269 | /*pointerId=*/0)); | ||||
13270 | } | ||||
13271 | |||||
13272 | TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWithSplitTouch) { | ||||
13273 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
13274 | |||||
13275 | sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window", | ||||
13276 | ADISPLAY_ID_DEFAULT); | ||||
13277 | left->setFrame(Rect(0, 0, 100, 100)); | ||||
13278 | sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher, | ||||
13279 | "Right Window", ADISPLAY_ID_DEFAULT); | ||||
13280 | right->setFrame(Rect(100, 0, 200, 100)); | ||||
13281 | sp<FakeWindowHandle> spy = | ||||
13282 | sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT); | ||||
13283 | spy->setFrame(Rect(0, 0, 200, 100)); | ||||
13284 | spy->setTrustedOverlay(true); | ||||
13285 | spy->setSpy(true); | ||||
13286 | |||||
13287 | mDispatcher->onWindowInfosChanged( | ||||
13288 | {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0}); | ||||
13289 | |||||
13290 | // First pointer down on left window. | ||||
13291 | mDispatcher->notifyMotion( | ||||
13292 | MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
13293 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) | ||||
13294 | .build()); | ||||
13295 | |||||
13296 | left->consumeMotionDown(); | ||||
13297 | spy->consumeMotionDown(); | ||||
13298 | |||||
13299 | ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13300 | /*pointerId=*/0)); | ||||
13301 | ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13302 | /*pointerId=*/0)); | ||||
13303 | ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13304 | /*pointerId=*/0)); | ||||
13305 | |||||
13306 | // Second pointer down on right window. | ||||
13307 | mDispatcher->notifyMotion( | ||||
13308 | MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) | ||||
13309 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) | ||||
13310 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50)) | ||||
13311 | .build()); | ||||
13312 | |||||
13313 | left->consumeMotionMove(); | ||||
13314 | right->consumeMotionDown(); | ||||
13315 | spy->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); | ||||
13316 | |||||
13317 | ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13318 | /*pointerId=*/0)); | ||||
13319 | ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13320 | /*pointerId=*/0)); | ||||
13321 | ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13322 | /*pointerId=*/0)); | ||||
13323 | ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13324 | /*pointerId=*/1)); | ||||
13325 | ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13326 | /*pointerId=*/1)); | ||||
13327 | ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13328 | /*pointerId=*/1)); | ||||
13329 | |||||
13330 | // Second pointer up. | ||||
13331 | mDispatcher->notifyMotion( | ||||
13332 | MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
13333 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) | ||||
13334 | .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50)) | ||||
13335 | .build()); | ||||
13336 | |||||
13337 | left->consumeMotionMove(); | ||||
13338 | right->consumeMotionUp(); | ||||
13339 | spy->consumeMotionEvent(WithMotionAction(POINTER_1_UP)); | ||||
13340 | |||||
13341 | ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13342 | /*pointerId=*/0)); | ||||
13343 | ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13344 | /*pointerId=*/0)); | ||||
13345 | ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13346 | /*pointerId=*/0)); | ||||
13347 | ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13348 | /*pointerId=*/1)); | ||||
13349 | ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13350 | /*pointerId=*/1)); | ||||
13351 | ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13352 | /*pointerId=*/1)); | ||||
13353 | |||||
13354 | // First pointer up. | ||||
13355 | mDispatcher->notifyMotion( | ||||
13356 | MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) | ||||
13357 | .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) | ||||
13358 | .build()); | ||||
13359 | |||||
13360 | left->consumeMotionUp(); | ||||
13361 | spy->consumeMotionUp(); | ||||
13362 | |||||
13363 | ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13364 | /*pointerId=*/0)); | ||||
13365 | ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13366 | /*pointerId=*/0)); | ||||
13367 | ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13368 | /*pointerId=*/0)); | ||||
13369 | } | ||||
13370 | |||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 13371 | TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse_legacy) { |
13372 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); | ||||
Prabir Pradhan | 64f21d2 | 2023-11-28 21:19:42 +0000 | [diff] [blame] | 13373 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); |
13374 | |||||
13375 | sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window", | ||||
13376 | ADISPLAY_ID_DEFAULT); | ||||
13377 | left->setFrame(Rect(0, 0, 100, 100)); | ||||
13378 | sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher, | ||||
13379 | "Right Window", ADISPLAY_ID_DEFAULT); | ||||
13380 | right->setFrame(Rect(100, 0, 200, 100)); | ||||
13381 | |||||
13382 | mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0}); | ||||
13383 | |||||
13384 | ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13385 | /*pointerId=*/0)); | ||||
13386 | ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13387 | /*pointerId=*/0)); | ||||
13388 | |||||
13389 | // Hover move into the window. | ||||
13390 | mDispatcher->notifyMotion( | ||||
13391 | MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) | ||||
13392 | .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50)) | ||||
13393 | .rawXCursorPosition(50) | ||||
13394 | .rawYCursorPosition(50) | ||||
13395 | .deviceId(DEVICE_ID) | ||||
13396 | .build()); | ||||
13397 | |||||
13398 | left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
13399 | |||||
13400 | ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13401 | /*pointerId=*/0)); | ||||
13402 | |||||
13403 | // Move the mouse with another device. This cancels the hovering pointer from the first device. | ||||
13404 | mDispatcher->notifyMotion( | ||||
13405 | MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) | ||||
13406 | .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50)) | ||||
13407 | .rawXCursorPosition(51) | ||||
13408 | .rawYCursorPosition(50) | ||||
13409 | .deviceId(SECOND_DEVICE_ID) | ||||
13410 | .build()); | ||||
13411 | |||||
13412 | left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); | ||||
13413 | left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
13414 | |||||
13415 | // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets | ||||
13416 | // a HOVER_EXIT from the first device. | ||||
13417 | ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13418 | /*pointerId=*/0)); | ||||
13419 | ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, | ||||
13420 | SECOND_DEVICE_ID, | ||||
13421 | /*pointerId=*/0)); | ||||
13422 | |||||
13423 | // Move the mouse outside the window. Document the current behavior, where the window does not | ||||
13424 | // receive HOVER_EXIT even though the mouse left the window. | ||||
13425 | mDispatcher->notifyMotion( | ||||
13426 | MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) | ||||
13427 | .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50)) | ||||
13428 | .rawXCursorPosition(150) | ||||
13429 | .rawYCursorPosition(50) | ||||
13430 | .deviceId(SECOND_DEVICE_ID) | ||||
13431 | .build()); | ||||
13432 | |||||
13433 | left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); | ||||
13434 | right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
13435 | ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13436 | /*pointerId=*/0)); | ||||
13437 | ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, | ||||
13438 | SECOND_DEVICE_ID, | ||||
13439 | /*pointerId=*/0)); | ||||
13440 | } | ||||
13441 | |||||
Siarhei Vishniakou | ed89cbb | 2023-10-13 10:42:44 -0700 | [diff] [blame] | 13442 | /** |
13443 | * TODO(b/313689709) - correctly support multiple mouse devices, because they should be controlling | ||||
13444 | * the same cursor, and therefore have a shared motion event stream. | ||||
13445 | */ | ||||
13446 | TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse) { | ||||
13447 | SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); | ||||
13448 | std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); | ||||
13449 | |||||
13450 | sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window", | ||||
13451 | ADISPLAY_ID_DEFAULT); | ||||
13452 | left->setFrame(Rect(0, 0, 100, 100)); | ||||
13453 | sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher, | ||||
13454 | "Right Window", ADISPLAY_ID_DEFAULT); | ||||
13455 | right->setFrame(Rect(100, 0, 200, 100)); | ||||
13456 | |||||
13457 | mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0}); | ||||
13458 | |||||
13459 | ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13460 | /*pointerId=*/0)); | ||||
13461 | ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13462 | /*pointerId=*/0)); | ||||
13463 | |||||
13464 | // Hover move into the window. | ||||
13465 | mDispatcher->notifyMotion( | ||||
13466 | MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) | ||||
13467 | .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50)) | ||||
13468 | .rawXCursorPosition(50) | ||||
13469 | .rawYCursorPosition(50) | ||||
13470 | .deviceId(DEVICE_ID) | ||||
13471 | .build()); | ||||
13472 | |||||
13473 | left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
13474 | |||||
13475 | ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13476 | /*pointerId=*/0)); | ||||
13477 | |||||
13478 | // Move the mouse with another device | ||||
13479 | mDispatcher->notifyMotion( | ||||
13480 | MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) | ||||
13481 | .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50)) | ||||
13482 | .rawXCursorPosition(51) | ||||
13483 | .rawYCursorPosition(50) | ||||
13484 | .deviceId(SECOND_DEVICE_ID) | ||||
13485 | .build()); | ||||
13486 | left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
13487 | |||||
13488 | // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets | ||||
13489 | // a HOVER_EXIT from the first device. | ||||
13490 | ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13491 | /*pointerId=*/0)); | ||||
13492 | ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, | ||||
13493 | SECOND_DEVICE_ID, | ||||
13494 | /*pointerId=*/0)); | ||||
13495 | |||||
13496 | // Move the mouse outside the window. Document the current behavior, where the window does not | ||||
13497 | // receive HOVER_EXIT even though the mouse left the window. | ||||
13498 | mDispatcher->notifyMotion( | ||||
13499 | MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) | ||||
13500 | .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50)) | ||||
13501 | .rawXCursorPosition(150) | ||||
13502 | .rawYCursorPosition(50) | ||||
13503 | .deviceId(SECOND_DEVICE_ID) | ||||
13504 | .build()); | ||||
13505 | |||||
13506 | right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); | ||||
13507 | ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID, | ||||
13508 | /*pointerId=*/0)); | ||||
13509 | ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, | ||||
13510 | SECOND_DEVICE_ID, | ||||
13511 | /*pointerId=*/0)); | ||||
13512 | } | ||||
13513 | |||||
Garfield Tan | e84e6f9 | 2019-08-29 17:28:41 -0700 | [diff] [blame] | 13514 | } // namespace android::inputdispatcher |