我們通常在手機上旋轉屏幕可以應用主動旋轉,也可以讓應用隨系統旋轉。這裏我們先分析應用隨系統旋轉的情況。
設置選項(旋轉屏幕)
隨系統選裝的話,我們先要在手機設置中選擇顯示項,設備旋轉時自動旋轉。最終會調用RotationPolicy.setRotationLockForAccessibility函數,我們先來看下這個函數
- 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);
-
- setRotationLock(enabled, NATURAL_ROTATION);
- }
setRotationLock函數會根據參數調用WMS的freezeRotation和thawRotation函數。
- private static void setRotationLock(final boolean enabled, final int rotation) {
- AsyncTask.execute(new Runnable() {
- @Override
- public void run() {
- try {
- IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
- if (enabled) {
- wm.freezeRotation(rotation);
- } else {
- wm.thawRotation();
- }
- } catch (RemoteException exc) {
- Log.w(TAG, "Unable to save auto-rotate setting");
- }
- }
- });
- }
寫入設置數據庫
我們先來看看WMS的thawRotation函數,先會調用PhoneWindowManager的setUserRotationMode函數,然後調用upateRotationUnchecked(這裏處理設備旋轉,我們下篇博客分析)。
- 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);
-
- long origId = Binder.clearCallingIdentity();
- try {
- mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE,
- 777); // rot not used
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
-
- updateRotationUnchecked(false, false);//後續分析
- }
我們再來看看freezeRotation函數,只是調用PhoneWindowManager的setUserRotationMode的參數不一樣,這裏是Locked,而thawRotation傳下去的參數是free
- @Override
- public void freezeRotation(int rotation) {
- if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
- "freezeRotation()")) {
- throw new SecurityException("Requires SET_ORIENTATION permission");
- }
- if (rotation < -1 || rotation > Surface.ROTATION_270) {
- throw new IllegalArgumentException("Rotation argument must be -1 or a valid "
- + "rotation constant.");
- }
-
- if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation);
-
- long origId = Binder.clearCallingIdentity();
- try {
- mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED,
- rotation == -1 ? mRotation : rotation);
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
-
- updateRotationUnchecked(false, false);
- }
PhoneWindowManager的setUserRotationMode只是設置Settings數據庫,然後這肯定會有監聽的。
- @Override
- 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);
- }
- }
PhoneWindowManager監聽旋轉相關Settings數據項
下面就是監測Settings相關數據庫,當設置改變後會調用onChange,然後調用updateSettings和updateRotation,updateRotation就是調用WMS的updateRotationUnchecked函數,我們下篇博客分析。
- class SettingsObserver extends ContentObserver {
- SettingsObserver(Handler handler) {
- super(handler);
- }
-
- void observe() {
- // Observe all users' changes
- ContentResolver resolver = mContext.getContentResolver();
- resolver.registerContentObserver(Settings.System.getUriFor(
- Settings.System.END_BUTTON_BEHAVIOR), false, this,
- UserHandle.USER_ALL);
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR), false, this,
- UserHandle.USER_ALL);
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.WAKE_GESTURE_ENABLED), false, this,
- UserHandle.USER_ALL);
- resolver.registerContentObserver(Settings.System.getUriFor(
- Settings.System.ACCELEROMETER_ROTATION), false, this,
- UserHandle.USER_ALL);
- resolver.registerContentObserver(Settings.System.getUriFor(
- Settings.System.USER_ROTATION), false, this,
- UserHandle.USER_ALL);
- resolver.registerContentObserver(Settings.System.getUriFor(
- Settings.System.SCREEN_OFF_TIMEOUT), false, this,
- UserHandle.USER_ALL);
- resolver.registerContentObserver(Settings.System.getUriFor(
- Settings.System.POINTER_LOCATION), false, this,
- UserHandle.USER_ALL);
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.DEFAULT_INPUT_METHOD), false, this,
- UserHandle.USER_ALL);
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS), false, this,
- UserHandle.USER_ALL);
- resolver.registerContentObserver(Settings.Global.getUriFor(
- Settings.Global.POLICY_CONTROL), false, this,
- UserHandle.USER_ALL);
- updateSettings();
- }
-
- @Override public void onChange(boolean selfChange) {
- updateSettings();
- updateRotation(false);
- }
- }
updateSettings中,當設置不一致的時候會調用updateOrientationListenerLp函數和updateRotation之前提過,是調用WMS的updateRotationUnchecked函數。
- public void updateSettings() {
- ......
-
- // 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);
- }
- }
註冊 取消傳感器回調
updateOrientationListenerLp函數就是enable和disable傳感器。
- void updateOrientationListenerLp() {
- if (!mOrientationListener.canDetectOrientation()) {
- // If sensor is turned off or nonexistent for some reason
- return;
- }
-
- boolean disable = true;
- if (mScreenOnEarly && mAwake &&
- mKeyguardDrawComplete && mWindowManagerDrawComplete) {
- if (needSensorRunningLp()) {
- disable = false;
- //enable listener if not already enabled
- if (!mOrientationSensorEnabled) {
- mOrientationListener.enable();
- mOrientationSensorEnabled = true;
- }
- }
- }
- //check if sensors need to be disabled
- if (disable && mOrientationSensorEnabled) {
- mOrientationListener.disable();
- mOrientationSensorEnabled = false;
- }
- }
mOrientationListener的enable和disable函數只是註冊傳感器回調和去除傳感器回調。
- public void enable() {
- synchronized (mLock) {
- if (mSensor == null) {
- Slog.w(TAG, "Cannot detect sensors. Not enabled");
- return;
- }
- if (mEnabled == false) {
- if (LOG) {
- Slog.d(TAG, "WindowOrientationListener enabled");
- }
- mOrientationJudge.resetLocked();
- mSensorManager.registerListener(mOrientationJudge, mSensor, mRate, mHandler);
- mEnabled = true;
- }
- }
- }
-
- /**
- * Disables the WindowOrientationListener.
- */
- public void disable() {
- synchronized (mLock) {
- if (mSensor == null) {
- Slog.w(TAG, "Cannot detect sensors. Invalid disable");
- return;
- }
- if (mEnabled == true) {
- if (LOG) {
- Slog.d(TAG, "WindowOrientationListener disabled");
- }
- mSensorManager.unregisterListener(mOrientationJudge);
- mEnabled = false;
- }
- }
- }
這裏我們主要關心註冊傳感器的mOrientationJudge的回調。二mOrientationJudge就是OrientationSensorJudge 類型,當傳感器數據過來時會調用onSensorChanged函數,最後調用onProposedRotationChanged,這個onProposedRotationChanged是WindowOrientationListener的函數。而WindowOrientationListener是在PhoneWindowManger中新建的。
- final class OrientationSensorJudge extends OrientationJudge {
- ......
-
- @Override
- public void onSensorChanged(SensorEvent event) {
- int newRotation;
- synchronized (mLock) {
- mDesiredRotation = (int) event.values[0];
- newRotation = evaluateRotationChangeLocked();
- }
- if (newRotation >=0) {
- onProposedRotationChanged(newRotation);
- }
- }
最後就到MyOrientationListener 的onProposedRotationChanged函數,這裏就是發送了一個消息。
- class MyOrientationListener extends WindowOrientationListener {
- private final Runnable mUpdateRotationRunnable = new Runnable() {
- @Override
- public void run() {
- // send interaction hint to improve redraw performance
- mPowerManagerInternal.powerHint(PowerManagerInternal.POWER_HINT_INTERACTION, 0);
- updateRotation(false);
- }
- };
-
- MyOrientationListener(Context context, Handler handler) {
- super(context, handler);
- }
-
- @Override
- public void onProposedRotationChanged(int rotation) {
- if (localLOGV) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation);
- mHandler.post(mUpdateRotationRunnable);
- }
- }
最後就調用其run函數,run函數先會提升性能(cpu頻率),然後調用了updateRotation,這個函數一樣就到WMS的updateRotationUnchecked函數了。