Android Configuration

来源:互联网 发布:阿里云mysql远程连接 编辑:程序博客网 时间:2024/06/16 13:45

Android Configuration学习随笔

在学习资源加载时发现Configuration有决定性的作用,所以详细看了下Configuration相关的内容。
看Configuration时需要先明白一个设计:系统中有两个configuration, 一个是common的configuration,暂且叫service configuration, 一个是Activity的override configuration.
原则是override configuration的优先级比较高,如果存在override configuration会优先使用。
所有的Configuration初始化从WMS开始,先从DisplayManagerService去拿基本的display信息,然后WMS中也会根据用户设置进行一些初始化。并把得到的Configuration设置重新设置给DMS,同时也会设置给AMS。
另外AMS在启动新的Task时也会为根据每个task的bounds计算override configuration。


Launch一个新的Activity时给的configuration参数:
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);

Service Configuration

  1. Service configuration的初始化

WMS起来时,如果display已经准备好,就开始对configuration进行初始化
1). 从DMS获取display info对DisplayConent初始化
2). 读取用户设置的display信息进行设置
3). 对AMS的configuration进行设置
4). AMS中的更新会再借助WMS完成计算,由于WMS中可能再对configuration做调整,所以会再把更新后的Configuration sync会DMS. overrideconfiguration.

public void displayReady() {
for (Display display : mDisplays) {
displayReady(display.getDisplayId());
}
synchronized(mWindowMap) {
final DisplayContent displayContent = getDefaultDisplayContentLocked();
readForcedDisplayPropertiesLocked(displayContent);
mDisplayReady = true;
}

try {    mActivityManager.updateConfiguration(null);} catch (RemoteException e) {}

}

从DMS获取最原始的Display信息,给DisplayContent进行设置

void initializeDisplayBaseInfo() {
// Bootstrap the default logical display from the display manager.
final DisplayInfo newDisplayInfo =
mService.mDisplayManagerInternal.getDisplayInfo(mDisplayId);
if (newDisplayInfo != null) {
mDisplayInfo.copyFrom(newDisplayInfo);
}
mBaseDisplayWidth = mInitialDisplayWidth = mDisplayInfo.logicalWidth;
mBaseDisplayHeight = mInitialDisplayHeight = mDisplayInfo.logicalHeight;
mBaseDisplayDensity = mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight);
}

ActivityManagerService

AMS内的config通过WMS计算得到
public void updateConfiguration(Configuration values) {
synchronized(this) {
if (values == null && mWindowManager != null) {
// sentinel: fetch the current configuration from the window manager
values = mWindowManager.computeNewConfiguration();
}
}

WindowManagerService
WMS内部计算时,
1. 先更新display信息
2. 此时,displayInfo已经是更新过的,用来再计算config

private Configuration computeNewConfigurationLocked() {
if (!mDisplayReady) {
return null;
}
Configuration config = new Configuration();
config.fontScale = 0;
computeScreenConfigurationLocked(config);
return config;
}

/* Do not call if mDisplayReady == false /
void computeScreenConfigurationLocked(Configuration config) {
final DisplayInfo displayInfo = updateDisplayAndOrientationLocked(
config.uiMode);

final int dw = displayInfo.logicalWidth;final int dh = displayInfo.logicalHeight;config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :        Configuration.ORIENTATION_LANDSCAPE;config.screenWidthDp =        (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation, config.uiMode) /                mDisplayMetrics.density);config.screenHeightDp =        (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation, config.uiMode) /                mDisplayMetrics.density);final boolean rotated = (mRotation == Surface.ROTATION_90        || mRotation == Surface.ROTATION_270);computeSizeRangesAndScreenLayout(displayInfo, rotated, config.uiMode, dw, dh,        mDisplayMetrics.density, config);config.screenLayout = (config.screenLayout & ~Configuration.SCREENLAYOUT_ROUND_MASK)        | ((displayInfo.flags & Display.FLAG_ROUND) != 0                ? Configuration.SCREENLAYOUT_ROUND_YES                : Configuration.SCREENLAYOUT_ROUND_NO);config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, config.uiMode,        mDisplayMetrics, dw, dh);config.densityDpi = displayInfo.logicalDensityDpi;// Update the configuration based on available input devices, lid switch,// and platform configuration.config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;config.keyboard = Configuration.KEYBOARD_NOKEYS;config.navigation = Configuration.NAVIGATION_NONAV;// Let the policy update hidden states.config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);

}

先拿到displayContent, DisplayContent中的一些内容可能已经被WMS做了新的设置,(例如PhoneWindowManager的设置),再计算其他一些更新
然后和DisplayManagerService同步,将更新后的overrideConfig设置过去
displayContent中的其他内容更新
最后还计算了一下CompatibleScreenScale,不晓得有啥用?

/* Do not call if mDisplayReady == false /
DisplayInfo updateDisplayAndOrientationLocked(int uiMode) {
// TODO(multidisplay): For now, apply Configuration to main screen only.
final DisplayContent displayContent = getDefaultDisplayContentLocked();

// Use the effective "visual" dimensions based on current rotationfinal boolean rotated = (mRotation == Surface.ROTATION_90        || mRotation == Surface.ROTATION_270);final int realdw = rotated ?        displayContent.mBaseDisplayHeight : displayContent.mBaseDisplayWidth;final int realdh = rotated ?        displayContent.mBaseDisplayWidth : displayContent.mBaseDisplayHeight;int dw = realdw;int dh = realdh;// Update application display metrics.final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation, uiMode);final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation, uiMode);final DisplayInfo displayInfo = displayContent.getDisplayInfo();displayInfo.rotation = mRotation;displayInfo.logicalWidth = dw;displayInfo.logicalHeight = dh;displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity;displayInfo.appWidth = appWidth;displayInfo.appHeight = appHeight;displayInfo.getLogicalMetrics(mRealDisplayMetrics,        CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);displayInfo.getAppMetrics(mDisplayMetrics);mDisplayManagerInternal.**setDisplayInfoOverrideFromWindowManager**(        displayContent.getDisplayId(), displayInfo);displayContent.mBaseDisplayRect.set(0, 0, dw, dh);if (false) {    Slog.i(TAG_WM, "Set app display size: " + appWidth + " x " + appHeight);}mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(mDisplayMetrics,        mCompatDisplayMetrics);return displayInfo;

}

设置OverrideDisplayInfo到DisplayManagerService
public boolean setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo info) {
if (info != null) {
if (mOverrideDisplayInfo == null) {
mOverrideDisplayInfo = new DisplayInfo(info);
mInfo = null;
return true;
}
if (!mOverrideDisplayInfo.equals(info)) {
mOverrideDisplayInfo.copyFrom(info);
mInfo = null;
return true;
}
} else if (mOverrideDisplayInfo != null) {
mOverrideDisplayInfo = null;
mInfo = null;
return true;
}
return false;
}

override configuration

根据bounds算的override config

Configuration updateOverrideConfiguration(Rect bounds, @Nullable Rect insetBounds) {

mFullscreen = bounds == null;if (mFullscreen) {    if (mBounds != null && StackId.persistTaskBounds(stack.mStackId)) {        mLastNonFullscreenBounds = mBounds;    }    mBounds = null;    mOverrideConfig = Configuration.EMPTY;} else {    mTmpRect.set(bounds);    adjustForMinimalTaskDimensions(mTmpRect);    if (mBounds == null) {        mBounds = new Rect(mTmpRect);    } else {        mBounds.set(mTmpRect);    }    if (stack == null || StackId.persistTaskBounds(stack.mStackId)) {        mLastNonFullscreenBounds = mBounds;    }    mOverrideConfig = **calculateOverrideConfig**(mTmpRect, insetBounds,            mTmpRect.right != bounds.right, mTmpRect.bottom != bounds.bottom);}return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;

}

如下函数可以看到override configuration的计算过程,例如根据宽高直接计算到新的的orientation.
所以对一个Activity做resize, 如果width > height, 会重新加载landscape的资源。

private Configuration calculateOverrideConfig(Rect bounds, Rect insetBounds,
boolean overrideWidth, boolean overrideHeight) {
mTmpNonDecorBounds.set(bounds);
mTmpStableBounds.set(bounds);
subtractNonDecorInsets(
mTmpNonDecorBounds, insetBounds != null ? insetBounds : bounds,
overrideWidth, overrideHeight);
subtractStableInsets(
mTmpStableBounds, insetBounds != null ? insetBounds : bounds,
overrideWidth, overrideHeight);

// For calculating screenWidthDp, screenWidthDp, we use the stable inset screen area,// i.e. the screen area without the system bars.final Configuration serviceConfig = mService.mConfiguration;final Configuration config = new Configuration(Configuration.EMPTY);// TODO(multidisplay): Update Dp to that of display stack is on.final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;config.screenWidthDp =        Math.min((int)(mTmpStableBounds.width() / density), serviceConfig.screenWidthDp);config.screenHeightDp =        Math.min((int)(mTmpStableBounds.height() / density), serviceConfig.screenHeightDp);// TODO: Orientation?config.orientation = (config.screenWidthDp <= config.screenHeightDp)        ? Configuration.ORIENTATION_PORTRAIT        : Configuration.ORIENTATION_LANDSCAPE;// Always set fontScale to be euqal to global. Can't set to 0, as that makes the override// config not equal to EMPTY. Also can't set to 1, as Configuration.updateFrom will use// the override scale as long as it's non-zero, and we'll always use 1.config.fontScale = serviceConfig.fontScale;// For calculating screen layout, we need to use the non-decor inset screen area for the// calculation for compatibility reasons, i.e. screen area without system bars that could// never go away in Honeycomb.final int compatScreenWidthDp = (int)(mTmpNonDecorBounds.width() / density);final int compatScreenHeightDp = (int)(mTmpNonDecorBounds.height() / density);final int sl = Configuration.resetScreenLayout(serviceConfig.screenLayout);final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp);final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);;config.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize);config.smallestScreenWidthDp = mService.mWindowManager.getSmallestWidthForTaskBounds(        insetBounds != null ? insetBounds : bounds);return config;

}

原创粉丝点击