blob: 91be4a30bf9c47ec298d6d1fd77361a68f953dc8 [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) {
53 sp<IBinder> focusableWindowToken = new BBinder();
54 sp<IBinder> invisibleWindowToken = new BBinder();
55 sp<IBinder> unfocusableWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -050056 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nairc519ff72021-01-21 08:23:08 -080057 windows.push_back(new FakeWindowHandle("Focusable", focusableWindowToken, true /* focusable */,
58 true /* visible */));
59 windows.push_back(new FakeWindowHandle("Invisible", invisibleWindowToken, true /* focusable */,
60 false /* visible */));
61 windows.push_back(new FakeWindowHandle("unfocusable", unfocusableWindowToken,
62 false /* focusable */, true /* visible */));
63
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) {
88 sp<IBinder> focusableWindowToken = new BBinder();
89 std::vector<sp<WindowInfoHandle>> windows;
90 windows.push_back(new FakeWindowHandle("Focusable", focusableWindowToken, true /* focusable */,
91 true /* visible */));
92
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) {
112 sp<IBinder> focusableWindowToken = new BBinder();
113 sp<IBinder> invisibleWindowToken = new BBinder();
114 sp<IBinder> unfocusableWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500115 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nairc519ff72021-01-21 08:23:08 -0800116 windows.push_back(new FakeWindowHandle("Mirror1", focusableWindowToken, true /* focusable */,
117 true /* visible */));
118 windows.push_back(new FakeWindowHandle("Mirror1", focusableWindowToken, true /* focusable */,
119 true /* visible */));
120
121 windows.push_back(new FakeWindowHandle("Mirror2Visible", invisibleWindowToken,
122 true /* focusable */, true /* visible */));
123 windows.push_back(new FakeWindowHandle("Mirror2Invisible", invisibleWindowToken,
124 true /* focusable */, false /* visible */));
125
126 windows.push_back(new FakeWindowHandle("Mirror3Focusable", unfocusableWindowToken,
127 true /* focusable */, true /* visible */));
128 windows.push_back(new FakeWindowHandle("Mirror3Unfocusable", unfocusableWindowToken,
129 false /* focusable */, true /* visible */));
130
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) {
152 sp<IBinder> focusableWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500153 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nairc519ff72021-01-21 08:23:08 -0800154 sp<FakeWindowHandle> window = new FakeWindowHandle("Focusable", focusableWindowToken,
155 true /* focusable */, true /* visible */);
156 windows.push_back(window);
157
158 // focusable window can get focused
159 FocusRequest request;
160 request.displayId = 42;
161 request.token = focusableWindowToken;
162 FocusResolver focusResolver;
163 std::optional<FocusResolver::FocusChanges> changes =
164 focusResolver.setFocusedWindow(request, windows);
165 ASSERT_EQ(focusableWindowToken, changes->newFocus);
166
Vishnu Nair1dcad982021-02-24 14:38:25 -0800167 // Window visibility changes and the window loses focus
Vishnu Nairc519ff72021-01-21 08:23:08 -0800168 window->setVisible(false);
169 changes = focusResolver.setInputWindows(request.displayId, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800170 ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ nullptr);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800171}
172
173TEST(FocusResolverTest, FocusRequestsCanBePending) {
174 sp<IBinder> invisibleWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500175 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nairc519ff72021-01-21 08:23:08 -0800176
177 sp<FakeWindowHandle> invisibleWindow =
178 new FakeWindowHandle("Invisible", invisibleWindowToken, true /* focusable */,
179 false /* visible */);
180 windows.push_back(invisibleWindow);
181
182 // invisible window cannot get focused
183 FocusRequest request;
184 request.displayId = 42;
185 request.token = invisibleWindowToken;
186 FocusResolver focusResolver;
187 std::optional<FocusResolver::FocusChanges> changes =
188 focusResolver.setFocusedWindow(request, windows);
189 ASSERT_FALSE(changes);
190
191 // Window visibility changes and the window gets focused
192 invisibleWindow->setVisible(true);
193 changes = focusResolver.setInputWindows(request.displayId, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800194 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ invisibleWindowToken);
195}
196
197TEST(FocusResolverTest, FocusRequestsArePersistent) {
198 sp<IBinder> windowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500199 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair1dcad982021-02-24 14:38:25 -0800200
201 sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken,
202 false /* focusable */, true /* visible */);
203 windows.push_back(window);
204
205 // non-focusable window cannot get focused
206 FocusRequest request;
207 request.displayId = 42;
208 request.token = windowToken;
209 FocusResolver focusResolver;
210 std::optional<FocusResolver::FocusChanges> changes =
211 focusResolver.setFocusedWindow(request, windows);
212 ASSERT_FALSE(changes);
213
214 // Focusability changes and the window gets focused
215 window->setFocusable(true);
216 changes = focusResolver.setInputWindows(request.displayId, windows);
217 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
218
219 // Visibility changes and the window loses focus
220 window->setVisible(false);
221 changes = focusResolver.setInputWindows(request.displayId, windows);
222 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
223
224 // Visibility changes and the window gets focused
225 window->setVisible(true);
226 changes = focusResolver.setInputWindows(request.displayId, windows);
227 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
228
229 // Window is gone and the window loses focus
230 changes = focusResolver.setInputWindows(request.displayId, {});
231 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
232
233 // Window returns and the window gains focus
234 changes = focusResolver.setInputWindows(request.displayId, windows);
235 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
236}
237
238TEST(FocusResolverTest, ConditionalFocusRequestsAreNotPersistent) {
239 sp<IBinder> hostWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500240 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair1dcad982021-02-24 14:38:25 -0800241
242 sp<FakeWindowHandle> hostWindow =
243 new FakeWindowHandle("Host Window", hostWindowToken, true /* focusable */,
244 true /* visible */);
245 windows.push_back(hostWindow);
246 sp<IBinder> embeddedWindowToken = new BBinder();
247 sp<FakeWindowHandle> embeddedWindow =
248 new FakeWindowHandle("Embedded Window", embeddedWindowToken, true /* focusable */,
249 true /* visible */);
250 windows.push_back(embeddedWindow);
251
252 FocusRequest request;
253 request.displayId = 42;
254 request.token = hostWindowToken;
255 FocusResolver focusResolver;
256 std::optional<FocusResolver::FocusChanges> changes =
257 focusResolver.setFocusedWindow(request, windows);
258 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ hostWindowToken);
259
260 request.focusedToken = hostWindow->getToken();
261 request.token = embeddedWindowToken;
262 changes = focusResolver.setFocusedWindow(request, windows);
263 ASSERT_FOCUS_CHANGE(changes, /*from*/ hostWindowToken, /*to*/ embeddedWindowToken);
264
265 embeddedWindow->setFocusable(false);
266 changes = focusResolver.setInputWindows(request.displayId, windows);
267 // The embedded window is no longer focusable, provide focus back to the original focused
268 // window.
269 ASSERT_FOCUS_CHANGE(changes, /*from*/ embeddedWindowToken, /*to*/ hostWindowToken);
270
271 embeddedWindow->setFocusable(true);
272 changes = focusResolver.setInputWindows(request.displayId, windows);
273 // The embedded window is focusable again, but we it cannot gain focus unless there is another
274 // focus request.
275 ASSERT_FALSE(changes);
276
277 embeddedWindow->setVisible(false);
278 changes = focusResolver.setFocusedWindow(request, windows);
279 // If the embedded window is not visible/focusable, then we do not grant it focus and the
280 // request is dropped.
281 ASSERT_FALSE(changes);
282
283 embeddedWindow->setVisible(true);
284 changes = focusResolver.setInputWindows(request.displayId, windows);
285 // If the embedded window becomes visble/focusable, nothing changes since the request has been
286 // dropped.
287 ASSERT_FALSE(changes);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800288}
Vishnu Nair599f1412021-06-21 10:39:58 -0700289TEST(FocusResolverTest, FocusRequestsAreClearedWhenWindowIsRemoved) {
290 sp<IBinder> windowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500291 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair599f1412021-06-21 10:39:58 -0700292
293 sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken,
294 true /* focusable */, true /* visible */);
295 windows.push_back(window);
296
297 FocusRequest request;
298 request.displayId = 42;
299 request.token = windowToken;
300 FocusResolver focusResolver;
301 std::optional<FocusResolver::FocusChanges> changes =
302 focusResolver.setFocusedWindow(request, windows);
303 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
304 ASSERT_EQ(request.displayId, changes->displayId);
305
306 // Start with a focused window
307 window->setFocusable(true);
308 changes = focusResolver.setInputWindows(request.displayId, windows);
309 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
310
311 // When a display is removed, all windows are removed from the display
312 // and our focused window loses focus
313 changes = focusResolver.setInputWindows(request.displayId, {});
314 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
315 focusResolver.displayRemoved(request.displayId);
316
317 // When a display is readded, the window does not get focus since the request was cleared.
318 changes = focusResolver.setInputWindows(request.displayId, windows);
319 ASSERT_FALSE(changes);
320}
Vishnu Nairc519ff72021-01-21 08:23:08 -0800321
322} // namespace android::inputdispatcher