Loading services/inputflinger/dispatcher/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ filegroup { "AnrTracker.cpp", "Connection.cpp", "Entry.cpp", "FocusResolver.cpp", "InjectionState.cpp", "InputDispatcher.cpp", "InputDispatcherFactory.cpp", Loading services/inputflinger/dispatcher/Entry.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -102,7 +102,7 @@ std::string DeviceResetEntry::getDescription() const { // Focus notifications always go to apps, so set the flag POLICY_FLAG_PASS_TO_USER for all entries FocusEntry::FocusEntry(int32_t id, nsecs_t eventTime, sp<IBinder> connectionToken, bool hasFocus, std::string_view reason) const std::string& reason) : EventEntry(id, Type::FOCUS, eventTime, POLICY_FLAG_PASS_TO_USER), connectionToken(connectionToken), hasFocus(hasFocus), Loading services/inputflinger/dispatcher/Entry.h +2 −2 Original line number Diff line number Diff line Loading @@ -93,10 +93,10 @@ struct DeviceResetEntry : EventEntry { struct FocusEntry : EventEntry { sp<IBinder> connectionToken; bool hasFocus; std::string_view reason; std::string reason; FocusEntry(int32_t id, nsecs_t eventTime, sp<IBinder> connectionToken, bool hasFocus, std::string_view reason); const std::string& reason); std::string getDescription() const override; virtual ~FocusEntry(); Loading services/inputflinger/dispatcher/FocusResolver.cpp 0 → 100644 +225 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "FocusResolver" #define ATRACE_TAG ATRACE_TAG_INPUT #define INDENT " " #define INDENT2 " " // Log debug messages about input focus tracking. static constexpr bool DEBUG_FOCUS = false; #include <inttypes.h> #include <android-base/stringprintf.h> #include <binder/Binder.h> #include <input/InputWindow.h> #include <input/NamedEnum.h> #include <log/log.h> #include "FocusResolver.h" namespace android::inputdispatcher { sp<IBinder> FocusResolver::getFocusedWindowToken(int32_t displayId) const { auto it = mFocusedWindowTokenByDisplay.find(displayId); return it != mFocusedWindowTokenByDisplay.end() ? it->second.second : nullptr; } std::optional<FocusRequest> FocusResolver::getPendingRequest(int32_t displayId) { auto it = mPendingFocusRequests.find(displayId); return it != mPendingFocusRequests.end() ? std::make_optional<>(it->second) : std::nullopt; } std::optional<FocusResolver::FocusChanges> FocusResolver::setInputWindows( int32_t displayId, const std::vector<sp<InputWindowHandle>>& windows) { // If the current focused window becomes unfocusable, remove focus. sp<IBinder> currentFocus = getFocusedWindowToken(displayId); if (currentFocus) { FocusResult result = isTokenFocusable(currentFocus, windows); if (result != FocusResult::OK) { return updateFocusedWindow(displayId, NamedEnum::string(result), nullptr); } } // Check if any pending focus requests can be resolved. std::optional<FocusRequest> pendingRequest = getPendingRequest(displayId); if (!pendingRequest) { return std::nullopt; } sp<IBinder> requestedFocus = pendingRequest->token; std::string windowName = pendingRequest->windowName; if (currentFocus == requestedFocus) { ALOGD_IF(DEBUG_FOCUS, "setFocusedWindow %s on display %" PRId32 " ignored, reason: already focused", windowName.c_str(), displayId); mPendingFocusRequests.erase(displayId); return std::nullopt; } FocusResult result = isTokenFocusable(requestedFocus, windows); // If the window from the pending request is now visible, provide it focus. if (result == FocusResult::OK) { mPendingFocusRequests.erase(displayId); return updateFocusedWindow(displayId, "Window became visible", requestedFocus, windowName); } if (result != FocusResult::NOT_VISIBLE) { // Drop the request if we are unable to change the focus for a reason other than visibility. ALOGW("Focus request %s on display %" PRId32 " ignored, reason:%s", windowName.c_str(), displayId, NamedEnum::string(result).c_str()); mPendingFocusRequests.erase(displayId); } return std::nullopt; } std::optional<FocusResolver::FocusChanges> FocusResolver::setFocusedWindow( const FocusRequest& request, const std::vector<sp<InputWindowHandle>>& windows) { const int32_t displayId = request.displayId; const sp<IBinder> currentFocus = getFocusedWindowToken(displayId); if (request.focusedToken && currentFocus != request.focusedToken) { ALOGW("setFocusedWindow %s on display %" PRId32 " ignored, reason: focusedToken %s is not focused", request.windowName.c_str(), displayId, request.focusedWindowName.c_str()); return std::nullopt; } std::optional<FocusRequest> pendingRequest = getPendingRequest(displayId); if (pendingRequest) { ALOGW("Pending focus request %s on display %" PRId32 " ignored, reason:replaced by new request", pendingRequest->windowName.c_str(), displayId); // clear any pending focus requests mPendingFocusRequests.erase(displayId); } if (currentFocus == request.token) { ALOGD_IF(DEBUG_FOCUS, "setFocusedWindow %s on display %" PRId32 " ignored, reason:already focused", request.windowName.c_str(), displayId); return std::nullopt; } FocusResult result = isTokenFocusable(request.token, windows); if (result == FocusResult::OK) { std::string reason = (request.focusedToken) ? "setFocusedWindow with focus check" : "setFocusedWindow"; return updateFocusedWindow(displayId, reason, request.token, request.windowName); } if (result == FocusResult::NOT_VISIBLE) { // The requested window is not currently visible. Wait for the window to become visible // and then provide it focus. This is to handle situations where a user action triggers // a new window to appear. We want to be able to queue any key events after the user // action and deliver it to the newly focused window. In order for this to happen, we // take focus from the currently focused window so key events can be queued. ALOGD_IF(DEBUG_FOCUS, "setFocusedWindow %s on display %" PRId32 " pending, reason: window is not visible", request.windowName.c_str(), displayId); mPendingFocusRequests[displayId] = request; return updateFocusedWindow(displayId, "Waiting for window to be visible", nullptr); } else { ALOGW("setFocusedWindow %s on display %" PRId32 " ignored, reason:%s", request.windowName.c_str(), displayId, NamedEnum::string(result).c_str()); } return std::nullopt; } FocusResolver::FocusResult FocusResolver::isTokenFocusable( const sp<IBinder>& token, const std::vector<sp<InputWindowHandle>>& windows) { bool allWindowsAreFocusable = true; bool visibleWindowFound = false; bool windowFound = false; for (const sp<InputWindowHandle>& window : windows) { if (window->getToken() != token) { continue; } windowFound = true; if (window->getInfo()->visible) { // Check if at least a single window is visible. visibleWindowFound = true; } if (!window->getInfo()->focusable) { // Check if all windows with the window token are focusable. allWindowsAreFocusable = false; break; } } if (!windowFound) { return FocusResult::NO_WINDOW; } if (!allWindowsAreFocusable) { return FocusResult::NOT_FOCUSABLE; } if (!visibleWindowFound) { return FocusResult::NOT_VISIBLE; } return FocusResult::OK; } std::optional<FocusResolver::FocusChanges> FocusResolver::updateFocusedWindow( int32_t displayId, const std::string& reason, const sp<IBinder>& newFocus, const std::string& tokenName) { sp<IBinder> oldFocus = getFocusedWindowToken(displayId); if (newFocus == oldFocus) { return std::nullopt; } if (newFocus) { mFocusedWindowTokenByDisplay[displayId] = {tokenName, newFocus}; } else { mFocusedWindowTokenByDisplay.erase(displayId); } return {{oldFocus, newFocus, displayId, reason}}; } std::string FocusResolver::dumpFocusedWindows() const { if (mFocusedWindowTokenByDisplay.empty()) { return INDENT "FocusedWindows: <none>\n"; } std::string dump; dump += INDENT "FocusedWindows:\n"; for (const auto& [displayId, namedToken] : mFocusedWindowTokenByDisplay) { dump += base::StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s'\n", displayId, namedToken.first.c_str()); } return dump; } std::string FocusResolver::dump() const { std::string dump = dumpFocusedWindows(); if (mPendingFocusRequests.empty()) { return dump + INDENT "PendingFocusRequests: <none>\n"; } dump += INDENT "PendingFocusRequests:\n"; for (const auto& [displayId, request] : mPendingFocusRequests) { dump += base::StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s'\n", displayId, request.windowName.c_str()); } return dump; } } // namespace android::inputdispatcher services/inputflinger/dispatcher/FocusResolver.h 0 → 100644 +101 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <stdint.h> #include <optional> #include <unordered_map> #include <android/FocusRequest.h> #include <binder/Binder.h> #include <input/InputWindow.h> namespace android::inputdispatcher { // Keeps track of the focused window per display. The class listens to updates from input dispatcher // and provides focus changes. // // Focus Policy // Window focusabilty - A window token can be focused if there is at least one window handle that // is visible with the same token and all window handles with the same token are focusable. // See FocusResolver::isTokenFocusable // // Focus request - Request will be granted if the window is focusable. If the window is not // visible, then the request is kept in a pending state and granted when it becomes visible. // If window becomes not focusable, or another request comes in, the pending request is dropped. // // Window handle updates - Focus is lost when the currently focused window becomes not focusable. class FocusResolver { public: // Returns the focused window token on the specified display. sp<IBinder> getFocusedWindowToken(int32_t displayId) const; struct FocusChanges { sp<IBinder> oldFocus; sp<IBinder> newFocus; int32_t displayId; std::string reason; }; std::optional<FocusResolver::FocusChanges> setInputWindows( int32_t displayId, const std::vector<sp<InputWindowHandle>>& windows); std::optional<FocusResolver::FocusChanges> setFocusedWindow( const FocusRequest& request, const std::vector<sp<InputWindowHandle>>& windows); // exposed for debugging bool hasFocusedWindowTokens() const { return !mFocusedWindowTokenByDisplay.empty(); } std::string dumpFocusedWindows() const; std::string dump() const; private: enum class FocusResult { OK, NO_WINDOW, NOT_FOCUSABLE, NOT_VISIBLE, }; // Checks if the window token can be focused on a display. The token can be focused if there is // at least one window handle that is visible with the same token and all window handles with // the same token are focusable. // // In the case of mirroring, two windows may share the same window token and their visibility // might be different. Example, the mirrored window can cover the window its mirroring. However, // we expect the focusability of the windows to match since its hard to reason why one window // can receive focus events and the other cannot when both are backed by the same input channel. // static FocusResult isTokenFocusable(const sp<IBinder>& token, const std::vector<sp<InputWindowHandle>>& windows); // Focus tracking for keys, trackball, etc. A window token can be associated with one or // more InputWindowHandles. If a window is mirrored, the window and its mirror will share // the same token. Focus is tracked by the token per display and the events are dispatched // to the channel associated by this token. typedef std::pair<std::string /* name */, sp<IBinder>> NamedToken; std::unordered_map<int32_t /* displayId */, NamedToken> mFocusedWindowTokenByDisplay; // This map will store a single pending focus request per display that cannot be currently // processed. This can happen if the window requested to be focused is not currently visible. // Such a window might become visible later, and these requests would be processed at that time. std::unordered_map<int32_t /* displayId */, FocusRequest> mPendingFocusRequests; std::optional<FocusResolver::FocusChanges> updateFocusedWindow( int32_t displayId, const std::string& reason, const sp<IBinder>& token, const std::string& tokenName = ""); std::optional<FocusRequest> getPendingRequest(int32_t displayId); }; } // namespace android::inputdispatcher No newline at end of file Loading
services/inputflinger/dispatcher/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ filegroup { "AnrTracker.cpp", "Connection.cpp", "Entry.cpp", "FocusResolver.cpp", "InjectionState.cpp", "InputDispatcher.cpp", "InputDispatcherFactory.cpp", Loading
services/inputflinger/dispatcher/Entry.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -102,7 +102,7 @@ std::string DeviceResetEntry::getDescription() const { // Focus notifications always go to apps, so set the flag POLICY_FLAG_PASS_TO_USER for all entries FocusEntry::FocusEntry(int32_t id, nsecs_t eventTime, sp<IBinder> connectionToken, bool hasFocus, std::string_view reason) const std::string& reason) : EventEntry(id, Type::FOCUS, eventTime, POLICY_FLAG_PASS_TO_USER), connectionToken(connectionToken), hasFocus(hasFocus), Loading
services/inputflinger/dispatcher/Entry.h +2 −2 Original line number Diff line number Diff line Loading @@ -93,10 +93,10 @@ struct DeviceResetEntry : EventEntry { struct FocusEntry : EventEntry { sp<IBinder> connectionToken; bool hasFocus; std::string_view reason; std::string reason; FocusEntry(int32_t id, nsecs_t eventTime, sp<IBinder> connectionToken, bool hasFocus, std::string_view reason); const std::string& reason); std::string getDescription() const override; virtual ~FocusEntry(); Loading
services/inputflinger/dispatcher/FocusResolver.cpp 0 → 100644 +225 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "FocusResolver" #define ATRACE_TAG ATRACE_TAG_INPUT #define INDENT " " #define INDENT2 " " // Log debug messages about input focus tracking. static constexpr bool DEBUG_FOCUS = false; #include <inttypes.h> #include <android-base/stringprintf.h> #include <binder/Binder.h> #include <input/InputWindow.h> #include <input/NamedEnum.h> #include <log/log.h> #include "FocusResolver.h" namespace android::inputdispatcher { sp<IBinder> FocusResolver::getFocusedWindowToken(int32_t displayId) const { auto it = mFocusedWindowTokenByDisplay.find(displayId); return it != mFocusedWindowTokenByDisplay.end() ? it->second.second : nullptr; } std::optional<FocusRequest> FocusResolver::getPendingRequest(int32_t displayId) { auto it = mPendingFocusRequests.find(displayId); return it != mPendingFocusRequests.end() ? std::make_optional<>(it->second) : std::nullopt; } std::optional<FocusResolver::FocusChanges> FocusResolver::setInputWindows( int32_t displayId, const std::vector<sp<InputWindowHandle>>& windows) { // If the current focused window becomes unfocusable, remove focus. sp<IBinder> currentFocus = getFocusedWindowToken(displayId); if (currentFocus) { FocusResult result = isTokenFocusable(currentFocus, windows); if (result != FocusResult::OK) { return updateFocusedWindow(displayId, NamedEnum::string(result), nullptr); } } // Check if any pending focus requests can be resolved. std::optional<FocusRequest> pendingRequest = getPendingRequest(displayId); if (!pendingRequest) { return std::nullopt; } sp<IBinder> requestedFocus = pendingRequest->token; std::string windowName = pendingRequest->windowName; if (currentFocus == requestedFocus) { ALOGD_IF(DEBUG_FOCUS, "setFocusedWindow %s on display %" PRId32 " ignored, reason: already focused", windowName.c_str(), displayId); mPendingFocusRequests.erase(displayId); return std::nullopt; } FocusResult result = isTokenFocusable(requestedFocus, windows); // If the window from the pending request is now visible, provide it focus. if (result == FocusResult::OK) { mPendingFocusRequests.erase(displayId); return updateFocusedWindow(displayId, "Window became visible", requestedFocus, windowName); } if (result != FocusResult::NOT_VISIBLE) { // Drop the request if we are unable to change the focus for a reason other than visibility. ALOGW("Focus request %s on display %" PRId32 " ignored, reason:%s", windowName.c_str(), displayId, NamedEnum::string(result).c_str()); mPendingFocusRequests.erase(displayId); } return std::nullopt; } std::optional<FocusResolver::FocusChanges> FocusResolver::setFocusedWindow( const FocusRequest& request, const std::vector<sp<InputWindowHandle>>& windows) { const int32_t displayId = request.displayId; const sp<IBinder> currentFocus = getFocusedWindowToken(displayId); if (request.focusedToken && currentFocus != request.focusedToken) { ALOGW("setFocusedWindow %s on display %" PRId32 " ignored, reason: focusedToken %s is not focused", request.windowName.c_str(), displayId, request.focusedWindowName.c_str()); return std::nullopt; } std::optional<FocusRequest> pendingRequest = getPendingRequest(displayId); if (pendingRequest) { ALOGW("Pending focus request %s on display %" PRId32 " ignored, reason:replaced by new request", pendingRequest->windowName.c_str(), displayId); // clear any pending focus requests mPendingFocusRequests.erase(displayId); } if (currentFocus == request.token) { ALOGD_IF(DEBUG_FOCUS, "setFocusedWindow %s on display %" PRId32 " ignored, reason:already focused", request.windowName.c_str(), displayId); return std::nullopt; } FocusResult result = isTokenFocusable(request.token, windows); if (result == FocusResult::OK) { std::string reason = (request.focusedToken) ? "setFocusedWindow with focus check" : "setFocusedWindow"; return updateFocusedWindow(displayId, reason, request.token, request.windowName); } if (result == FocusResult::NOT_VISIBLE) { // The requested window is not currently visible. Wait for the window to become visible // and then provide it focus. This is to handle situations where a user action triggers // a new window to appear. We want to be able to queue any key events after the user // action and deliver it to the newly focused window. In order for this to happen, we // take focus from the currently focused window so key events can be queued. ALOGD_IF(DEBUG_FOCUS, "setFocusedWindow %s on display %" PRId32 " pending, reason: window is not visible", request.windowName.c_str(), displayId); mPendingFocusRequests[displayId] = request; return updateFocusedWindow(displayId, "Waiting for window to be visible", nullptr); } else { ALOGW("setFocusedWindow %s on display %" PRId32 " ignored, reason:%s", request.windowName.c_str(), displayId, NamedEnum::string(result).c_str()); } return std::nullopt; } FocusResolver::FocusResult FocusResolver::isTokenFocusable( const sp<IBinder>& token, const std::vector<sp<InputWindowHandle>>& windows) { bool allWindowsAreFocusable = true; bool visibleWindowFound = false; bool windowFound = false; for (const sp<InputWindowHandle>& window : windows) { if (window->getToken() != token) { continue; } windowFound = true; if (window->getInfo()->visible) { // Check if at least a single window is visible. visibleWindowFound = true; } if (!window->getInfo()->focusable) { // Check if all windows with the window token are focusable. allWindowsAreFocusable = false; break; } } if (!windowFound) { return FocusResult::NO_WINDOW; } if (!allWindowsAreFocusable) { return FocusResult::NOT_FOCUSABLE; } if (!visibleWindowFound) { return FocusResult::NOT_VISIBLE; } return FocusResult::OK; } std::optional<FocusResolver::FocusChanges> FocusResolver::updateFocusedWindow( int32_t displayId, const std::string& reason, const sp<IBinder>& newFocus, const std::string& tokenName) { sp<IBinder> oldFocus = getFocusedWindowToken(displayId); if (newFocus == oldFocus) { return std::nullopt; } if (newFocus) { mFocusedWindowTokenByDisplay[displayId] = {tokenName, newFocus}; } else { mFocusedWindowTokenByDisplay.erase(displayId); } return {{oldFocus, newFocus, displayId, reason}}; } std::string FocusResolver::dumpFocusedWindows() const { if (mFocusedWindowTokenByDisplay.empty()) { return INDENT "FocusedWindows: <none>\n"; } std::string dump; dump += INDENT "FocusedWindows:\n"; for (const auto& [displayId, namedToken] : mFocusedWindowTokenByDisplay) { dump += base::StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s'\n", displayId, namedToken.first.c_str()); } return dump; } std::string FocusResolver::dump() const { std::string dump = dumpFocusedWindows(); if (mPendingFocusRequests.empty()) { return dump + INDENT "PendingFocusRequests: <none>\n"; } dump += INDENT "PendingFocusRequests:\n"; for (const auto& [displayId, request] : mPendingFocusRequests) { dump += base::StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s'\n", displayId, request.windowName.c_str()); } return dump; } } // namespace android::inputdispatcher
services/inputflinger/dispatcher/FocusResolver.h 0 → 100644 +101 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <stdint.h> #include <optional> #include <unordered_map> #include <android/FocusRequest.h> #include <binder/Binder.h> #include <input/InputWindow.h> namespace android::inputdispatcher { // Keeps track of the focused window per display. The class listens to updates from input dispatcher // and provides focus changes. // // Focus Policy // Window focusabilty - A window token can be focused if there is at least one window handle that // is visible with the same token and all window handles with the same token are focusable. // See FocusResolver::isTokenFocusable // // Focus request - Request will be granted if the window is focusable. If the window is not // visible, then the request is kept in a pending state and granted when it becomes visible. // If window becomes not focusable, or another request comes in, the pending request is dropped. // // Window handle updates - Focus is lost when the currently focused window becomes not focusable. class FocusResolver { public: // Returns the focused window token on the specified display. sp<IBinder> getFocusedWindowToken(int32_t displayId) const; struct FocusChanges { sp<IBinder> oldFocus; sp<IBinder> newFocus; int32_t displayId; std::string reason; }; std::optional<FocusResolver::FocusChanges> setInputWindows( int32_t displayId, const std::vector<sp<InputWindowHandle>>& windows); std::optional<FocusResolver::FocusChanges> setFocusedWindow( const FocusRequest& request, const std::vector<sp<InputWindowHandle>>& windows); // exposed for debugging bool hasFocusedWindowTokens() const { return !mFocusedWindowTokenByDisplay.empty(); } std::string dumpFocusedWindows() const; std::string dump() const; private: enum class FocusResult { OK, NO_WINDOW, NOT_FOCUSABLE, NOT_VISIBLE, }; // Checks if the window token can be focused on a display. The token can be focused if there is // at least one window handle that is visible with the same token and all window handles with // the same token are focusable. // // In the case of mirroring, two windows may share the same window token and their visibility // might be different. Example, the mirrored window can cover the window its mirroring. However, // we expect the focusability of the windows to match since its hard to reason why one window // can receive focus events and the other cannot when both are backed by the same input channel. // static FocusResult isTokenFocusable(const sp<IBinder>& token, const std::vector<sp<InputWindowHandle>>& windows); // Focus tracking for keys, trackball, etc. A window token can be associated with one or // more InputWindowHandles. If a window is mirrored, the window and its mirror will share // the same token. Focus is tracked by the token per display and the events are dispatched // to the channel associated by this token. typedef std::pair<std::string /* name */, sp<IBinder>> NamedToken; std::unordered_map<int32_t /* displayId */, NamedToken> mFocusedWindowTokenByDisplay; // This map will store a single pending focus request per display that cannot be currently // processed. This can happen if the window requested to be focused is not currently visible. // Such a window might become visible later, and these requests would be processed at that time. std::unordered_map<int32_t /* displayId */, FocusRequest> mPendingFocusRequests; std::optional<FocusResolver::FocusChanges> updateFocusedWindow( int32_t displayId, const std::string& reason, const sp<IBinder>& token, const std::string& tokenName = ""); std::optional<FocusRequest> getPendingRequest(int32_t displayId); }; } // namespace android::inputdispatcher No newline at end of file