blob: ffce9f68cc99911f9a02b763cb75e36e5ff28700 [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
87TEST(FocusResolverTest, SetFocusedMirroredWindow) {
88 sp<IBinder> focusableWindowToken = new BBinder();
89 sp<IBinder> invisibleWindowToken = new BBinder();
90 sp<IBinder> unfocusableWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -050091 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nairc519ff72021-01-21 08:23:08 -080092 windows.push_back(new FakeWindowHandle("Mirror1", focusableWindowToken, true /* focusable */,
93 true /* visible */));
94 windows.push_back(new FakeWindowHandle("Mirror1", focusableWindowToken, true /* focusable */,
95 true /* visible */));
96
97 windows.push_back(new FakeWindowHandle("Mirror2Visible", invisibleWindowToken,
98 true /* focusable */, true /* visible */));
99 windows.push_back(new FakeWindowHandle("Mirror2Invisible", invisibleWindowToken,
100 true /* focusable */, false /* visible */));
101
102 windows.push_back(new FakeWindowHandle("Mirror3Focusable", unfocusableWindowToken,
103 true /* focusable */, true /* visible */));
104 windows.push_back(new FakeWindowHandle("Mirror3Unfocusable", unfocusableWindowToken,
105 false /* focusable */, true /* visible */));
106
107 // mirrored window can get focused
108 FocusRequest request;
109 request.displayId = 42;
110 request.token = focusableWindowToken;
111 FocusResolver focusResolver;
112 std::optional<FocusResolver::FocusChanges> changes =
113 focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800114 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ focusableWindowToken);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800115
116 // mirrored window with one visible window can get focused
117 request.token = invisibleWindowToken;
118 changes = focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800119 ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ invisibleWindowToken);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800120
121 // mirrored window with one or more unfocusable window cannot get focused
122 request.token = unfocusableWindowToken;
123 changes = focusResolver.setFocusedWindow(request, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800124 ASSERT_FOCUS_CHANGE(changes, /*from*/ invisibleWindowToken, /*to*/ nullptr);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800125}
126
127TEST(FocusResolverTest, SetInputWindows) {
128 sp<IBinder> focusableWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500129 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nairc519ff72021-01-21 08:23:08 -0800130 sp<FakeWindowHandle> window = new FakeWindowHandle("Focusable", focusableWindowToken,
131 true /* focusable */, true /* visible */);
132 windows.push_back(window);
133
134 // focusable window can get focused
135 FocusRequest request;
136 request.displayId = 42;
137 request.token = focusableWindowToken;
138 FocusResolver focusResolver;
139 std::optional<FocusResolver::FocusChanges> changes =
140 focusResolver.setFocusedWindow(request, windows);
141 ASSERT_EQ(focusableWindowToken, changes->newFocus);
142
Vishnu Nair1dcad982021-02-24 14:38:25 -0800143 // Window visibility changes and the window loses focus
Vishnu Nairc519ff72021-01-21 08:23:08 -0800144 window->setVisible(false);
145 changes = focusResolver.setInputWindows(request.displayId, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800146 ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ nullptr);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800147}
148
149TEST(FocusResolverTest, FocusRequestsCanBePending) {
150 sp<IBinder> invisibleWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500151 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nairc519ff72021-01-21 08:23:08 -0800152
153 sp<FakeWindowHandle> invisibleWindow =
154 new FakeWindowHandle("Invisible", invisibleWindowToken, true /* focusable */,
155 false /* visible */);
156 windows.push_back(invisibleWindow);
157
158 // invisible window cannot get focused
159 FocusRequest request;
160 request.displayId = 42;
161 request.token = invisibleWindowToken;
162 FocusResolver focusResolver;
163 std::optional<FocusResolver::FocusChanges> changes =
164 focusResolver.setFocusedWindow(request, windows);
165 ASSERT_FALSE(changes);
166
167 // Window visibility changes and the window gets focused
168 invisibleWindow->setVisible(true);
169 changes = focusResolver.setInputWindows(request.displayId, windows);
Vishnu Nair1dcad982021-02-24 14:38:25 -0800170 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ invisibleWindowToken);
171}
172
173TEST(FocusResolverTest, FocusRequestsArePersistent) {
174 sp<IBinder> windowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500175 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair1dcad982021-02-24 14:38:25 -0800176
177 sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken,
178 false /* focusable */, true /* visible */);
179 windows.push_back(window);
180
181 // non-focusable window cannot get focused
182 FocusRequest request;
183 request.displayId = 42;
184 request.token = windowToken;
185 FocusResolver focusResolver;
186 std::optional<FocusResolver::FocusChanges> changes =
187 focusResolver.setFocusedWindow(request, windows);
188 ASSERT_FALSE(changes);
189
190 // Focusability changes and the window gets focused
191 window->setFocusable(true);
192 changes = focusResolver.setInputWindows(request.displayId, windows);
193 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
194
195 // Visibility changes and the window loses focus
196 window->setVisible(false);
197 changes = focusResolver.setInputWindows(request.displayId, windows);
198 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
199
200 // Visibility changes and the window gets focused
201 window->setVisible(true);
202 changes = focusResolver.setInputWindows(request.displayId, windows);
203 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
204
205 // Window is gone and the window loses focus
206 changes = focusResolver.setInputWindows(request.displayId, {});
207 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
208
209 // Window returns and the window gains focus
210 changes = focusResolver.setInputWindows(request.displayId, windows);
211 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
212}
213
214TEST(FocusResolverTest, ConditionalFocusRequestsAreNotPersistent) {
215 sp<IBinder> hostWindowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500216 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair1dcad982021-02-24 14:38:25 -0800217
218 sp<FakeWindowHandle> hostWindow =
219 new FakeWindowHandle("Host Window", hostWindowToken, true /* focusable */,
220 true /* visible */);
221 windows.push_back(hostWindow);
222 sp<IBinder> embeddedWindowToken = new BBinder();
223 sp<FakeWindowHandle> embeddedWindow =
224 new FakeWindowHandle("Embedded Window", embeddedWindowToken, true /* focusable */,
225 true /* visible */);
226 windows.push_back(embeddedWindow);
227
228 FocusRequest request;
229 request.displayId = 42;
230 request.token = hostWindowToken;
231 FocusResolver focusResolver;
232 std::optional<FocusResolver::FocusChanges> changes =
233 focusResolver.setFocusedWindow(request, windows);
234 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ hostWindowToken);
235
236 request.focusedToken = hostWindow->getToken();
237 request.token = embeddedWindowToken;
238 changes = focusResolver.setFocusedWindow(request, windows);
239 ASSERT_FOCUS_CHANGE(changes, /*from*/ hostWindowToken, /*to*/ embeddedWindowToken);
240
241 embeddedWindow->setFocusable(false);
242 changes = focusResolver.setInputWindows(request.displayId, windows);
243 // The embedded window is no longer focusable, provide focus back to the original focused
244 // window.
245 ASSERT_FOCUS_CHANGE(changes, /*from*/ embeddedWindowToken, /*to*/ hostWindowToken);
246
247 embeddedWindow->setFocusable(true);
248 changes = focusResolver.setInputWindows(request.displayId, windows);
249 // The embedded window is focusable again, but we it cannot gain focus unless there is another
250 // focus request.
251 ASSERT_FALSE(changes);
252
253 embeddedWindow->setVisible(false);
254 changes = focusResolver.setFocusedWindow(request, windows);
255 // If the embedded window is not visible/focusable, then we do not grant it focus and the
256 // request is dropped.
257 ASSERT_FALSE(changes);
258
259 embeddedWindow->setVisible(true);
260 changes = focusResolver.setInputWindows(request.displayId, windows);
261 // If the embedded window becomes visble/focusable, nothing changes since the request has been
262 // dropped.
263 ASSERT_FALSE(changes);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800264}
Vishnu Nair599f1412021-06-21 10:39:58 -0700265TEST(FocusResolverTest, FocusRequestsAreClearedWhenWindowIsRemoved) {
266 sp<IBinder> windowToken = new BBinder();
chaviw3277faf2021-05-19 16:45:23 -0500267 std::vector<sp<WindowInfoHandle>> windows;
Vishnu Nair599f1412021-06-21 10:39:58 -0700268
269 sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken,
270 true /* focusable */, true /* visible */);
271 windows.push_back(window);
272
273 FocusRequest request;
274 request.displayId = 42;
275 request.token = windowToken;
276 FocusResolver focusResolver;
277 std::optional<FocusResolver::FocusChanges> changes =
278 focusResolver.setFocusedWindow(request, windows);
279 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
280 ASSERT_EQ(request.displayId, changes->displayId);
281
282 // Start with a focused window
283 window->setFocusable(true);
284 changes = focusResolver.setInputWindows(request.displayId, windows);
285 ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
286
287 // When a display is removed, all windows are removed from the display
288 // and our focused window loses focus
289 changes = focusResolver.setInputWindows(request.displayId, {});
290 ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
291 focusResolver.displayRemoved(request.displayId);
292
293 // When a display is readded, the window does not get focus since the request was cleared.
294 changes = focusResolver.setInputWindows(request.displayId, windows);
295 ASSERT_FALSE(changes);
296}
Vishnu Nairc519ff72021-01-21 08:23:08 -0800297
298} // namespace android::inputdispatcher