Android6.0 旋轉屏幕(一)WMS註冊傳感器回調

我們通常在手機上旋轉屏幕可以應用主動旋轉,也可以讓應用隨系統旋轉。這裏我們先分析應用隨系統旋轉的情況。


設置選項(旋轉屏幕)

隨系統選裝的話,我們先要在手機設置中選擇顯示項,設備旋轉時自動旋轉。最終會調用RotationPolicy.setRotationLockForAccessibility函數,我們先來看下這個函數

  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. setRotationLock(enabled, NATURAL_ROTATION);
  6. }

setRotationLock函數會根據參數調用WMS的freezeRotation和thawRotation函數。

  1. private static void setRotationLock(final boolean enabled, final int rotation) {
  2. AsyncTask.execute(new Runnable() {
  3. @Override
  4. public void run() {
  5. try {
  6. IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
  7. if (enabled) {
  8. wm.freezeRotation(rotation);
  9. } else {
  10. wm.thawRotation();
  11. }
  12. } catch (RemoteException exc) {
  13. Log.w(TAG, "Unable to save auto-rotate setting");
  14. }
  15. }
  16. });
  17. }

寫入設置數據庫

我們先來看看WMS的thawRotation函數,先會調用PhoneWindowManager的setUserRotationMode函數,然後調用upateRotationUnchecked(這裏處理設備旋轉,我們下篇博客分析)。

  1. public void thawRotation() {
  2. if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
  3. "thawRotation()")) {
  4. throw new SecurityException("Requires SET_ORIENTATION permission");
  5. }
  6. if (DEBUG_ORIENTATION) Slog.v(TAG, "thawRotation: mRotation=" + mRotation);
  7. long origId = Binder.clearCallingIdentity();
  8. try {
  9. mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE,
  10. 777); // rot not used
  11. } finally {
  12. Binder.restoreCallingIdentity(origId);
  13. }
  14. updateRotationUnchecked(false, false);//後續分析
  15. }

我們再來看看freezeRotation函數,只是調用PhoneWindowManager的setUserRotationMode的參數不一樣,這裏是Locked,而thawRotation傳下去的參數是free

  1. @Override
  2. public void freezeRotation(int rotation) {
  3. if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
  4. "freezeRotation()")) {
  5. throw new SecurityException("Requires SET_ORIENTATION permission");
  6. }
  7. if (rotation < -1 || rotation > Surface.ROTATION_270) {
  8. throw new IllegalArgumentException("Rotation argument must be -1 or a valid "
  9. + "rotation constant.");
  10. }
  11. if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation);
  12. long origId = Binder.clearCallingIdentity();
  13. try {
  14. mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED,
  15. rotation == -1 ? mRotation : rotation);
  16. } finally {
  17. Binder.restoreCallingIdentity(origId);
  18. }
  19. updateRotationUnchecked(false, false);
  20. }



PhoneWindowManager的setUserRotationMode只是設置Settings數據庫,然後這肯定會有監聽的。

  1. @Override
  2. public void setUserRotationMode(int mode, int rot) {
  3. ContentResolver res = mContext.getContentResolver();
  4. // mUserRotationMode and mUserRotation will be assigned by the content observer
  5. if (mode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
  6. Settings.System.putIntForUser(res,
  7. Settings.System.USER_ROTATION,
  8. rot,
  9. UserHandle.USER_CURRENT);
  10. Settings.System.putIntForUser(res,
  11. Settings.System.ACCELEROMETER_ROTATION,
  12. 0,
  13. UserHandle.USER_CURRENT);
  14. } else {
  15. Settings.System.putIntForUser(res,
  16. Settings.System.ACCELEROMETER_ROTATION,
  17. 1,
  18. UserHandle.USER_CURRENT);
  19. }
  20. }


PhoneWindowManager監聽旋轉相關Settings數據項

下面就是監測Settings相關數據庫,當設置改變後會調用onChange,然後調用updateSettings和updateRotation,updateRotation就是調用WMS的updateRotationUnchecked函數,我們下篇博客分析。

  1. class SettingsObserver extends ContentObserver {
  2. SettingsObserver(Handler handler) {
  3. super(handler);
  4. }
  5. void observe() {
  6. // Observe all users' changes
  7. ContentResolver resolver = mContext.getContentResolver();
  8. resolver.registerContentObserver(Settings.System.getUriFor(
  9. Settings.System.END_BUTTON_BEHAVIOR), false, this,
  10. UserHandle.USER_ALL);
  11. resolver.registerContentObserver(Settings.Secure.getUriFor(
  12. Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR), false, this,
  13. UserHandle.USER_ALL);
  14. resolver.registerContentObserver(Settings.Secure.getUriFor(
  15. Settings.Secure.WAKE_GESTURE_ENABLED), false, this,
  16. UserHandle.USER_ALL);
  17. resolver.registerContentObserver(Settings.System.getUriFor(
  18. Settings.System.ACCELEROMETER_ROTATION), false, this,
  19. UserHandle.USER_ALL);
  20. resolver.registerContentObserver(Settings.System.getUriFor(
  21. Settings.System.USER_ROTATION), false, this,
  22. UserHandle.USER_ALL);
  23. resolver.registerContentObserver(Settings.System.getUriFor(
  24. Settings.System.SCREEN_OFF_TIMEOUT), false, this,
  25. UserHandle.USER_ALL);
  26. resolver.registerContentObserver(Settings.System.getUriFor(
  27. Settings.System.POINTER_LOCATION), false, this,
  28. UserHandle.USER_ALL);
  29. resolver.registerContentObserver(Settings.Secure.getUriFor(
  30. Settings.Secure.DEFAULT_INPUT_METHOD), false, this,
  31. UserHandle.USER_ALL);
  32. resolver.registerContentObserver(Settings.Secure.getUriFor(
  33. Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS), false, this,
  34. UserHandle.USER_ALL);
  35. resolver.registerContentObserver(Settings.Global.getUriFor(
  36. Settings.Global.POLICY_CONTROL), false, this,
  37. UserHandle.USER_ALL);
  38. updateSettings();
  39. }
  40. @Override public void onChange(boolean selfChange) {
  41. updateSettings();
  42. updateRotation(false);
  43. }
  44. }

updateSettings中,當設置不一致的時候會調用updateOrientationListenerLp函數和updateRotation之前提過,是調用WMS的updateRotationUnchecked函數。

  1. public void updateSettings() {
  2. ......
  3. // Configure rotation lock.
  4. int userRotation = Settings.System.getIntForUser(resolver,
  5. Settings.System.USER_ROTATION, Surface.ROTATION_0,
  6. UserHandle.USER_CURRENT);
  7. if (mUserRotation != userRotation) {
  8. mUserRotation = userRotation;
  9. updateRotation = true;
  10. }
  11. int userRotationMode = Settings.System.getIntForUser(resolver,
  12. Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0 ?
  13. WindowManagerPolicy.USER_ROTATION_FREE :
  14. WindowManagerPolicy.USER_ROTATION_LOCKED;
  15. if (mUserRotationMode != userRotationMode) {
  16. mUserRotationMode = userRotationMode;
  17. updateRotation = true;
  18. updateOrientationListenerLp();
  19. }
  20. ......
  21. if (updateRotation) {
  22. updateRotation(true);
  23. }
  24. }


註冊 取消傳感器回調

updateOrientationListenerLp函數就是enable和disable傳感器。

  1. void updateOrientationListenerLp() {
  2. if (!mOrientationListener.canDetectOrientation()) {
  3. // If sensor is turned off or nonexistent for some reason
  4. return;
  5. }
  6. boolean disable = true;
  7. if (mScreenOnEarly && mAwake &&
  8. mKeyguardDrawComplete && mWindowManagerDrawComplete) {
  9. if (needSensorRunningLp()) {
  10. disable = false;
  11. //enable listener if not already enabled
  12. if (!mOrientationSensorEnabled) {
  13. mOrientationListener.enable();
  14. mOrientationSensorEnabled = true;
  15. }
  16. }
  17. }
  18. //check if sensors need to be disabled
  19. if (disable && mOrientationSensorEnabled) {
  20. mOrientationListener.disable();
  21. mOrientationSensorEnabled = false;
  22. }
  23. }

mOrientationListener的enable和disable函數只是註冊傳感器回調和去除傳感器回調。

  1. public void enable() {
  2. synchronized (mLock) {
  3. if (mSensor == null) {
  4. Slog.w(TAG, "Cannot detect sensors. Not enabled");
  5. return;
  6. }
  7. if (mEnabled == false) {
  8. if (LOG) {
  9. Slog.d(TAG, "WindowOrientationListener enabled");
  10. }
  11. mOrientationJudge.resetLocked();
  12. mSensorManager.registerListener(mOrientationJudge, mSensor, mRate, mHandler);
  13. mEnabled = true;
  14. }
  15. }
  16. }
  17. /**
  18. * Disables the WindowOrientationListener.
  19. */
  20. public void disable() {
  21. synchronized (mLock) {
  22. if (mSensor == null) {
  23. Slog.w(TAG, "Cannot detect sensors. Invalid disable");
  24. return;
  25. }
  26. if (mEnabled == true) {
  27. if (LOG) {
  28. Slog.d(TAG, "WindowOrientationListener disabled");
  29. }
  30. mSensorManager.unregisterListener(mOrientationJudge);
  31. mEnabled = false;
  32. }
  33. }
  34. }

這裏我們主要關心註冊傳感器的mOrientationJudge的回調。二mOrientationJudge就是OrientationSensorJudge 類型,當傳感器數據過來時會調用onSensorChanged函數,最後調用onProposedRotationChanged,這個onProposedRotationChanged是WindowOrientationListener的函數。而WindowOrientationListener是在PhoneWindowManger中新建的。

  1. final class OrientationSensorJudge extends OrientationJudge {
  2. ......
  3. @Override
  4. public void onSensorChanged(SensorEvent event) {
  5. int newRotation;
  6. synchronized (mLock) {
  7. mDesiredRotation = (int) event.values[0];
  8. newRotation = evaluateRotationChangeLocked();
  9. }
  10. if (newRotation >=0) {
  11. onProposedRotationChanged(newRotation);
  12. }
  13. }

最後就到MyOrientationListener 的onProposedRotationChanged函數,這裏就是發送了一個消息。

  1. class MyOrientationListener extends WindowOrientationListener {
  2. private final Runnable mUpdateRotationRunnable = new Runnable() {
  3. @Override
  4. public void run() {
  5. // send interaction hint to improve redraw performance
  6. mPowerManagerInternal.powerHint(PowerManagerInternal.POWER_HINT_INTERACTION, 0);
  7. updateRotation(false);
  8. }
  9. };
  10. MyOrientationListener(Context context, Handler handler) {
  11. super(context, handler);
  12. }
  13. @Override
  14. public void onProposedRotationChanged(int rotation) {
  15. if (localLOGV) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation);
  16. mHandler.post(mUpdateRotationRunnable);
  17. }
  18. }
最後就調用其run函數,run函數先會提升性能(cpu頻率),然後調用了updateRotation,這個函數一樣就到WMS的updateRotationUnchecked函數了。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章