blob: 662be8063ececb055881e2644a098361798717f1 [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
Vishnu Nairc519ff72021-01-21 08:23:08 -080044 void setFocusable(bool focusable) { mInfo.focusable = focusable; }
45 void setVisible(bool visible) { mInfo.visible = visible; }
46};
47
48TEST(FocusResolverTest, SetFocusedWindow) {
49 sp<IBinder> focusableWindowToken = new BBinder();
50 sp<IBinder> invisibleWindowToken = new BBinder();
51 sp<IBinder> unfocusableWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -050052 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nairc519ff72021-01-21 08:23:08 -080053 windows.push_back(new FakeWindowHandle("Focusable", focusableWindowToken, true /* focusable */,
54 true /* visible */));
55 windows.push_back(new FakeWindowHandle("Invisible", invisibleWindowToken, true /* focusable */,
56 false /* visible */));
57 windows.push_back(new FakeWindowHandle("unfocusable", unfocusableWindowToken,
58 false /* focusable */, true /* visible */));
59
60 // focusable window can get focused
61 FocusRequest request;
62 request.displayId = 42;
63 request.token = focusableWindowToken;
64 FocusResolver focusResolver;
65 std::optional<FocusResolver::FocusChanges> changes =
66 focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -080067 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ focusableWindowToken);
Vishnu Nairc519ff72021-01-21 08:23:08 -080068 ASSERT_EQ(request.displayId, changes->displayId);
69
70 // invisible window cannot get focused
71 request.token = invisibleWindowToken;
72 changes = focusResolver.setFocusedWindow(request, windows);
73 ASSERT_EQ(focusableWindowToken, changes->oldFocus);
74 ASSERT_EQ(nullptr, changes->newFocus);
Vishnu Nair1dcad982021-02-24 14:38:25 -080075 ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ nullptr);
Vishnu Nairc519ff72021-01-21 08:23:08 -080076
77 // unfocusableWindowToken window cannot get focused
78 request.token = unfocusableWindowToken;
79 changes = focusResolver.setFocusedWindow(request, windows);
80 ASSERT_FALSE(changes);
81}
82
83TEST(FocusResolverTest, SetFocusedMirroredWindow) {
84 sp<IBinder> focusableWindowToken = new BBinder();
85 sp<IBinder> invisibleWindowToken = new BBinder();
86 sp<IBinder> unfocusableWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -050087 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nairc519ff72021-01-21 08:23:08 -080088 windows.push_back(new FakeWindowHandle("Mirror1", focusableWindowToken, true /* focusable */,
89 true /* visible */));
90 windows.push_back(new FakeWindowHandle("Mirror1", focusableWindowToken, true /* focusable */,
91 true /* visible */));
92
93 windows.push_back(new FakeWindowHandle("Mirror2Visible", invisibleWindowToken,
94 true /* focusable */, true /* visible */));
95 windows.push_back(new FakeWindowHandle("Mirror2Invisible", invisibleWindowToken,
96 true /* focusable */, false /* visible */));
97
98 windows.push_back(new FakeWindowHandle("Mirror3Focusable", unfocusableWindowToken,
99 true /* focusable */, true /* visible */));
100 windows.push_back(new FakeWindowHandle("Mirror3Unfocusable", unfocusableWindowToken,
101 false /* focusable */, true /* visible */));
102
103 // mirrored window can get focused
104 FocusRequest request;
105 request.displayId = 42;
106 request.token = focusableWindowToken;
107 FocusResolver focusResolver;
108 std::optional<FocusResolver::FocusChanges> changes =
109 focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800110 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ focusableWindowToken);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800111
112 // mirrored window with one visible window can get focused
113 request.token = invisibleWindowToken;
114 changes = focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800115 ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ invisibleWindowToken);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800116
117 // mirrored window with one or more unfocusable window cannot get focused
118 request.token = unfocusableWindowToken;
119 changes = focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800120 ASSERT_FOCUS_CHANGE(changes, /*from*/ invisibleWindowToken, /*to*/ nullptr);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800121}
122
123TEST(FocusResolverTest, SetInputWindows) {
124 sp<IBinder> focusableWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500125 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nairc519ff72021-01-21 08:23:08 -0800126 sp<FakeWindowHandle> window = new FakeWindowHandle("Focusable", focusableWindowToken,
127 true /* focusable */, true /* visible */);
128 windows.push_back(window);
129
130 // focusable window can get focused
131 FocusRequest request;
132 request.displayId = 42;
133 request.token = focusableWindowToken;
134 FocusResolver focusResolver;
135 std::optional<FocusResolver::FocusChanges> changes =
136 focusResolver.setFocusedWindow(request, windows);
137 ASSERT_EQ(focusableWindowToken, changes->newFocus);
138
Vishnu Nair1dcad982021-02-24 14:38:25 -0800139 // Window visibility changes and the window loses focus
Vishnu Nairc519ff72021-01-21 08:23:08 -0800140 window->setVisible(false);
141 changes = focusResolver.setInputWindows(request.displayId, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800142 ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ nullptr);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800143}
144
145TEST(FocusResolverTest, FocusRequestsCanBePending) {
146 sp<IBinder> invisibleWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500147 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nairc519ff72021-01-21 08:23:08 -0800148
149 sp<FakeWindowHandle> invisibleWindow =
150 new FakeWindowHandle("Invisible", invisibleWindowToken, true /* focusable */,
151 false /* visible */);
152 windows.push_back(invisibleWindow);
153
154 // invisible window cannot get focused
155 FocusRequest request;
156 request.displayId = 42;
157 request.token = invisibleWindowToken;
158 FocusResolver focusResolver;
159 std::optional<FocusResolver::FocusChanges> changes =
160 focusResolver.setFocusedWindow(request, windows);
161 ASSERT_FALSE(changes);
162
163 // Window visibility changes and the window gets focused
164 invisibleWindow->setVisible(true);
165 changes = focusResolver.setInputWindows(request.displayId, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800166 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ invisibleWindowToken);
167}
168
169TEST(FocusResolverTest, FocusRequestsArePersistent) {
170 sp<IBinder> windowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500171 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair1dcad982021-02-24 14:38:25 -0800172
173 sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken,
174 false /* focusable */, true /* visible */);
175 windows.push_back(window);
176
177 // non-focusable window cannot get focused
178 FocusRequest request;
179 request.displayId = 42;
180 request.token = windowToken;
181 FocusResolver focusResolver;
182 std::optional<FocusResolver::FocusChanges> changes =
183 focusResolver.setFocusedWindow(request, windows);
184 ASSERT_FALSE(changes);
185
186 // Focusability changes and the window gets focused
187 window->setFocusable(true);
188 changes = focusResolver.setInputWindows(request.displayId, windows);
189 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
190
191 // Visibility changes and the window loses focus
192 window->setVisible(false);
193 changes = focusResolver.setInputWindows(request.displayId, windows);
194 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
195
196 // Visibility changes and the window gets focused
197 window->setVisible(true);
198 changes = focusResolver.setInputWindows(request.displayId, windows);
199 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
200
201 // Window is gone and the window loses focus
202 changes = focusResolver.setInputWindows(request.displayId, {});
203 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
204
205 // Window returns and the window gains focus
206 changes = focusResolver.setInputWindows(request.displayId, windows);
207 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
208}
209
210TEST(FocusResolverTest, ConditionalFocusRequestsAreNotPersistent) {
211 sp<IBinder> hostWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500212 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair1dcad982021-02-24 14:38:25 -0800213
214 sp<FakeWindowHandle> hostWindow =
215 new FakeWindowHandle("Host Window", hostWindowToken, true /* focusable */,
216 true /* visible */);
217 windows.push_back(hostWindow);
218 sp<IBinder> embeddedWindowToken = new BBinder();
219 sp<FakeWindowHandle> embeddedWindow =
220 new FakeWindowHandle("Embedded Window", embeddedWindowToken, true /* focusable */,
221 true /* visible */);
222 windows.push_back(embeddedWindow);
223
224 FocusRequest request;
225 request.displayId = 42;
226 request.token = hostWindowToken;
227 FocusResolver focusResolver;
228 std::optional<FocusResolver::FocusChanges> changes =
229 focusResolver.setFocusedWindow(request, windows);
230 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ hostWindowToken);
231
232 request.focusedToken = hostWindow->getToken();
233 request.token = embeddedWindowToken;
234 changes = focusResolver.setFocusedWindow(request, windows);
235 ASSERT_FOCUS_CHANGE(changes, /*from*/ hostWindowToken, /*to*/ embeddedWindowToken);
236
237 embeddedWindow->setFocusable(false);
238 changes = focusResolver.setInputWindows(request.displayId, windows);
239 // The embedded window is no longer focusable, provide focus back to the original focused
240 // window.
241 ASSERT_FOCUS_CHANGE(changes, /*from*/ embeddedWindowToken, /*to*/ hostWindowToken);
242
243 embeddedWindow->setFocusable(true);
244 changes = focusResolver.setInputWindows(request.displayId, windows);
245 // The embedded window is focusable again, but we it cannot gain focus unless there is another
246 // focus request.
247 ASSERT_FALSE(changes);
248
249 embeddedWindow->setVisible(false);
250 changes = focusResolver.setFocusedWindow(request, windows);
251 // If the embedded window is not visible/focusable, then we do not grant it focus and the
252 // request is dropped.
253 ASSERT_FALSE(changes);
254
255 embeddedWindow->setVisible(true);
256 changes = focusResolver.setInputWindows(request.displayId, windows);
257 // If the embedded window becomes visble/focusable, nothing changes since the request has been
258 // dropped.
259 ASSERT_FALSE(changes);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800260}
Vishnu Nair599f1412021-06-21 10:39:58 -0700261TEST(FocusResolverTest, FocusRequestsAreClearedWhenWindowIsRemoved) {
262 sp<IBinder> windowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500263 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair599f1412021-06-21 10:39:58 -0700264
265 sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken,
266 true /* focusable */, true /* visible */);
267 windows.push_back(window);
268
269 FocusRequest request;
270 request.displayId = 42;
271 request.token = windowToken;
272 FocusResolver focusResolver;
273 std::optional<FocusResolver::FocusChanges> changes =
274 focusResolver.setFocusedWindow(request, windows);
275 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
276 ASSERT_EQ(request.displayId, changes->displayId);
277
278 // Start with a focused window
279 window->setFocusable(true);
280 changes = focusResolver.setInputWindows(request.displayId, windows);
281 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
282
283 // When a display is removed, all windows are removed from the display
284 // and our focused window loses focus
285 changes = focusResolver.setInputWindows(request.displayId, {});
286 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
287 focusResolver.displayRemoved(request.displayId);
288
289 // When a display is readded, the window does not get focus since the request was cleared.
290 changes = focusResolver.setInputWindows(request.displayId, windows);
291 ASSERT_FALSE(changes);
292}
Vishnu Nairc519ff72021-01-21 08:23:08 -0800293
294} // namespace android::inputdispatcher