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_EQ(_oldFocus, _changes->oldFocus);           \
24         ASSERT_EQ(_newFocus, _changes->newFocus);           \
25     }
26 
27 // atest inputflinger_tests:FocusResolverTest
28 
29 using android::gui::FocusRequest;
30 using android::gui::WindowInfoHandle;
31 
32 namespace android::inputdispatcher {
33 
34 class FakeWindowHandle : public WindowInfoHandle {
35 public:
FakeWindowHandle(const std::string & name,const sp<IBinder> & token,bool focusable,bool visible)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 
setFocusable(bool focusable)44     void setFocusable(bool focusable) { mInfo.focusable = focusable; }
setVisible(bool visible)45     void setVisible(bool visible) { mInfo.visible = visible; }
46 };
47 
TEST(FocusResolverTest,SetFocusedWindow)48 TEST(FocusResolverTest, SetFocusedWindow) {
49     sp<IBinder> focusableWindowToken = new BBinder();
50     sp<IBinder> invisibleWindowToken = new BBinder();
51     sp<IBinder> unfocusableWindowToken = new BBinder();
52     std::vector<sp<WindowInfoHandle>> windows;
53     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);
67     ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ focusableWindowToken);
68     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);
75     ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ nullptr);
76 
77     // unfocusableWindowToken window cannot get focused
78     request.token = unfocusableWindowToken;
79     changes = focusResolver.setFocusedWindow(request, windows);
80     ASSERT_FALSE(changes);
81 }
82 
TEST(FocusResolverTest,SetFocusedMirroredWindow)83 TEST(FocusResolverTest, SetFocusedMirroredWindow) {
84     sp<IBinder> focusableWindowToken = new BBinder();
85     sp<IBinder> invisibleWindowToken = new BBinder();
86     sp<IBinder> unfocusableWindowToken = new BBinder();
87     std::vector<sp<WindowInfoHandle>> windows;
88     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);
110     ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ focusableWindowToken);
111 
112     // mirrored window with one visible window can get focused
113     request.token = invisibleWindowToken;
114     changes = focusResolver.setFocusedWindow(request, windows);
115     ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ invisibleWindowToken);
116 
117     // mirrored window with one or more unfocusable window cannot get focused
118     request.token = unfocusableWindowToken;
119     changes = focusResolver.setFocusedWindow(request, windows);
120     ASSERT_FOCUS_CHANGE(changes, /*from*/ invisibleWindowToken, /*to*/ nullptr);
121 }
122 
TEST(FocusResolverTest,SetInputWindows)123 TEST(FocusResolverTest, SetInputWindows) {
124     sp<IBinder> focusableWindowToken = new BBinder();
125     std::vector<sp<WindowInfoHandle>> windows;
126     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 
139     // Window visibility changes and the window loses focus
140     window->setVisible(false);
141     changes = focusResolver.setInputWindows(request.displayId, windows);
142     ASSERT_FOCUS_CHANGE(changes, /*from*/ focusableWindowToken, /*to*/ nullptr);
143 }
144 
TEST(FocusResolverTest,FocusRequestsCanBePending)145 TEST(FocusResolverTest, FocusRequestsCanBePending) {
146     sp<IBinder> invisibleWindowToken = new BBinder();
147     std::vector<sp<WindowInfoHandle>> windows;
148 
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);
166     ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ invisibleWindowToken);
167 }
168 
TEST(FocusResolverTest,FocusRequestsArePersistent)169 TEST(FocusResolverTest, FocusRequestsArePersistent) {
170     sp<IBinder> windowToken = new BBinder();
171     std::vector<sp<WindowInfoHandle>> windows;
172 
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 
TEST(FocusResolverTest,ConditionalFocusRequestsAreNotPersistent)210 TEST(FocusResolverTest, ConditionalFocusRequestsAreNotPersistent) {
211     sp<IBinder> hostWindowToken = new BBinder();
212     std::vector<sp<WindowInfoHandle>> windows;
213 
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);
260 }
TEST(FocusResolverTest,FocusRequestsAreClearedWhenWindowIsRemoved)261 TEST(FocusResolverTest, FocusRequestsAreClearedWhenWindowIsRemoved) {
262     sp<IBinder> windowToken = new BBinder();
263     std::vector<sp<WindowInfoHandle>> windows;
264 
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 }
293 
294 } // namespace android::inputdispatcher
295