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. }



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