blob: cb8c3cb03cc968f0679eea116331ffb21863724c [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 { \
Prabir Pradhan3fea36d2024-03-06 21:20:04 +000023 ASSERT_TRUE(_changes.has_value()); \
Vishnu Nair1dcad982021-02-24 14:38:25 -080024 ASSERT_EQ(_oldFocus, _changes->oldFocus); \
25 ASSERT_EQ(_newFocus, _changes->newFocus); \
26 }
27
Vishnu Nairc519ff72021-01-21 08:23:08 -080028// atest inputflinger_tests:FocusResolverTest
29
chaviw3277faf2021-05-19 16:45:23 -050030using android::gui::FocusRequest;
31using android::gui::WindowInfoHandle;
32
Vishnu Nairc519ff72021-01-21 08:23:08 -080033namespace android::inputdispatcher {
34
Siarhei Vishniakouadeb6fa2023-05-26 09:11:06 -070035namespace {
36
chaviw3277faf2021-05-19 16:45:23 -050037class FakeWindowHandle : public WindowInfoHandle {
Vishnu Nairc519ff72021-01-21 08:23:08 -080038public:
39 FakeWindowHandle(const std::string& name, const sp<IBinder>& token, bool focusable,
40 bool visible) {
41 mInfo.token = token;
42 mInfo.name = name;
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080043 setFocusable(focusable);
44 setVisible(visible);
Vishnu Nairc519ff72021-01-21 08:23:08 -080045 }
46
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080047 void setFocusable(bool focusable) {
48 mInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_FOCUSABLE, !focusable);
49 }
50 void setVisible(bool visible) {
51 mInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visible);
52 }
Vishnu Nairc519ff72021-01-21 08:23:08 -080053};
54
Siarhei Vishniakouadeb6fa2023-05-26 09:11:06 -070055} // namespace
56
Vishnu Nairc519ff72021-01-21 08:23:08 -080057TEST(FocusResolverTest, SetFocusedWindow) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070058 sp<IBinder> focusableWindowToken = sp<BBinder>::make();
59 sp<IBinder> invisibleWindowToken = sp<BBinder>::make();
60 sp<IBinder> unfocusableWindowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -050061 std::vector<sp<WindowInfoHandle>> windows;
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070062 windows.push_back(sp<FakeWindowHandle>::make("Focusable", focusableWindowToken,
Harry Cutts33476232023-01-30 19:57:29 +000063 /*focusable=*/true, /*visible=*/true));
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070064 windows.push_back(sp<FakeWindowHandle>::make("Invisible", invisibleWindowToken,
Harry Cutts33476232023-01-30 19:57:29 +000065 /*focusable=*/true, /*visible=*/false));
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070066 windows.push_back(sp<FakeWindowHandle>::make("unfocusable", unfocusableWindowToken,
Harry Cutts33476232023-01-30 19:57:29 +000067 /*focusable=*/false, /*visible=*/true));
Vishnu Nairc519ff72021-01-21 08:23:08 -080068
69 // focusable window can get focused
70 FocusRequest request;
71 request.displayId = 42;
72 request.token = focusableWindowToken;
73 FocusResolver focusResolver;
74 std::optional<FocusResolver::FocusChanges> changes =
75 focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -080076 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ focusableWindowToken);
Vishnu Nairc519ff72021-01-21 08:23:08 -080077 ASSERT_EQ(request.displayId, changes->displayId);
78
79 // invisible window cannot get focused
80 request.token = invisibleWindowToken;
81 changes = focusResolver.setFocusedWindow(request, windows);
82 ASSERT_EQ(focusableWindowToken, changes->oldFocus);
83 ASSERT_EQ(nullptr, changes->newFocus);
Vishnu Nair1dcad982021-02-24 14:38:25 -080084 ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ nullptr);
Vishnu Nairc519ff72021-01-21 08:23:08 -080085
86 // unfocusableWindowToken window cannot get focused
87 request.token = unfocusableWindowToken;
88 changes = focusResolver.setFocusedWindow(request, windows);
89 ASSERT_FALSE(changes);
90}
91
HQ Liu62105c72022-02-14 17:11:52 -080092TEST(FocusResolverTest, RemoveFocusFromFocusedWindow) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070093 sp<IBinder> focusableWindowToken = sp<BBinder>::make();
HQ Liu62105c72022-02-14 17:11:52 -080094 std::vector<sp<WindowInfoHandle>> windows;
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070095 windows.push_back(sp<FakeWindowHandle>::make("Focusable", focusableWindowToken,
Harry Cutts33476232023-01-30 19:57:29 +000096 /*focusable=*/true, /*visible=*/true));
HQ Liu62105c72022-02-14 17:11:52 -080097
98 FocusRequest request;
99 request.displayId = 42;
100 request.token = focusableWindowToken;
101 FocusResolver focusResolver;
102 // Focusable window gets focus.
103 request.token = focusableWindowToken;
104 std::optional<FocusResolver::FocusChanges> changes =
105 focusResolver.setFocusedWindow(request, windows);
106 ASSERT_FOCUS_CHANGE(changes, nullptr, focusableWindowToken);
107
108 // Window token of a request is null, focus should be revoked.
109 request.token = NULL;
110 changes = focusResolver.setFocusedWindow(request, windows);
111 ASSERT_EQ(focusableWindowToken, changes->oldFocus);
112 ASSERT_EQ(nullptr, changes->newFocus);
113 ASSERT_FOCUS_CHANGE(changes, focusableWindowToken, nullptr);
114}
115
Vishnu Nairc519ff72021-01-21 08:23:08 -0800116TEST(FocusResolverTest, SetFocusedMirroredWindow) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700117 sp<IBinder> focusableWindowToken = sp<BBinder>::make();
118 sp<IBinder> invisibleWindowToken = sp<BBinder>::make();
119 sp<IBinder> unfocusableWindowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -0500120 std::vector<sp<WindowInfoHandle>> windows;
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700121 windows.push_back(sp<FakeWindowHandle>::make("Mirror1", focusableWindowToken,
Harry Cutts33476232023-01-30 19:57:29 +0000122 /*focusable=*/true, /*visible=*/true));
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700123 windows.push_back(sp<FakeWindowHandle>::make("Mirror1", focusableWindowToken,
Harry Cutts33476232023-01-30 19:57:29 +0000124 /*focusable=*/true, /*visible=*/true));
Vishnu Nairc519ff72021-01-21 08:23:08 -0800125
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700126 windows.push_back(sp<FakeWindowHandle>::make("Mirror2Visible", invisibleWindowToken,
Harry Cutts33476232023-01-30 19:57:29 +0000127 /*focusable=*/true, /*visible=*/true));
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700128 windows.push_back(sp<FakeWindowHandle>::make("Mirror2Invisible", invisibleWindowToken,
Harry Cutts33476232023-01-30 19:57:29 +0000129 /*focusable=*/true, /*visible=*/false));
Vishnu Nairc519ff72021-01-21 08:23:08 -0800130
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700131 windows.push_back(sp<FakeWindowHandle>::make("Mirror3Focusable", unfocusableWindowToken,
Harry Cutts33476232023-01-30 19:57:29 +0000132 /*focusable=*/true, /*visible=*/true));
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700133 windows.push_back(sp<FakeWindowHandle>::make("Mirror3Unfocusable", unfocusableWindowToken,
Harry Cutts33476232023-01-30 19:57:29 +0000134 /*focusable=*/false, /*visible=*/true));
Vishnu Nairc519ff72021-01-21 08:23:08 -0800135
136 // mirrored window can get focused
137 FocusRequest request;
138 request.displayId = 42;
139 request.token = focusableWindowToken;
140 FocusResolver focusResolver;
141 std::optional<FocusResolver::FocusChanges> changes =
142 focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800143 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ focusableWindowToken);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800144
145 // mirrored window with one visible window can get focused
146 request.token = invisibleWindowToken;
147 changes = focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800148 ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ invisibleWindowToken);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800149
150 // mirrored window with one or more unfocusable window cannot get focused
151 request.token = unfocusableWindowToken;
152 changes = focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800153 ASSERT_FOCUS_CHANGE(changes, /*from*/ invisibleWindowToken, /*to*/ nullptr);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800154}
155
Prabir Pradhan3fea36d2024-03-06 21:20:04 +0000156TEST(FocusResolverTest, FocusTransferToMirror) {
157 sp<IBinder> focusableWindowToken = sp<BBinder>::make();
158 auto window = sp<FakeWindowHandle>::make("Window", focusableWindowToken,
159 /*focusable=*/true, /*visible=*/true);
160 auto mirror = sp<FakeWindowHandle>::make("Mirror", focusableWindowToken,
161 /*focusable=*/true, /*visible=*/true);
162
163 FocusRequest request;
164 request.displayId = 42;
165 request.token = focusableWindowToken;
166 FocusResolver focusResolver;
167 std::optional<FocusResolver::FocusChanges> changes =
168 focusResolver.setFocusedWindow(request, {window, mirror});
169 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ focusableWindowToken);
170
171 // The mirror window now comes on top, and the focus does not change
172 changes = focusResolver.setInputWindows(request.displayId, {mirror, window});
173 ASSERT_FALSE(changes.has_value());
174
175 // The window now comes on top while the mirror is removed, and the focus does not change
176 changes = focusResolver.setInputWindows(request.displayId, {window});
177 ASSERT_FALSE(changes.has_value());
178
179 // The window is removed but the mirror is on top, and focus does not change
180 changes = focusResolver.setInputWindows(request.displayId, {mirror});
181 ASSERT_FALSE(changes.has_value());
182
183 // All windows removed
184 changes = focusResolver.setInputWindows(request.displayId, {});
185 ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ nullptr);
186}
187
Vishnu Nairc519ff72021-01-21 08:23:08 -0800188TEST(FocusResolverTest, SetInputWindows) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700189 sp<IBinder> focusableWindowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -0500190 std::vector<sp<WindowInfoHandle>> windows;
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700191 sp<FakeWindowHandle> window =
Harry Cutts33476232023-01-30 19:57:29 +0000192 sp<FakeWindowHandle>::make("Focusable", focusableWindowToken, /*focusable=*/true,
193 /*visible=*/true);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800194 windows.push_back(window);
195
196 // focusable window can get focused
197 FocusRequest request;
198 request.displayId = 42;
199 request.token = focusableWindowToken;
200 FocusResolver focusResolver;
201 std::optional<FocusResolver::FocusChanges> changes =
202 focusResolver.setFocusedWindow(request, windows);
203 ASSERT_EQ(focusableWindowToken, changes->newFocus);
204
Prabir Pradhan3fea36d2024-03-06 21:20:04 +0000205 // When there are no changes to the window, focus does not change
206 changes = focusResolver.setInputWindows(request.displayId, windows);
207 ASSERT_FALSE(changes.has_value());
208
Vishnu Nair1dcad982021-02-24 14:38:25 -0800209 // Window visibility changes and the window loses focus
Vishnu Nairc519ff72021-01-21 08:23:08 -0800210 window->setVisible(false);
211 changes = focusResolver.setInputWindows(request.displayId, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800212 ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ nullptr);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800213}
214
215TEST(FocusResolverTest, FocusRequestsCanBePending) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700216 sp<IBinder> invisibleWindowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -0500217 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nairc519ff72021-01-21 08:23:08 -0800218
219 sp<FakeWindowHandle> invisibleWindow =
Harry Cutts33476232023-01-30 19:57:29 +0000220 sp<FakeWindowHandle>::make("Invisible", invisibleWindowToken, /*focusable=*/true,
221 /*visible=*/false);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800222 windows.push_back(invisibleWindow);
223
224 // invisible window cannot get focused
225 FocusRequest request;
226 request.displayId = 42;
227 request.token = invisibleWindowToken;
228 FocusResolver focusResolver;
229 std::optional<FocusResolver::FocusChanges> changes =
230 focusResolver.setFocusedWindow(request, windows);
231 ASSERT_FALSE(changes);
232
233 // Window visibility changes and the window gets focused
234 invisibleWindow->setVisible(true);
235 changes = focusResolver.setInputWindows(request.displayId, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800236 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ invisibleWindowToken);
237}
238
239TEST(FocusResolverTest, FocusRequestsArePersistent) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700240 sp<IBinder> windowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -0500241 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair1dcad982021-02-24 14:38:25 -0800242
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700243 sp<FakeWindowHandle> window =
Harry Cutts33476232023-01-30 19:57:29 +0000244 sp<FakeWindowHandle>::make("Test Window", windowToken, /*focusable=*/false,
245 /*visible=*/true);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800246 windows.push_back(window);
247
248 // non-focusable window cannot get focused
249 FocusRequest request;
250 request.displayId = 42;
251 request.token = windowToken;
252 FocusResolver focusResolver;
253 std::optional<FocusResolver::FocusChanges> changes =
254 focusResolver.setFocusedWindow(request, windows);
255 ASSERT_FALSE(changes);
256
257 // Focusability changes and the window gets focused
258 window->setFocusable(true);
259 changes = focusResolver.setInputWindows(request.displayId, windows);
260 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
261
262 // Visibility changes and the window loses focus
263 window->setVisible(false);
264 changes = focusResolver.setInputWindows(request.displayId, windows);
265 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
266
267 // Visibility changes and the window gets focused
268 window->setVisible(true);
269 changes = focusResolver.setInputWindows(request.displayId, windows);
270 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
271
272 // Window is gone and the window loses focus
273 changes = focusResolver.setInputWindows(request.displayId, {});
274 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
275
276 // Window returns and the window gains focus
277 changes = focusResolver.setInputWindows(request.displayId, windows);
278 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
279}
280
Chavi Weingarten847e8512023-03-29 00:26:09 +0000281TEST(FocusResolverTest, FocusTransferTarget) {
282 sp<IBinder> hostWindowToken = sp<BBinder>::make();
283 std::vector<sp<WindowInfoHandle>> windows;
284
285 sp<FakeWindowHandle> hostWindow =
286 sp<FakeWindowHandle>::make("Host Window", hostWindowToken, /*focusable=*/true,
287 /*visible=*/true);
288 windows.push_back(hostWindow);
289 sp<IBinder> embeddedWindowToken = sp<BBinder>::make();
290 sp<FakeWindowHandle> embeddedWindow =
291 sp<FakeWindowHandle>::make("Embedded Window", embeddedWindowToken, /*focusable=*/false,
292 /*visible=*/true);
293 windows.push_back(embeddedWindow);
294
295 FocusRequest request;
296 request.displayId = 42;
297 request.token = hostWindowToken;
298
299 // Host wants to transfer touch to embedded.
300 hostWindow->editInfo()->focusTransferTarget = embeddedWindowToken;
301
302 FocusResolver focusResolver;
303 std::optional<FocusResolver::FocusChanges> changes =
304 focusResolver.setFocusedWindow(request, windows);
305 // Embedded was not focusable so host gains focus.
306 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ hostWindowToken);
307
308 // Embedded is now focusable so will gain focus
309 embeddedWindow->setFocusable(true);
310 changes = focusResolver.setInputWindows(request.displayId, windows);
311 ASSERT_FOCUS_CHANGE(changes, /*from*/ hostWindowToken, /*to*/ embeddedWindowToken);
312
313 // Embedded is not visible so host will get focus
314 embeddedWindow->setVisible(false);
315 changes = focusResolver.setInputWindows(request.displayId, windows);
316 ASSERT_FOCUS_CHANGE(changes, /*from*/ embeddedWindowToken, /*to*/ hostWindowToken);
317
318 // Embedded is now visible so will get focus
319 embeddedWindow->setVisible(true);
320 changes = focusResolver.setInputWindows(request.displayId, windows);
321 ASSERT_FOCUS_CHANGE(changes, /*from*/ hostWindowToken, /*to*/ embeddedWindowToken);
322
323 // Remove focusTransferTarget from host. Host will gain focus.
324 hostWindow->editInfo()->focusTransferTarget = nullptr;
325 changes = focusResolver.setInputWindows(request.displayId, windows);
326 ASSERT_FOCUS_CHANGE(changes, /*from*/ embeddedWindowToken, /*to*/ hostWindowToken);
327
328 // Set invalid token for focusTransferTarget. Host will remain focus
329 hostWindow->editInfo()->focusTransferTarget = sp<BBinder>::make();
330 changes = focusResolver.setInputWindows(request.displayId, windows);
331 ASSERT_FALSE(changes);
332}
333
334TEST(FocusResolverTest, FocusTransferMultipleInChain) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700335 sp<IBinder> hostWindowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -0500336 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair1dcad982021-02-24 14:38:25 -0800337
338 sp<FakeWindowHandle> hostWindow =
Harry Cutts33476232023-01-30 19:57:29 +0000339 sp<FakeWindowHandle>::make("Host Window", hostWindowToken, /*focusable=*/true,
340 /*visible=*/true);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800341 windows.push_back(hostWindow);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700342 sp<IBinder> embeddedWindowToken = sp<BBinder>::make();
Vishnu Nair1dcad982021-02-24 14:38:25 -0800343 sp<FakeWindowHandle> embeddedWindow =
Harry Cutts33476232023-01-30 19:57:29 +0000344 sp<FakeWindowHandle>::make("Embedded Window", embeddedWindowToken, /*focusable=*/true,
345 /*visible=*/true);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800346 windows.push_back(embeddedWindow);
347
Chavi Weingarten847e8512023-03-29 00:26:09 +0000348 sp<IBinder> embeddedWindowToken2 = sp<BBinder>::make();
349 sp<FakeWindowHandle> embeddedWindow2 =
350 sp<FakeWindowHandle>::make("Embedded Window2", embeddedWindowToken2, /*focusable=*/true,
351 /*visible=*/true);
352 windows.push_back(embeddedWindow2);
353
Vishnu Nair1dcad982021-02-24 14:38:25 -0800354 FocusRequest request;
355 request.displayId = 42;
356 request.token = hostWindowToken;
Chavi Weingarten847e8512023-03-29 00:26:09 +0000357
358 hostWindow->editInfo()->focusTransferTarget = embeddedWindowToken;
359 embeddedWindow->editInfo()->focusTransferTarget = embeddedWindowToken2;
360
Vishnu Nair1dcad982021-02-24 14:38:25 -0800361 FocusResolver focusResolver;
362 std::optional<FocusResolver::FocusChanges> changes =
363 focusResolver.setFocusedWindow(request, windows);
Chavi Weingarten847e8512023-03-29 00:26:09 +0000364 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ embeddedWindowToken2);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800365}
Chavi Weingarten847e8512023-03-29 00:26:09 +0000366
367TEST(FocusResolverTest, FocusTransferTargetCycle) {
368 sp<IBinder> hostWindowToken = sp<BBinder>::make();
369 std::vector<sp<WindowInfoHandle>> windows;
370
371 sp<FakeWindowHandle> hostWindow =
372 sp<FakeWindowHandle>::make("Host Window", hostWindowToken, /*focusable=*/true,
373 /*visible=*/true);
374 windows.push_back(hostWindow);
375 sp<IBinder> embeddedWindowToken = sp<BBinder>::make();
376 sp<FakeWindowHandle> embeddedWindow =
377 sp<FakeWindowHandle>::make("Embedded Window", embeddedWindowToken, /*focusable=*/true,
378 /*visible=*/true);
379 windows.push_back(embeddedWindow);
380
381 sp<IBinder> embeddedWindowToken2 = sp<BBinder>::make();
382 sp<FakeWindowHandle> embeddedWindow2 =
383 sp<FakeWindowHandle>::make("Embedded Window2", embeddedWindowToken2, /*focusable=*/true,
384 /*visible=*/true);
385 windows.push_back(embeddedWindow2);
386
387 FocusRequest request;
388 request.displayId = 42;
389 request.token = hostWindowToken;
390
391 hostWindow->editInfo()->focusTransferTarget = embeddedWindowToken;
392 embeddedWindow->editInfo()->focusTransferTarget = embeddedWindowToken2;
393 embeddedWindow2->editInfo()->focusTransferTarget = hostWindowToken;
394
395 FocusResolver focusResolver;
396 std::optional<FocusResolver::FocusChanges> changes =
397 focusResolver.setFocusedWindow(request, windows);
398 // Cycle will be detected and stop right before trying to transfer token to host again.
399 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ embeddedWindowToken2);
400}
401
Vishnu Nair599f1412021-06-21 10:39:58 -0700402TEST(FocusResolverTest, FocusRequestsAreClearedWhenWindowIsRemoved) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700403 sp<IBinder> windowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -0500404 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair599f1412021-06-21 10:39:58 -0700405
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700406 sp<FakeWindowHandle> window =
Harry Cutts33476232023-01-30 19:57:29 +0000407 sp<FakeWindowHandle>::make("Test Window", windowToken, /*focusable=*/true,
408 /*visible=*/true);
Vishnu Nair599f1412021-06-21 10:39:58 -0700409 windows.push_back(window);
410
411 FocusRequest request;
412 request.displayId = 42;
413 request.token = windowToken;
414 FocusResolver focusResolver;
415 std::optional<FocusResolver::FocusChanges> changes =
416 focusResolver.setFocusedWindow(request, windows);
417 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
418 ASSERT_EQ(request.displayId, changes->displayId);
419
Vishnu Nair599f1412021-06-21 10:39:58 -0700420 // When a display is removed, all windows are removed from the display
421 // and our focused window loses focus
422 changes = focusResolver.setInputWindows(request.displayId, {});
423 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
424 focusResolver.displayRemoved(request.displayId);
425
Prabir Pradhan3fea36d2024-03-06 21:20:04 +0000426 // When a display is re-added, the window does not get focus since the request was cleared.
Vishnu Nair599f1412021-06-21 10:39:58 -0700427 changes = focusResolver.setInputWindows(request.displayId, windows);
428 ASSERT_FALSE(changes);
429}
Vishnu Nairc519ff72021-01-21 08:23:08 -0800430
431} // namespace android::inputdispatcher