• 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 #define LOG_TAG "FocusResolver"
18 #define ATRACE_TAG ATRACE_TAG_INPUT
19 
20 #define INDENT "  "
21 #define INDENT2 "    "
22 
23 // Log debug messages about input focus tracking.
24 static constexpr bool DEBUG_FOCUS = false;
25 
26 #include <inttypes.h>
27 
28 #include <android-base/stringprintf.h>
29 #include <binder/Binder.h>
30 #include <input/InputWindow.h>
31 #include <input/NamedEnum.h>
32 #include <log/log.h>
33 
34 #include "FocusResolver.h"
35 
36 namespace android::inputdispatcher {
37 
getFocusedWindowToken(int32_t displayId) const38 sp<IBinder> FocusResolver::getFocusedWindowToken(int32_t displayId) const {
39     auto it = mFocusedWindowTokenByDisplay.find(displayId);
40     return it != mFocusedWindowTokenByDisplay.end() ? it->second.second : nullptr;
41 }
42 
getFocusRequest(int32_t displayId)43 std::optional<FocusRequest> FocusResolver::getFocusRequest(int32_t displayId) {
44     auto it = mFocusRequestByDisplay.find(displayId);
45     return it != mFocusRequestByDisplay.end() ? std::make_optional<>(it->second) : std::nullopt;
46 }
47 
48 /**
49  * 'setInputWindows' is called when the window properties change. Here we will check whether the
50  * currently focused window can remain focused. If the currently focused window remains eligible
51  * for focus ('isTokenFocusable' returns OK), then we will continue to grant it focus otherwise
52  * we will check if the previous focus request is eligible to receive focus.
53  */
setInputWindows(int32_t displayId,const std::vector<sp<InputWindowHandle>> & windows)54 std::optional<FocusResolver::FocusChanges> FocusResolver::setInputWindows(
55         int32_t displayId, const std::vector<sp<InputWindowHandle>>& windows) {
56     std::string removeFocusReason;
57 
58     // Check if the currently focused window is still focusable.
59     const sp<IBinder> currentFocus = getFocusedWindowToken(displayId);
60     if (currentFocus) {
61         Focusability result = isTokenFocusable(currentFocus, windows);
62         if (result == Focusability::OK) {
63             return std::nullopt;
64         }
65         removeFocusReason = NamedEnum::string(result);
66     }
67 
68     // We don't have a focused window or the currently focused window is no longer focusable. Check
69     // to see if we can grant focus to the window that previously requested focus.
70     const std::optional<FocusRequest> request = getFocusRequest(displayId);
71     if (request) {
72         sp<IBinder> requestedFocus = request->token;
73         const Focusability result = isTokenFocusable(requestedFocus, windows);
74         const Focusability previousResult = mLastFocusResultByDisplay[displayId];
75         mLastFocusResultByDisplay[displayId] = result;
76         if (result == Focusability::OK) {
77             return updateFocusedWindow(displayId,
78                                        "Window became focusable. Previous reason: " +
79                                                NamedEnum::string(previousResult),
80                                        requestedFocus, request->windowName);
81         }
82     }
83 
84     // Focused window is no longer focusable and we don't have a suitable focus request to grant.
85     // Remove focus if needed.
86     return updateFocusedWindow(displayId, removeFocusReason, nullptr);
87 }
88 
setFocusedWindow(const FocusRequest & request,const std::vector<sp<InputWindowHandle>> & windows)89 std::optional<FocusResolver::FocusChanges> FocusResolver::setFocusedWindow(
90         const FocusRequest& request, const std::vector<sp<InputWindowHandle>>& windows) {
91     const int32_t displayId = request.displayId;
92     const sp<IBinder> currentFocus = getFocusedWindowToken(displayId);
93     if (currentFocus == request.token) {
94         ALOGD_IF(DEBUG_FOCUS,
95                  "setFocusedWindow %s on display %" PRId32 " ignored, reason: already focused",
96                  request.windowName.c_str(), displayId);
97         return std::nullopt;
98     }
99 
100     // Handle conditional focus requests, i.e. requests that have a focused token. These requests
101     // are not persistent. If the window is no longer focusable, we expect focus to go back to the
102     // previously focused window.
103     if (request.focusedToken) {
104         if (currentFocus != request.focusedToken) {
105             ALOGW("setFocusedWindow %s on display %" PRId32
106                   " ignored, reason: focusedToken %s is not focused",
107                   request.windowName.c_str(), displayId, request.focusedWindowName.c_str());
108             return std::nullopt;
109         }
110         Focusability result = isTokenFocusable(request.token, windows);
111         if (result == Focusability::OK) {
112             return updateFocusedWindow(displayId, "setFocusedWindow with focus check",
113                                        request.token, request.windowName);
114         }
115         ALOGW("setFocusedWindow %s on display %" PRId32 " ignored, reason: %s",
116               request.windowName.c_str(), displayId, NamedEnum::string(result).c_str());
117         return std::nullopt;
118     }
119 
120     Focusability result = isTokenFocusable(request.token, windows);
121     // Update focus request. The focus resolver will always try to handle this request if there is
122     // no focused window on the display.
123     mFocusRequestByDisplay[displayId] = request;
124     mLastFocusResultByDisplay[displayId] = result;
125 
126     if (result == Focusability::OK) {
127         return updateFocusedWindow(displayId, "setFocusedWindow", request.token,
128                                    request.windowName);
129     }
130 
131     // The requested window is not currently focusable. Wait for the window to become focusable
132     // but remove focus from the current window so that input events can go into a pending queue
133     // and be sent to the window when it becomes focused.
134     return updateFocusedWindow(displayId, "Waiting for window because " + NamedEnum::string(result),
135                                nullptr);
136 }
137 
isTokenFocusable(const sp<IBinder> & token,const std::vector<sp<InputWindowHandle>> & windows)138 FocusResolver::Focusability FocusResolver::isTokenFocusable(
139         const sp<IBinder>& token, const std::vector<sp<InputWindowHandle>>& windows) {
140     bool allWindowsAreFocusable = true;
141     bool visibleWindowFound = false;
142     bool windowFound = false;
143     for (const sp<InputWindowHandle>& window : windows) {
144         if (window->getToken() != token) {
145             continue;
146         }
147         windowFound = true;
148         if (window->getInfo()->visible) {
149             // Check if at least a single window is visible.
150             visibleWindowFound = true;
151         }
152         if (!window->getInfo()->focusable) {
153             // Check if all windows with the window token are focusable.
154             allWindowsAreFocusable = false;
155             break;
156         }
157     }
158 
159     if (!windowFound) {
160         return Focusability::NO_WINDOW;
161     }
162     if (!allWindowsAreFocusable) {
163         return Focusability::NOT_FOCUSABLE;
164     }
165     if (!visibleWindowFound) {
166         return Focusability::NOT_VISIBLE;
167     }
168 
169     return Focusability::OK;
170 }
171 
updateFocusedWindow(int32_t displayId,const std::string & reason,const sp<IBinder> & newFocus,const std::string & tokenName)172 std::optional<FocusResolver::FocusChanges> FocusResolver::updateFocusedWindow(
173         int32_t displayId, const std::string& reason, const sp<IBinder>& newFocus,
174         const std::string& tokenName) {
175     sp<IBinder> oldFocus = getFocusedWindowToken(displayId);
176     if (newFocus == oldFocus) {
177         return std::nullopt;
178     }
179     if (newFocus) {
180         mFocusedWindowTokenByDisplay[displayId] = {tokenName, newFocus};
181     } else {
182         mFocusedWindowTokenByDisplay.erase(displayId);
183     }
184 
185     return {{oldFocus, newFocus, displayId, reason}};
186 }
187 
dumpFocusedWindows() const188 std::string FocusResolver::dumpFocusedWindows() const {
189     if (mFocusedWindowTokenByDisplay.empty()) {
190         return INDENT "FocusedWindows: <none>\n";
191     }
192 
193     std::string dump;
194     dump += INDENT "FocusedWindows:\n";
195     for (const auto& [displayId, namedToken] : mFocusedWindowTokenByDisplay) {
196         dump += base::StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s'\n", displayId,
197                                    namedToken.first.c_str());
198     }
199     return dump;
200 }
201 
dump() const202 std::string FocusResolver::dump() const {
203     std::string dump = dumpFocusedWindows();
204     if (mFocusRequestByDisplay.empty()) {
205         return dump + INDENT "FocusRequests: <none>\n";
206     }
207 
208     dump += INDENT "FocusRequests:\n";
209     for (const auto& [displayId, request] : mFocusRequestByDisplay) {
210         auto it = mLastFocusResultByDisplay.find(displayId);
211         std::string result =
212                 it != mLastFocusResultByDisplay.end() ? NamedEnum::string(it->second) : "";
213         dump += base::StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s' result='%s'\n",
214                                    displayId, request.windowName.c_str(), result.c_str());
215     }
216     return dump;
217 }
218 
displayRemoved(int32_t displayId)219 void FocusResolver::displayRemoved(int32_t displayId) {
220     mFocusRequestByDisplay.erase(displayId);
221     mLastFocusResultByDisplay.erase(displayId);
222 }
223 
224 } // namespace android::inputdispatcher
225