转载: https://blog.csdn.net/kc58236582/article/details/53741445
有时候我们也可以强制应用横频,这又是如何做到的?
就是调用了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);
-
}
-
}