blob: f794da5daf616464a4f8ba281add386357d999c8 [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);
Linnan Li13bf76a2024-05-05 19:18:02 +080077 ASSERT_EQ(ui::LogicalDisplayId{request.displayId}, changes->displayId);
Vishnu Nairc519ff72021-01-21 08:23:08 -080078
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
Linnan Li13bf76a2024-05-05 19:18:02 +0800172 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId},
173 {mirror, window});
Prabir Pradhan3fea36d2024-03-06 21:20:04 +0000174 ASSERT_FALSE(changes.has_value());
175
176 // The window now comes on top while the mirror is removed, and the focus does not change
Linnan Li13bf76a2024-05-05 19:18:02 +0800177 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, {window});
Prabir Pradhan3fea36d2024-03-06 21:20:04 +0000178 ASSERT_FALSE(changes.has_value());
179
180 // The window is removed but the mirror is on top, and focus does not change
Linnan Li13bf76a2024-05-05 19:18:02 +0800181 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, {mirror});
Prabir Pradhan3fea36d2024-03-06 21:20:04 +0000182 ASSERT_FALSE(changes.has_value());
183
184 // All windows removed
Linnan Li13bf76a2024-05-05 19:18:02 +0800185 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, {});
Prabir Pradhan3fea36d2024-03-06 21:20:04 +0000186 ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ nullptr);
187}
188
Vishnu Nairc519ff72021-01-21 08:23:08 -0800189TEST(FocusResolverTest, SetInputWindows) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700190 sp<IBinder> focusableWindowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -0500191 std::vector<sp<WindowInfoHandle>> windows;
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700192 sp<FakeWindowHandle> window =
Harry Cutts33476232023-01-30 19:57:29 +0000193 sp<FakeWindowHandle>::make("Focusable", focusableWindowToken, /*focusable=*/true,
194 /*visible=*/true);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800195 windows.push_back(window);
196
197 // focusable window can get focused
198 FocusRequest request;
199 request.displayId = 42;
200 request.token = focusableWindowToken;
201 FocusResolver focusResolver;
202 std::optional<FocusResolver::FocusChanges> changes =
203 focusResolver.setFocusedWindow(request, windows);
204 ASSERT_EQ(focusableWindowToken, changes->newFocus);
205
Prabir Pradhan3fea36d2024-03-06 21:20:04 +0000206 // When there are no changes to the window, focus does not change
Linnan Li13bf76a2024-05-05 19:18:02 +0800207 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
Prabir Pradhan3fea36d2024-03-06 21:20:04 +0000208 ASSERT_FALSE(changes.has_value());
209
Vishnu Nair1dcad982021-02-24 14:38:25 -0800210 // Window visibility changes and the window loses focus
Vishnu Nairc519ff72021-01-21 08:23:08 -0800211 window->setVisible(false);
Linnan Li13bf76a2024-05-05 19:18:02 +0800212 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800213 ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ nullptr);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800214}
215
216TEST(FocusResolverTest, FocusRequestsCanBePending) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700217 sp<IBinder> invisibleWindowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -0500218 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nairc519ff72021-01-21 08:23:08 -0800219
220 sp<FakeWindowHandle> invisibleWindow =
Harry Cutts33476232023-01-30 19:57:29 +0000221 sp<FakeWindowHandle>::make("Invisible", invisibleWindowToken, /*focusable=*/true,
222 /*visible=*/false);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800223 windows.push_back(invisibleWindow);
224
225 // invisible window cannot get focused
226 FocusRequest request;
227 request.displayId = 42;
228 request.token = invisibleWindowToken;
229 FocusResolver focusResolver;
230 std::optional<FocusResolver::FocusChanges> changes =
231 focusResolver.setFocusedWindow(request, windows);
232 ASSERT_FALSE(changes);
233
234 // Window visibility changes and the window gets focused
235 invisibleWindow->setVisible(true);
Linnan Li13bf76a2024-05-05 19:18:02 +0800236 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800237 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ invisibleWindowToken);
238}
239
240TEST(FocusResolverTest, FocusRequestsArePersistent) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700241 sp<IBinder> windowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -0500242 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair1dcad982021-02-24 14:38:25 -0800243
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700244 sp<FakeWindowHandle> window =
Harry Cutts33476232023-01-30 19:57:29 +0000245 sp<FakeWindowHandle>::make("Test Window", windowToken, /*focusable=*/false,
246 /*visible=*/true);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800247 windows.push_back(window);
248
249 // non-focusable window cannot get focused
250 FocusRequest request;
251 request.displayId = 42;
252 request.token = windowToken;
253 FocusResolver focusResolver;
254 std::optional<FocusResolver::FocusChanges> changes =
255 focusResolver.setFocusedWindow(request, windows);
256 ASSERT_FALSE(changes);
257
258 // Focusability changes and the window gets focused
259 window->setFocusable(true);
Linnan Li13bf76a2024-05-05 19:18:02 +0800260 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800261 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
262
263 // Visibility changes and the window loses focus
264 window->setVisible(false);
Linnan Li13bf76a2024-05-05 19:18:02 +0800265 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800266 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
267
268 // Visibility changes and the window gets focused
269 window->setVisible(true);
Linnan Li13bf76a2024-05-05 19:18:02 +0800270 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800271 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
272
273 // Window is gone and the window loses focus
Linnan Li13bf76a2024-05-05 19:18:02 +0800274 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, {});
Vishnu Nair1dcad982021-02-24 14:38:25 -0800275 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
276
277 // Window returns and the window gains focus
Linnan Li13bf76a2024-05-05 19:18:02 +0800278 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800279 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
280}
281
Chavi Weingarten847e8512023-03-29 00:26:09 +0000282TEST(FocusResolverTest, FocusTransferTarget) {
283 sp<IBinder> hostWindowToken = sp<BBinder>::make();
284 std::vector<sp<WindowInfoHandle>> windows;
285
286 sp<FakeWindowHandle> hostWindow =
287 sp<FakeWindowHandle>::make("Host Window", hostWindowToken, /*focusable=*/true,
288 /*visible=*/true);
289 windows.push_back(hostWindow);
290 sp<IBinder> embeddedWindowToken = sp<BBinder>::make();
291 sp<FakeWindowHandle> embeddedWindow =
292 sp<FakeWindowHandle>::make("Embedded Window", embeddedWindowToken, /*focusable=*/false,
293 /*visible=*/true);
294 windows.push_back(embeddedWindow);
295
296 FocusRequest request;
297 request.displayId = 42;
298 request.token = hostWindowToken;
299
300 // Host wants to transfer touch to embedded.
301 hostWindow->editInfo()->focusTransferTarget = embeddedWindowToken;
302
303 FocusResolver focusResolver;
304 std::optional<FocusResolver::FocusChanges> changes =
305 focusResolver.setFocusedWindow(request, windows);
306 // Embedded was not focusable so host gains focus.
307 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ hostWindowToken);
308
309 // Embedded is now focusable so will gain focus
310 embeddedWindow->setFocusable(true);
Linnan Li13bf76a2024-05-05 19:18:02 +0800311 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
Chavi Weingarten847e8512023-03-29 00:26:09 +0000312 ASSERT_FOCUS_CHANGE(changes, /*from*/ hostWindowToken, /*to*/ embeddedWindowToken);
313
314 // Embedded is not visible so host will get focus
315 embeddedWindow->setVisible(false);
Linnan Li13bf76a2024-05-05 19:18:02 +0800316 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
Chavi Weingarten847e8512023-03-29 00:26:09 +0000317 ASSERT_FOCUS_CHANGE(changes, /*from*/ embeddedWindowToken, /*to*/ hostWindowToken);
318
319 // Embedded is now visible so will get focus
320 embeddedWindow->setVisible(true);
Linnan Li13bf76a2024-05-05 19:18:02 +0800321 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
Chavi Weingarten847e8512023-03-29 00:26:09 +0000322 ASSERT_FOCUS_CHANGE(changes, /*from*/ hostWindowToken, /*to*/ embeddedWindowToken);
323
324 // Remove focusTransferTarget from host. Host will gain focus.
325 hostWindow->editInfo()->focusTransferTarget = nullptr;
Linnan Li13bf76a2024-05-05 19:18:02 +0800326 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
Chavi Weingarten847e8512023-03-29 00:26:09 +0000327 ASSERT_FOCUS_CHANGE(changes, /*from*/ embeddedWindowToken, /*to*/ hostWindowToken);
328
329 // Set invalid token for focusTransferTarget. Host will remain focus
330 hostWindow->editInfo()->focusTransferTarget = sp<BBinder>::make();
Linnan Li13bf76a2024-05-05 19:18:02 +0800331 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
Chavi Weingarten847e8512023-03-29 00:26:09 +0000332 ASSERT_FALSE(changes);
333}
334
335TEST(FocusResolverTest, FocusTransferMultipleInChain) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700336 sp<IBinder> hostWindowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -0500337 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair1dcad982021-02-24 14:38:25 -0800338
339 sp<FakeWindowHandle> hostWindow =
Harry Cutts33476232023-01-30 19:57:29 +0000340 sp<FakeWindowHandle>::make("Host Window", hostWindowToken, /*focusable=*/true,
341 /*visible=*/true);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800342 windows.push_back(hostWindow);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700343 sp<IBinder> embeddedWindowToken = sp<BBinder>::make();
Vishnu Nair1dcad982021-02-24 14:38:25 -0800344 sp<FakeWindowHandle> embeddedWindow =
Harry Cutts33476232023-01-30 19:57:29 +0000345 sp<FakeWindowHandle>::make("Embedded Window", embeddedWindowToken, /*focusable=*/true,
346 /*visible=*/true);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800347 windows.push_back(embeddedWindow);
348
Chavi Weingarten847e8512023-03-29 00:26:09 +0000349 sp<IBinder> embeddedWindowToken2 = sp<BBinder>::make();
350 sp<FakeWindowHandle> embeddedWindow2 =
351 sp<FakeWindowHandle>::make("Embedded Window2", embeddedWindowToken2, /*focusable=*/true,
352 /*visible=*/true);
353 windows.push_back(embeddedWindow2);
354
Vishnu Nair1dcad982021-02-24 14:38:25 -0800355 FocusRequest request;
356 request.displayId = 42;
357 request.token = hostWindowToken;
Chavi Weingarten847e8512023-03-29 00:26:09 +0000358
359 hostWindow->editInfo()->focusTransferTarget = embeddedWindowToken;
360 embeddedWindow->editInfo()->focusTransferTarget = embeddedWindowToken2;
361
Vishnu Nair1dcad982021-02-24 14:38:25 -0800362 FocusResolver focusResolver;
363 std::optional<FocusResolver::FocusChanges> changes =
364 focusResolver.setFocusedWindow(request, windows);
Chavi Weingarten847e8512023-03-29 00:26:09 +0000365 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ embeddedWindowToken2);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800366}
Chavi Weingarten847e8512023-03-29 00:26:09 +0000367
368TEST(FocusResolverTest, FocusTransferTargetCycle) {
369 sp<IBinder> hostWindowToken = sp<BBinder>::make();
370 std::vector<sp<WindowInfoHandle>> windows;
371
372 sp<FakeWindowHandle> hostWindow =
373 sp<FakeWindowHandle>::make("Host Window", hostWindowToken, /*focusable=*/true,
374 /*visible=*/true);
375 windows.push_back(hostWindow);
376 sp<IBinder> embeddedWindowToken = sp<BBinder>::make();
377 sp<FakeWindowHandle> embeddedWindow =
378 sp<FakeWindowHandle>::make("Embedded Window", embeddedWindowToken, /*focusable=*/true,
379 /*visible=*/true);
380 windows.push_back(embeddedWindow);
381
382 sp<IBinder> embeddedWindowToken2 = sp<BBinder>::make();
383 sp<FakeWindowHandle> embeddedWindow2 =
384 sp<FakeWindowHandle>::make("Embedded Window2", embeddedWindowToken2, /*focusable=*/true,
385 /*visible=*/true);
386 windows.push_back(embeddedWindow2);
387
388 FocusRequest request;
389 request.displayId = 42;
390 request.token = hostWindowToken;
391
392 hostWindow->editInfo()->focusTransferTarget = embeddedWindowToken;
393 embeddedWindow->editInfo()->focusTransferTarget = embeddedWindowToken2;
394 embeddedWindow2->editInfo()->focusTransferTarget = hostWindowToken;
395
396 FocusResolver focusResolver;
397 std::optional<FocusResolver::FocusChanges> changes =
398 focusResolver.setFocusedWindow(request, windows);
399 // Cycle will be detected and stop right before trying to transfer token to host again.
400 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ embeddedWindowToken2);
401}
402
Vishnu Nair599f1412021-06-21 10:39:58 -0700403TEST(FocusResolverTest, FocusRequestsAreClearedWhenWindowIsRemoved) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700404 sp<IBinder> windowToken = sp<BBinder>::make();
chaviw3277faf2021-05-19 16:45:23 -0500405 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair599f1412021-06-21 10:39:58 -0700406
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700407 sp<FakeWindowHandle> window =
Harry Cutts33476232023-01-30 19:57:29 +0000408 sp<FakeWindowHandle>::make("Test Window", windowToken, /*focusable=*/true,
409 /*visible=*/true);
Vishnu Nair599f1412021-06-21 10:39:58 -0700410 windows.push_back(window);
411
412 FocusRequest request;
413 request.displayId = 42;
414 request.token = windowToken;
415 FocusResolver focusResolver;
416 std::optional<FocusResolver::FocusChanges> changes =
417 focusResolver.setFocusedWindow(request, windows);
418 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
Linnan Li13bf76a2024-05-05 19:18:02 +0800419 ASSERT_EQ(ui::LogicalDisplayId{request.displayId}, changes->displayId);
Vishnu Nair599f1412021-06-21 10:39:58 -0700420
Vishnu Nair599f1412021-06-21 10:39:58 -0700421 // When a display is removed, all windows are removed from the display
422 // and our focused window loses focus
Linnan Li13bf76a2024-05-05 19:18:02 +0800423 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, {});
Vishnu Nair599f1412021-06-21 10:39:58 -0700424 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
Linnan Li13bf76a2024-05-05 19:18:02 +0800425 focusResolver.displayRemoved(ui::LogicalDisplayId{request.displayId});
Vishnu Nair599f1412021-06-21 10:39:58 -0700426
Prabir Pradhan3fea36d2024-03-06 21:20:04 +0000427 // When a display is re-added, the window does not get focus since the request was cleared.
Linnan Li13bf76a2024-05-05 19:18:02 +0800428 changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
Vishnu Nair599f1412021-06-21 10:39:58 -0700429 ASSERT_FALSE(changes);
430}
Vishnu Nairc519ff72021-01-21 08:23:08 -0800431
432} // namespace android::inputdispatcher