blob: 4da846bcf822300b2c50a5c66091384b95527d5e [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 */
Arthur Hungb060def2022-05-26 07:41:33 +000016#define LOG_TAG "InputDispatcher"
Vishnu Nairc519ff72021-01-21 08:23:08 -080017#define ATRACE_TAG ATRACE_TAG_INPUT
18
19#define INDENT " "
20#define INDENT2 " "
21
Vishnu Nairc519ff72021-01-21 08:23:08 -080022#include <inttypes.h>
23
24#include <android-base/stringprintf.h>
25#include <binder/Binder.h>
Dominik Laskowski75788452021-02-09 18:51:25 -080026#include <ftl/enum.h>
chaviw98318de2021-05-19 16:45:23 -050027#include <gui/WindowInfo.h>
Vishnu Nairc519ff72021-01-21 08:23:08 -080028
Arthur Hungb060def2022-05-26 07:41:33 +000029#include "DebugConfig.h"
Vishnu Nairc519ff72021-01-21 08:23:08 -080030#include "FocusResolver.h"
31
chaviw98318de2021-05-19 16:45:23 -050032using android::gui::FocusRequest;
33using android::gui::WindowInfoHandle;
34
Vishnu Nairc519ff72021-01-21 08:23:08 -080035namespace android::inputdispatcher {
36
37sp<IBinder> FocusResolver::getFocusedWindowToken(int32_t displayId) const {
38 auto it = mFocusedWindowTokenByDisplay.find(displayId);
39 return it != mFocusedWindowTokenByDisplay.end() ? it->second.second : nullptr;
40}
41
Vishnu Nair1dcad982021-02-24 14:38:25 -080042std::optional<FocusRequest> FocusResolver::getFocusRequest(int32_t displayId) {
43 auto it = mFocusRequestByDisplay.find(displayId);
44 return it != mFocusRequestByDisplay.end() ? std::make_optional<>(it->second) : std::nullopt;
Vishnu Nairc519ff72021-01-21 08:23:08 -080045}
46
Vishnu Nair1dcad982021-02-24 14:38:25 -080047/**
48 * 'setInputWindows' is called when the window properties change. Here we will check whether the
49 * currently focused window can remain focused. If the currently focused window remains eligible
50 * for focus ('isTokenFocusable' returns OK), then we will continue to grant it focus otherwise
51 * we will check if the previous focus request is eligible to receive focus.
52 */
Vishnu Nairc519ff72021-01-21 08:23:08 -080053std::optional<FocusResolver::FocusChanges> FocusResolver::setInputWindows(
chaviw98318de2021-05-19 16:45:23 -050054 int32_t displayId, const std::vector<sp<WindowInfoHandle>>& windows) {
Vishnu Nair1dcad982021-02-24 14:38:25 -080055 std::string removeFocusReason;
56
57 // Check if the currently focused window is still focusable.
58 const sp<IBinder> currentFocus = getFocusedWindowToken(displayId);
Vishnu Nairc519ff72021-01-21 08:23:08 -080059 if (currentFocus) {
Vishnu Nair1dcad982021-02-24 14:38:25 -080060 Focusability result = isTokenFocusable(currentFocus, windows);
61 if (result == Focusability::OK) {
62 return std::nullopt;
63 }
Dominik Laskowski75788452021-02-09 18:51:25 -080064 removeFocusReason = ftl::enum_string(result);
Vishnu Nair1dcad982021-02-24 14:38:25 -080065 }
66
67 // We don't have a focused window or the currently focused window is no longer focusable. Check
68 // to see if we can grant focus to the window that previously requested focus.
69 const std::optional<FocusRequest> request = getFocusRequest(displayId);
70 if (request) {
71 sp<IBinder> requestedFocus = request->token;
72 const Focusability result = isTokenFocusable(requestedFocus, windows);
73 const Focusability previousResult = mLastFocusResultByDisplay[displayId];
74 mLastFocusResultByDisplay[displayId] = result;
75 if (result == Focusability::OK) {
76 return updateFocusedWindow(displayId,
77 "Window became focusable. Previous reason: " +
Dominik Laskowski75788452021-02-09 18:51:25 -080078 ftl::enum_string(previousResult),
Vishnu Nair1dcad982021-02-24 14:38:25 -080079 requestedFocus, request->windowName);
Vishnu Nairc519ff72021-01-21 08:23:08 -080080 }
81 }
82
Vishnu Nair1dcad982021-02-24 14:38:25 -080083 // Focused window is no longer focusable and we don't have a suitable focus request to grant.
84 // Remove focus if needed.
85 return updateFocusedWindow(displayId, removeFocusReason, nullptr);
Vishnu Nairc519ff72021-01-21 08:23:08 -080086}
87
88std::optional<FocusResolver::FocusChanges> FocusResolver::setFocusedWindow(
chaviw98318de2021-05-19 16:45:23 -050089 const FocusRequest& request, const std::vector<sp<WindowInfoHandle>>& windows) {
Vishnu Nairc519ff72021-01-21 08:23:08 -080090 const int32_t displayId = request.displayId;
91 const sp<IBinder> currentFocus = getFocusedWindowToken(displayId);
Vishnu Nairc519ff72021-01-21 08:23:08 -080092 if (currentFocus == request.token) {
93 ALOGD_IF(DEBUG_FOCUS,
Vishnu Nair1dcad982021-02-24 14:38:25 -080094 "setFocusedWindow %s on display %" PRId32 " ignored, reason: already focused",
Vishnu Nairc519ff72021-01-21 08:23:08 -080095 request.windowName.c_str(), displayId);
96 return std::nullopt;
97 }
98
Vishnu Nair1dcad982021-02-24 14:38:25 -080099 // Handle conditional focus requests, i.e. requests that have a focused token. These requests
100 // are not persistent. If the window is no longer focusable, we expect focus to go back to the
101 // previously focused window.
102 if (request.focusedToken) {
103 if (currentFocus != request.focusedToken) {
104 ALOGW("setFocusedWindow %s on display %" PRId32
105 " ignored, reason: focusedToken %s is not focused",
106 request.windowName.c_str(), displayId, request.focusedWindowName.c_str());
107 return std::nullopt;
108 }
109 Focusability result = isTokenFocusable(request.token, windows);
110 if (result == Focusability::OK) {
111 return updateFocusedWindow(displayId, "setFocusedWindow with focus check",
112 request.token, request.windowName);
113 }
114 ALOGW("setFocusedWindow %s on display %" PRId32 " ignored, reason: %s",
Dominik Laskowski75788452021-02-09 18:51:25 -0800115 request.windowName.c_str(), displayId, ftl::enum_string(result).c_str());
Vishnu Nair1dcad982021-02-24 14:38:25 -0800116 return std::nullopt;
Vishnu Nairc519ff72021-01-21 08:23:08 -0800117 }
118
Vishnu Nair1dcad982021-02-24 14:38:25 -0800119 Focusability result = isTokenFocusable(request.token, windows);
120 // Update focus request. The focus resolver will always try to handle this request if there is
121 // no focused window on the display.
122 mFocusRequestByDisplay[displayId] = request;
123 mLastFocusResultByDisplay[displayId] = result;
124
125 if (result == Focusability::OK) {
126 return updateFocusedWindow(displayId, "setFocusedWindow", request.token,
127 request.windowName);
128 }
129
130 // The requested window is not currently focusable. Wait for the window to become focusable
131 // but remove focus from the current window so that input events can go into a pending queue
132 // and be sent to the window when it becomes focused.
Dominik Laskowski75788452021-02-09 18:51:25 -0800133 return updateFocusedWindow(displayId, "Waiting for window because " + ftl::enum_string(result),
Vishnu Nair1dcad982021-02-24 14:38:25 -0800134 nullptr);
Vishnu Nairc519ff72021-01-21 08:23:08 -0800135}
136
Vishnu Nair1dcad982021-02-24 14:38:25 -0800137FocusResolver::Focusability FocusResolver::isTokenFocusable(
chaviw98318de2021-05-19 16:45:23 -0500138 const sp<IBinder>& token, const std::vector<sp<WindowInfoHandle>>& windows) {
Vishnu Nairc519ff72021-01-21 08:23:08 -0800139 bool allWindowsAreFocusable = true;
140 bool visibleWindowFound = false;
141 bool windowFound = false;
chaviw98318de2021-05-19 16:45:23 -0500142 for (const sp<WindowInfoHandle>& window : windows) {
Vishnu Nairc519ff72021-01-21 08:23:08 -0800143 if (window->getToken() != token) {
144 continue;
145 }
146 windowFound = true;
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800147 if (!window->getInfo()->inputConfig.test(gui::WindowInfo::InputConfig::NOT_VISIBLE)) {
Vishnu Nairc519ff72021-01-21 08:23:08 -0800148 // Check if at least a single window is visible.
149 visibleWindowFound = true;
150 }
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800151 if (window->getInfo()->inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE)) {
Vishnu Nairc519ff72021-01-21 08:23:08 -0800152 // Check if all windows with the window token are focusable.
153 allWindowsAreFocusable = false;
154 break;
155 }
156 }
157
158 if (!windowFound) {
Vishnu Nair1dcad982021-02-24 14:38:25 -0800159 return Focusability::NO_WINDOW;
Vishnu Nairc519ff72021-01-21 08:23:08 -0800160 }
161 if (!allWindowsAreFocusable) {
Vishnu Nair1dcad982021-02-24 14:38:25 -0800162 return Focusability::NOT_FOCUSABLE;
Vishnu Nairc519ff72021-01-21 08:23:08 -0800163 }
164 if (!visibleWindowFound) {
Vishnu Nair1dcad982021-02-24 14:38:25 -0800165 return Focusability::NOT_VISIBLE;
Vishnu Nairc519ff72021-01-21 08:23:08 -0800166 }
167
Vishnu Nair1dcad982021-02-24 14:38:25 -0800168 return Focusability::OK;
Vishnu Nairc519ff72021-01-21 08:23:08 -0800169}
170
171std::optional<FocusResolver::FocusChanges> FocusResolver::updateFocusedWindow(
172 int32_t displayId, const std::string& reason, const sp<IBinder>& newFocus,
173 const std::string& tokenName) {
174 sp<IBinder> oldFocus = getFocusedWindowToken(displayId);
175 if (newFocus == oldFocus) {
176 return std::nullopt;
177 }
178 if (newFocus) {
179 mFocusedWindowTokenByDisplay[displayId] = {tokenName, newFocus};
180 } else {
181 mFocusedWindowTokenByDisplay.erase(displayId);
182 }
183
184 return {{oldFocus, newFocus, displayId, reason}};
185}
186
187std::string FocusResolver::dumpFocusedWindows() const {
188 if (mFocusedWindowTokenByDisplay.empty()) {
189 return INDENT "FocusedWindows: <none>\n";
190 }
191
192 std::string dump;
193 dump += INDENT "FocusedWindows:\n";
194 for (const auto& [displayId, namedToken] : mFocusedWindowTokenByDisplay) {
195 dump += base::StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s'\n", displayId,
196 namedToken.first.c_str());
197 }
198 return dump;
199}
200
201std::string FocusResolver::dump() const {
202 std::string dump = dumpFocusedWindows();
Vishnu Nair1dcad982021-02-24 14:38:25 -0800203 if (mFocusRequestByDisplay.empty()) {
204 return dump + INDENT "FocusRequests: <none>\n";
Vishnu Nairc519ff72021-01-21 08:23:08 -0800205 }
206
Vishnu Nair1dcad982021-02-24 14:38:25 -0800207 dump += INDENT "FocusRequests:\n";
208 for (const auto& [displayId, request] : mFocusRequestByDisplay) {
209 auto it = mLastFocusResultByDisplay.find(displayId);
210 std::string result =
Dominik Laskowski75788452021-02-09 18:51:25 -0800211 it != mLastFocusResultByDisplay.end() ? ftl::enum_string(it->second) : "";
Vishnu Nair1dcad982021-02-24 14:38:25 -0800212 dump += base::StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s' result='%s'\n",
213 displayId, request.windowName.c_str(), result.c_str());
Vishnu Nairc519ff72021-01-21 08:23:08 -0800214 }
215 return dump;
216}
217
Vishnu Nair599f1412021-06-21 10:39:58 -0700218void FocusResolver::displayRemoved(int32_t displayId) {
219 mFocusRequestByDisplay.erase(displayId);
220 mLastFocusResultByDisplay.erase(displayId);
221}
222
Vishnu Nairc519ff72021-01-21 08:23:08 -0800223} // namespace android::inputdispatcher