Android6.0 旋转屏幕(四)应用强制设置方向

有时候我们也可以强制应用横频,这又是如何做到的?

就是调用了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);
        }
    }



©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值