Discuz! Board

标题: 看看wms中间如何处理sensor旋转的时候,屏幕选择的 [打印本页]

作者: zangcf    时间: 2016-5-7 16:03
标题: 看看wms中间如何处理sensor旋转的时候,屏幕选择的
横屏机制

启动横屏应用时的整个逻辑:首先会从WindowManagerService那边获取屏幕的方向,然后再设置到ActivityManagerService中来,最后再启动Window的显示逻辑。

这三个步骤分别对应下面这三个函数(横屏最重要的三个调用函数):


(1). WindowManagerService.updateRotationUncheckedLocked()

(2). ActivityManagerService.updateConfigurationLocked(config, r, false, false)

(3). WindowManagerService.setNewConfiguration(mConfiguration)

这三个函数是配套使用的。对于转屏应用,首先是

我们找一个具体的转屏场景来分析,启动横屏activity。先给出时序图:

[attach]202[/attach]

上图的调用也验证了前面所说的转屏会走的三个步骤。注意一下调用updateOrientationFromAppTokens()函数时,会先调用r.mayFreezeScreenLocked(r.app)函数,这个函数判断该activity是否已经跟目标进程关联,并且关联的进程正常运行,如果满足,那么就将ActivityRecord.appToken作为参数。

step1、WMS.updateOrientationFromAppTokens()


[html] view plain copy



函数简单调用updateOrientationFromAppTokensLocked(),注意传进来的参数,currentConfig是当前的config信息,freezeThisOneIfNeeded就是前面说的ActivityRecord.appToken,继续往下研究。

step2、updateOrientationFromAppTokensLocked()


[html] view plain copy



step3、updateOrientationFromAppTokensLocked(false)

[html] view plain copy






上面的解释的非常清楚这个函数是干嘛的,就是首先从非activity窗口中计算orientation,如果非activity窗口未指定orientation,那么接着从activity窗口中计算orientation。如果计算的orientation跟last不一样,那么首先调用PhoneWindowManager.setCurrentOrientationLw()打开或关闭sensor的listener;接着调用updateRotationUncheckedLocked()做出屏幕转变后WMS侧的处理逻辑。

上面逻辑中第④点中mForcedAppOrientation的赋值非常非常重要,为什么?因为当前启动的应用需要转屏,但是第⑥点中调用updateRotationUncheckedLocked()在很多场景下是无法update orientation的,比如前一个orientation 动画未播完或Rotation被Deferred等,难道就不update orientation了?当然不是,WMS这边在播完orientation动画、resumeRotation、亮屏、等一系列逻辑下会调用updateRotationUnchecked()函数,该函数会完成前面未完成的update orientation工作。看看updateRotationUnchecked()函数:


调用updateRotationUncheckedLocked()函数继续完成WMS侧的update orientation工作,那updateRotationUncheckedLocked()怎么知道之前有过update orientation的需求?看看这个函数中调用mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);就清楚了,mForcedAppOrientation在前面重新赋值过了。哈哈,现在整个逻辑就清楚了,如果应用需要update new orientation,但是此刻WMS侧又无法update orientation成功,那么会在其他逻辑处理完成后调用updateRotationUnchecked()继续把update orientation工作做完,updateRotationUnchecked()函数调用updateRotationUncheckedLocked()更新orientation,如果确实更新了orientation,文章最开始就说了三个步骤缺一不可,第二个跟第三个步骤在哪调用呢?哈哈,就在sendNewConfiguration()中


主动调用AMS的updateConfiguration()函数,updateConfiguration()函数中必然调用了第三个步骤:WindowManagerService.setNewConfiguration(mConfiguration)。

step4、updateRotationUncheckedLocked()

更新 new orientation 到WMS中来,如果更新失败,那么返回false,更新成功则返回true。如果更新失败,那么在其他逻辑完成后调用 updateRotationUnchecked()时会重新update orientation到WMS中来,正如step3中所说的mForcedAppOrientation是个关键变量,保存着request orientation。

这个函数是WMS侧的屏幕旋转逻辑主要处理函数,WMS侧几乎所有的屏幕旋转操作都在此函数中完成。AMS侧自然是updateConfigurationLocked()函数。

1)、PhoneWindowManager.setRotationLw(int rotation)将rotation传到PhoneWindowManager中去


[html] view plain copy



mOrientationListener是一个MyOrientationListener extends WindowOrientationListener类对象,rotation保存在mCurrentRotation中:

[html] view plain copy



总结起来这个函数就是静止灭屏、冻结触摸事件、创建ScreenRotationAnimation对象。难道这就是冻结屏幕???

3)、computeScreenConfigurationLocked(),来分析下。

总结:这个函数其实就是根据mRotation值更新DisplayInfo、config.orientation值。

step5、AMS.updateConfigurationLocked()

先来详细分析下第④点中将config传递到每个应用进程中去ActivityThread.scheduleConfigurationChanged(),这个函数调用ActivityThead.handleConfigurationChanged()进一步处理

再来分析下第⑦点中调用的ActivityStack.ensureActivityConfigurationLocked()函数。

















作者: zangcf    时间: 2016-5-7 16:09
标题: Android4.1 关于Rotation相关的Configuration整体分析2

这篇文章继续当旋转手机的时候,系统会做什么操作去通知Activity要旋转界面了。

在上一篇文章中我们看到如果我们在Settings选中了“Auto-rotate”的时候,PhoneWindowManager调用updateOrientationListenerLp去SensorManager里面去注册一个Listener,这样当Sensor发生变化的时候,PhoneWindowManager就可以监听到并且调用回调onProposeRotationChanged。

1. MyOrientationListener.onProposeRotationChange


[java] view plain copy




2. PhoneWindowManager.updateRotation(boolean alwaysSendConfiguration)

    注意上面传下来的alwaysSendConfiguration是false。


[java] view plain copy




3. WindowManagerService.updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout)

    alwaysSendConfiguration = false;

    forceRelayout = false;

    updateRotation中直接调用了updateRotatinUnchecked(false, false);

    1. 在updateRotatinUnchecked中先通过updateRotationUncheckedLocked(false) 去检测是否Rotation发生改变了。

    2. performLayoutAndPlaceSurfacesLocked();  //这个函数太复杂....

    3. 如果Rotation发生变化了或者alwaysSendConfiguration为true,就sendNewConfiguration给AMS。


[java] view plain copy






[java] view plain copy




3.1 WindowManagerService.updateRotationUncheckedLocked(boolean inTransaction)  // inTrasaction = false

     1. 请求mPolicy.rotationForOrientationLw去获取当前的rotation

     2. 如果发现当然的mRotation与刚才取出来的rotation是一样的并且mAltOrientation跟刚才取出来的altOrientation是一样就返回false

         要不然就 rotation,altOrientation放在mRotation和mAltOrientation 中保存起来;

     3. mPolicy.setRotationLw(mRotation); 把mRotation保存在mOrientationListener的mCurrentRotation中。

     4. computeScreenConfigurationLocked()调用这个函数主要是更新Screen size的信息,包括Rotation啊,width,height...

     5. mDisplayManagerService.performTraversalInTransactionFromWindowManager();

     6. 遍历所有windows,把有Surface的Window的mOrientationChanging设为true.


[java] view plain copy




3.1.1 PhoneWindowManager.rotationForOrientationLw(int orientation, int lastRotation)

  1.  通过mOrientationListener.getPropsoeRotation() 从Sensor那边获取建议的Rotation,返回给sensorRotation.

  2.  定义一个perferredRotation,然后根据一系列的判断条件找到一个符合条件的Rotation赋值给perferredRotation,

  3. 然后再根据传进来的应用程序自己设定的orientation,如果有设定强制哪种横竖屏方式就直接返回与横竖屏对应的Rotation,如果没有强制设定,默认就返回perferredRotation。


[java] view plain copy




3.2 WindowManagerService.performLayoutAndPlaceSurfacesLocked()

      1. 在performLayoutAndPlaceSurfacesLocked中就调用了一次performLayoutAndPlaceSurfacesLockedLoop()


[java] view plain copy





3.3 WindowManagerService.sendNewConfiguration()

    1. 去调AMS的updateConfiguration.



[java] view plain copy




3.3.1 updateConfigurationLocked(Configuration values, ActivityRecord starting, boolean persistent, boolean initLocale)

      先通过mWindowManager.computeNewConfiguration(); 去获取WMS中最新的configuration,然后通过mSystemThread.applyConfigurationToResources(configCopy);去更新AMS所在进程资源。


  1. 通过app.thread.scheduleConfigurationChanged(configCopy); 给让每个进程去update configuration

  2. 发送一个Intent.ACTION_CONFIGURATION_CHANGED的broadcast出去。

  3. starting = mMainStack.topRunningActivityLocked(null);

      kept = mMainStack.ensureActivityConfigurationLocked(starting, changes);
      mMainStack.ensureActivitiesVisibleLocked(starting, changes);


[java] view plain copy




3.3.1.1 ActivityThread.handleConfigurationChanged()

    1.  applyConfigurationToResourcesLocked(config, compat);  // 更新该进程的资源相关的东西

    2.  performConfigurationChanged() // 调用callback的onConfigurationChanged


[java] view plain copy





3.3.1.3 ActivityStack.ensureActivityConfigurationLocked(ActivityRecord r, int globalChanges)



[java] view plain copy





作者: zangcf    时间: 2016-5-7 16:38
1. 如果要强制设置一个Activity的横竖屏可以通过Manifest去设置,跟Activity相关的信息都会保存在ActivityInfo当中。
[html] view plain copy
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。
[html] view plain copy
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的时候其作用。
[java] view plain copy
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);  
[java] view plain copy
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。
[java] view plain copy
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。
[java] view plain copy
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相关的东西,大多都在这个函数中进行。
[java] view plain copy
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。
[java] view plain copy
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的。
[java] view plain copy
public void setCurrentOrientationLw(int newOrientation) {  
    synchronized (mLock) {  
        if (newOrientation != mCurrentAppOrientation) {  
            mCurrentAppOrientation = newOrientation;  
            updateOrientationListenerLp();  
        }  
    }  
}  

3.2.3 WMS. computeNewConfiguration()
      通过computeNewConfigurationLocked() 计算出一个新的configuration.
[java] view plain copy
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的条件。不过一般都不会满足这个条件。
[java] view plain copy
    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端。
[java] view plain copy
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();
[java] view plain copy
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();
[java] view plain copy
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




欢迎光临 Discuz! Board (http://47.89.242.157:9000/bbs/discuz/) Powered by Discuz! X3.2