您的位置:首页 > 移动开发 > Android开发

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

2013-01-22 19:22 302 查看
关于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) {
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: