Android焦点之FocusWindow切换流程
关键调用是setInputWindows
InputDispatcher::dispatchFocusLocked:在这里打印日志"Focus entering" 或 "Focus leaving"
SurfaceFlinger::updateInputFlinger
notifyWindowInfos();
mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, mInputWindowCommands.syncInputWindows);
@frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
listener->onWindowInfosChanged(windowInfos, shouldSync ? mWindowInfosReportedListener : nullptr);
setInputWindows(handlesPerDisplay);
InputDispatcher::setInputWindowsLocked
// 对每一个windowInfo进行判断和处理
//更新mWindowHandlesByDisplay这个map,然后通过getWindowHandlesLocked()找newFocusedWindowHandle
updateWindowHandlesForDisplayLocked(windowInfoHandles, displayId);
std::vector<sp<WindowInfoHandle>> newHandles;
newHandles.push_back(handle);
mWindowHandlesByDisplay[displayId] = newHandles;
const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
auto it = mWindowHandlesByDisplay.find(displayId);
return it != mWindowHandlesByDisplay.end() ? it->second : EMPTY_WINDOW_HANDLES;
@frameworks/native/services/inputflinger/dispatcher/FocusResolver.cpp
// 对FocusChanges进行处理,同步给FocusResolver来更新窗口状态
std::optional<FocusResolver::FocusChanges> changes = mFocusResolver.setInputWindows(displayId, windowHandles);
//当窗口属性更改时,将调用“setInputWindows”。这里我们将检查当前聚焦的窗口是否可以保持聚焦
//如果当前聚焦的窗口仍然有资格获得焦点(“isTokenFocusable”返回 OK),那么我们将继续授予它焦点
const sp<IBinder> currentFocus = getFocusedWindowToken(displayId); // 获取当前的焦点窗口
const std::optional<FocusRequest> request = getFocusRequest(displayId); //请求焦点,WMS把focusRequest发给surfaceFlinger,surfaceFlinger传递到这里。
// 根据最新的 FocusRequest 查找下一个焦点令牌。如果请求的焦点窗口无法获得焦点,则焦点将被移除。
if (request) {
const Focusability result = isTokenFocusable(requestedFocus, windows);
// 遍历InputDispatcher中保存的所有窗口信息
for (const sp<WindowInfoHandle>& window : windows) {
if (window->getToken() != token) { continue; } // 一直走这个分支的话,就是找不到目标窗口
windowFound = true;
if (window->getInfo()->visible) { visibleWindowFound = true; } // 窗口可见的
if (!window->getInfo()->focusable) { allWindowsAreFocusable = false; } //窗口就是不能获取焦点
// 根据前面的遍历查找结果设置焦点窗口状态
if (!windowFound) { return Focusability::NO_WINDOW; }
if (!allWindowsAreFocusable) { return Focusability::NOT_FOCUSABLE; }
if (!visibleWindowFound) { return Focusability::NOT_VISIBLE; }
return Focusability::OK; // 仅当窗口可以聚焦时才ok
if (result == Focusability::OK) { //只有获取的状态为ok
// 如果可以获取焦点,则更新焦点窗口
return updateFocusedWindow(displayId, "Window became focusable. Previous reason: " + NamedEnum::string(previousResult), requestedFocus, request->windowName);
// 无法获取焦点,则焦点为空
return updateFocusedWindow(displayId, removeFocusReason, nullptr);
if (changes) { onFocusChangedLocked(*changes); } //Focus entering 5e40cef org.mozilla.firefox/org.mozilla.fenix.HomeActivity (server), reason=Window became focusable. Previous reason: NOT_VISIBLE
enqueueFocusEventLocked(changes.newFocus, true /*hasFocus*/, changes.reason);
@frameworks/native/services/inputflinger/InputManager.cpp
for (const auto& focusRequest : mInputWindowCommands.focusRequests) { mInputFlinger->setFocusedWindow(focusRequest); }
/* 将焦点设置到由标记标识的窗口。必须在更新任何输入窗口句柄后调用此函数。Params:
* request.token - 输入通道令牌用于标识应该获得焦点的窗口
* request.focusedToken - 调用者期望当前关注的令牌。如果指定的令牌与当前聚焦的窗口不匹配,则该请求将被丢弃。
* 如果指定的焦点标记与当前焦点窗口匹配,则调用将成功。如果无论当前聚焦的令牌是什么,此调用都应该成功,则将其设置为“null”
* request.timestamp - 请求焦点更改时客户端 (wm) 设置的 SYSTEM_TIME_MONOTONIC 时间戳(以纳秒为单位)。如果存在来自另一个源(例如指针向下)的焦点更改请求,这将确定哪个请求优先。*/
mDispatcher->setFocusedWindow(request);
@frameworks/native/services/inputflinger/dispatcher/FocusResolver.cpp
//当窗口属性更改时,将调用“setInputWindows”。这里我们将检查当前聚焦的窗口是否可以保持聚焦
//如果当前聚焦的窗口仍然有资格获得焦点(“isTokenFocusable”返回 OK),那么我们将继续授予它焦点,否则我们将检查先前的焦点请求是否有资格获得焦点。
std::optional<FocusResolver::FocusChanges> changes = mFocusResolver.setFocusedWindow(request, getWindowHandlesLocked(request.displayId));
const sp<IBinder> currentFocus = getFocusedWindowToken(displayId); // 获取当前的焦点窗口
mFocusRequestByDisplay[displayId] = request; //赋值mFocusRequestByDisplay
if (changes) { onFocusChangedLocked(*changes); } //Focus leaving 9fd3baa org.mozilla.firefox/org.mozilla.fenix.HomeActivity (server), reason=Waiting for window because NO_WINDOW
if (changes.newFocus) { enqueueFocusEventLocked(changes.newFocus, true /*hasFocus*/, changes.reason); }
//该事件应该位于队列的前面,但位于所有其他焦点事件之后,找到最后一个焦点事件,并在其后面插入mInboundQueue队列
std::deque<std::shared_ptr<EventEntry>>::reverse_iterator it = std::find_if(mInboundQueue.rbegin(), mInboundQueue.rend(), [](const std::shared_ptr<EventEntry>& event) { return event->type == EventEntry::Type::FOCUS; });
// 维护焦点事件的顺序。在所有其他焦点事件之后插入条目
mInboundQueue.insert(it.base(), std::move(focusEntry));
InputDispatcher::dispatchOnce
dispatchOnceInnerLocked(&nextWakeupTime);
mPendingEvent = mInboundQueue.front();
case EventEntry::Type::FOCUS: {
//关键log"Focus entering" 或 "Focus leaving" 打印地方
dispatchFocusLocked(currentTime, typedEntry);
std::string message = std::string("Focus ") + (entry->hasFocus ? "entering " : "leaving ") + channel->getName();
std::string reason = std::string("reason=").append(entry->reason);
android_log_event_list(LOGTAG_INPUT_FOCUS) << message << reason << LOG_ID_EVENTS;
dispatchEventLocked(currentTime, entry, {target});
原文地址:https://blog.csdn.net/wenwang88/article/details/140463011
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!