有时候我们也可以强制应用横频,这又是如何做到的?
就是调用了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);
}
}