关于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().
- public static void setRotationLockForAccessibility(Context context, final boolean enabled) {
- Settings.System.putIntForUser(context.getContentResolver(),
- Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, enabled ? 1 : 0,
- UserHandle.USER_CURRENT);
- AsyncTask.execute(new Runnable() {
- @Override
- public void run() {
- try {
- IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
- if (enabled) {
- wm.freezeRotation(Surface.ROTATION_0);
- } else {
- wm.thawRotation();
- }
- } catch (RemoteException exc) {
- Log.w(TAG, "Unable to save auto-rotate setting");
- }
- }
- });
- }
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
- public void freezeRotation(int rotation) {
- ... ...
- if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation);
- mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED,
- rotation == -1 ? mRotation : rotation);
- updateRotationUnchecked(false, false);
- }
1.1.1 SettingsObserver.onChange()
1. updateSettings(); 跟新系统相关的设置 //goto 1.1.1.1
2. updateRotation(false);
- @Override public void onChange(boolean selfChange) {
- updateSettings();
- updateRotation(false);
- }
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。 //这时候还不会执行
- public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
- long origId = Binder.clearCallingIdentity();
- boolean changed;
- synchronized(mWindowMap) {
- changed = updateRotationUncheckedLocked(false); // goto 1.1.2.1
- if (!changed || forceRelayout) {
- getDefaultDisplayContentLocked().layoutNeeded = true;
- performLayoutAndPlaceSurfacesLocked(); //后续分析
- }
- }
- if (changed || alwaysSendConfiguration) {
- sendNewConfiguration();
- }
- }
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. 跟新屏幕相关的信息。
- 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;
- }
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返回回去。
- 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) {
- .... ...
- } 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;
- }
- }
- }
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了。
- public void updateSettings() {
- ContentResolver resolver = mContext.getContentResolver();
- boolean updateRotation = false;
- synchronized (mLock) {
- ... ...
- // Configure rotation lock.
- int userRotation = Settings.System.getIntForUser(resolver,
- Settings.System.USER_ROTATION, Surface.ROTATION_0,
- UserHandle.USER_CURRENT);
- if (mUserRotation != userRotation) {
- mUserRotation = userRotation;
- updateRotation = true;
- }
- int userRotationMode = Settings.System.getIntForUser(resolver,
- Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0 ?
- WindowManagerPolicy.USER_ROTATION_FREE :
- WindowManagerPolicy.USER_ROTATION_LOCKED;
- if (mUserRotationMode != userRotationMode) {
- mUserRotationMode = userRotationMode;
- updateRotation = true;
- updateOrientationListenerLp();
- }
- }
- if (updateRotation) {
- updateRotation(true);
- }
- }
1.1.1.1.1 PhoneWindowManager.updateOrientationListenerLp();
这是函数很简单,由于我们把Rotation打开了,所以就去enable mOrientationListener (MyOrientationListener),作为Sensor变化的一个listener的回调函数。
- void updateOrientationListenerLp() {
- if (!mOrientationListener.canDetectOrientation()) {
- // If sensor is turned off or nonexistent for some reason
- return;
- }
- //Could have been invoked due to screen turning on or off or
- //change of the currently visible window's orientation
- if (localLOGV) Log.v(TAG, "Screen status="+mScreenOnEarly+
- ", current orientation="+mCurrentAppOrientation+
- ", SensorEnabled="+mOrientationSensorEnabled);
- boolean disable = true;
- if (mScreenOnEarly) {
- if (needSensorRunningLp()) {
- disable = false;
- //enable listener if not already enabled
- if (!mOrientationSensorEnabled) {
- mOrientationListener.enable();
- if(localLOGV) Log.v(TAG, "Enabling listeners");
- mOrientationSensorEnabled = true;
- }
- }
- }
- //check if sensors need to be disabled
- if (disable && mOrientationSensorEnabled) {
- mOrientationListener.disable();
- if(localLOGV) Log.v(TAG, "Disabling listeners");
- mOrientationSensorEnabled = false;
- }
1.1.1.1 PhoneWindowManager.sendNewConfiguration()
调用AMS去updateconfigurattion,后续分析
- void sendNewConfiguration() {
- try {
- mActivityManager.updateConfiguration(null);
- } catch (RemoteException e) {
- }
- }