天天看點

droid應用程式鍵盤(Keyboard)消息處理機制分析(10)

Step 2. ViewRoot.requestLayout

這個函數定義在frameworks/base/core/java/android/view/ViewRoot.java檔案中:

public final class ViewRoot extends Handler implements ViewParent,  

        View.AttachInfo.Callbacks {  

    ......  

    public void requestLayout() {  

        ......  

        mLayoutRequested = true;  

        scheduleTraversals();  

    }  

}  

        這個函數調用了scheduleTraversals函數來進一步執行操作,由于篇幅關系,我們就不較長的描述scheduleTraversals函數了,簡單來說,在scheduleTraversals函數中,會通過sendEmptyMessage(DO_TRAVERSAL)發送一個消息到應用程式的消息隊列中,這個消息最終由ViewRoot的handleMessage函數處理,而ViewRoot的handleMessage函數把這個消息交給ViewRoot類的performTraversals來處理,在performTraversals函數中,又會調用ViewRoot類的relayoutWindow函數來進一步執行操作,最後在relayoutWindow函數中,就會通過WindowManagerService内部類Session的遠端接口sWindowSession的relayout函數來進入到WindowManagerService中。

        Step 3. WindowManagerService.Session.relayout

        這個函數定義在frameworks/base/services/java/com/android/server/WindowManagerService.java 檔案中:

public class WindowManagerService extends IWindowManager.Stub  

        implements Watchdog.Monitor {  

    private final class Session extends IWindowSession.Stub  

            implements IBinder.DeathRecipient {  

        public int relayout(IWindow window, WindowManager.LayoutParams attrs,  

                int requestedWidth, int requestedHeight, int viewFlags,  

                boolean insetsPending, Rect outFrame, Rect outContentInsets,  

                Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {  

            //Log.d(TAG, ">>>>>> ENTERED relayout from " + Binder.getCallingPid());  

            int res = relayoutWindow(this, window, attrs,  

                    requestedWidth, requestedHeight, viewFlags, insetsPending,  

                    outFrame, outContentInsets, outVisibleInsets, outConfig, outSurface);  

            //Log.d(TAG, "<<<<<< EXITING relayout to " + Binder.getCallingPid());  

            return res;  

        }  

        這個函數隻是簡單地調用WindowManagerService的成員函數relayoutWIndow來進一步處理。

        Step 4. WindowManagerService.relayoutWIndow

    public int relayoutWindow(Session session, IWindow client,  

            WindowManager.LayoutParams attrs, int requestedWidth,  

            int requestedHeight, int viewVisibility, boolean insetsPending,  

            Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,  

            Configuration outConfig, Surface outSurface) {  

        synchronized(mWindowMap) {  

            ......  

            mInputMonitor.updateInputWindowsLw();  

         這個函數又會繼續調用mInputMonitor的updateInputWindowsLw成員函數來更新目前的輸入視窗,mInputMonitor是WindowManagerService的成員變量,它的類型為InputMonitor。

         Step 5. InputMonitor.updateInputWindowsLw

         這個函數定義在frameworks/base/services/java/com/android/server/WindowManagerService.java 檔案中:

    final class InputMonitor {  

        /* Updates the cached window information provided to the input dispatcher. */  

        public void updateInputWindowsLw() {  

            // Populate the input window list with information about all of the windows that  

            // could potentially receive input.  

            // As an optimization, we could try to prune the list of windows but this turns  

            // out to be difficult because only the native code knows for sure which window  

            // currently has touch focus.  

            final ArrayList<WindowState> windows = mWindows;  

            final int N = windows.size();  

            for (int i = N - 1; i >= 0; i--) {  

                final WindowState child = windows.get(i);  

                if (child.mInputChannel == null || child.mRemoved) {  

                    // Skip this window because it cannot possibly receive input.  

                    continue;  

                }  

                ......  

                // Add a window to our list of input windows.  

                final InputWindow inputWindow = mTempInputWindows.add();  

            }  

            // Send windows to native code.  

            mInputManager.setInputWindows(mTempInputWindows.toNullTerminatedArray());  

        這個函數将目前系統中帶有InputChannel的Activity視窗都設定為InputManager的輸入視窗,但是後面我們會看到,隻有目前激活的視窗才會響應鍵盤消息。

        Step 6. InputManager.setInputWindows

        這個函數定義在frameworks/base/services/java/com/android/server/InputManager.java檔案中:

public class InputManager {  

    public void setInputWindows(InputWindow[] windows) {  

        nativeSetInputWindows(windows);  

        這個函數調用了本地方法nativeSetInputWindows來進一步執行操作。

        Step 7. InputManager.nativeSetInputWindows

        這個函數定義在frameworks/base/services/jni/com_android_server_InputManager.cpp 檔案中:

static void android_server_InputManager_nativeSetInputWindows(JNIEnv* env, jclass clazz,  

        jobjectArray windowObjArray) {  

    if (checkInputManagerUnitialized(env)) {  

        return;  

    gNativeInputManager->setInputWindows(env, windowObjArray);  

        這裡的gNativeInputManager我們前面分析InputManager的啟動過程時已經見過了,這是一個本地InputManager對象,通過它進一步設定目前系統的輸入視窗。

本文轉自 Luoshengyang 51CTO部落格,原文連結:xxxxxxx,如需轉載請自行聯系原作者

繼續閱讀