blob: 5d5cf9c1087a1bc39c0003f38d6cc390dddb4749 [file] [log] [blame]
Vishnu Nairc519ff72021-01-21 08:23:08 -08001/*
2 * Copyright (C) 2021 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
17#include <gtest/gtest.h>
18
19#include "../FocusResolver.h"
20
Vishnu Nair1dcad982021-02-24 14:38:25 -080021#define ASSERT_FOCUS_CHANGE(_changes, _oldFocus, _newFocus) \
22 { \
23 ASSERT_EQ(_oldFocus, _changes->oldFocus); \
24 ASSERT_EQ(_newFocus, _changes->newFocus); \
25 }
26
Vishnu Nairc519ff72021-01-21 08:23:08 -080027// atest inputflinger_tests:FocusResolverTest
28
chaviw3277faf2021-05-19 16:45:23 -050029using android::gui::FocusRequest;
30using android::gui::WindowInfoHandle;
31
Vishnu Nairc519ff72021-01-21 08:23:08 -080032namespace android::inputdispatcher {
33
chaviw3277faf2021-05-19 16:45:23 -050034class FakeWindowHandle : public WindowInfoHandle {
Vishnu Nairc519ff72021-01-21 08:23:08 -080035public:
36 FakeWindowHandle(const std::string& name, const sp<IBinder>& token, bool focusable,
37 bool visible) {
38 mInfo.token = token;
39 mInfo.name = name;
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080040 setFocusable(focusable);
41 setVisible(visible);
Vishnu Nairc519ff72021-01-21 08:23:08 -080042 }
43
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080044 void setFocusable(bool focusable) {
45 mInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_FOCUSABLE, !focusable);
46 }
47 void setVisible(bool visible) {
48 mInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visible);
49 }
Vishnu Nairc519ff72021-01-21 08:23:08 -080050};
51
52TEST(FocusResolverTest, SetFocusedWindow) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070053 sp<IBinder> focusableWindowToken = sp<BBinder>::make();
54 sp<IBinder> invisibleWindowToken = sp<BBinder>::make();
55 sp<IBinder> unfocusableWindowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -050056 std::vector<sp<WindowInfoHandle>> windows;
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070057 windows.push_back(sp<FakeWindowHandle>::make("Focusable", focusableWindowToken,
58 true /* focusable */, true /* visible */));
59 windows.push_back(sp<FakeWindowHandle>::make("Invisible", invisibleWindowToken,
60 true /* focusable */, false /* visible */));
61 windows.push_back(sp<FakeWindowHandle>::make("unfocusable", unfocusableWindowToken,
62 false /* focusable */, true /* visible */));
Vishnu Nairc519ff72021-01-21 08:23:08 -080063
64 // focusable window can get focused
65 FocusRequest request;
66 request.displayId = 42;
67 request.token = focusableWindowToken;
68 FocusResolver focusResolver;
69 std::optional<FocusResolver::FocusChanges> changes =
70 focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -080071 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ focusableWindowToken);
Vishnu Nairc519ff72021-01-21 08:23:08 -080072 ASSERT_EQ(request.displayId, changes->displayId);
73
74 // invisible window cannot get focused
75 request.token = invisibleWindowToken;
76 changes = focusResolver.setFocusedWindow(request, windows);
77 ASSERT_EQ(focusableWindowToken, changes->oldFocus);
78 ASSERT_EQ(nullptr, changes->newFocus);
Vishnu Nair1dcad982021-02-24 14:38:25 -080079 ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ nullptr);
Vishnu Nairc519ff72021-01-21 08:23:08 -080080
81 // unfocusableWindowToken window cannot get focused
82 request.token = unfocusableWindowToken;
83 changes = focusResolver.setFocusedWindow(request, windows);
84 ASSERT_FALSE(changes);
85}
86
HQ Liu62105c72022-02-14 17:11:52 -080087TEST(FocusResolverTest, RemoveFocusFromFocusedWindow) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070088 sp<IBinder> focusableWindowToken = sp<BBinder>::make();
HQ Liu62105c72022-02-14 17:11:52 -080089 std::vector<sp<WindowInfoHandle>> windows;
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070090 windows.push_back(sp<FakeWindowHandle>::make("Focusable", focusableWindowToken,
91 true /* focusable */, true /* visible */));
HQ Liu62105c72022-02-14 17:11:52 -080092
93 FocusRequest request;
94 request.displayId = 42;
95 request.token = focusableWindowToken;
96 FocusResolver focusResolver;
97 // Focusable window gets focus.
98 request.token = focusableWindowToken;
99 std::optional<FocusResolver::FocusChanges> changes =
100 focusResolver.setFocusedWindow(request, windows);
101 ASSERT_FOCUS_CHANGE(changes, nullptr, focusableWindowToken);
102
103 // Window token of a request is null, focus should be revoked.
104 request.token = NULL;
105 changes = focusResolver.setFocusedWindow(request, windows);
106 ASSERT_EQ(focusableWindowToken, changes->oldFocus);
107 ASSERT_EQ(nullptr, changes->newFocus);
108 ASSERT_FOCUS_CHANGE(changes, focusableWindowToken, nullptr);
109}
110
Vishnu Nairc519ff72021-01-21 08:23:08 -0800111TEST(FocusResolverTest, SetFocusedMirroredWindow) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700112 sp<IBinder> focusableWindowToken = sp<BBinder>::make();
113 sp<IBinder> invisibleWindowToken = sp<BBinder>::make();
114 sp<IBinder> unfocusableWindowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -0500115 std::vector<sp<WindowInfoHandle>> windows;
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700116 windows.push_back(sp<FakeWindowHandle>::make("Mirror1", focusableWindowToken,
117 true /* focusable */, true /* visible */));
118 windows.push_back(sp<FakeWindowHandle>::make("Mirror1", focusableWindowToken,
119 true /* focusable */, true /* visible */));
Vishnu Nairc519ff72021-01-21 08:23:08 -0800120
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700121 windows.push_back(sp<FakeWindowHandle>::make("Mirror2Visible", invisibleWindowToken,
122 true /* focusable */, true /* visible */));
123 windows.push_back(sp<FakeWindowHandle>::make("Mirror2Invisible", invisibleWindowToken,
124 true /* focusable */, false /* visible */));
Vishnu Nairc519ff72021-01-21 08:23:08 -0800125
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700126 windows.push_back(sp<FakeWindowHandle>::make("Mirror3Focusable", unfocusableWindowToken,
127 true /* focusable */, true /* visible */));
128 windows.push_back(sp<FakeWindowHandle>::make("Mirror3Unfocusable", unfocusableWindowToken,
129 false /* focusable */, true /* visible */));
Vishnu Nairc519ff72021-01-21 08:23:08 -0800130
131 // mirrored window can get focused
132 FocusRequest request;
133 request.displayId = 42;
134 request.token = focusableWindowToken;
135 FocusResolver focusResolver;
136 std::optional<FocusResolver::FocusChanges> changes =
137 focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800138 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ focusableWindowToken);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800139
140 // mirrored window with one visible window can get focused
141 request.token = invisibleWindowToken;
142 changes = focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800143 ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ invisibleWindowToken);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800144
145 // mirrored window with one or more unfocusable window cannot get focused
146 request.token = unfocusableWindowToken;
147 changes = focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800148 ASSERT_FOCUS_CHANGE(changes, /*from*/ invisibleWindowToken, /*to*/ nullptr);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800149}
150
151TEST(FocusResolverTest, SetInputWindows) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700152 sp<IBinder> focusableWindowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -0500153 std::vector<sp<WindowInfoHandle>> windows;
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700154 sp<FakeWindowHandle> window =
155 sp<FakeWindowHandle>::make("Focusable", focusableWindowToken, true /* focusable */,
156 true /* visible */);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800157 windows.push_back(window);
158
159 // focusable window can get focused
160 FocusRequest request;
161 request.displayId = 42;
162 request.token = focusableWindowToken;
163 FocusResolver focusResolver;
164 std::optional<FocusResolver::FocusChanges> changes =
165 focusResolver.setFocusedWindow(request, windows);
166 ASSERT_EQ(focusableWindowToken, changes->newFocus);
167
Vishnu Nair1dcad982021-02-24 14:38:25 -0800168 // Window visibility changes and the window loses focus
Vishnu Nairc519ff72021-01-21 08:23:08 -0800169 window->setVisible(false);
170 changes = focusResolver.setInputWindows(request.displayId, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800171 ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ nullptr);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800172}
173
174TEST(FocusResolverTest, FocusRequestsCanBePending) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700175 sp<IBinder> invisibleWindowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -0500176 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nairc519ff72021-01-21 08:23:08 -0800177
178 sp<FakeWindowHandle> invisibleWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700179 sp<FakeWindowHandle>::make("Invisible", invisibleWindowToken, true /* focusable */,
180 false /* visible */);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800181 windows.push_back(invisibleWindow);
182
183 // invisible window cannot get focused
184 FocusRequest request;
185 request.displayId = 42;
186 request.token = invisibleWindowToken;
187 FocusResolver focusResolver;
188 std::optional<FocusResolver::FocusChanges> changes =
189 focusResolver.setFocusedWindow(request, windows);
190 ASSERT_FALSE(changes);
191
192 // Window visibility changes and the window gets focused
193 invisibleWindow->setVisible(true);
194 changes = focusResolver.setInputWindows(request.displayId, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800195 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ invisibleWindowToken);
196}
197
198TEST(FocusResolverTest, FocusRequestsArePersistent) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700199 sp<IBinder> windowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -0500200 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair1dcad982021-02-24 14:38:25 -0800201
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700202 sp<FakeWindowHandle> window =
203 sp<FakeWindowHandle>::make("Test Window", windowToken, false /* focusable */,
204 true /* visible */);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800205 windows.push_back(window);
206
207 // non-focusable window cannot get focused
208 FocusRequest request;
209 request.displayId = 42;
210 request.token = windowToken;
211 FocusResolver focusResolver;
212 std::optional<FocusResolver::FocusChanges> changes =
213 focusResolver.setFocusedWindow(request, windows);
214 ASSERT_FALSE(changes);
215
216 // Focusability changes and the window gets focused
217 window->setFocusable(true);
218 changes = focusResolver.setInputWindows(request.displayId, windows);
219 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
220
221 // Visibility changes and the window loses focus
222 window->setVisible(false);
223 changes = focusResolver.setInputWindows(request.displayId, windows);
224 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
225
226 // Visibility changes and the window gets focused
227 window->setVisible(true);
228 changes = focusResolver.setInputWindows(request.displayId, windows);
229 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
230
231 // Window is gone and the window loses focus
232 changes = focusResolver.setInputWindows(request.displayId, {});
233 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
234
235 // Window returns and the window gains focus
236 changes = focusResolver.setInputWindows(request.displayId, windows);
237 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
238}
239
240TEST(FocusResolverTest, ConditionalFocusRequestsAreNotPersistent) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700241 sp<IBinder> hostWindowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -0500242 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair1dcad982021-02-24 14:38:25 -0800243
244 sp<FakeWindowHandle> hostWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700245 sp<FakeWindowHandle>::make("Host Window", hostWindowToken, true /* focusable */,
246 true /* visible */);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800247 windows.push_back(hostWindow);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700248 sp<IBinder> embeddedWindowToken = sp<BBinder>::make();
Vishnu Nair1dcad982021-02-24 14:38:25 -0800249 sp<FakeWindowHandle> embeddedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700250 sp<FakeWindowHandle>::make("Embedded Window", embeddedWindowToken, true /* focusable */,
251 true /* visible */);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800252 windows.push_back(embeddedWindow);
253
254 FocusRequest request;
255 request.displayId = 42;
256 request.token = hostWindowToken;
257 FocusResolver focusResolver;
258 std::optional<FocusResolver::FocusChanges> changes =
259 focusResolver.setFocusedWindow(request, windows);
260 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ hostWindowToken);
261
262 request.focusedToken = hostWindow->getToken();
263 request.token = embeddedWindowToken;
264 changes = focusResolver.setFocusedWindow(request, windows);
265 ASSERT_FOCUS_CHANGE(changes, /*from*/ hostWindowToken, /*to*/ embeddedWindowToken);
266
267 embeddedWindow->setFocusable(false);
268 changes = focusResolver.setInputWindows(request.displayId, windows);
269 // The embedded window is no longer focusable, provide focus back to the original focused
270 // window.
271 ASSERT_FOCUS_CHANGE(changes, /*from*/ embeddedWindowToken, /*to*/ hostWindowToken);
272
273 embeddedWindow->setFocusable(true);
274 changes = focusResolver.setInputWindows(request.displayId, windows);
275 // The embedded window is focusable again, but we it cannot gain focus unless there is another
276 // focus request.
277 ASSERT_FALSE(changes);
278
279 embeddedWindow->setVisible(false);
280 changes = focusResolver.setFocusedWindow(request, windows);
281 // If the embedded window is not visible/focusable, then we do not grant it focus and the
282 // request is dropped.
283 ASSERT_FALSE(changes);
284
285 embeddedWindow->setVisible(true);
286 changes = focusResolver.setInputWindows(request.displayId, windows);
287 // If the embedded window becomes visble/focusable, nothing changes since the request has been
288 // dropped.
289 ASSERT_FALSE(changes);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800290}
Vishnu Nair599f1412021-06-21 10:39:58 -0700291TEST(FocusResolverTest, FocusRequestsAreClearedWhenWindowIsRemoved) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700292 sp<IBinder> windowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -0500293 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair599f1412021-06-21 10:39:58 -0700294
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700295 sp<FakeWindowHandle> window =
296 sp<FakeWindowHandle>::make("Test Window", windowToken, true /* focusable */,
297 true /* visible */);
Vishnu Nair599f1412021-06-21 10:39:58 -0700298 windows.push_back(window);
299
300 FocusRequest request;
301 request.displayId = 42;
302 request.token = windowToken;
303 FocusResolver focusResolver;
304 std::optional<FocusResolver::FocusChanges> changes =
305 focusResolver.setFocusedWindow(request, windows);
306 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
307 ASSERT_EQ(request.displayId, changes->displayId);
308
309 // Start with a focused window
310 window->setFocusable(true);
311 changes = focusResolver.setInputWindows(request.displayId, windows);
312 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
313
314 // When a display is removed, all windows are removed from the display
315 // and our focused window loses focus
316 changes = focusResolver.setInputWindows(request.displayId, {});
317 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
318 focusResolver.displayRemoved(request.displayId);
319
320 // When a display is readded, the window does not get focus since the request was cleared.
321 changes = focusResolver.setInputWindows(request.displayId, windows);
322 ASSERT_FALSE(changes);
323}
Vishnu Nairc519ff72021-01-21 08:23:08 -0800324
325} // namespace android::inputdispatcher