• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
21 #define ASSERT_FOCUS_CHANGE(_changes, _oldFocus, _newFocus) \
22     {                                                       \
23         ASSERT_TRUE(_changes.has_value());                  \
24         ASSERT_EQ(_oldFocus, _changes->oldFocus);           \
25         ASSERT_EQ(_newFocus, _changes->newFocus);           \
26     }
27 
28 // atest inputflinger_tests:FocusResolverTest
29 
30 using android::gui::FocusRequest;
31 using android::gui::WindowInfoHandle;
32 
33 namespace android::inputdispatcher {
34 
35 namespace {
36 
37 class FakeWindowHandle : public WindowInfoHandle {
38 public:
FakeWindowHandle(const std::string & name,const sp<IBinder> & token,bool focusable,bool visible)39     FakeWindowHandle(const std::string& name, const sp<IBinder>& token, bool focusable,
40                      bool visible) {
41         mInfo.token = token;
42         mInfo.name = name;
43         setFocusable(focusable);
44         setVisible(visible);
45     }
46 
setFocusable(bool focusable)47     void setFocusable(bool focusable) {
48         mInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_FOCUSABLE, !focusable);
49     }
setVisible(bool visible)50     void setVisible(bool visible) {
51         mInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visible);
52     }
53 };
54 
55 } // namespace
56 
TEST(FocusResolverTest,SetFocusedWindow)57 TEST(FocusResolverTest, SetFocusedWindow) {
58     sp<IBinder> focusableWindowToken = sp<BBinder>::make();
59     sp<IBinder> invisibleWindowToken = sp<BBinder>::make();
60     sp<IBinder> unfocusableWindowToken = sp<BBinder>::make();
61     std::vector<sp<WindowInfoHandle>> windows;
62     windows.push_back(sp<FakeWindowHandle>::make("Focusable", focusableWindowToken,
63                                                  /*focusable=*/true, /*visible=*/true));
64     windows.push_back(sp<FakeWindowHandle>::make("Invisible", invisibleWindowToken,
65                                                  /*focusable=*/true, /*visible=*/false));
66     windows.push_back(sp<FakeWindowHandle>::make("unfocusable", unfocusableWindowToken,
67                                                  /*focusable=*/false, /*visible=*/true));
68 
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);
76     ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ focusableWindowToken);
77     ASSERT_EQ(ui::LogicalDisplayId{request.displayId}, changes->displayId);
78 
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);
84     ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ nullptr);
85 
86     // unfocusableWindowToken window cannot get focused
87     request.token = unfocusableWindowToken;
88     changes = focusResolver.setFocusedWindow(request, windows);
89     ASSERT_FALSE(changes);
90 }
91 
TEST(FocusResolverTest,RemoveFocusFromFocusedWindow)92 TEST(FocusResolverTest, RemoveFocusFromFocusedWindow) {
93     sp<IBinder> focusableWindowToken = sp<BBinder>::make();
94     std::vector<sp<WindowInfoHandle>> windows;
95     windows.push_back(sp<FakeWindowHandle>::make("Focusable", focusableWindowToken,
96                                                  /*focusable=*/true, /*visible=*/true));
97 
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 
TEST(FocusResolverTest,SetFocusedMirroredWindow)116 TEST(FocusResolverTest, SetFocusedMirroredWindow) {
117     sp<IBinder> focusableWindowToken = sp<BBinder>::make();
118     sp<IBinder> invisibleWindowToken = sp<BBinder>::make();
119     sp<IBinder> unfocusableWindowToken = sp<BBinder>::make();
120     std::vector<sp<WindowInfoHandle>> windows;
121     windows.push_back(sp<FakeWindowHandle>::make("Mirror1", focusableWindowToken,
122                                                  /*focusable=*/true, /*visible=*/true));
123     windows.push_back(sp<FakeWindowHandle>::make("Mirror1", focusableWindowToken,
124                                                  /*focusable=*/true, /*visible=*/true));
125 
126     windows.push_back(sp<FakeWindowHandle>::make("Mirror2Visible", invisibleWindowToken,
127                                                  /*focusable=*/true, /*visible=*/true));
128     windows.push_back(sp<FakeWindowHandle>::make("Mirror2Invisible", invisibleWindowToken,
129                                                  /*focusable=*/true, /*visible=*/false));
130 
131     windows.push_back(sp<FakeWindowHandle>::make("Mirror3Focusable", unfocusableWindowToken,
132                                                  /*focusable=*/true, /*visible=*/true));
133     windows.push_back(sp<FakeWindowHandle>::make("Mirror3Unfocusable", unfocusableWindowToken,
134                                                  /*focusable=*/false, /*visible=*/true));
135 
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);
143     ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ focusableWindowToken);
144 
145     // mirrored window with one visible window can get focused
146     request.token = invisibleWindowToken;
147     changes = focusResolver.setFocusedWindow(request, windows);
148     ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ invisibleWindowToken);
149 
150     // mirrored window with one or more unfocusable window cannot get focused
151     request.token = unfocusableWindowToken;
152     changes = focusResolver.setFocusedWindow(request, windows);
153     ASSERT_FOCUS_CHANGE(changes, /*from*/ invisibleWindowToken, /*to*/ nullptr);
154 }
155 
TEST(FocusResolverTest,FocusTransferToMirror)156 TEST(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
172     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId},
173                                             {mirror, window});
174     ASSERT_FALSE(changes.has_value());
175 
176     // The window now comes on top while the mirror is removed, and the focus does not change
177     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, {window});
178     ASSERT_FALSE(changes.has_value());
179 
180     // The window is removed but the mirror is on top, and focus does not change
181     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, {mirror});
182     ASSERT_FALSE(changes.has_value());
183 
184     // All windows removed
185     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, {});
186     ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ nullptr);
187 }
188 
TEST(FocusResolverTest,SetInputWindows)189 TEST(FocusResolverTest, SetInputWindows) {
190     sp<IBinder> focusableWindowToken = sp<BBinder>::make();
191     std::vector<sp<WindowInfoHandle>> windows;
192     sp<FakeWindowHandle> window =
193             sp<FakeWindowHandle>::make("Focusable", focusableWindowToken, /*focusable=*/true,
194                                        /*visible=*/true);
195     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 
206     // When there are no changes to the window, focus does not change
207     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
208     ASSERT_FALSE(changes.has_value());
209 
210     // Window visibility changes and the window loses focus
211     window->setVisible(false);
212     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
213     ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ nullptr);
214 }
215 
TEST(FocusResolverTest,FocusRequestsCanBePending)216 TEST(FocusResolverTest, FocusRequestsCanBePending) {
217     sp<IBinder> invisibleWindowToken = sp<BBinder>::make();
218     std::vector<sp<WindowInfoHandle>> windows;
219 
220     sp<FakeWindowHandle> invisibleWindow =
221             sp<FakeWindowHandle>::make("Invisible", invisibleWindowToken, /*focusable=*/true,
222                                        /*visible=*/false);
223     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);
236     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
237     ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ invisibleWindowToken);
238 }
239 
TEST(FocusResolverTest,FocusRequestsArePersistent)240 TEST(FocusResolverTest, FocusRequestsArePersistent) {
241     sp<IBinder> windowToken = sp<BBinder>::make();
242     std::vector<sp<WindowInfoHandle>> windows;
243 
244     sp<FakeWindowHandle> window =
245             sp<FakeWindowHandle>::make("Test Window", windowToken, /*focusable=*/false,
246                                        /*visible=*/true);
247     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);
260     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
261     ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
262 
263     // Visibility changes and the window loses focus
264     window->setVisible(false);
265     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
266     ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
267 
268     // Visibility changes and the window gets focused
269     window->setVisible(true);
270     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
271     ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
272 
273     // Window is gone and the window loses focus
274     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, {});
275     ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
276 
277     // Window returns and the window gains focus
278     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
279     ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
280 }
281 
TEST(FocusResolverTest,FocusTransferTarget)282 TEST(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);
311     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
312     ASSERT_FOCUS_CHANGE(changes, /*from*/ hostWindowToken, /*to*/ embeddedWindowToken);
313 
314     // Embedded is not visible so host will get focus
315     embeddedWindow->setVisible(false);
316     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
317     ASSERT_FOCUS_CHANGE(changes, /*from*/ embeddedWindowToken, /*to*/ hostWindowToken);
318 
319     // Embedded is now visible so will get focus
320     embeddedWindow->setVisible(true);
321     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
322     ASSERT_FOCUS_CHANGE(changes, /*from*/ hostWindowToken, /*to*/ embeddedWindowToken);
323 
324     // Remove focusTransferTarget from host. Host will gain focus.
325     hostWindow->editInfo()->focusTransferTarget = nullptr;
326     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
327     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();
331     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
332     ASSERT_FALSE(changes);
333 }
334 
TEST(FocusResolverTest,FocusTransferMultipleInChain)335 TEST(FocusResolverTest, FocusTransferMultipleInChain) {
336     sp<IBinder> hostWindowToken = sp<BBinder>::make();
337     std::vector<sp<WindowInfoHandle>> windows;
338 
339     sp<FakeWindowHandle> hostWindow =
340             sp<FakeWindowHandle>::make("Host Window", hostWindowToken, /*focusable=*/true,
341                                        /*visible=*/true);
342     windows.push_back(hostWindow);
343     sp<IBinder> embeddedWindowToken = sp<BBinder>::make();
344     sp<FakeWindowHandle> embeddedWindow =
345             sp<FakeWindowHandle>::make("Embedded Window", embeddedWindowToken, /*focusable=*/true,
346                                        /*visible=*/true);
347     windows.push_back(embeddedWindow);
348 
349     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 
355     FocusRequest request;
356     request.displayId = 42;
357     request.token = hostWindowToken;
358 
359     hostWindow->editInfo()->focusTransferTarget = embeddedWindowToken;
360     embeddedWindow->editInfo()->focusTransferTarget = embeddedWindowToken2;
361 
362     FocusResolver focusResolver;
363     std::optional<FocusResolver::FocusChanges> changes =
364             focusResolver.setFocusedWindow(request, windows);
365     ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ embeddedWindowToken2);
366 }
367 
TEST(FocusResolverTest,FocusTransferTargetCycle)368 TEST(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 
TEST(FocusResolverTest,FocusRequestsAreClearedWhenWindowIsRemoved)403 TEST(FocusResolverTest, FocusRequestsAreClearedWhenWindowIsRemoved) {
404     sp<IBinder> windowToken = sp<BBinder>::make();
405     std::vector<sp<WindowInfoHandle>> windows;
406 
407     sp<FakeWindowHandle> window =
408             sp<FakeWindowHandle>::make("Test Window", windowToken, /*focusable=*/true,
409                                        /*visible=*/true);
410     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);
419     ASSERT_EQ(ui::LogicalDisplayId{request.displayId}, changes->displayId);
420 
421     // When a display is removed, all windows are removed from the display
422     // and our focused window loses focus
423     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, {});
424     ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
425     focusResolver.displayRemoved(ui::LogicalDisplayId{request.displayId});
426 
427     // When a display is re-added, the window does not get focus since the request was cleared.
428     changes = focusResolver.setInputWindows(ui::LogicalDisplayId{request.displayId}, windows);
429     ASSERT_FALSE(changes);
430 }
431 
432 } // namespace android::inputdispatcher
433