Discuz! Board

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2|回复: 2
打印 上一主题 下一主题

看看wms中间如何处理sensor旋转的时候,屏幕选择的

[复制链接]

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
跳转到指定楼层
楼主
发表于 2016-5-7 16:03:53 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
横屏机制

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

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


(1). WindowManagerService.updateRotationUncheckedLocked()

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

(3). WindowManagerService.setNewConfiguration(mConfiguration)

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

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

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

step1、WMS.updateOrientationFromAppTokens()


[html] view plain copy


  • public Configuration updateOrientationFromAppTokens(  
  •         Configuration currentConfig, IBinder freezeThisOneIfNeeded) {  
  •     if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,  
  •             "updateOrientationFromAppTokens()")) {  
  •         throw new SecurityException("Requires MANAGE_APP_TOKENS permission");  
  •     }  
  •   
  •     Configuration config = null;  
  •     long ident = Binder.clearCallingIdentity();  
  •   
  •     synchronized(mWindowMap) {  
  •         config = updateOrientationFromAppTokensLocked(currentConfig,  
  •                 freezeThisOneIfNeeded);   
  •     }  
  •   
  •     Binder.restoreCallingIdentity(ident);  
  •     return config;  
  • }  

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

step2、updateOrientationFromAppTokensLocked()


[html] view plain copy


  • private Configuration updateOrientationFromAppTokensLocked(  
  •         Configuration currentConfig, IBinder freezeThisOneIfNeeded) {  
  •     Configuration config = null;  
  •   
  •     if (updateOrientationFromAppTokensLocked(false)) {   //①满足这个条件是很苛刻的:从函数名就可以看出来是从可见的应用窗口获取orientation,并且orientation与last orientation不同,同时还必须将new orientation成功update到WMS中,也就是updateRotationUncheckedLocked()也要返回TRUE;  
  •         if (freezeThisOneIfNeeded != null) {  
  •             AppWindowToken atoken = findAppWindowToken(freezeThisOneIfNeeded);  
  •             if (atoken != null) {                        //②屏幕旋转,并且freezeThisOneIfNeeded不为null,那么调用startAppFreezingScreenLocked()冻结screen;  
  •                 startAppFreezingScreenLocked(atoken, ActivityInfo.CONFIG_ORIENTATION);  
  •             }  
  •         }  
  •         config = computeNewConfigurationLocked();      //③调用computeNewConfigurationLocked()计算config;  
  •   
  •     } else if (currentConfig != null) {                  //④什么时候会走这个逻辑呢,具体看step3和step4中return false情况,也就是说没有update new orientation到WMS中。包括,1.可见应用窗口orientation与上一次相同;2.orientation与上一次不同,但是前一次转屏动画还在播放;3.屏幕是灭屏状态;4.PhoneWindowManager策略类综合出的orientation跟上一次相同;;  
  •         // 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();              //⑤下面这些逻辑就是即使不从应用窗口更改orientation,还有其他config需要核对差异。  
  •         mTempConfiguration.fontScale = currentConfig.fontScale;  
  •         //Flyme Theme: save the theme flag.  
  •         mTempConfiguration.themeChanged = currentConfig.themeChanged;  
  •         //Flyme Theme: save the theme flag.  
  •         if (computeScreenConfigurationLocked(mTempConfiguration)) {   
  •             if (currentConfig.diff(mTempConfiguration) != 0) {  
  •                 mWaitingForConfig = true;  
  •                 final DisplayContent displayContent = getDefaultDisplayContentLocked();  
  •                 displayContent.layoutNeeded = true;  
  •                 int anim[] = new int[2];  
  •                 if (displayContent.isDimming()) {  
  •                     anim[0] = anim[1] = 0;  
  •                 } else {  
  •                     mPolicy.selectRotationAnimationLw(anim);  
  •                 }  
  •                 startFreezingDisplayLocked(false, anim[0], anim[1]);  
  •                 config = new Configuration(mTempConfiguration);  
  •             }  
  •         }  
  •     }  
  •   
  •     return config;  
  • }  

step3、updateOrientationFromAppTokensLocked(false)

[html] view plain copy


  • /*  
  • * Determine the new desired orientation of the display, returning  
  • * a non-null new Configuration if it has changed from the current  
  • * orientation.  IF TRUE IS RETURNED SOMEONE MUST CALL  
  • * setNewConfiguration() TO TELL THE WINDOW MANAGER IT CAN UNFREEZE THE  
  • * SCREEN.  This will typically be done for you if you call  
  • * sendNewConfiguration().  
  • *  
  • * The orientation is computed from non-application windows first. If none of  
  • * the non-application windows specify orientation, the orientation is computed from  
  • * application tokens.  
  • * @see android.view.IWindowManager#updateOrientationFromAppTokens(  
  • * android.os.IBinder)  
  • */  
  • boolean updateOrientationFromAppTokensLocked(boolean inTransaction) {   
  •     long ident = Binder.clearCallingIdentity();  
  •     try {  
  •         int req = getOrientationFromWindowsLocked();         //①从非activity窗口中提取orientation;  
  •         if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {  
  •             req = getOrientationFromAppTokensLocked();        //②从activity窗口中提取orientation;  
  •         }  
  •   
  •         if (req != mForcedAppOrientation) {              //③窗口设置的orientation与当前orientation不同,即更改orientation;  
  •             mForcedAppOrientation = req;                 //④这个变量值得更改非常重要;  
  •             //send a message to Policy indicating orientation change to take  
  •             //action like disabling/enabling sensors etc.,  
  •             mPolicy.setCurrentOrientationLw(req);        //⑤告诉PhoneWindowManager orientation,这样采取关闭或开启sensor;比如打开一个强制横屏的窗口,那么必然要关闭sensor嘛,如何关闭,自然是关闭sensor的listener了!  
  •             if (updateRotationUncheckedLocked(inTransaction)) {   //⑥调用updateRotationUncheckedLocked()改变WMS侧屏幕方向,如果确实更新了orientation,那么返回TRUE,如果orientation没有更新,那自然返回false;  
  •                 // changed  
  •                 return true;  
  •             }  
  •         }  
  •   
  •         return false;  
  •     } finally {  
  •         Binder.restoreCallingIdentity(ident);  
  •     }  
  • }  




上面的解释的非常清楚这个函数是干嘛的,就是首先从非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()函数:


  • public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {  
  •     if(DEBUG_ORIENTATION) Slog.v(TAG, "updateRotationUnchecked("  
  •                + "alwaysSendConfiguration=" + alwaysSendConfiguration + ")");  
  •   
  •     long origId = Binder.clearCallingIdentity();  
  •     boolean changed;  
  •     synchronized(mWindowMap) {  
  •         changed = updateRotationUncheckedLocked(false);  
  •         if (!changed || forceRelayout) {  
  •             getDefaultDisplayContentLocked().layoutNeeded = true;  
  •             performLayoutAndPlaceSurfacesLocked();  
  •         }  
  •     }  
  •   
  •     if (changed || alwaysSendConfiguration) {  
  •         sendNewConfiguration();  
  •     }  
  •   
  •     Binder.restoreCallingIdentity(origId);  
  • }  

调用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()中

  • void sendNewConfiguration() {  
  •     try {  
  •         mActivityManager.updateConfiguration(null);  
  •     } catch (RemoteException e) {  
  •     }  
  • }  

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

step4、updateRotationUncheckedLocked()

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

  • // TODO(multidisplay): Rotate any display?  
  • /**  
  • * Updates the current rotation.  
  • *  
  • * Returns true if the rotation has been changed.  In this case YOU  
  • * MUST CALL sendNewConfiguration() TO UNFREEZE THE SCREEN.  
  • */  
  • public boolean updateRotationUncheckedLocked(boolean inTransaction) {  
  •     if (mDeferredRotationPauseCount > 0) {      //①如果调用了pauseRotationLocked()来pauses rotation changes,那么mDeferredRotationPauseCount值会加1,此时便不能change rotation;待调用resumeRotationLocked()将mDeferredRotationPauseCount值减为0,便会调用updateRotationUncheckedLocked()再次change rotation;  
  •         // Rotation updates have been paused temporarily.  Defer the update until  
  •         // updates have been resumed.  
  •         if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, rotation is paused.");  
  •         return false;  
  •     }  
  •   
  •     ScreenRotationAnimation screenRotationAnimation =  
  •             mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);  
  •     if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {   //②如果此刻正在做屏幕旋转动画,也是不能change rotation的;  
  •         // Rotation updates cannot be performed while the previous rotation change  
  •         // animation is still in progress.  Skip this update.  We will try updating  
  •         // again after the animation is finished and the display is unfrozen.  
  •         if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, animation in progress.");  
  •         return false;  
  •     }  
  •   
  •     if (!mDisplayEnabled) {         //③灭屏时也是不能change rotation的;  
  •         // No point choosing a rotation if the display is not enabled.  
  •         if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, display is not enabled.");  
  •         return false;  
  •     }  
  •   
  •     // TODO: Implement forced rotation changes.  
  •     //       Set mAltOrientation to indicate that the application is receiving  
  •     //       an orientation that has different metrics than it expected.  
  •     //       eg. Portrait instead of Landscape.  
  •   
  •     int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);   //④根据mForcedAppOrientation和mRotation、传感器方向等值来综合考虑出orientation。mForcedAppOrientation保存着request orientation,mRotation是当前正在使用的屏幕方向。  
  •     boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(  
  •             mForcedAppOrientation, rotation);  
  •   
  •     if (DEBUG_ORIENTATION) {  
  •         Slog.v(TAG, "Application requested orientation "  
  •                 + mForcedAppOrientation + ", got rotation " + rotation  
  •                 + " which has " + (altOrientation ? "incompatible" : "compatible")  
  •                 + " metrics");  
  •     }  
  •   
  •     if (mRotation == rotation && mAltOrientation == altOrientation) {         //⑤如果综合出来的orientation与last orientation相同,便无需update orientation;  
  •         // No change.  
  •         return false;  
  •     }  
  •   
  •     if (DEBUG_ORIENTATION) {  
  •         Slog.v(TAG,  
  •             "Rotation changed to " + rotation + (altOrientation ? " (alt)" : "")  
  •             + " from " + mRotation + (mAltOrientation ? " (alt)" : "")  
  •             + ", forceApp=" + mForcedAppOrientation);  
  •     }  
  •                                       //⑥以下逻辑是需要update orientation;  
  •     mRotation = rotation;  
  •     mAltOrientation = altOrientation;  
  •     mPolicy.setRotationLw(mRotation);   //⑦将mRotation设置到PhoneWindowManager中;  
  •   
  •     mWindowsFreezingScreen = true;       //⑧准备冻结屏幕;  
  •     mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);  
  •     mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);  
  •     mWaitingForConfig = true;  
  •     final DisplayContent displayContent = getDefaultDisplayContentLocked();  
  •     displayContent.layoutNeeded = true;        //⑨layoutNeeded为true;这样needsLayout()函数就可以返回true;  
  •     final int[] anim = new int[2];  
  •     if (displayContent.isDimming()) {  
  •         anim[0] = anim[1] = 0;  
  •     } else {  
  •         mPolicy.selectRotationAnimationLw(anim);   //⑨PhoneWindowManager选择进入和退出转屏动画;        
  •     }  
  •     startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);     //⑨调用startFreezingDisplayLocked()冻结屏幕,参数中传入了进入和退出动画,这个函数在下面将详细分析;  
  •     // startFreezingDisplayLocked can reset the ScreenRotationAnimation.  
  •     screenRotationAnimation =  
  •             mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);   //⑨获取DisplayContentsAnimator类对象,这个类中包含一个ScreenRotationAnimation类对象;  
  •   
  •     // We need to update our screen size information to match the new  
  •     // rotation.  Note that this is redundant with the later call to  
  •     // sendNewConfiguration() that must be called after this function  
  •     // returns...  however we need to do the screen size part of that  
  •     // before then so we have the correct size to use when initializing  
  •     // the rotation animation for the new rotation.  
  •     computeScreenConfigurationLocked(null);                       //⑨更新DisplayInfo信息;  
  •   
  •     final DisplayInfo displayInfo = displayContent.getDisplayInfo();  
  •     if (!inTransaction) {  
  •         if (SHOW_TRANSACTIONS) {  
  •             Slog.i(TAG, ">>> OPEN TRANSACTION setRotationUnchecked");  
  •         }  
  •         SurfaceControl.openTransaction();  
  •     }  
  •     try {  
  •         // NOTE: We disable the rotation in the emulator because  
  •         //       it doesn't support hardware OpenGL emulation yet.  
  •         if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null  
  •                 && screenRotationAnimation.hasScreenshot()) {         //⑨create Rotation Matrix and set Matrix to mSurfaceControl(截图surface)  
  •             if (screenRotationAnimation.setRotationInTransaction(  
  •                     rotation, mFxSession,  
  •                     MAX_ANIMATION_DURATION, mTransitionAnimationScale,  
  •                     displayInfo.logicalWidth, displayInfo.logicalHeight)) {  
  •                 scheduleAnimationLocked();  
  •             }  
  •         }  
  •   
  •         mDisplayManagerService.performTraversalInTransactionFromWindowManager();   //⑨这个是干啥的??  
  •     } finally {  
  •         if (!inTransaction) {  
  •             SurfaceControl.closeTransaction();  
  •             if (SHOW_LIGHT_TRANSACTIONS) {  
  •                 Slog.i(TAG, "<<< CLOSE TRANSACTION setRotationUnchecked");  
  •             }  
  •         }  
  •     }  
  •   
  •     final WindowList windows = displayContent.getWindowList();  
  •     for (int i = windows.size() - 1; i >= 0; i--) {                               //⑨对于未销毁surface的window,将WindowState.mOrientationChanging设为true;  
  •         WindowState w = windows.get(i);  
  •         if (w.mHasSurface  
  •                 // FLYME_BEGIN  
  •                 // FUNCTIONptimize the efficiency of rotating screen . added by fujinzhi. transplanted by duzhenhui.  
  •                 /*&& !w.prohibitRotation()*/  
  •                 // FLYME_END 2014.04.17  
  •                 ) {  
  •             if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);  
  •             w.mOrientationChanging = true;  
  •             mInnerFields.mOrientationChangeComplete = false;  
  •         }  
  •         w.mLastFreezeDuration = 0;  
  •     }  
  •   
  •     for (int i=mRotationWatchers.size()-1; i>=0; i--) {                      //⑨将rotation发布到PhoneWindow、KeyguardFaceUnlockView、LegacySensorManager中去;重点是PhoneWindow,这个将在下面详细分析;  
  •         try {  
  •             mRotationWatchers.get(i).watcher.onRotationChanged(rotation);  
  •         } catch (RemoteException e) {  
  •         }  
  •     }  
  •   
  •     //TODO (multidisplay): Magnification is supported only for the default display.  
  •     if (mDisplayMagnifier != null  
  •             && displayContent.getDisplayId() == Display.DEFAULT_DISPLAY) {              //⑨如果打开手势放大,那么回调mDisplayMagnifier.onRotationChangedLocked()函数;  
  •         mDisplayMagnifier.onRotationChangedLocked(getDefaultDisplayContentLocked(), rotation);  
  •     }  
  •   
  •     return true;  
  • }  

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

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


[html] view plain copy


  • @Override  
  • public void setRotationLw(int rotation) {  
  •     mOrientationListener.setCurrentRotation(rotation);  
  • }  

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

[html] view plain copy


  • /**  
  • * Sets the current rotation.  
  • *  
  • * @param rotation The current rotation.  
  • */  
  • public void setCurrentRotation(int rotation) {  
  •     synchronized (mLock) {  
  •         mCurrentRotation = rotation;         
  •     }  
  • }  

  • private void startFreezingDisplayLocked(boolean inTransaction, int exitAnim, int enterAnim) {  
  •     if (mDisplayFrozen) {           //①mDisplayFrozen变量为true,表示正在调用startFreezingDisplayLocked()冻结屏幕,并且还未调用stopFreezingDisplayLocked()进行解冻;  
  •         return;  
  •     }  
  •   
  •     if (!mDisplayReady || !mPolicy.isScreenOnFully()) {     //②系统还未ready或灭屏状态(PhoneWindowManager.mScreenOnFully==false);  
  •         // No need to freeze the screen before the system is ready or if  
  •         // the screen is off.  
  •         return;  
  •     }  
  •   
  •     mScreenFrozenLock.acquire();           //③获得一把唤醒锁,防止freeze screen期间系统灭屏并锁屏,锁屏会更改orientation;  
  •   
  •     mDisplayFrozen = true;  
  •     mDisplayFreezeTime = SystemClock.elapsedRealtime();  
  •     mLastFinishedFreezeSource = null;  
  •   
  •     mInputMonitor.freezeInputDispatchingLw();       //④freeze Input Dispatcher,也就是禁止触摸时间上报;  
  •   
  •     // Clear the last input window -- that is just used for  
  •     // clean transitions between IMEs, and if we are freezing  
  •     // the screen then the whole world is changing behind the scenes.  
  •     mPolicy.setLastInputMethodWindowLw(null, null);      
  •   
  •     if (mAppTransition.isTransitionSet()) {        //④如果设置了activity切换动画,那么调用mAppTransition.freeze()设置mAppTransitionState=APP_STATE_READY;  
  •         mAppTransition.freeze();  
  •     }  
  •   
  •     if (PROFILE_ORIENTATION) {  
  •         File file = new File("/data/system/frozen");  
  •         Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);  
  •     }  
  •   
  •     if (CUSTOM_SCREEN_ROTATION) {  
  •         mExitAnimId = exitAnim;  
  •         mEnterAnimId = enterAnim;  
  •         final DisplayContent displayContent = getDefaultDisplayContentLocked();  
  •         final int displayId = displayContent.getDisplayId();  
  •         ResSchedulerManager mResSchedulerManager;  
  •         ScreenRotationAnimation screenRotationAnimation =  
  •                 mAnimator.getScreenRotationAnimationLocked(displayId);      
  •         if (screenRotationAnimation != null) {                //⑤如果上次转屏动画还在播放,那么kill掉;  
  •             screenRotationAnimation.kill();  
  •         }  
  •         mResSchedulerManager = (ResSchedulerManager) mContext  
  • .getSystemService(Context.RES_SCHEDULER_SERVICE);  
  •         mResSchedulerManager.dispatchSwitchPerfModeCMD(mResSchedulerManager.APP_ROTATE);  
  •   
  •         // TODO(multidisplay): rotation on main screen only.  
  •         screenRotationAnimation = new ScreenRotationAnimation(this,mContext, displayContent,  
  •                 mFxSession, inTransaction, mPolicy.isDefaultOrientationForced(),mDisableScreenRotationForHdmi);  
  •         mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);        //⑥设置一个ScreenRotationAnimation对象到DisplayContentsAnimator.mScreenRotationAnimation中;  
  •     }  
  • }  

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

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

  • boolean computeScreenConfigurationLocked(Configuration config) {  
  •     if (!mDisplayReady) {  
  •         return false;  
  •     }  
  •   
  •     // TODO(multidisplay): For now, apply Configuration to main screen only.  
  •     final DisplayContent displayContent = getDefaultDisplayContentLocked();  
  •   
  •     // Use the effective "visual" dimensions based on current rotation  
  •     final boolean rotated = (mRotation == Surface.ROTATION_90  
  •             || mRotation == Surface.ROTATION_270);        //①根据mRotation值,计算出屏幕宽度和高度;mRotation值在是在调用该函数之前已经更新;  
  •     final int realdw = rotated ?  
  •             displayContent.mBaseDisplayHeight : displayContent.mBaseDisplayWidth;  
  •     final int realdh = rotated ?  
  •             displayContent.mBaseDisplayWidth : displayContent.mBaseDisplayHeight;  
  •     int dw = realdw;  
  •     int dh = realdh;  
  •   
  •     if (mAltOrientation) {  
  •         if (realdw > realdh) {  
  •             // Turn landscape into portrait.  
  •             int maxw = (int)(realdh/1.3f);  
  •             if (maxw < realdw) {  
  •                 dw = maxw;  
  •             }  
  •         } else {  
  •             // Turn portrait into landscape.  
  •             int maxh = (int)(realdw/1.3f);  
  •             if (maxh < realdh) {  
  •                 dh = maxh;  
  •             }  
  •         }  
  •     }  
  •   
  •     if (config != null) {  
  •         config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :  
  •                 Configuration.ORIENTATION_LANDSCAPE;  
  •     }  
  •   
  •     // Update application display metrics.  
  •     final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);  
  •     final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);  
  •     final DisplayInfo displayInfo = displayContent.getDisplayInfo();  
  •     synchronized(displayContent.mDisplaySizeLock) {  
  •         displayInfo.rotation = mRotation;  
  •         displayInfo.logicalWidth = dw;  
  •         displayInfo.logicalHeight = dh;  
  •         displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity;  
  •         displayInfo.appWidth = appWidth;  
  •         displayInfo.appHeight = appHeight;  
  •         displayInfo.getLogicalMetrics(mRealDisplayMetrics,  
  •                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);  
  •         displayInfo.getAppMetrics(mDisplayMetrics);  
  •         mDisplayManagerService.setDisplayInfoOverrideFromWindowManager(  
  •                 displayContent.getDisplayId(), displayInfo);  
  •     }  
  •     if (false) {  
  •         Slog.i(TAG, "Set app display size: " + appWidth + " x " + appHeight);  
  •     }  
  •   
  •     final DisplayMetrics dm = mDisplayMetrics;  
  •     mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm,  
  •             mCompatDisplayMetrics);  
  •   
  •     if (config != null) {  
  •         config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation)  
  •                 / dm.density);  
  •         config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation)  
  •                 / dm.density);  
  •         computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh, dm.density, config);  
  •   
  •         config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);  
  •         config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);  
  •         config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh);  
  •         config.densityDpi = displayContent.mBaseDisplayDensity;  
  •   
  •         // Update the configuration based on available input devices, lid switch,  
  •         // and platform configuration.  
  •         config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;  
  •         config.keyboard = Configuration.KEYBOARD_NOKEYS;  
  •         config.navigation = Configuration.NAVIGATION_NONAV;  
  •   
  •         int keyboardPresence = 0;  
  •         int navigationPresence = 0;  
  •         final InputDevice[] devices = mInputManager.getInputDevices();  
  •         final int len = devices.length;  
  •         for (int i = 0; i < len; i++) {  
  •             InputDevice device = devices;  
  •             if (!device.isVirtual()) {  
  •                 final int sources = device.getSources();  
  •                 final int presenceFlag = device.isExternal() ?  
  •                         WindowManagerPolicy.PRESENCE_EXTERNAL :  
  •                                 WindowManagerPolicy.PRESENCE_INTERNAL;  
  •   
  •                 if (mIsTouchDevice) {  
  •                     if ((sources & InputDevice.SOURCE_TOUCHSCREEN) ==  
  •                             InputDevice.SOURCE_TOUCHSCREEN) {  
  •                         config.touchscreen = Configuration.TOUCHSCREEN_FINGER;  
  •                     }  
  •                 } else {  
  •                     config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;  
  •                 }  
  •   
  •                 if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {  
  •                     config.navigation = Configuration.NAVIGATION_TRACKBALL;  
  •                     navigationPresence |= presenceFlag;  
  •                 } else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD  
  •                         && config.navigation == Configuration.NAVIGATION_NONAV) {  
  •                     config.navigation = Configuration.NAVIGATION_DPAD;  
  •                     navigationPresence |= presenceFlag;  
  •                 }  
  •   
  •                 if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {  
  •                     config.keyboard = Configuration.KEYBOARD_QWERTY;  
  •                     keyboardPresence |= presenceFlag;  
  •                 }  
  •             }  
  •         }  
  •   
  •         // Determine whether a hard keyboard is available and enabled.  
  •         boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;  
  •         if (hardKeyboardAvailable != mHardKeyboardAvailable) {  
  •             mHardKeyboardAvailable = hardKeyboardAvailable;  
  •             mHardKeyboardEnabled = hardKeyboardAvailable;  
  •             mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);  
  •             mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);  
  •         }  
  •         if (!mHardKeyboardEnabled) {  
  •             config.keyboard = Configuration.KEYBOARD_NOKEYS;  
  •         }  
  •   
  •         // Let the policy update hidden states.  
  •         config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;  
  •         config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;  
  •         config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;  
  •         mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);  
  •     }  
  •   
  •     return true;  
  • }  

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

step5、AMS.updateConfigurationLocked()

  • /**  
  • * Do either or both things: (1) change the current configuration, and (2)  
  • * make sure the given activity is running with the (now) current  
  • * configuration.  Returns true if the activity has been left running, or  
  • * false if <var>starting</var> is being destroyed to match the new  
  • * configuration.  
  • * @param persistent TODO  
  • */  
  • boolean updateConfigurationLocked(Configuration values,  
  •         ActivityRecord starting, boolean persistent, boolean initLocale) {  
  •     // do nothing if we are headless  
  •     if (mHeadless) return true;  
  •   
  •     int changes = 0;  
  •   
  •     if (values != null) {  
  •         Configuration newConfig = new Configuration(mConfiguration);  
  •         changes = newConfig.updateFrom(values);  
  •         if (changes != 0) {  
  •             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {  
  •                 Slog.i(TAG, "Updating configuration to: " + values);  
  •             }  
  •               
  •             EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);  
  •   
  •             if (values.locale != null && !initLocale) {  
  •                 saveLocaleLocked(values.locale,   
  •                                  !values.locale.equals(mConfiguration.locale),  
  •                                  values.userSetLocale);  
  •             }  
  •   
  •             mConfigurationSeq++;  
  •             if (mConfigurationSeq <= 0) {  
  •                 mConfigurationSeq = 1;  
  •             }  
  •             newConfig.seq = mConfigurationSeq;  
  •             mConfiguration = newConfig;                                //①将mConfiguration更新到最新config;  
  •             Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + newConfig);  
  •   
  •             final Configuration configCopy = new Configuration(mConfiguration);  
  •               
  •             // TODO: If our config changes, should we auto dismiss any currently  
  •             // showing dialogs?  
  •             mShowDialogs = shouldShowDialogs(newConfig);  
  •   
  •             AttributeCache ac = AttributeCache.instance();  
  •             if (ac != null) {  
  •                 ac.updateConfiguration(configCopy);  
  •             }  
  •   
  •             // Make sure all resources in our process are updated  
  •             // right now, so that anyone who is going to retrieve  
  •             // resource values after we return will be sure to get  
  •             // the new ones.  This is especially important during  
  •             // boot, where the first config change needs to guarantee  
  •             // all resources have that config before following boot  
  •             // code is executed.  
  •             mSystemThread.applyConfigurationToResources(configCopy);      //②将config更新到ResourcesManager中去;  
  •   
  •             if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {  
  •                 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);       //③post一个update消息,该消息处理函数中调用Settings.System.putConfiguration()保存config;  
  •                 msg.obj = new Configuration(configCopy);  
  •                 mHandler.sendMessage(msg);  
  •             }  
  •                
  •             for (int i=mLruProcesses.size()-1; i>=0; i--) {                 //④将横屏config通过调用ActivityThread.scheduleConfigurationChanged()传递每个应用进程中去,这个将在下面进行详细分析;  
  •                 ProcessRecord app = mLruProcesses.get(i);  
  •                 try {  
  •                     if (app.thread != null) {  
  •                         if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending to proc "  
  •                                 + app.processName + " new config " + mConfiguration);  
  •                         app.thread.scheduleConfigurationChanged(configCopy);   
  •                     }  
  •                 } catch (Exception e) {  
  •                 }  
  •             }  
  •             Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);  
  •             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY  
  •                     | Intent.FLAG_RECEIVER_REPLACE_PENDING  
  •                     | Intent.FLAG_RECEIVER_FOREGROUND);  
  •             broadcastIntentLocked(null, null, intent, null, null, 0, null, null,     //⑤发送一个config changed广播;  
  •                     null, AppOpsManager.OP_NONE, false, false, MY_PID,  
  •                     Process.SYSTEM_UID, UserHandle.USER_ALL);  
  •             if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {  
  •                 intent = new Intent(Intent.ACTION_LOCALE_CHANGED);  
  •                 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);  
  •                 broadcastIntentLocked(null, null, intent,  
  •                         null, null, 0, null, null, null, AppOpsManager.OP_NONE,  
  •                         false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);  
  •             }  
  •         }  
  •     }  
  •   
  •     boolean kept = true;  
  •     final ActivityStack mainStack = mStackSupervisor.getFocusedStack();      
  •     if (changes != 0 && starting == null) {                                     //⑥如果start 横屏Activity时,参数starting就是正要启动的横屏Activity;如果是旋转屏幕,starting 就为null,此时把top Activity取出来;  
  •         // If the configuration changed, and the caller is not already  
  •         // in the process of starting an activity, then find the top  
  •         // activity to check if its configuration needs to change.  
  •         starting = mainStack.topRunningActivityLocked(null);  
  •     }  
  •   
  •     if (starting != null) {  
  •         kept = mainStack.ensureActivityConfigurationLocked(starting, changes);   //⑦将config设置到starting中去,下面会详细分析这个函数;  
  •         // And we need to make sure at this point that all other activities  
  •         // are made visible with the correct configuration.  
  •         mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes);       //⑧调用ensureActivitiesVisibleLocked()  
  •     }  
  •   
  •     if (values != null && mWindowManager != null) {  
  •         mWindowManager.setNewConfiguration(mConfiguration);                     //⑨调用WindowManagerService.setNewConfiguration()启动performLayoutAndPlaceSurfacesLocked()  
  •     }  
  •   
  •     return kept;  
  • }  

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

  • final void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) {  
  •   
  •     int configDiff = 0;  
  •   
  •     synchronized (mResourcesManager) {  
  •         if (mPendingConfiguration != null) {  
  •             if (!mPendingConfiguration.isOtherSeqNewer(config)) {  
  •                 config = mPendingConfiguration;  
  •                 mCurDefaultDisplayDpi = config.densityDpi;  
  •                 updateDefaultDensity();  
  •             }  
  •             mPendingConfiguration = null;  
  •         }  
  •   
  •         if (config == null) {  
  •             return;  
  •         }  
  •          
  •         if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle configuration changed: "  
  •                 + config);  
  •   
  •         mResourcesManager.applyConfigurationToResourcesLocked(config, compat);      //①将config更新到应用进程的ResourcesManager中去  
  •   
  •         if (mConfiguration == null) {  
  •             mConfiguration = new Configuration();  
  •         }  
  •         if (!mConfiguration.isOtherSeqNewer(config) && compat == null) {  
  •             return;  
  •         }  
  •         configDiff = mConfiguration.diff(config);  
  •         mConfiguration.updateFrom(config);  
  •         config = applyCompatConfiguration(mCurDefaultDisplayDpi);  
  •     }  
  •   
  •     ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config);  
  •   
  •     // Cleanup hardware accelerated stuff  
  •     WindowManagerGlobal.getInstance().trimLocalMemory();  
  •   
  •     freeTextLayoutCachesIfNeeded(configDiff);  
  •   
  •     if (callbacks != null) {  
  •         final int N = callbacks.size();  
  •         for (int i=0; i<N; i++) {  
  •             performConfigurationChanged(callbacks.get(i), config);  
  •         }  
  •     }  
  • }  

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

  • /**  
  • * Make sure the given activity matches the current configuration.  Returns  
  • * false if the activity had to be destroyed.  Returns true if the  
  • * configuration is the same, or the activity will remain running as-is  
  • * for whatever reason.  Ensures the HistoryRecord is updated with the  
  • * correct configuration and all other bookkeeping is handled.  
  • */  
  • final boolean ensureActivityConfigurationLocked(ActivityRecord r,  
  •         int globalChanges) {  
  •     if (mConfigWillChange) {  
  •         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •                 "Skipping config check (will change): " + r);  
  •         return true;  
  •     }  
  •   
  •     if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •             "Ensuring correct configuration: " + r);  
  •   
  •     // Short circuit: if the two configurations are the exact same  
  •     // object (the common case), then there is nothing to do.  
  •     Configuration newConfig = mService.mConfiguration;  
  •     if (r.configuration == newConfig && !r.forceNewConfig) {  
  •         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •                 "Configuration unchanged in " + r);  
  •         return true;  
  •     }  
  •   
  •     // We don't worry about activities that are finishing.  
  •     if (r.finishing) {                                         //①正在finish的Activity则无需关心;  
  •         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •                 "Configuration doesn't matter in finishing " + r);  
  •         r.stopFreezingScreenLocked(false);  
  •         return true;  
  •     }  
  •   
  •     // Okay we now are going to make this activity have the new config.  
  •     // But then we need to figure out how it needs to deal with that.  
  •     Configuration oldConfig = r.configuration;  
  •     r.configuration = newConfig;                              //②更新ActivityRecord.configuration值;   
  •   
  •     // Determine what has changed.  May be nothing, if this is a config  
  •     // that has come back from the app after going idle.  In that case  
  •     // we just want to leave the official config object now in the  
  •     // activity and do nothing else.  
  •     final int changes = oldConfig.diff(newConfig);  
  •     if (changes == 0 && !r.forceNewConfig) {  
  •         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •                 "Configuration no differences in " + r);  
  •         return true;  
  •     }  
  •   
  •     // If the activity isn't currently running, just leave the new  
  •     // configuration and it will pick that up next time it starts.  
  •     if (r.app == null || r.app.thread == null) {  
  •         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •                 "Configuration doesn't matter not running " + r);  
  •         r.stopFreezingScreenLocked(false);  
  •         r.forceNewConfig = false;  
  •         return true;  
  •     }  
  •   
  •     // Figure out how to handle the changes between the configurations.  
  •     if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {  
  •         Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"  
  •                 + Integer.toHexString(changes) + ", handles=0x"  
  •                 + Integer.toHexString(r.info.getRealConfigChanged())  
  •                 + ", newConfig=" + newConfig);  
  •     }  
  •     if ((changes&(~r.info.getRealConfigChanged())) != 0 || r.forceNewConfig) {  
  •         // Aha,   
  •         r.configChangeFlags |= changes;  
  •         r.startFreezingScreenLocked(r.app, globalChanges);  
  •         r.forceNewConfig = false;  
  •         if (r.app == null || r.app.thread == null) {  
  •             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •                     "Config is destroying non-running " + r);  
  •             destroyActivityLocked(r, true, false, "config");  
  •         } else if (r.state == ActivityState.PAUSING) {  
  •             // A little annoying: we are waiting for this activity to  
  •             // finish pausing.  Let's not do anything now, but just  
  •             // flag that it needs to be restarted when done pausing.  
  •             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •                     "Config is skipping already pausing " + r);  
  •             r.configDestroy = true;  
  •             return true;  
  •         } else if (r.state == ActivityState.RESUMED) {  
  •             // Try to optimize this case: the configuration is changing  
  •             // and we need to restart the top, resumed activity.  
  •             // Instead of doing the normal handshaking, just say  
  •             // "restart!".  
  •             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •                     "Config is relaunching resumed " + r);  
  •             relaunchActivityLocked(r, r.configChangeFlags, true);  
  •             r.configChangeFlags = 0;  
  •         } else {  
  •             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •                     "Config is relaunching non-resumed " + r);  
  •             relaunchActivityLocked(r, r.configChangeFlags, false);  
  •             r.configChangeFlags = 0;  
  •         }  
  •   
  •         // All done...  tell the caller we weren't able to keep this  
  •         // activity around.  
  •         return false;  
  •     }  
  •   
  •     // Default case: the activity can handle this new configuration, so  
  •     // hand it over.  Note that we don't need to give it the new  
  •     // configuration, since we always send configuration changes to all  
  •     // process when they happen so it can just use whatever configuration  
  •     // it last got.  
  •     if (r.app != null && r.app.thread != null) {  
  •         try {  
  •             if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + r);  
  •             r.app.thread.scheduleActivityConfigurationChanged(r.appToken);    //③调用ActivityThread.scheduleActivityConfigurationChanged();  
  •         } catch (RemoteException e) {  
  •             // If process died, whatever.  
  •         }  
  •     }  
  •     r.stopFreezingScreenLocked(false);  
  •   
  •     return true;  
  • }  















本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
沙发
 楼主| 发表于 2016-5-7 16:09:57 | 只看该作者

Android4.1 关于Rotation相关的Configuration整体分析2

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

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

1. MyOrientationListener.onProposeRotationChange


[java] view plain copy


  • class MyOrientationListener extends WindowOrientationListener {  
  •       
  •     @Override  
  •     public void onProposedRotationChanged(int rotation) {  
  •         if (localLOGV) Log.v(TAG, "onProposedRotationChanged, rotation=" + rotation);  
  •         updateRotation(false);  
  •     }  
  • }  


2. PhoneWindowManager.updateRotation(boolean alwaysSendConfiguration)

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


[java] view plain copy


  • void updateRotation(boolean alwaysSendConfiguration) {  
  •     try {  
  •         //set orientation on WindowManager  
  •         mWindowManager.updateRotation(alwaysSendConfiguration, false);  
  •     } catch (RemoteException e) {  
  •         // Ignore  
  •     }  
  • }  


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


  • public void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) {  
  •     updateRotationUnchecked(alwaysSendConfiguration, forceRelayout);  
  • }  




[java] view plain copy


  • public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {  
  •     boolean changed;  
  •     synchronized(mWindowMap) {  
  •         changed = updateRotationUncheckedLocked(false);  
  •         if (!changed || forceRelayout) {  
  •             getDefaultDisplayContentLocked().layoutNeeded = true;  
  •             performLayoutAndPlaceSurfacesLocked();  
  •         }  
  •     }  
  •   
  •     if (changed || alwaysSendConfiguration) {  
  •         sendNewConfiguration();  
  •     }  
  •     ... ...  
  • }  


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


  • public boolean updateRotationUncheckedLocked(boolean inTransaction) {  
  •     ... ...  
  •   
  •     int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);  
  •     boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(  
  •             mForcedAppOrientation, rotation);  
  •     ... ...  
  •   
  •     if (mRotation == rotation && mAltOrientation == altOrientation) {  
  •         // No change.  
  •         return false;  
  •     }  
  •     ... ...  
  •   
  •     mRotation = rotation;  
  •     mAltOrientation = altOrientation;  
  •     mPolicy.setRotationLw(mRotation);  
  •   
  •     mWindowsFreezingScreen = true;  
  •     mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);  
  •     mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),  
  •             WINDOW_FREEZE_TIMEOUT_DURATION);  
  •     mWaitingForConfig = true;  
  •     getDefaultDisplayContentLocked().layoutNeeded = true;  
  •     startFreezingDisplayLocked(inTransaction, 0, 0);  
  •     // startFreezingDisplayLocked can reset the ScreenRotationAnimation.  
  •     screenRotationAnimation =  
  •             mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);  
  •   
  •     // We need to update our screen size information to match the new  
  •     // rotation.  Note that this is redundant with the later call to  
  •     // sendNewConfiguration() that must be called after this function  
  •     // returns...  however we need to do the screen size part of that  
  •     // before then so we have the correct size to use when initializing  
  •     // the rotation animation for the new rotation.  
  •     computeScreenConfigurationLocked(null);  
  •   
  •     final DisplayContent displayContent = getDefaultDisplayContentLocked();  
  •     final DisplayInfo displayInfo = displayContent.getDisplayInfo();  
  •     if (!inTransaction) {  
  •         if (SHOW_TRANSACTIONS) {  
  •             Slog.i(TAG, ">>> OPEN TRANSACTION setRotationUnchecked");  
  •         }  
  •         Surface.openTransaction();  
  •     }  
  •     try {  
  •         // NOTE: We disable the rotation in the emulator because  
  •         //       it doesn't support hardware OpenGL emulation yet.  
  •         if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null  
  •                 && screenRotationAnimation.hasScreenshot()) {  
  •             if (screenRotationAnimation.setRotationInTransaction(  
  •                     rotation, mFxSession,  
  •                     MAX_ANIMATION_DURATION, mTransitionAnimationScale,  
  •                     displayInfo.logicalWidth, displayInfo.logicalHeight)) {  
  •                 updateLayoutToAnimationLocked();  
  •             }  
  •         }  
  •   
  •         mDisplayManagerService.performTraversalInTransactionFromWindowManager();  
  •     } finally {  
  •         if (!inTransaction) {  
  •             Surface.closeTransaction();  
  •             if (SHOW_LIGHT_TRANSACTIONS) {  
  •                 Slog.i(TAG, "<<< CLOSE TRANSACTION setRotationUnchecked");  
  •             }  
  •         }  
  •     }  
  •   
  •     final WindowList windows = displayContent.getWindowList();  
  •     for (int i = windows.size() - 1; i >= 0; i--) {  
  •         WindowState w = windows.get(i);  
  •         if (w.mHasSurface) {  
  •             if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);  
  •             w.mOrientationChanging = true;  
  •             mInnerFields.mOrientationChangeComplete = false;  
  •         }  
  •     }  
  •   
  •     for (int i=mRotationWatchers.size()-1; i>=0; i--) {  
  •         try {  
  •             mRotationWatchers.get(i).onRotationChanged(rotation);  
  •         } catch (RemoteException e) {  
  •         }  
  •     }  
  •   
  •     scheduleNotifyRotationChangedIfNeededLocked(displayContent, rotation);  
  •   
  •     return true;  
  • }  


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


  • public int rotationForOrientationLw(int orientation, int lastRotation) {  
  •     ... ...  
  •     synchronized (mLock) {  
  •         int sensorRotation = mOrientationListener.getProposedRotation(); // may be -1  
  •         if (sensorRotation < 0) {  
  •             sensorRotation = lastRotation;  
  •         }  
  •   
  •         final int preferredRotation;  
  •         if (mLidState == LID_OPEN && mLidOpenRotation >= 0) {  
  •             // Ignore sensor when lid switch is open and rotation is forced.  
  •             preferredRotation = mLidOpenRotation;  
  •         } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR  
  •                 && (mCarDockEnablesAccelerometer || mCarDockRotation >= 0)) {  
  •             // Ignore sensor when in car dock unless explicitly enabled.  
  •             // This case can override the behavior of NOSENSOR, and can also  
  •             // enable 180 degree rotation while docked.  
  •             preferredRotation = mCarDockEnablesAccelerometer  
  •                     ? sensorRotation : mCarDockRotation;  
  •         } else if ((mDockMode == Intent.EXTRA_DOCK_STATE_DESK  
  •                 || mDockMode == Intent.EXTRA_DOCK_STATE_LE_DESK  
  •                 || mDockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)  
  •                 && (mDeskDockEnablesAccelerometer || mDeskDockRotation >= 0)) {  
  •             // Ignore sensor when in desk dock unless explicitly enabled.  
  •             // This case can override the behavior of NOSENSOR, and can also  
  •             // enable 180 degree rotation while docked.  
  •             preferredRotation = mDeskDockEnablesAccelerometer  
  •                     ? sensorRotation : mDeskDockRotation;  
  •         } else if (mHdmiPlugged && mHdmiRotationLock) {  
  •             // Ignore sensor when plugged into HDMI.  
  •             // Note that the dock orientation overrides the HDMI orientation.  
  •             preferredRotation = mHdmiRotation;  
  •         } else if ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE  
  •                         && (orientation == ActivityInfo.SCREEN_ORIENTATION_USER  
  •                                 || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED))  
  •                 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR  
  •                 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR  
  •                 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE  
  •                 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {  
  •             // Otherwise, use sensor only if requested by the application or enabled  
  •             // by default for USER or UNSPECIFIED modes.  Does not apply to NOSENSOR.  
  •             if (mAllowAllRotations < 0) {  
  •                 // Can't read this during init() because the context doesn't  
  •                 // have display metrics at that time so we cannot determine  
  •                 // tablet vs. phone then.  
  •                 mAllowAllRotations = mContext.getResources().getBoolean(  
  •                         com.android.internal.R.bool.config_allowAllRotations) ? 1 : 0;  
  •             }  
  •             if (sensorRotation != Surface.ROTATION_180  
  •                     || mAllowAllRotations == 1  
  •                     || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR) {  
  •                 preferredRotation = sensorRotation;  
  •             } else {  
  •                 preferredRotation = lastRotation;  
  •             }  
  •         } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED  
  •                 && orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {  
  •             // Apply rotation lock.  Does not apply to NOSENSOR.  
  •             // The idea is that the user rotation expresses a weak preference for the direction  
  •             // of gravity and as NOSENSOR is never affected by gravity, then neither should  
  •             // NOSENSOR be affected by rotation lock (although it will be affected by docks).  
  •             preferredRotation = mUserRotation;  
  •         } else {  
  •             // No overriding preference.  
  •             // We will do exactly what the application asked us to do.  
  •             preferredRotation = -1;  
  •         }  
  •   
  •         switch (orientation) {  
  •             case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:  
  •                 // Return portrait unless overridden.  
  •                 if (isAnyPortrait(preferredRotation)) {  
  •                     return preferredRotation;  
  •                 }  
  •                 return mPortraitRotation;  
  •   
  •             case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:  
  •                 // Return landscape unless overridden.  
  •                 if (isLandscapeOrSeascape(preferredRotation)) {  
  •                     return preferredRotation;  
  •                 }  
  •                 return mLandscapeRotation;  
  •   
  •             case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:  
  •                 // Return reverse portrait unless overridden.  
  •                 if (isAnyPortrait(preferredRotation)) {  
  •                     return preferredRotation;  
  •                 }  
  •                 return mUpsideDownRotation;  
  •   
  •             case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:  
  •                 // Return seascape unless overridden.  
  •                 if (isLandscapeOrSeascape(preferredRotation)) {  
  •                     return preferredRotation;  
  •                 }  
  •                 return mSeascapeRotation;  
  •   
  •             case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:  
  •                 // Return either landscape rotation.  
  •                 if (isLandscapeOrSeascape(preferredRotation)) {  
  •                     return preferredRotation;  
  •                 }  
  •                 if (isLandscapeOrSeascape(lastRotation)) {  
  •                     return lastRotation;  
  •                 }  
  •                 return mLandscapeRotation;  
  •   
  •             case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:  
  •                 // Return either portrait rotation.  
  •                 if (isAnyPortrait(preferredRotation)) {  
  •                     return preferredRotation;  
  •                 }  
  •                 if (isAnyPortrait(lastRotation)) {  
  •                     return lastRotation;  
  •                 }  
  •                 return mPortraitRotation;  
  •   
  •             default:  
  •                 // For USER, UNSPECIFIED, NOSENSOR, SENSOR and FULL_SENSOR,  
  •                 // just return the preferred orientation we already calculated.  
  •                 if (preferredRotation >= 0) {  
  •                     return preferredRotation;  
  •                 }  
  •                 return Surface.ROTATION_0;  
  •         }  
  •     }  


3.2 WindowManagerService.performLayoutAndPlaceSurfacesLocked()

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


[java] view plain copy


  • private final void performLayoutAndPlaceSurfacesLocked() {  
  •     int loopCount = 6;  
  •     do {  
  •         mTraversalScheduled = false;  
  •         performLayoutAndPlaceSurfacesLockedLoop();  
  •         mH.removeMessages(H.DO_TRAVERSAL);  
  •         loopCount--;  
  •     } while (mTraversalScheduled && loopCount > 0);  
  • }  



3.3 WindowManagerService.sendNewConfiguration()

    1. 去调AMS的updateConfiguration.



[java] view plain copy


  • void sendNewConfiguration() {  
  •     try {  
  •         mActivityManager.updateConfiguration(null);  
  •     } catch (RemoteException e) {  
  •     }  
  • }  


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


  • boolean updateConfigurationLocked(Configuration values,  
  •         ActivityRecord starting, boolean persistent, boolean initLocale) {  
  •     // do nothing if we are headless  
  •     if (mHeadless) return true;  
  •   
  •     int changes = 0;  
  •       
  •     boolean kept = true;  
  •       
  •     if (values != null) {  
  •         Configuration newConfig = new Configuration(mConfiguration);  
  •         changes = newConfig.updateFrom(values);  
  •         if (changes != 0) {  
  •             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {  
  •                 Slog.i(TAG, "Updating configuration to: " + values);  
  •             }  
  •               
  •             EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);  
  •   
  •             if (values.locale != null && !initLocale) {  
  •                 saveLocaleLocked(values.locale,   
  •                                  !values.locale.equals(mConfiguration.locale),  
  •                                  values.userSetLocale);  
  •             }  
  •   
  •             mConfigurationSeq++;  
  •             if (mConfigurationSeq <= 0) {  
  •                 mConfigurationSeq = 1;  
  •             }  
  •             newConfig.seq = mConfigurationSeq;  
  •             mConfiguration = newConfig;  
  •             Slog.i(TAG, "Config changed: " + newConfig);  
  •   
  •             final Configuration configCopy = new Configuration(mConfiguration);  
  •               
  •             // TODO: If our config changes, should we auto dismiss any currently  
  •             // showing dialogs?  
  •             mShowDialogs = shouldShowDialogs(newConfig);  
  •   
  •             AttributeCache ac = AttributeCache.instance();  
  •             if (ac != null) {  
  •                 ac.updateConfiguration(configCopy);  
  •             }  
  •   
  •             // Make sure all resources in our process are updated  
  •             // right now, so that anyone who is going to retrieve  
  •             // resource values after we return will be sure to get  
  •             // the new ones.  This is especially important during  
  •             // boot, where the first config change needs to guarantee  
  •             // all resources have that config before following boot  
  •             // code is executed.  
  •             mSystemThread.applyConfigurationToResources(configCopy);  
  •   
  •             if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {  
  •                 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);  
  •                 msg.obj = new Configuration(configCopy);  
  •                 mHandler.sendMessage(msg);  
  •             }  
  •       
  •             for (int i=mLruProcesses.size()-1; i>=0; i--) {  
  •                 ProcessRecord app = mLruProcesses.get(i);  
  •                 try {  
  •                     if (app.thread != null) {  
  •                         if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending to proc "  
  •                                 + app.processName + " new config " + mConfiguration);  
  •                         app.thread.scheduleConfigurationChanged(configCopy);  
  •                     }  
  •                 } catch (Exception e) {  
  •                 }  
  •             }  
  •             Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);  
  •             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY  
  •                     | Intent.FLAG_RECEIVER_REPLACE_PENDING  
  •                     | Intent.FLAG_RECEIVER_FOREGROUND);  
  •             broadcastIntentLocked(null, null, intent, null, null, 0, null, null,  
  •                     null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);  
  •             if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {  
  •                 intent = new Intent(Intent.ACTION_LOCALE_CHANGED);  
  •                 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);  
  •                 broadcastIntentLocked(null, null, intent,  
  •                         null, null, 0, null, null,  
  •                         null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);  
  •             }  
  •         }  
  •     }  
  •       
  •     if (changes != 0 && starting == null) {  
  •         // If the configuration changed, and the caller is not already  
  •         // in the process of starting an activity, then find the top  
  •         // activity to check if its configuration needs to change.  
  •         starting = mMainStack.topRunningActivityLocked(null);  
  •     }  
  •       
  •     if (starting != null) {  
  •         kept = mMainStack.ensureActivityConfigurationLocked(starting, changes);  
  •         // And we need to make sure at this point that all other activities  
  •         // are made visible with the correct configuration.  
  •         mMainStack.ensureActivitiesVisibleLocked(starting, changes);  
  •     }  
  •       
  •     if (values != null && mWindowManager != null) {  
  •         mWindowManager.setNewConfiguration(mConfiguration);  
  •     }  
  •       
  •     return kept;  
  • }  


3.3.1.1 ActivityThread.handleConfigurationChanged()

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

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


[java] view plain copy


  • final void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) {  
  •   
  •     int configDiff = 0;  
  •   
  •     synchronized (mPackages) {  
  •         ... ...  
  •         applyConfigurationToResourcesLocked(config, compat);  
  •          
  •         if (mConfiguration == null) {  
  •             mConfiguration = new Configuration();  
  •         }  
  •         if (!mConfiguration.isOtherSeqNewer(config) && compat == null) {  
  •             return;  
  •         }  
  •         configDiff = mConfiguration.diff(config);  
  •         mConfiguration.updateFrom(config);  
  •         config = applyCompatConfiguration(mCurDefaultDisplayDpi);  
  •     }  
  •   
  •     ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config);  
  •     ... ...  
  •     if (callbacks != null) {  
  •         final int N = callbacks.size();  
  •         for (int i=0; i<N; i++) {  
  •             performConfigurationChanged(callbacks.get(i), config);  
  •         }  
  •     }  
  • }  



3.3.1.3 ActivityStack.ensureActivityConfigurationLocked(ActivityRecord r, int globalChanges)



[java] view plain copy


  • final boolean ensureActivityConfigurationLocked(ActivityRecord r,  
  •         int globalChanges) {  
  •     if (mConfigWillChange) {  
  •         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •                 "Skipping config check (will change): " + r);  
  •         return true;  
  •     }  
  •       
  •     if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •             "Ensuring correct configuration: " + r);  
  •       
  •     // Short circuit: if the two configurations are the exact same  
  •     // object (the common case), then there is nothing to do.  
  •     Configuration newConfig = mService.mConfiguration;  
  •     if (r.configuration == newConfig && !r.forceNewConfig) {  
  •         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •                 "Configuration unchanged in " + r);  
  •         return true;  
  •     }  
  •       
  •     // We don't worry about activities that are finishing.  
  •     if (r.finishing) {  
  •         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •                 "Configuration doesn't matter in finishing " + r);  
  •         r.stopFreezingScreenLocked(false);  
  •         return true;  
  •     }  
  •       
  •     // Okay we now are going to make this activity have the new config.  
  •     // But then we need to figure out how it needs to deal with that.  
  •     Configuration oldConfig = r.configuration;  
  •     r.configuration = newConfig;  
  •   
  •     // Determine what has changed.  May be nothing, if this is a config  
  •     // that has come back from the app after going idle.  In that case  
  •     // we just want to leave the official config object now in the  
  •     // activity and do nothing else.  
  •     final int changes = oldConfig.diff(newConfig);  
  •     if (changes == 0 && !r.forceNewConfig) {  
  •         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •                 "Configuration no differences in " + r);  
  •         return true;  
  •     }  
  •   
  •     // If the activity isn't currently running, just leave the new  
  •     // configuration and it will pick that up next time it starts.  
  •     if (r.app == null || r.app.thread == null) {  
  •         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •                 "Configuration doesn't matter not running " + r);  
  •         r.stopFreezingScreenLocked(false);  
  •         r.forceNewConfig = false;  
  •         return true;  
  •     }  
  •       
  •     // Figure out how to handle the changes between the configurations.  
  •     if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {  
  •         Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"  
  •                 + Integer.toHexString(changes) + ", handles=0x"  
  •                 + Integer.toHexString(r.info.getRealConfigChanged())  
  •                 + ", newConfig=" + newConfig);  
  •     }  
  •     if ((changes&(~r.info.getRealConfigChanged())) != 0 || r.forceNewConfig) {  
  •         // Aha, the activity isn't handling the change, so DIE DIE DIE.  
  •         r.configChangeFlags |= changes;  
  •         r.startFreezingScreenLocked(r.app, globalChanges);  
  •         r.forceNewConfig = false;  
  •         if (r.app == null || r.app.thread == null) {  
  •             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •                     "Config is destroying non-running " + r);  
  •             destroyActivityLocked(r, true, false, "config");  
  •         } else if (r.state == ActivityState.PAUSING) {  
  •             // A little annoying: we are waiting for this activity to  
  •             // finish pausing.  Let's not do anything now, but just  
  •             // flag that it needs to be restarted when done pausing.  
  •             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •                     "Config is skipping already pausing " + r);  
  •             r.configDestroy = true;  
  •             return true;  
  •         } else if (r.state == ActivityState.RESUMED) {  
  •             // Try to optimize this case: the configuration is changing  
  •             // and we need to restart the top, resumed activity.  
  •             // Instead of doing the normal handshaking, just say  
  •             // "restart!".  
  •             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •                     "Config is relaunching resumed " + r);  
  •             relaunchActivityLocked(r, r.configChangeFlags, true);  
  •             r.configChangeFlags = 0;  
  •         } else {  
  •             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,  
  •                     "Config is relaunching non-resumed " + r);  
  •             relaunchActivityLocked(r, r.configChangeFlags, false);  
  •             r.configChangeFlags = 0;  
  •         }  
  •          
  •         // All done...  tell the caller we weren't able to keep this  
  •         // activity around.  
  •         return false;  
  •     }  
  •       
  •     // Default case: the activity can handle this new configuration, so  
  •     // hand it over.  Note that we don't need to give it the new  
  •     // configuration, since we always send configuration changes to all  
  •     // process when they happen so it can just use whatever configuration  
  •     // it last got.  
  •     if (r.app != null && r.app.thread != null) {  
  •         try {  
  •             if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + r);  
  •             r.app.thread.scheduleActivityConfigurationChanged(r.appToken);  
  •         } catch (RemoteException e) {  
  •             // If process died, whatever.  
  •         }  
  •     }  
  •     r.stopFreezingScreenLocked(false);  
  •       
  •     return true;  


回复 支持 反对

使用道具 举报

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
板凳
 楼主| 发表于 2016-5-7 16:38:44 | 只看该作者
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
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Comsenz Inc.

GMT+8, 2025-12-15 01:49 , Processed in 0.045540 second(s), 7 queries , Apc On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表