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});

 

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薛文旺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值