Android6.0 旋轉屏幕(四)應用強制設置方向

有時候我們也可以強制應用橫頻,這又是如何做到的?

就是調用了AMS的setRequestedOrientation接口,這個接口先是調用WMS的setAppOrientation函數設置這個Activity在WMS中的方向。然後在調用WMS的updateOrientationFromAppTokens函數旋轉屏幕,最後在調用updateConfigurationLocked這個函數之前博客分析過就是是否讓Activity重新Launch等。

  1. @Override
  2. public void setRequestedOrientation(IBinder token, int requestedOrientation) {
  3. synchronized (this) {
  4. ActivityRecord r = ActivityRecord.isInStackLocked(token);
  5. if (r == null) {
  6. return;
  7. }
  8. if (r.task != null && r.task.mResizeable) {
  9. // Fixed screen orientation isn't supported with resizeable activities.
  10. return;
  11. }
  12. final long origId = Binder.clearCallingIdentity();
  13. mWindowManager.setAppOrientation(r.appToken, requestedOrientation);
  14. Configuration config = mWindowManager.updateOrientationFromAppTokens(
  15. mConfiguration, r.mayFreezeScreenLocked(r.app) ? r.appToken : null);
  16. if (config != null) {
  17. r.frozenBeforeDestroy = true;
  18. if (!updateConfigurationLocked(config, r, false, false)) {
  19. mStackSupervisor.resumeTopActivitiesLocked();
  20. }
  21. }
  22. Binder.restoreCallingIdentity(origId);
  23. }
  24. }

我們先看下WMS的setAppOrientation函數,很簡單就是找到這個apptoken的APPWindowToken,然後將其requestedOrientation值賦值。

  1. @Override
  2. public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
  3. if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
  4. "setAppOrientation()")) {
  5. throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
  6. }
  7. synchronized(mWindowMap) {
  8. AppWindowToken atoken = findAppWindowToken(token.asBinder());
  9. if (atoken == null) {
  10. Slog.w(TAG, "Attempted to set orientation of non-existing app token: " + token);
  11. return;
  12. }
  13. atoken.requestedOrientation = requestedOrientation;
  14. }
  15. }

然後我們再來看WMS的updateOrientationFromAppTokens函數,這個函數主要調用了updateOrientationFromAppTokensLocked函數,這個函數先調用另一個updateOrientationFromAppTokensLocked函數,根據這個函數的返回值,返回true代表要旋轉,就調用computeNewConfigurationLocked計算Configuration返回。

  1. private Configuration updateOrientationFromAppTokensLocked(
  2. Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
  3. if (!mDisplayReady) {
  4. return null;
  5. }
  6. Configuration config = null;
  7. if (updateOrientationFromAppTokensLocked(false)) {
  8. if (freezeThisOneIfNeeded != null) {
  9. AppWindowToken atoken = findAppWindowToken(freezeThisOneIfNeeded);
  10. if (atoken != null) {
  11. startAppFreezingScreenLocked(atoken);
  12. }
  13. }
  14. config = computeNewConfigurationLocked();
  15. } else if (currentConfig != null) {
  16. // No obvious action we need to take, but if our current
  17. // state mismatches the activity manager's, update it,
  18. // disregarding font scale, which should remain set to
  19. // the value of the previous configuration.
  20. mTempConfiguration.setToDefaults();
  21. mTempConfiguration.fontScale = currentConfig.fontScale;
  22. computeScreenConfigurationLocked(mTempConfiguration);
  23. if (currentConfig.diff(mTempConfiguration) != 0) {
  24. mWaitingForConfig = true;
  25. final DisplayContent displayContent = getDefaultDisplayContentLocked();
  26. displayContent.layoutNeeded = true;
  27. int anim[] = new int[2];
  28. if (displayContent.isDimming()) {
  29. anim[0] = anim[1] = 0;
  30. } else {
  31. mPolicy.selectRotationAnimationLw(anim);
  32. }
  33. startFreezingDisplayLocked(false, anim[0], anim[1]);
  34. config = new Configuration(mTempConfiguration);
  35. }
  36. }
  37. return config;
  38. }
我們來看下updateOrientationFromAppTokensLocked函數,我們先調用了getOrientationLocked函數獲取上次強制設置的方向,如果不同就調用updateRotationUncheckedLocked函數,這個函數之前博客分析過了,流程就一樣了。最後就到DisplayManagerService中設置設備的方向。
  1. boolean updateOrientationFromAppTokensLocked(boolean inTransaction) {
  2. long ident = Binder.clearCallingIdentity();
  3. try {
  4. int req = getOrientationLocked();
  5. if (req != mForcedAppOrientation) {
  6. mForcedAppOrientation = req;
  7. //send a message to Policy indicating orientation change to take
  8. //action like disabling/enabling sensors etc.,
  9. mPolicy.setCurrentOrientationLw(req);
  10. if (updateRotationUncheckedLocked(inTransaction)) {
  11. // changed
  12. return true;
  13. }
  14. }
  15. return false;
  16. } finally {
  17. Binder.restoreCallingIdentity(ident);
  18. }
  19. }
最後我們回到AMS的setRequestedOrientation函數,我們調用updateConfigurationLocked函數,當返回false,就是現在的狀態要改變(比如重啓Activity),然後就調用ActivityStackSupervisor的resumeTopActivitiesLocked函數來啓動最上面的Activity。
  1. public void setRequestedOrientation(IBinder token, int requestedOrientation) {
  2. synchronized (this) {
  3. ActivityRecord r = ActivityRecord.isInStackLocked(token);
  4. if (r == null) {
  5. return;
  6. }
  7. if (r.task != null && r.task.mResizeable) {
  8. // Fixed screen orientation isn't supported with resizeable activities.
  9. return;
  10. }
  11. final long origId = Binder.clearCallingIdentity();
  12. mWindowManager.setAppOrientation(r.appToken, requestedOrientation);
  13. Configuration config = mWindowManager.updateOrientationFromAppTokens(
  14. mConfiguration, r.mayFreezeScreenLocked(r.app) ? r.appToken : null);
  15. if (config != null) {
  16. r.frozenBeforeDestroy = true;
  17. if (!updateConfigurationLocked(config, r, false, false)) {
  18. mStackSupervisor.resumeTopActivitiesLocked();
  19. }
  20. }
  21. Binder.restoreCallingIdentity(origId);
  22. }
  23. }



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