补充:4.4.4bug已经被修改
切入正题
在AccessibilitySettings.java中,点击自动旋转的调用以下函数
private void handleLockScreenRotationPreferenceClick() {
RotationPolicy.setRotationLockForAccessibility(getActivity(),
!mToggleLockScreenRotationPreference.isChecked());
}
很自然的跟踪到RotationPolicy.java
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.
2.
在WindowManagerService.java中看到这个函数
public void thawRotation() {
if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
"thawRotation()")) {
throw new SecurityException("Requires SET_ORIENTATION permission");
}
if (DEBUG_ORIENTATION) Slog.v(TAG, "thawRotation: mRotation=" + mRotation);
mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE, 777); // rot not used
updateRotationUnchecked(false, false);
}
关键点来了:mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE, 777); // rot not used
看样子这个是主要部分。控制着旋转
updateRotationUnchecked(false, false);看起来是个状态更新。到时候更下去看看
紧跟着PhoneWindowManager.java
public void setUserRotationMode(int mode, int rot) {
ContentResolver res = mContext.getContentResolver();
// mUserRotationMode and mUserRotation will be assigned by the content observer
if (mode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
Settings.System.putIntForUser(res,
Settings.System.USER_ROTATION,
rot,
UserHandle.USER_CURRENT);
Settings.System.putIntForUser(res,
Settings.System.ACCELEROMETER_ROTATION,
0,
UserHandle.USER_CURRENT);
} else {
Settings.System.putIntForUser(res,
Settings.System.ACCELEROMETER_ROTATION,
1,
UserHandle.USER_CURRENT);
}
}
这个函数居然也只是状态更新啊。蛋疼。那在哪里做的.
重新回到WindowManagerService.java分析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);
}
一句句分析
long origId = Binder.clearCallingIdentity();---à清除调用进程的UID、PID,重置为被调用进程的UID、PID
updateRotationUncheckedL
贴源码
// TODO(multidisplay): Rotate any display?
public boolean updateRotationUncheckedLocked(boolean inTransaction) {
if (mDeferredRotationPauseCount > 0) {
// 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);
//这玩意儿是旋转的动画,mAnimator是singleton,保存了ScreenRotationAnimation,同时,又持有DimSurface,想来这个就是最终要使用的Surface了吧。这里不做详细解释。
if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
// 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) {
// 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);//#这里比较重要。后续的计算都基于这个值。看下取到的是什么?
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) {
// No change.
return false;
}
if (DEBUG_ORIENTATION) {
Slog.v(TAG,
"Rotation changed to " + rotation + (altOrientation ? " (alt)" : "")
+ " from " + mRotation + (mAltOrientation ? " (alt)" : "")
+ ", forceApp=" + mForcedAppOrientation);
}
mRotation = rotation;
mAltOrientation = altOrientation;
mPolicy.setRotationLw(mRotation);//更新旋转状态,同步到WindowOrientationListener中---------------系统默认设置中的旋转bug就在这里没做好。
mWindowsFreezingScreen = true;
mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),
WINDOW_FREEZE_TIMEOUT_DURATION);//重新保存window信息
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;
}
补充下Surface.java中,四个方向的定义
public static final int ROTATION_0 = 0;
public static final int ROTATION_90 = 1;
public static final int ROTATION_180 = 2;
public static final int ROTATION_270 = 3;
int rotation = mPolicy.rotationForOrientationLw
切换到PhoneWindowManager.java
@Override
public int rotationForOrientationLw(int orientation, int lastRotation) {
if (true) {
Slog.v("WindowManager", "aaaaaaaaaa rotationForOrientationLw(orient="
+ orientation + ", last=" + lastRotation
+ "); user=" + mUserRotation + " "
+ ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED)
? "USER_ROTATION_LOCKED" : "")
);
}
synchronized (mLock) {
int sensorRotation = mOrientationListener.getProposedRotation(); // may be -1
if (sensorRotation < 0) {
sensorRotation = lastRotation;
}
…
…
这部分都是些系统旋转的东西
…
…
}
而这里是getProposedRotation,是在WindowOrientationListene
直接返回mProposedRotation。
mPolicy.setRotationLw(mRotation);
更新了这个listener的状态。
那么。WindowOrientationListene
跟进去后发现,在disable的状态中,没有重新初始化数字,依旧保存了上次的数值。导致了这个问题
public void disable() {
if (mSensor == null) {
Log.w(TAG, "Cannot detect sensors. Invalid disable");
return;
}
if (mEnabled == true) {
if (LOG) {
Log.d(TAG, "WindowOrientationListener disabled");
}
mSensorEventListener.reset();////添加这句
mSensorManager.unregisterListener(mSensorEventListener);
mEnabled = false;
}
}