Android4.1 關於Rotation相關的Configuration整體分析3


1. 如果要強制設置一個Activity的橫豎屏可以通過Manifest去設置,跟Activity相關的信息都會保存在ActivityInfo當中。

android:screenOrientation=["unspecified" | "user" | "behind" |
                                     "landscape" | "portrait" |
                                     "reverseLandscape" | "reversePortrait" |
                                     "sensorLandscape" | "sensorPortrait" |
                                     "sensor" | "fullSensor" | "nosensor"]
    這個screenOrientation會保存在ActivityInfo.screenOrientation中,而且這個值也會在wm.addView(decor, l);的時候傳遞到WMS中。

2. 如果是要強制設置一個Window的橫豎屏可以通過 LayoutParams.screenOrientation來設置。在通過WindowManager.addView的時候把對應的LayoutParams傳遞給WMS。

WindowManager.LayoutParams.screenOrientation

  

3. 關於需要轉屏的兩種情況

  Activity -- 啓動一個有設置screenOrientation的Activity

3.1 將ActivityRecord中的AppToken添加添加到WMS中

        在ActivityStack.startActivityLocked中,AMS會把ActivityRecord相關的Token加到WMS中,有且僅在這個方法中。這時候會把screenOrientation傳遞過去。

        atoken.requestedOrientation = requestedOrientation; 這個AppToken會在WMS獲取相關App Orientation的時候其作用。

mService.mWindowManager.addAppToken(addPos, r.userId, r.appToken,
                                r.task.taskId, r.info.screenOrientation, r.fullscreen,
                                (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
    public void addAppToken(int addPos, int userId, IApplicationToken token,
            int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked) {
        ... ...
        synchronized(mWindowMap) {
            AppWindowToken atoken = findAppWindowToken(token.asBinder());
            if (atoken != null) {
                Slog.w(TAG, "Attempted to add existing app token: " + token);
                return;
            }
            atoken = new AppWindowToken(this, userId, token);
            atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
            atoken.groupId = groupId;
            atoken.appFullscreen = fullscreen;
            atoken.showWhenLocked = showWhenLocked;
            atoken.requestedOrientation = requestedOrientation;
            if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
                    + " at " + addPos);
            mAppTokens.add(addPos, atoken);
            addAppTokenToAnimating(addPos, atoken);
            mTokenMap.put(token.asBinder(), atoken);

            // Application tokens start out hidden.
            atoken.hidden = true;
            atoken.hiddenRequested = true;

            //dump();
        }
    }

3.2 在啓動Activity之前去獲取當前WMS中的Orientation的Config

      在resumeTopActivityLocked和realStartActivityLocked中回去獲取最新的Orientation的config

       1. 通過mWindowManager.updateOrientationFromAppTokens去更新當前WMS中的Orientation值,把WMS中的config返回給AMS  //goto 3.2.1

       2. 通過updateConfigurationLocked去更新AMS中的config,發給每一個ActiviytThread

                synchronized (mService) {
                    Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
                            mService.mConfiguration,
                            next.mayFreezeScreenLocked(next.app) ? next.appToken : null);
                    if (config != null) {
                        next.frozenBeforeDestroy = true;
                    }
                    updated = mService.updateConfigurationLocked(config, next, false, false);
                }

3.2.1 WMS.updateOrientationFroemAppTokens 會直接去調updateOrientationFromAppTokensLocked

          1. 去調用updateOrientationFromAppTokensLocked(false) 做真正的update Orientation的工作,如果返回是true,說明方向發生了變化,就需要去做app的轉屏動作。

          2. 如果freezeThisOneIfNeed不爲null,說明要做屏幕的轉屏操做,就會把當前的atoken freeze掉。

          3. computeNewConfigurationLocked()  計算當前的Configuration,然後返回給AMS。

    private Configuration updateOrientationFromAppTokensLocked(
            Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
        Configuration config = null;

        if (updateOrientationFromAppTokensLocked(false)) {
            if (freezeThisOneIfNeeded != null) {
                AppWindowToken atoken = findAppWindowToken(
                        freezeThisOneIfNeeded);
                if (atoken != null) {
                    startAppFreezingScreenLocked(atoken,
                            ActivityInfo.CONFIG_ORIENTATION);
                }
            }
            config = computeNewConfigurationLocked();

        } else if (currentConfig != null) {
            // No obvious action we need to take, but if our current
            // state mismatches the activity manager's, update it,
            // disregarding font scale, which should remain set to
            // the value of the previous configuration.
            mTempConfiguration.setToDefaults();
            mTempConfiguration.fontScale = currentConfig.fontScale;
            if (computeScreenConfigurationLocked(mTempConfiguration)) {
                if (currentConfig.diff(mTempConfiguration) != 0) {
                    mWaitingForConfig = true;
                    getDefaultDisplayContentLocked().layoutNeeded = true;
                    startFreezingDisplayLocked(false, 0, 0);
                    config = new Configuration(mTempConfiguration);
                }
            }
        }

        return config;
    }

3.2.1.1   updateOrientationFromAppTokensLocked 會查找出當前是否有需要強制Orientation的App或者Window
         1. computeForcedAppOrientationLocked  //goto 3.2.1.1.1

         2. 如果ForcedAppOrientation發生了變化, 就會去通知WindowPolicy去設置當前的Sensor的狀態。//goto 3.2.1.1.2

         3. updateRotationUncheckedLocked(inTransaction),由於Orientation可能發生變化,所以需要去重新獲取一下Rotation;具體就可以參照前一節了。

             如果Rotation發生了變化就返回true。跟configuration相關的東西,大多都在這個函數中進行。

    boolean updateOrientationFromAppTokensLocked(boolean inTransaction) {
        long ident = Binder.clearCallingIdentity();
        try {
            int req = computeForcedAppOrientationLocked();

            if (req != mForcedAppOrientation) {
                mForcedAppOrientation = req;
                //send a message to Policy indicating orientation change to take
                //action like disabling/enabling sensors etc.,
                mPolicy.setCurrentOrientationLw(req);
                if (updateRotationUncheckedLocked(inTransaction)) {
                    // changed
                    return true;
                }
            }

            return false;
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }


3.2.1.1.1 computeForcedAppOrientationLocked

     這個函數的作用就是去查詢當前即將要顯示的Activity或者Window有沒有需要強制Orientation的

     1. 先通過 getOrientationFromWindowsLocked去遍歷WMS中的WindowList。

          1)如果在最上面的Window是一個AppWindow就直接返回mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED

          2)如果不是AppWindow,判斷這個Window是否可見,如果不可見就continue

          3)最後如果這個Window既不是AppWindow又要是可見的,並且他是有指定ScreenOrientation的,就返回這個window的orientatin。mLastWindowForcedOrientation=req

    2. 如果getOrientationFromWindowsLocked找到的是一個AppWindow或者當前沒有指定Orientation的Window,就會走到getOrientationFromAppTokensLocked();

        1)這個函數會去遍歷AppWindowToken List去查找需要強制Orientation的Token,這個時候就是根據我們之前在AMS中傳遞進來的atoken.requestedOrientation;來進行判斷,如果設置了就返回回去給req。

    int computeForcedAppOrientationLocked() {
        int req = getOrientationFromWindowsLocked();
        if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
            req = getOrientationFromAppTokensLocked();
        }
        if (mForceLandScape &&
                req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
            req = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
        }
        return req;
    }


3.2.1.1.2 PhoneWindowManager.setCurrentOrientationLw()

     1. 用mCurrentAppOrientation保存當前新的Orientation.

     2. updateOrientationListenerLp,通過名字就知道他只是去管理是否啓動Sensor Listener的。

    public void setCurrentOrientationLw(int newOrientation) {
        synchronized (mLock) {
            if (newOrientation != mCurrentAppOrientation) {
                mCurrentAppOrientation = newOrientation;
                updateOrientationListenerLp();
            }
        }
    }

3.2.3 WMS. computeNewConfiguration()

      通過computeNewConfigurationLocked() 計算出一個新的configuration.

    public Configuration computeNewConfiguration() {
        synchronized (mWindowMap) {
            Configuration config = computeNewConfigurationLocked();
            if (config == null && mWaitingForConfig) {
                // Nothing changed but we are waiting for something... stop that!
                mWaitingForConfig = false;
                performLayoutAndPlaceSurfacesLocked();
            }
            return config;
        }
    }


3.3 AMS端的工作完成之後,就到ActivityThread和ViewRootImpl的工作了

     3.3.1 在ActivityThread的handleResume的時候會把Activity對應的DectorView加到WMS中,在WMS中會調用addWindow. 如果我們自己添加一個Window的話也是走到這邊。

               在AddWindow的時候有可能對Orietation和Configuration

              前提是這個win的isVisibleOrAdding的條件。不過一般都不會滿足這個條件。

            if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
                reportNewConfig = true;
            }
        }

        if (reportNewConfig) {
            sendNewConfiguration();
        }

3.3.2 當addWindow完成之後,ViewRootImpl就會去requestLayout,而requestLayout實際上就是去做scheduleTraversals 

             1. 在performTraversals中會先去做一次measureHierarchy計算一下View所需的大小。

             2. 然後會調用relayoutWindow去請求WMS幫助實際計算當前Window的佈局,創建一個Surface,並且返回對應的Frame。


3.3.2.2 WMS.relayoutWindow()

       1. 根據傳進來的requestWidth和requestHeight 或者attrChange的變化來決定是不是真的要relayout,並且把win.mLayoutNeeded設置爲true。在performLayoutAndPlaceSurfacesLocked的會根據這個值做判斷。

       2. 如果當前的WindowState還沒有Surface就調用 winAnimator.createSurfaceLocked();去創建一個Surface會帶回給ViewRootImpl

       3. 如果focus window發生變化了就updateFocusedWindowLocked

           如果Layer變化了就調用assignLayersLocked

       4. 再次調用updateOrientationFromAppTokensLocked去判斷當前的Orietation是不是發生變化了。//在這個調用中如果有Orientation發生了變化,如果有變化就會調用computeNewConfigurationLocked()去更新DisplayContent相關的信息並且計算出一個新的Configuration

       5. 調用performLayoutAndPlaceSurfacesLocked

       6. 把WindowState中的三個Frame返回給Client端。

    public int relayoutWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int requestedWidth,
            int requestedHeight, int viewVisibility, int flags,
            Rect outFrame, Rect outContentInsets,
            Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
        boolean toBeDisplayed = false;
        boolean inTouchMode;
        boolean configChanged;
        boolean surfaceChanged = false;
        boolean animating;
        ... ...
        synchronized(mWindowMap) {
            // TODO(cmautner): synchronize on mAnimator or win.mWinAnimator.
            WindowState win = windowForClientLocked(session, client, false);
            ... ...
            WindowStateAnimator winAnimator = win.mWinAnimator;
            if (win.mRequestedWidth != requestedWidth
                    || win.mRequestedHeight != requestedHeight) {
                win.mLayoutNeeded = true;
                win.mRequestedWidth = requestedWidth;
                win.mRequestedHeight = requestedHeight;
            }
            if (attrs != null && seq == win.mSeq) {
                win.mSystemUiVisibility = systemUiVisibility;
            }

            if (attrs != null) {
                mPolicy.adjustWindowParamsLw(attrs);
            }

            winAnimator.mSurfaceDestroyDeferred =
                    (flags&WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY) != 0;

            int attrChanges = 0;
            int flagChanges = 0;
            if (attrs != null) {

                flagChanges = win.mAttrs.flags ^= attrs.flags;
                attrChanges = win.mAttrs.copyFrom(attrs);
                if ((attrChanges & (WindowManager.LayoutParams.LAYOUT_CHANGED
                        | WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) {
                    win.mLayoutNeeded = true;
                }
            }
            ... ...
            if (viewVisibility == View.VISIBLE &&
                    (win.mAppToken == null || !win.mAppToken.clientHidden)) {
                toBeDisplayed = !win.isVisibleLw();

    
                if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
                    // To change the format, we need to re-build the surface.
                    winAnimator.destroySurfaceLocked(false);
                    toBeDisplayed = true;
                    surfaceChanged = true;
                }
                try {
                    if (!win.mHasSurface) {
                        surfaceChanged = true;
                    }
                    Surface surface = winAnimator.createSurfaceLocked();
                    if (surface != null) {
                        outSurface.copyFrom(surface);
                        if (SHOW_TRANSACTIONS) Slog.i(TAG,
                                "  OUT SURFACE " + outSurface + ": copied");
                    } else {
                        // For some reason there isn't a surface.  Clear the
                        // caller's object so they see the same state.
                        outSurface.release();
                    }
                } catch (Exception e) {

                }
                if (toBeDisplayed) {
                    focusMayChange = isDefaultDisplay;
                }
                if (win.mAttrs.type == TYPE_INPUT_METHOD
                        && mInputMethodWindow == null) {
                    mInputMethodWindow = win;
                    imMayMove = true;
                }
                if (win.mAttrs.type == TYPE_BASE_APPLICATION
                        && win.mAppToken != null
                        && win.mAppToken.startingWindow != null) {
                    // Special handling of starting window over the base
                    // window of the app: propagate lock screen flags to it,
                    // to provide the correct semantics while starting.
                    final int mask =
                        WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                        | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
                        | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
                    WindowManager.LayoutParams sa = win.mAppToken.startingWindow.mAttrs;
                    sa.flags = (sa.flags&~mask) | (win.mAttrs.flags&mask);
                }
            } else {
                winAnimator.mEnterAnimationPending = false;
                if (winAnimator.mSurface != null) {
                    if (DEBUG_VISIBILITY) Slog.i(TAG, "Relayout invis " + win
                            + ": mExiting=" + win.mExiting);
                    // If we are not currently running the exit animation, we
                    // need to see about starting one.
                    if (!win.mExiting) {
                        surfaceChanged = true;
                        // Try starting an animation; if there isn't one, we
                        // can destroy the surface right away.
                        int transit = WindowManagerPolicy.TRANSIT_EXIT;
                        if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
                            transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
                        }
                        if (win.isWinVisibleLw() &&
                                winAnimator.applyAnimationLocked(transit, false)) {
                            focusMayChange = isDefaultDisplay;
                            win.mExiting = true;
                        } else if (win.mWinAnimator.isAnimating()) {
                            // Currently in a hide animation... turn this into
                            // an exit.
                            win.mExiting = true;
                        } else if (win == mWallpaperTarget) {
                            // If the wallpaper is currently behind this
                            // window, we need to change both of them inside
                            // of a transaction to avoid artifacts.
                            win.mExiting = true;
                            win.mWinAnimator.mAnimating = true;
                        } else {
                            if (mInputMethodWindow == win) {
                                mInputMethodWindow = null;
                            }
                            winAnimator.destroySurfaceLocked(false);
                        }
                        scheduleNotifyWindowTranstionIfNeededLocked(win, transit);
                    }
                }

                outSurface.release();
                if (DEBUG_VISIBILITY) Slog.i(TAG, "Releasing surface in: " + win);
            }

            if (focusMayChange) {
                //System.out.println("Focus may change: " + win.mAttrs.getTitle());
                if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
                        false /*updateInputWindows*/)) {
                    imMayMove = false;
                }
                //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus);
            }

            // updateFocusedWindowLocked() already assigned layers so we only need to
            // reassign them at this point if the IM window state gets shuffled
            boolean assignLayers = false;
            ... ...
            if (assignLayers) {
                assignLayersLocked(win.getWindowList());
            }
            configChanged = updateOrientationFromAppTokensLocked(false);
            performLayoutAndPlaceSurfacesLocked();
            if (toBeDisplayed && win.mIsWallpaper) {
                DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
                updateWallpaperOffsetLocked(win,
                        displayInfo.appWidth, displayInfo.appHeight, false);
            }
            if (win.mAppToken != null) {
                win.mAppToken.updateReportedVisibilityLocked();
            }
            outFrame.set(win.mCompatFrame);
            outContentInsets.set(win.mContentInsets);
            outVisibleInsets.set(win.mVisibleInsets);
            ... ...

            mInputMonitor.updateInputWindowsLw(true /*force*/);

        }

        if (configChanged) {
            sendNewConfiguration();
        }

3.3.2.2.6 WMS.performLayoutAndPlaceSurfacesLocked

                WMS.performLayoutAndPlaceSurfacesLockedLoop()

        performLayoutAndPlaceSurfacesLocked直接去調performLayoutAndPlaceSurfacesLockedLoop, 在performLayoutAndPlaceSurfacesLockedLoop裏面做兩個最主要的操作。

        1. performLayoutAndPlaceSurfacesLockedInner();

        2. requestTraversalLocked();

    private final void performLayoutAndPlaceSurfacesLockedLoop() {
        ... ...

        mInLayout = true;
        boolean recoveringMemory = false;
        ... ...        
        try {
            performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);

            mInLayout = false;

            if (needsLayout()) {
                if (++mLayoutRepeatCount < 6) {
                    requestTraversalLocked();
                } else {
                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
                    mLayoutRepeatCount = 0;
                }
            } else {
                mLayoutRepeatCount = 0;
            }

            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
                mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
                mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE));
            }
        } catch (RuntimeException e) {
            mInLayout = false;
            Log.wtf(TAG, "Unhandled exception while laying out windows", e);
        }

        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
    }

3.3.2.2.6.1 WMS.performLayoutAndPlaceSurfacesLockedInner(false)

         1. 首先會獲取當前的一個DsiplayContent,由於這個DisplayContent在updateOrientationFromAppTokensLocked的時候已經根據最新的window狀態進行跟新過,所以現在的DsiplayContent應該是最新的值。

         2. performLayoutLockedInner; 這個函數回去遍歷每一個Window,然後根據當前的DisplayContent去更新Layout.             

              這個方法會根據最新的DisplayContent去判斷所有的window是否需要重新layout

              第一步,通過mPolicy.beginLayoutLw去給policy設置一個標準把當前的Content信息設置進去

              第二步, mPolicy.layoutWindowLw(win, win.mAttrs, null); 給win做真正的layout,layout主要做了什麼?有幾個重要的變量?

                               在layoutWindow中會通過computeFrameLw去計算WindowState的中的Frame,有三個Frame;

         3. updateResizingWindows(w);

              如果WindowState其中的w.mContentInsetsChanged || w.mVisibleInsetsChanged  || winAnimator.mSurfaceResized|| configChanged 任意的一個發生變化了就會加入到mResizingWindows數組中。並且把對應的Window Freezing。

         4. 遍歷mResizingWindows, 調用win.mClient.resized通過IPC告訴Clinet端要做resize

             最終ViewRootImpl就會發送一個MSG_RESIZED去處理,WMS會把裏面的三個Frame和Configuration發回給Clinet。ViewRoot會保存最新的三個Frame和updateConfiguration,最後 requestLayout();

   private final void performLayoutAndPlaceSurfacesLockedInner(boolean recoveringMemory) {
        ... ...
        Surface.openTransaction();
        try {

            boolean focusDisplayed = false;
            boolean updateAllDrawn = false;

            DisplayContentsIterator iterator = new DisplayContentsIterator();
            while (iterator.hasNext()) {
                final DisplayContent displayContent = iterator.next();
                WindowList windows = displayContent.getWindowList();
                DisplayInfo displayInfo = displayContent.getDisplayInfo();
                final int displayId = displayContent.getDisplayId();
                final int dw = displayInfo.logicalWidth;
                final int dh = displayInfo.logicalHeight;
                final int innerDw = displayInfo.appWidth;
                final int innerDh = displayInfo.appHeight;
                final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);

                // Reset for each display unless we are forcing mirroring.
                if (mInnerFields.mDisplayHasContent != LayoutFields.DISPLAY_CONTENT_MIRROR) {
                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN;
                }
                ... ...
                int repeats = 0;
                do {
                    repeats++;
                    ... ...
                    // FIRST LOOP: Perform a layout, if needed.
                    if (repeats < 4) {
                        performLayoutLockedInner(displayContent, repeats == 1,
                                false /*updateInputWindows*/);
                    } else {
                        Slog.w(TAG, "Layout repeat skipped after too many iterations");
                    }
                    ... ...
                } while (displayContent.pendingLayoutChanges != 0);

                // Only used if default window
                final boolean someoneLosingFocus = !mLosingFocus.isEmpty();

                final int N = windows.size();
                for (i=N-1; i>=0; i--) {
                    WindowState w = windows.get(i);
                    ... ...

                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
                    w.mContentChanged = false;

                    // Moved from updateWindowsAndWallpaperLocked().
                    if (w.mHasSurface) {
                        // Take care of the window being ready to display.
                        ... ...
                        }
                        ... ...
                        }
                    }

                    if (isDefaultDisplay && someoneLosingFocus && (w == mCurrentFocus)
                            && w.isDisplayedLw()) {
                        focusDisplayed = true;
                    }

                    updateResizingWindows(w);
                }

          ... ...

        for (i = mResizingWindows.size() - 1; i >= 0; i--) {
            WindowState win = mResizingWindows.get(i);
            if (win.mAppFreezing) {
                // Don't remove this window until rotation has completed.
                continue;
            }
            final WindowStateAnimator winAnimator = win.mWinAnimator;
            try {
                if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
                        "Reporting new frame to " + win + ": " + win.mCompatFrame);
                int diff = 0;
                boolean configChanged = win.isConfigChanged();
                if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
                        && configChanged) {
                    Slog.i(TAG, "Sending new config to window " + win + ": "
                            + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
                            + " / " + mCurConfiguration + " / 0x"
                            + Integer.toHexString(diff));
                }
                win.setConfiguration(mCurConfiguration);
                if (DEBUG_ORIENTATION &&
                        winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
                        TAG, "Resizing " + win + " WITH DRAW PENDING");
                win.mClient.resized(win.mFrame, win.mLastContentInsets, win.mLastVisibleInsets,
                        winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
                        configChanged ? win.mConfiguration : null);
                win.mContentInsetsChanged = false;
                win.mVisibleInsetsChanged = false;
                winAnimator.mSurfaceResized = false;
            } catch (RemoteException e) {
                win.mOrientationChanging = false;
            }
            mResizingWindows.remove(i);
        }

        ... ...

        // Finally update all input windows now that the window changes have stabilized.
        mInputMonitor.updateInputWindowsLw(true /*force*/);
        ... ...
        }

        // Check to see if we are now in a state where the screen should
        // be enabled, because the window obscured flags have changed.
        enableScreenIfNeededLocked();

        updateLayoutToAnimationLocked();
        ... ...
    }

在WindowState中有幾個Frame

    // "Real" frame that the application sees, in display coordinate space.
    final Rect mFrame = new Rect();
    final Rect mLastFrame = new Rect();
    // Frame that is scaled to the application's coordinate space when in
    // screen size compatibility mode.
    final Rect mCompatFrame = new Rect();


    final Rect mContainingFrame = new Rect();
    final Rect mDisplayFrame = new Rect();
    final Rect mContentFrame = new Rect();
    final Rect mParentFrame = new Rect();
    final Rect mVisibleFrame = new Rect();




     Window

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章