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

于Rotation方面在Android中有点会涉及到。

1. 在Settings->Display中有“Auto-rotate screen” 选项,当enable或者disable的时候都会影响到系统的Rotation

2. 当旋转手机的时候,系统会做怎么的操作去通知Activity要旋转界面了。

3. 当新启一个应用需要强制横屏或者竖屏的时候,系统是怎么去判断的。


1. 当我们enable或者disable “Auto-rotate screen”的时候,系统会做什么

1.  RotationPolicy.setRotationLockForAccessibility()

     1. 当用户enable或者disable “Auto-rotate screen”的时候,会调用RotationPolicy.setRotationLockForAccessibility(), 而在这个函数里面如果是enable就调用wm.freezeRotation(Suface.ROTATION_0);   // goto 1.1

      2. 否则就调用wm.thawRotation().

[java]  view plain copy
  1. public static void setRotationLockForAccessibility(Context context, final boolean enabled) {  
  2.     Settings.System.putIntForUser(context.getContentResolver(),  
  3.             Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, enabled ? 1 : 0,  
  4.                     UserHandle.USER_CURRENT);  
  5.   
  6.     AsyncTask.execute(new Runnable() {  
  7.         @Override  
  8.         public void run() {  
  9.             try {  
  10.                 IWindowManager wm = WindowManagerGlobal.getWindowManagerService();  
  11.                 if (enabled) {  
  12.                     wm.freezeRotation(Surface.ROTATION_0);  
  13.                 } else {  
  14.                     wm.thawRotation();  
  15.                 }  
  16.             } catch (RemoteException exc) {  
  17.                 Log.w(TAG, "Unable to save auto-rotate setting");  
  18.             }  
  19.         }  
  20.     });  
  21. }  

1.1 WindowManagerService.freezeRotation()

      1. mPolicy.setUserRotationMode 通过PhoneWindowManager.setUserRotationMode()去设置Settings.System相关的数据库值,在PhoneWindowManager中会有一个Observe去监听Settings.System的数值变化,如果有变动就去调用SettingsObserver.onChange()   //goto 1.1.1

       2. updateRotationUnchecked(false, false);   // goto  1.1.2

[java]  view plain copy
  1. public void freezeRotation(int rotation) {  
  2.     ... ...  
  3.     if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation);  
  4.   
  5.     mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED,  
  6.             rotation == -1 ? mRotation : rotation);  
  7.     updateRotationUnchecked(falsefalse);  
  8. }  

1.1.1 SettingsObserver.onChange()

    1. updateSettings();  跟新系统相关的设置  //goto 1.1.1.1

    2. updateRotation(false);  

[java]  view plain copy
  1. @Override public void onChange(boolean selfChange) {  
  2.     updateSettings();  
  3.     updateRotation(false);  
  4. }  


1.1.2  WindowManagerService.updateRotationUnchecked()

      这是freezeRotation里面做的第二个动作,为什么要把它写在前面,因为在debug的时候,发现这个函数中会调用policy中函数请求mLock的锁,然后block住1.1.1.1 PhoneWindowManager.updateSettings()。

     1. updateRotationUncheckedLocked(false);   如果返回的是false,就去直接执行performLayoutAndPlaceSurfacesLocked 去进行后续的刷新工作 // goto 1.1.2.1

     2. 如果满足相应的条件, performLayoutAndPlaceSurfacesLocked()  //

     3. 如果Configuration有变化或者明确要求sendConfiguration,就调用sendNewConfiguration(); 让AMS去updateConfiguration。 //这时候还不会执行

[java]  view plain copy
  1. public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {  
  2.   
  3.     long origId = Binder.clearCallingIdentity();  
  4.     boolean changed;  
  5.     synchronized(mWindowMap) {  
  6.         changed = updateRotationUncheckedLocked(false);  // goto 1.1.2.1  
  7.         if (!changed || forceRelayout) {  
  8.             getDefaultDisplayContentLocked().layoutNeeded = true;  
  9.             performLayoutAndPlaceSurfacesLocked();  //后续分析  
  10.         }  
  11.     }  
  12.   
  13.     if (changed || alwaysSendConfiguration) {  
  14.         sendNewConfiguration();  
  15.     }  
  16. }  


1.1.2.1 WindowManagerService.updateRotationUncheckedLocked()

      1. mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);   // 返回0  goto 1.1.2.1.1

      2.  mPolicy.rotationHasCompatibleMetricsLw 

      3. 如果roataion 和altOrientataion都没有发生变化就直接返回 false.  (这种情况是在portrait模式下enable rotation),如果是landscape模式下就应该往下走了。

      4. computeScreenConfigurationLocked(null); // Update application display metrics. 跟新屏幕相关的信息。

[java]  view plain copy
  1. public boolean updateRotationUncheckedLocked(boolean inTransaction) {  
  2.     ... ...  
  3.     int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);  
  4.     boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(  
  5.             mForcedAppOrientation, rotation);  
  6.   
  7.     if (mRotation == rotation && mAltOrientation == altOrientation) {  
  8.         // No change.  
  9.         return false;  
  10.     }  
  11.   
  12.     mRotation = rotation;  
  13.     mAltOrientation = altOrientation;  
  14.     mPolicy.setRotationLw(mRotation);  
  15.   
  16.     mWindowsFreezingScreen = true;  
  17.     mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);  
  18.     mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),  
  19.             WINDOW_FREEZE_TIMEOUT_DURATION);  
  20.     mWaitingForConfig = true;  
  21.     getDefaultDisplayContentLocked().layoutNeeded = true;  
  22.     startFreezingDisplayLocked(inTransaction, 00);  
  23.     // startFreezingDisplayLocked can reset the ScreenRotationAnimation.  
  24.     screenRotationAnimation =  
  25.             mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);  
  26.   
  27.     // We need to update our screen size information to match the new  
  28.     // rotation.  Note that this is redundant with the later call to  
  29.     // sendNewConfiguration() that must be called after this function  
  30.     // returns...  however we need to do the screen size part of that  
  31.     // before then so we have the correct size to use when initializing  
  32.     // the rotation animation for the new rotation.  
  33.     computeScreenConfigurationLocked(null);  
  34.   
  35.     final DisplayContent displayContent = getDefaultDisplayContentLocked();  
  36.     final DisplayInfo displayInfo = displayContent.getDisplayInfo();  
  37.     if (!inTransaction) {  
  38.         if (SHOW_TRANSACTIONS) {  
  39.             Slog.i(TAG, ">>> OPEN TRANSACTION setRotationUnchecked");  
  40.         }  
  41.         Surface.openTransaction();  
  42.     }  
  43.     try {  
  44.         // NOTE: We disable the rotation in the emulator because  
  45.         //       it doesn't support hardware OpenGL emulation yet.  
  46.         if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null  
  47.                 && screenRotationAnimation.hasScreenshot()) {  
  48.             if (screenRotationAnimation.setRotationInTransaction(  
  49.                     rotation, mFxSession,  
  50.                     MAX_ANIMATION_DURATION, mTransitionAnimationScale,  
  51.                     displayInfo.logicalWidth, displayInfo.logicalHeight)) {  
  52.                 updateLayoutToAnimationLocked();  
  53.             }  
  54.         }  
  55.   
  56.         mDisplayManagerService.performTraversalInTransactionFromWindowManager();  
  57.     } finally {  
  58.         if (!inTransaction) {  
  59.             Surface.closeTransaction();  
  60.             if (SHOW_LIGHT_TRANSACTIONS) {  
  61.                 Slog.i(TAG, "<<< CLOSE TRANSACTION setRotationUnchecked");  
  62.             }  
  63.         }  
  64.     }  
  65.   
  66.     final WindowList windows = displayContent.getWindowList();  
  67.     for (int i = windows.size() - 1; i >= 0; i--) {  
  68.         WindowState w = windows.get(i);  
  69.         if (w.mHasSurface) {  
  70.             if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);  
  71.             w.mOrientationChanging = true;  
  72.             mInnerFields.mOrientationChangeComplete = false;  
  73.         }  
  74.     }  
  75.   
  76.     for (int i=mRotationWatchers.size()-1; i>=0; i--) {  
  77.         try {  
  78.             mRotationWatchers.get(i).onRotationChanged(rotation);  
  79.         } catch (RemoteException e) {  
  80.         }  
  81.     }  
  82.   
  83.     scheduleNotifyRotationChangedIfNeededLocked(displayContent, rotation);  
  84.   
  85.     return true;  
  86. }  

1.1.2.1.1 PhoneWindowManager.rotationForOrientationLw()

       这个函数的主要作用是返回跟Orientation相关的rotation,如果没有固定的设置,系统会返回一个默认的Rotation值。

       1.  先去调用mOrientationListener.getProposeRotation()去获取Sensor认为的合适的rotation值,通常是-1,我debug的时候返回的就是。mOrientationListener 为MyOrientationListener对象

       2. 由于此时mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED 所以把preferredRotation = mUserRotation; 然后跟据对应的orientation选择对应的Rotation返回,我们这个case是走到default里面把preferredRotation返回回去。

[java]  view plain copy
  1. public int rotationForOrientationLw(int orientation, int lastRotation) {  
  2.   
  3.     synchronized (mLock) {  
  4.         int sensorRotation = mOrientationListener.getProposedRotation(); // may be -1  
  5.         if (sensorRotation < 0) {  
  6.             sensorRotation = lastRotation;  
  7.         }  
  8.   
  9.         final int preferredRotation;  
  10.         if (mLidState == LID_OPEN && mLidOpenRotation >= 0) {  
  11.            .... ...  
  12.         } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED  
  13.                 && orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {  
  14.             // Apply rotation lock.  Does not apply to NOSENSOR.  
  15.             // The idea is that the user rotation expresses a weak preference for the direction  
  16.             // of gravity and as NOSENSOR is never affected by gravity, then neither should  
  17.             // NOSENSOR be affected by rotation lock (although it will be affected by docks).  
  18.             preferredRotation = mUserRotation;  
  19.         } else {  
  20.             // No overriding preference.  
  21.             // We will do exactly what the application asked us to do.  
  22.             preferredRotation = -1;  
  23.         }  
  24.   
  25.         switch (orientation) {  
  26.             case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:  
  27.                 // Return portrait unless overridden.  
  28.                 if (isAnyPortrait(preferredRotation)) {  
  29.                     return preferredRotation;  
  30.                 }  
  31.                 return mPortraitRotation;  
  32.   
  33.             case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:  
  34.                 // Return landscape unless overridden.  
  35.                 if (isLandscapeOrSeascape(preferredRotation)) {  
  36.                     return preferredRotation;  
  37.                 }  
  38.                 return mLandscapeRotation;  
  39.   
  40.             case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:  
  41.                 // Return reverse portrait unless overridden.  
  42.                 if (isAnyPortrait(preferredRotation)) {  
  43.                     return preferredRotation;  
  44.                 }  
  45.                 return mUpsideDownRotation;  
  46.   
  47.             case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:  
  48.                 // Return seascape unless overridden.  
  49.                 if (isLandscapeOrSeascape(preferredRotation)) {  
  50.                     return preferredRotation;  
  51.                 }  
  52.                 return mSeascapeRotation;  
  53.   
  54.             case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:  
  55.                 // Return either landscape rotation.  
  56.                 if (isLandscapeOrSeascape(preferredRotation)) {  
  57.                     return preferredRotation;  
  58.                 }  
  59.                 if (isLandscapeOrSeascape(lastRotation)) {  
  60.                     return lastRotation;  
  61.                 }  
  62.                 return mLandscapeRotation;  
  63.   
  64.             case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:  
  65.                 // Return either portrait rotation.  
  66.                 if (isAnyPortrait(preferredRotation)) {  
  67.                     return preferredRotation;  
  68.                 }  
  69.                 if (isAnyPortrait(lastRotation)) {  
  70.                     return lastRotation;  
  71.                 }  
  72.                 return mPortraitRotation;  
  73.   
  74.             default:  
  75.                 // For USER, UNSPECIFIED, NOSENSOR, SENSOR and FULL_SENSOR,  
  76.                 // just return the preferred orientation we already calculated.  
  77.                 if (preferredRotation >= 0) {  
  78.                     return preferredRotation;  
  79.                 }  
  80.                 return Surface.ROTATION_0;  
  81.         }  
  82.     }  
  83. }  


1.1.1.1 PhoneWindowManager.updateSettings()

   当 1.1.2的lock释放之后,也就是 PhoneWindowManager.rotationForOrientationLw()执行完,updateSettings会等到mLock锁.

   由于userRotation和userRotationMode都发生了变化,所以会先后执行

     1. updateOrientationListenerLp();  // goto 1.1.1.1.1

      2. updateRotation(true);  //这个操作跟1.1.1.2是一样的,只不过这次需要去sendConfiguration了。

[java]  view plain copy
  1. public void updateSettings() {  
  2.     ContentResolver resolver = mContext.getContentResolver();  
  3.     boolean updateRotation = false;  
  4.     synchronized (mLock) {  
  5.         ... ...  
  6.   
  7.         // Configure rotation lock.  
  8.         int userRotation = Settings.System.getIntForUser(resolver,  
  9.                 Settings.System.USER_ROTATION, Surface.ROTATION_0,  
  10.                 UserHandle.USER_CURRENT);  
  11.         if (mUserRotation != userRotation) {  
  12.             mUserRotation = userRotation;  
  13.             updateRotation = true;  
  14.         }  
  15.         int userRotationMode = Settings.System.getIntForUser(resolver,  
  16.                 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0 ?  
  17.                         WindowManagerPolicy.USER_ROTATION_FREE :  
  18.                                 WindowManagerPolicy.USER_ROTATION_LOCKED;  
  19.         if (mUserRotationMode != userRotationMode) {  
  20.             mUserRotationMode = userRotationMode;  
  21.             updateRotation = true;  
  22.             updateOrientationListenerLp();  
  23.         }  
  24.   
  25.     }  
  26.     if (updateRotation) {  
  27.         updateRotation(true);  
  28.     }  
  29. }  

1.1.1.1.1 PhoneWindowManager.updateOrientationListenerLp();

  这是函数很简单,由于我们把Rotation打开了,所以就去enable mOrientationListener (MyOrientationListener),作为Sensor变化的一个listener的回调函数。

[java]  view plain copy
  1. void updateOrientationListenerLp() {  
  2.     if (!mOrientationListener.canDetectOrientation()) {  
  3.         // If sensor is turned off or nonexistent for some reason  
  4.         return;  
  5.     }  
  6.     //Could have been invoked due to screen turning on or off or  
  7.     //change of the currently visible window's orientation  
  8.     if (localLOGV) Log.v(TAG, "Screen status="+mScreenOnEarly+  
  9.             ", current orientation="+mCurrentAppOrientation+  
  10.             ", SensorEnabled="+mOrientationSensorEnabled);  
  11.     boolean disable = true;  
  12.     if (mScreenOnEarly) {  
  13.         if (needSensorRunningLp()) {  
  14.             disable = false;  
  15.             //enable listener if not already enabled  
  16.             if (!mOrientationSensorEnabled) {  
  17.                 mOrientationListener.enable();  
  18.                 if(localLOGV) Log.v(TAG, "Enabling listeners");  
  19.                 mOrientationSensorEnabled = true;  
  20.             }  
  21.         }   
  22.     }   
  23.     //check if sensors need to be disabled  
  24.     if (disable && mOrientationSensorEnabled) {  
  25.         mOrientationListener.disable();  
  26.         if(localLOGV) Log.v(TAG, "Disabling listeners");  
  27.         mOrientationSensorEnabled = false;  
  28.     }  

1.1.1.1 PhoneWindowManager.sendNewConfiguration()

 调用AMS去updateconfigurattion,后续分析

[java]  view plain copy
  1. void sendNewConfiguration() {  
  2.     try {  
  3.         mActivityManager.updateConfiguration(null);  
  4.     } catch (RemoteException e) {  

你可能感兴趣的:(Android4.1 关于Rotation相关的Configuration整体分析)