blob: 8c0edcae85d877bd2548d7087b0de66f5c3c519e [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;
40 mInfo.visible = visible;
41 mInfo.focusable = focusable;
42 }
43
44 bool updateInfo() { return true; }
45 void setFocusable(bool focusable) { mInfo.focusable = focusable; }
46 void setVisible(bool visible) { mInfo.visible = visible; }
47};
48
49TEST(FocusResolverTest, SetFocusedWindow) {
50 sp<IBinder> focusableWindowToken = new BBinder();
51 sp<IBinder> invisibleWindowToken = new BBinder();
52 sp<IBinder> unfocusableWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -050053 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nairc519ff72021-01-21 08:23:08 -080054 windows.push_back(new FakeWindowHandle("Focusable", focusableWindowToken, true /* focusable */,
55 true /* visible */));
56 windows.push_back(new FakeWindowHandle("Invisible", invisibleWindowToken, true /* focusable */,
57 false /* visible */));
58 windows.push_back(new FakeWindowHandle("unfocusable", unfocusableWindowToken,
59 false /* focusable */, true /* visible */));
60
61 // focusable window can get focused
62 FocusRequest request;
63 request.displayId = 42;
64 request.token = focusableWindowToken;
65 FocusResolver focusResolver;
66 std::optional<FocusResolver::FocusChanges> changes =
67 focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -080068 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ focusableWindowToken);
Vishnu Nairc519ff72021-01-21 08:23:08 -080069 ASSERT_EQ(request.displayId, changes->displayId);
70
71 // invisible window cannot get focused
72 request.token = invisibleWindowToken;
73 changes = focusResolver.setFocusedWindow(request, windows);
74 ASSERT_EQ(focusableWindowToken, changes->oldFocus);
75 ASSERT_EQ(nullptr, changes->newFocus);
Vishnu Nair1dcad982021-02-24 14:38:25 -080076 ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ nullptr);
Vishnu Nairc519ff72021-01-21 08:23:08 -080077
78 // unfocusableWindowToken window cannot get focused
79 request.token = unfocusableWindowToken;
80 changes = focusResolver.setFocusedWindow(request, windows);
81 ASSERT_FALSE(changes);
82}
83
84TEST(FocusResolverTest, SetFocusedMirroredWindow) {
85 sp<IBinder> focusableWindowToken = new BBinder();
86 sp<IBinder> invisibleWindowToken = new BBinder();
87 sp<IBinder> unfocusableWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -050088 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nairc519ff72021-01-21 08:23:08 -080089 windows.push_back(new FakeWindowHandle("Mirror1", focusableWindowToken, true /* focusable */,
90 true /* visible */));
91 windows.push_back(new FakeWindowHandle("Mirror1", focusableWindowToken, true /* focusable */,
92 true /* visible */));
93
94 windows.push_back(new FakeWindowHandle("Mirror2Visible", invisibleWindowToken,
95 true /* focusable */, true /* visible */));
96 windows.push_back(new FakeWindowHandle("Mirror2Invisible", invisibleWindowToken,
97 true /* focusable */, false /* visible */));
98
99 windows.push_back(new FakeWindowHandle("Mirror3Focusable", unfocusableWindowToken,
100 true /* focusable */, true /* visible */));
101 windows.push_back(new FakeWindowHandle("Mirror3Unfocusable", unfocusableWindowToken,
102 false /* focusable */, true /* visible */));
103
104 // mirrored window can get focused
105 FocusRequest request;
106 request.displayId = 42;
107 request.token = focusableWindowToken;
108 FocusResolver focusResolver;
109 std::optional<FocusResolver::FocusChanges> changes =
110 focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800111 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ focusableWindowToken);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800112
113 // mirrored window with one visible window can get focused
114 request.token = invisibleWindowToken;
115 changes = focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800116 ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ invisibleWindowToken);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800117
118 // mirrored window with one or more unfocusable window cannot get focused
119 request.token = unfocusableWindowToken;
120 changes = focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800121 ASSERT_FOCUS_CHANGE(changes, /*from*/ invisibleWindowToken, /*to*/ nullptr);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800122}
123
124TEST(FocusResolverTest, SetInputWindows) {
125 sp<IBinder> focusableWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500126 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nairc519ff72021-01-21 08:23:08 -0800127 sp<FakeWindowHandle> window = new FakeWindowHandle("Focusable", focusableWindowToken,
128 true /* focusable */, true /* visible */);
129 windows.push_back(window);
130
131 // focusable 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);
138 ASSERT_EQ(focusableWindowToken, changes->newFocus);
139
Vishnu Nair1dcad982021-02-24 14:38:25 -0800140 // Window visibility changes and the window loses focus
Vishnu Nairc519ff72021-01-21 08:23:08 -0800141 window->setVisible(false);
142 changes = focusResolver.setInputWindows(request.displayId, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800143 ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ nullptr);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800144}
145
146TEST(FocusResolverTest, FocusRequestsCanBePending) {
147 sp<IBinder> invisibleWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500148 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nairc519ff72021-01-21 08:23:08 -0800149
150 sp<FakeWindowHandle> invisibleWindow =
151 new FakeWindowHandle("Invisible", invisibleWindowToken, true /* focusable */,
152 false /* visible */);
153 windows.push_back(invisibleWindow);
154
155 // invisible window cannot get focused
156 FocusRequest request;
157 request.displayId = 42;
158 request.token = invisibleWindowToken;
159 FocusResolver focusResolver;
160 std::optional<FocusResolver::FocusChanges> changes =
161 focusResolver.setFocusedWindow(request, windows);
162 ASSERT_FALSE(changes);
163
164 // Window visibility changes and the window gets focused
165 invisibleWindow->setVisible(true);
166 changes = focusResolver.setInputWindows(request.displayId, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800167 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ invisibleWindowToken);
168}
169
170TEST(FocusResolverTest, FocusRequestsArePersistent) {
171 sp<IBinder> windowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500172 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair1dcad982021-02-24 14:38:25 -0800173
174 sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken,
175 false /* focusable */, true /* visible */);
176 windows.push_back(window);
177
178 // non-focusable window cannot get focused
179 FocusRequest request;
180 request.displayId = 42;
181 request.token = windowToken;
182 FocusResolver focusResolver;
183 std::optional<FocusResolver::FocusChanges> changes =
184 focusResolver.setFocusedWindow(request, windows);
185 ASSERT_FALSE(changes);
186
187 // Focusability changes and the window gets focused
188 window->setFocusable(true);
189 changes = focusResolver.setInputWindows(request.displayId, windows);
190 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
191
192 // Visibility changes and the window loses focus
193 window->setVisible(false);
194 changes = focusResolver.setInputWindows(request.displayId, windows);
195 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
196
197 // Visibility changes and the window gets focused
198 window->setVisible(true);
199 changes = focusResolver.setInputWindows(request.displayId, windows);
200 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
201
202 // Window is gone and the window loses focus
203 changes = focusResolver.setInputWindows(request.displayId, {});
204 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
205
206 // Window returns and the window gains focus
207 changes = focusResolver.setInputWindows(request.displayId, windows);
208 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
209}
210
211TEST(FocusResolverTest, ConditionalFocusRequestsAreNotPersistent) {
212 sp<IBinder> hostWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500213 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair1dcad982021-02-24 14:38:25 -0800214
215 sp<FakeWindowHandle> hostWindow =
216 new FakeWindowHandle("Host Window", hostWindowToken, true /* focusable */,
217 true /* visible */);
218 windows.push_back(hostWindow);
219 sp<IBinder> embeddedWindowToken = new BBinder();
220 sp<FakeWindowHandle> embeddedWindow =
221 new FakeWindowHandle("Embedded Window", embeddedWindowToken, true /* focusable */,
222 true /* visible */);
223 windows.push_back(embeddedWindow);
224
225 FocusRequest request;
226 request.displayId = 42;
227 request.token = hostWindowToken;
228 FocusResolver focusResolver;
229 std::optional<FocusResolver::FocusChanges> changes =
230 focusResolver.setFocusedWindow(request, windows);
231 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ hostWindowToken);
232
233 request.focusedToken = hostWindow->getToken();
234 request.token = embeddedWindowToken;
235 changes = focusResolver.setFocusedWindow(request, windows);
236 ASSERT_FOCUS_CHANGE(changes, /*from*/ hostWindowToken, /*to*/ embeddedWindowToken);
237
238 embeddedWindow->setFocusable(false);
239 changes = focusResolver.setInputWindows(request.displayId, windows);
240 // The embedded window is no longer focusable, provide focus back to the original focused
241 // window.
242 ASSERT_FOCUS_CHANGE(changes, /*from*/ embeddedWindowToken, /*to*/ hostWindowToken);
243
244 embeddedWindow->setFocusable(true);
245 changes = focusResolver.setInputWindows(request.displayId, windows);
246 // The embedded window is focusable again, but we it cannot gain focus unless there is another
247 // focus request.
248 ASSERT_FALSE(changes);
249
250 embeddedWindow->setVisible(false);
251 changes = focusResolver.setFocusedWindow(request, windows);
252 // If the embedded window is not visible/focusable, then we do not grant it focus and the
253 // request is dropped.
254 ASSERT_FALSE(changes);
255
256 embeddedWindow->setVisible(true);
257 changes = focusResolver.setInputWindows(request.displayId, windows);
258 // If the embedded window becomes visble/focusable, nothing changes since the request has been
259 // dropped.
260 ASSERT_FALSE(changes);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800261}
Vishnu Nair599f1412021-06-21 10:39:58 -0700262TEST(FocusResolverTest, FocusRequestsAreClearedWhenWindowIsRemoved) {
263 sp<IBinder> windowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500264 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair599f1412021-06-21 10:39:58 -0700265
266 sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken,
267 true /* focusable */, true /* visible */);
268 windows.push_back(window);
269
270 FocusRequest request;
271 request.displayId = 42;
272 request.token = windowToken;
273 FocusResolver focusResolver;
274 std::optional<FocusResolver::FocusChanges> changes =
275 focusResolver.setFocusedWindow(request, windows);
276 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
277 ASSERT_EQ(request.displayId, changes->displayId);
278
279 // Start with a focused window
280 window->setFocusable(true);
281 changes = focusResolver.setInputWindows(request.displayId, windows);
282 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
283
284 // When a display is removed, all windows are removed from the display
285 // and our focused window loses focus
286 changes = focusResolver.setInputWindows(request.displayId, {});
287 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
288 focusResolver.displayRemoved(request.displayId);
289
290 // When a display is readded, the window does not get focus since the request was cleared.
291 changes = focusResolver.setInputWindows(request.displayId, windows);
292 ASSERT_FALSE(changes);
293}
Vishnu Nairc519ff72021-01-21 08:23:08 -0800294
295} // namespace android::inputdispatcher