有時候我們也可以強制應用橫頻,這又是如何做到的?
就是調用了AMS的setRequestedOrientation接口,這個接口先是調用WMS的setAppOrientation函數設置這個Activity在WMS中的方向。然後在調用WMS的updateOrientationFromAppTokens函數旋轉屏幕,最後在調用updateConfigurationLocked這個函數之前博客分析過就是是否讓Activity重新Launch等。
- @Override
- public void setRequestedOrientation(IBinder token, int requestedOrientation) {
- synchronized (this) {
- ActivityRecord r = ActivityRecord.isInStackLocked(token);
- if (r == null) {
- return;
- }
- if (r.task != null && r.task.mResizeable) {
- // Fixed screen orientation isn't supported with resizeable activities.
- return;
- }
- final long origId = Binder.clearCallingIdentity();
- mWindowManager.setAppOrientation(r.appToken, requestedOrientation);
- Configuration config = mWindowManager.updateOrientationFromAppTokens(
- mConfiguration, r.mayFreezeScreenLocked(r.app) ? r.appToken : null);
- if (config != null) {
- r.frozenBeforeDestroy = true;
- if (!updateConfigurationLocked(config, r, false, false)) {
- mStackSupervisor.resumeTopActivitiesLocked();
- }
- }
- Binder.restoreCallingIdentity(origId);
- }
- }
我們先看下WMS的setAppOrientation函數,很簡單就是找到這個apptoken的APPWindowToken,然後將其requestedOrientation值賦值。
- @Override
- public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setAppOrientation()")) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
- }
-
- synchronized(mWindowMap) {
- AppWindowToken atoken = findAppWindowToken(token.asBinder());
- if (atoken == null) {
- Slog.w(TAG, "Attempted to set orientation of non-existing app token: " + token);
- return;
- }
-
- atoken.requestedOrientation = requestedOrientation;
- }
- }
然後我們再來看WMS的updateOrientationFromAppTokens函數,這個函數主要調用了updateOrientationFromAppTokensLocked函數,這個函數先調用另一個updateOrientationFromAppTokensLocked函數,根據這個函數的返回值,返回true代表要旋轉,就調用computeNewConfigurationLocked計算Configuration返回。
- private Configuration updateOrientationFromAppTokensLocked(
- Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
- if (!mDisplayReady) {
- return null;
- }
- Configuration config = null;
-
- if (updateOrientationFromAppTokensLocked(false)) {
- if (freezeThisOneIfNeeded != null) {
- AppWindowToken atoken = findAppWindowToken(freezeThisOneIfNeeded);
- if (atoken != null) {
- startAppFreezingScreenLocked(atoken);
- }
- }
- config = computeNewConfigurationLocked();
-
- } else if (currentConfig != null) {
- // No obvious action we need to take, but if our current
- // state mismatches the activity manager's, update it,
- // disregarding font scale, which should remain set to
- // the value of the previous configuration.
- mTempConfiguration.setToDefaults();
- mTempConfiguration.fontScale = currentConfig.fontScale;
- computeScreenConfigurationLocked(mTempConfiguration);
- if (currentConfig.diff(mTempConfiguration) != 0) {
- mWaitingForConfig = true;
- final DisplayContent displayContent = getDefaultDisplayContentLocked();
- displayContent.layoutNeeded = true;
- int anim[] = new int[2];
- if (displayContent.isDimming()) {
- anim[0] = anim[1] = 0;
- } else {
- mPolicy.selectRotationAnimationLw(anim);
- }
- startFreezingDisplayLocked(false, anim[0], anim[1]);
- config = new Configuration(mTempConfiguration);
- }
- }
-
- return config;
- }
我們來看下updateOrientationFromAppTokensLocked函數,我們先調用了getOrientationLocked函數獲取上次強制設置的方向,如果不同就調用updateRotationUncheckedLocked函數,這個函數之前博客分析過了,流程就一樣了。最後就到DisplayManagerService中設置設備的方向。
- boolean updateOrientationFromAppTokensLocked(boolean inTransaction) {
- long ident = Binder.clearCallingIdentity();
- try {
- int req = getOrientationLocked();
- if (req != mForcedAppOrientation) {
- mForcedAppOrientation = req;
- //send a message to Policy indicating orientation change to take
- //action like disabling/enabling sensors etc.,
- mPolicy.setCurrentOrientationLw(req);
- if (updateRotationUncheckedLocked(inTransaction)) {
- // changed
- return true;
- }
- }
-
- return false;
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
最後我們回到AMS的setRequestedOrientation函數,我們調用updateConfigurationLocked函數,當返回false,就是現在的狀態要改變(比如重啓Activity),然後就調用ActivityStackSupervisor的resumeTopActivitiesLocked函數來啓動最上面的Activity。
- public void setRequestedOrientation(IBinder token, int requestedOrientation) {
- synchronized (this) {
- ActivityRecord r = ActivityRecord.isInStackLocked(token);
- if (r == null) {
- return;
- }
- if (r.task != null && r.task.mResizeable) {
- // Fixed screen orientation isn't supported with resizeable activities.
- return;
- }
- final long origId = Binder.clearCallingIdentity();
- mWindowManager.setAppOrientation(r.appToken, requestedOrientation);
- Configuration config = mWindowManager.updateOrientationFromAppTokens(
- mConfiguration, r.mayFreezeScreenLocked(r.app) ? r.appToken : null);
- if (config != null) {
- r.frozenBeforeDestroy = true;
- if (!updateConfigurationLocked(config, r, false, false)) {
- mStackSupervisor.resumeTopActivitiesLocked();
- }
- }
- Binder.restoreCallingIdentity(origId);
- }
- }