一、强制设置方向
1.Activity
如果要强制设置一个Activity的横竖屏可以通过Manifest去设置,跟Activity相关的信息都会保存在ActivityInfo当中。
android:screenOrientation=["unspecified" | "user" | "behind" |
"landscape" | "portrait" |
"reverseLandscape" | "reversePortrait" |
"sensorLandscape" | "sensorPortrait" |
"sensor" | "fullSensor" | "nosensor"]
2.Window
如果是要强制设置一个Window的横竖屏可以通过 LayoutParams.screenOrientation来设置。在通过WindowManager.addView的时候把对应的LayoutParams传递给WMS。
WindowManager.LayoutParams.screenOrientation
二、屏幕转屏
2.1 Activity -- 启动一个有设置screenOrientation的Activity
在ActivityStack.startActivityLocked中,AMS会把ActivityRecord相关的Token加到WMS中,有且仅在这个方法中。这时候会把screenOrientation传递过去。
atoken.requestedOrientation = requestedOrientation; 这个AppToken会在WMS获取相关App Orientation的时候其作用。
mService.mWindowManager.addAppToken(addPos, r.userId, r.appToken,
r.task.taskId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
public void addAppToken(int addPos, int userId, IApplicationToken token,
int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked) {
... ...
synchronized(mWindowMap) {
AppWindowToken atoken = findAppWindowToken(token.asBinder());
if (atoken != null) {
Slog.w(TAG, "Attempted to add existing app token: " + token);
return;
}
atoken = new AppWindowToken(this, userId, token);
atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
atoken.groupId = groupId;
atoken.appFullscreen = fullscreen;
atoken.showWhenLocked = showWhenLocked;
atoken.requestedOrientation = requestedOrientation;//方向赋值
if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
+ " at " + addPos);
mAppTokens.add(addPos, atoken);
addAppTokenToAnimating(addPos, atoken);
mTokenMap.put(token.asBinder(), atoken);
// Application tokens start out hidden.
atoken.hidden = true;
atoken.hiddenRequested = true;
//dump();
}
}
2.2 在启动Activity之前去获取当前WMS中的Orientation的Config
在resumeTopActivityLocked和realStartActivityLocked中回去获取最新的Orientation的config
1. 通过mWindowManager.updateOrientationFromAppTokens去更新当前WMS中的Orientation值,把WMS中的config返回给AMS ,这个我们在之前http://blog.csdn.net/kc58236582/article/details/53741445博客分析过了
2. 通过updateConfigurationLocked去更新AMS中的config,发给每一个ActiviytThread。(会调用每个ActivityThread的onConfigurationChanged函数)
synchronized (mService) {
Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
mService.mConfiguration,
next.mayFreezeScreenLocked(next.app) ? next.appToken : null);
if (config != null) {
next.frozenBeforeDestroy = true;
}
updated = mService.updateConfigurationLocked(config, next, false, false);
}
WMS.updateOrientationFroemAppTokens 会直接去调updateOrientationFromAppTokensLocked
1. 去调用updateOrientationFromAppTokensLocked(false) 做真正的update Orientation的工作,如果返回是true,说明方向发生了变化,就需要去做app的转屏动作。
2. 如果freezeThisOneIfNeed不为null,说明要做屏幕的转屏操做,就会把当前的atoken freeze掉。
3. computeNewConfigurationLocked() 计算当前的Configuration,然后返回给AMS。
private Configuration updateOrientationFromAppTokensLocked(
Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
Configuration config = null;
if (updateOrientationFromAppTokensLocked(false)) {
if (freezeThisOneIfNeeded != null) {
AppWindowToken atoken = findAppWindowToken(
freezeThisOneIfNeeded);
if (atoken != null) {
startAppFreezingScreenLocked(atoken,
ActivityInfo.CONFIG_ORIENTATION);
}
}
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;
if (computeScreenConfigurationLocked(mTempConfiguration)) {
if (currentConfig.diff(mTempConfiguration) != 0) {