1.简介
- 位置在settings下的display选项,我们学习下红线这个设置
- font size,字体大小的修改,影响文本内容的缩放,修改的是Settings.System.FONT_SCALE,见1.7
- display size,修改的是density,影响所有尺寸的大小,简单点说就是 dp和像素的转化比例发生了变化。见1.6,最终走到6.1保存在本地文件里的。
1.1.display_settings.xml
<PreferenceCategory
android:title="@string/category_name_appearance">
<com.android.settings.display.darkmode.DarkModePreference
android:key="dark_ui_mode"
android:title="@string/dark_ui_mode"
android:fragment="com.android.settings.display.darkmode.DarkModeSettingsFragment"
android:widgetLayout="@null"
settings:widgetLayout="@null"
settings:controller="com.android.settings.display.DarkUIPreferenceController"
settings:keywords="@string/keywords_dark_ui_mode"/>
<!--图上对应的就是这个-->
<Preference
android:fragment="com.android.settings.accessibility.TextReadingPreferenceFragment"
android:key="text_reading_options"
android:persistent="false"
android:title="@string/accessibility_text_reading_options_title"
settings:controller="com.android.settings.accessibility.TextReadingFragmentForDisplaySettingsController"/>
</PreferenceCategory>
可以看到跳转的是TextReadingPreferenceFragment
1.2.TextReadingPreferenceFragment
效果图如下
>1.accessibility_text_reading_options.xml
参照上边的图就知道都是啥了
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:persistent="false"
android:title="@string/accessibility_text_reading_options_title">
<com.android.settings.accessibility.TextReadingPreviewPreference
android:key="preview"
android:selectable="false"/>
<com.android.settings.widget.LabeledSeekBarPreference
android:key="font_size"
android:summary="@string/short_summary_font_size"
android:title="@string/title_font_size"
settings:iconEnd="@drawable/ic_add_24dp"
settings:iconEndContentDescription="@string/font_size_make_larger_desc"
settings:iconStart="@drawable/ic_remove_24dp"
settings:iconStartContentDescription="@string/font_size_make_smaller_desc"
settings:keywords="@string/keywords_font_size" />
<com.android.settings.widget.LabeledSeekBarPreference
android:key="display_size"
android:summary="@string/screen_zoom_short_summary"
android:title="@string/screen_zoom_title"
settings:iconEnd="@drawable/ic_add_24dp"
settings:iconEndContentDescription="@string/screen_zoom_make_larger_desc"
settings:iconStart="@drawable/ic_remove_24dp"
settings:iconStartContentDescription="@string/screen_zoom_make_smaller_desc"
settings:keywords="@string/keywords_display_size" />
<SwitchPreference
android:key="toggle_force_bold_text"
android:persistent="false"
android:title="@string/force_bold_text"
settings:keywords="@string/keywords_bold_text" />
<SwitchPreference
android:key="toggle_high_text_contrast_preference"
android:persistent="false"
android:summary="@string/accessibility_toggle_high_text_contrast_preference_summary"
android:title="@string/accessibility_toggle_high_text_contrast_preference_title" />
<com.android.settingslib.widget.LayoutPreference
android:key="reset"
android:layout="@layout/accessibility_text_reading_reset_button"
android:persistent="false"
android:selectable="false" />
</PreferenceScreen>
>2.createPreferenceControllers
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
updateEntryPoint();
final List<AbstractPreferenceController> controllers = new ArrayList<>();
final FontSizeData fontSizeData = new FontSizeData(context);
final DisplaySizeData displaySizeData = createDisplaySizeData(context);
//预览控制器,见1.5
final TextReadingPreviewController previewController = new TextReadingPreviewController(
context, PREVIEW_KEY, fontSizeData, displaySizeData);
previewController.setEntryPoint(mEntryPoint);
controllers.add(previewController);
//font size控制器,见1.4
final PreviewSizeSeekBarController fontSizeController = new PreviewSizeSeekBarController(
context, FONT_SIZE_KEY, fontSizeData);
//seekbar的改变监听,回调就是上边的预览控制器
fontSizeController.setInteractionListener(previewController);
controllers.add(fontSizeController);
//display size控制器,见1.4
final PreviewSizeSeekBarController displaySizeController = new PreviewSizeSeekBarController(
context, DISPLAY_SIZE_KEY, displaySizeData);
//seekbar的改变监听,回调就是上边的预览控制器
displaySizeController.setInteractionListener(previewController);
controllers.add(displaySizeController);
mFontWeightAdjustmentController =
new FontWeightAdjustmentPreferenceController(context, BOLD_TEXT_KEY);
mFontWeightAdjustmentController.setEntryPoint(mEntryPoint);
controllers.add(mFontWeightAdjustmentController);
final HighTextContrastPreferenceController highTextContrastController =
new HighTextContrastPreferenceController(context, HIGH_TEXT_CONTRAST_KEY);
highTextContrastController.setEntryPoint(mEntryPoint);
controllers.add(highTextContrastController);
final TextReadingResetController resetController =
new TextReadingResetController(context, RESET_KEY,
v -> showDialog(DialogEnums.DIALOG_RESET_SETTINGS));
resetController.setEntryPoint(mEntryPoint);
controllers.add(resetController);
return controllers;
}
1.3.LabeledSeekBarPreference
这个就是个自定义的,显示布局数据用的,具体的操作处理是在PreviewSizeSeekBarController里的
>1.preference_labeled_slider.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:gravity="center_vertical"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingTop="16dp"
android:paddingBottom="8dp">
<!--标题,显示在顶部-->
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem"
android:hyphenationFrequency="normalFast"
android:textColor="?android:attr/textColorPrimary" />
<!--描述,显示在标题下边-->
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textAlignment="viewStart"
android:hyphenationFrequency="normalFast"
android:textColor="?android:attr/textColorSecondary" />
<!--拖动条,见补充2,显示在描述下边-->
<include
layout="@layout/icon_discrete_slider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@android:id/summary" />
<!--拖动条下边显示的额外提示,默认隐藏的-->
<LinearLayout
android:id="@+id/label_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/seekbar_frame"
android:orientation="horizontal"
android:visibility="gone">
<TextView
android:id="@android:id/text1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="start|top"
android:gravity="start"
android:layout_weight="1"/>
<TextView
android:id="@android:id/text2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="end|top"
android:gravity="end"
android:layout_weight="1"/>
</LinearLayout>
</RelativeLayout>
>2.icon_discrete_slider.xml
两边有个图标,中间就是seekbar
<LinearLayout
android:id="@+id/seekbar_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:gravity="center_vertical">
<FrameLayout
android:id="@+id/icon_start_frame"
android:layout_width="48dp"
android:layout_height="48dp"
android:clipChildren="false"
android:focusable="true"
android:visibility="gone">
<ImageView
android:id="@+id/icon_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:adjustViewBounds="true"
android:focusable="false"
android:tint="?android:attr/textColorPrimary"
android:tintMode="src_in" />
</FrameLayout>
<SeekBar
android:id="@*android:id/seekbar"
style="@android:style/Widget.Material.SeekBar.Discrete"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:paddingEnd="12dp"
android:paddingStart="0dp" />
<FrameLayout
android:id="@+id/icon_end_frame"
android:layout_width="48dp"
android:layout_height="48dp"
android:clipChildren="false"
android:focusable="true"
android:visibility="gone">
<ImageView
android:id="@+id/icon_end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:adjustViewBounds="true"
android:focusable="false"
android:tint="?android:attr/textColorPrimary"
android:tintMode="src_in" />
</FrameLayout>
</LinearLayout>
1.4.PreviewSizeSeekBarController
这个控制器就是监听seekbar的变化
PreviewSizeSeekBarController(Context context, String preferenceKey,
@NonNull PreviewSizeData<? extends Number> sizeData) {
super(context, preferenceKey);
//就是1.6和1.7的对象
mSizeData = sizeData;
}
>1.mSeekBarChangeListener
seekbar的改变监听,可以看到结果交给外部listener处理的,就是1.2.2里设置的预览控制器
private final SeekBar.OnSeekBarChangeListener mSeekBarChangeListener =
new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
mInteractionListener.notifyPreferenceChanged();
if (!mSeekByTouch && mInteractionListener != null) {
mInteractionListener.onProgressChanged();
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
mSeekByTouch = true;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
mSeekByTouch = false;
if (mInteractionListener != null) {
mInteractionListener.onEndTrackingTouch();
}
}
};
>2.displayPreference
//根据key找到xml里的preference,设置listener
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
//见1.6或者1.7
final int dataSize = mSizeData.getValues().size();
final int initialIndex = mSizeData.getInitialIndex();
mSeekBarPreference = screen.findPreference(getPreferenceKey());
mSeekBarPreference.setMax(dataSize - 1);
mSeekBarPreference.setProgress(initialIndex);
mSeekBarPreference.setContinuousUpdates(true);
//设置监听器
mSeekBarPreference.setOnSeekBarChangeListener(mSeekBarChangeListener);
}
1.5.TextReadingPreviewController
private static final long MIN_COMMIT_INTERVAL_MS = 800;
private static final long CHANGE_BY_SEEKBAR_DELAY_MS = 100;
private static final long CHANGE_BY_BUTTON_DELAY_MS = 300;
>1.seekbar最终的回调处理
//拖动中
public void onProgressChanged() {
postCommitDelayed(CHANGE_BY_BUTTON_DELAY_MS);//300ms
}
//拖动结束
public void onEndTrackingTouch() {
postCommitDelayed(CHANGE_BY_SEEKBAR_DELAY_MS);//100ms
}
>2.postCommitDelayed
延迟执行mCommit
void postCommitDelayed(long commitDelayMs) {
//两次间隔时间小于800ms
if (SystemClock.elapsedRealtime() - mLastCommitTime < MIN_COMMIT_INTERVAL_MS) {
//加上800ms
commitDelayMs += MIN_COMMIT_INTERVAL_MS;
}
final Choreographer choreographer = Choreographer.getInstance();
choreographer.removeFrameCallback(mCommit);
choreographer.postFrameCallbackDelayed(mCommit, commitDelayMs);
}
>3.mCommit
private final Choreographer.FrameCallback mCommit = f -> {
//检查是否变化,是的话进行处理
tryCommitFontSizeConfig();
tryCommitDisplaySizeConfig();
//记录下最后一次提交的时间
mLastCommitTime = SystemClock.elapsedRealtime();
};
//
private void tryCommitFontSizeConfig() {
final int fontProgress = mFontSizePreference.getProgress();
if (fontProgress != mLastFontProgress) {
//见1.7
mFontSizeData.commit(fontProgress);
mLastFontProgress = fontProgress;
}
}
//
private void tryCommitDisplaySizeConfig() {
final int displayProgress = mDisplaySizePreference.getProgress();
if (displayProgress != mLastDisplayProgress) {
//见1.6
mDisplaySizeData.commit(displayProgress);
mLastDisplayProgress = displayProgress;
}
}
1.6.DisplaySizeData
看下commit方法,可以看到是修改configuration了,具体看小节3
class DisplaySizeData extends PreviewSizeData<Integer> {
DisplaySizeData(Context context) {
super(context);
final DisplayDensityUtils density = new DisplayDensityUtils(getContext());
final int initialIndex = density.getCurrentIndex();
if (initialIndex < 0) {
//异常情况,不看
} else {
//数据来源见1.8.1
setDefaultValue(density.getDefaultDensity());
setInitialIndex(initialIndex);
setValues(Arrays.stream(density.getValues()).boxed().collect(Collectors.toList()));
}
}
@Override
void commit(int currentProgress) {
final int densityDpi = getValues().get(currentProgress);
if (densityDpi == getDefaultValue()) {
//见3.2,最终和3.3一样,设置的是默认值
DisplayDensityConfiguration.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY);
} else {
//见3.3,设置新的densityDpi
DisplayDensityConfiguration.setForcedDisplayDensity(Display.DEFAULT_DISPLAY,
densityDpi);
}
}
}
1.7.FontSizeData
看下commit方法,就是修改了Settings的值
final class FontSizeData extends PreviewSizeData<Float> {
private static final float FONT_SCALE_DEF_VALUE = 1.0f;
FontSizeData(Context context) {
super(context);
final Resources resources = getContext().getResources();
final ContentResolver resolver = getContext().getContentResolver();
//配置里读取,见补充1
final List<String> strEntryValues =
Arrays.asList(resources.getStringArray(R.array.entryvalues_font_size));
//默认值是1
setDefaultValue(FONT_SCALE_DEF_VALUE);
//读取settings的scale值
final float currentScale =
Settings.System.getFloat(resolver, Settings.System.FONT_SCALE, getDefaultValue());
//设置初始化的索引,索引获取见补充2
setInitialIndex(fontSizeValueToIndex(currentScale, strEntryValues.toArray(new String[0])));
//设置集合数据
setValues(strEntryValues.stream().map(Float::valueOf).collect(Collectors.toList()));
}
@Override
void commit(int currentProgress) {
final ContentResolver resolver = getContext().getContentResolver();
Settings.System.putFloat(resolver, Settings.System.FONT_SCALE,
getValues().get(currentProgress));
}
}
>1.entryvalues_font_size
<string-array name="entryvalues_font_size" translatable="false">
<item>0.85</item>
<item>1.0</item>
<item>1.15</item>
<item>1.30</item>
</string-array>
>2.fontSizeValueToIndex
找出当前值在数组里的index
public static int fontSizeValueToIndex(float val, String[] indices) {
float lastVal = Float.parseFloat(indices[0]);
for (int i = 1; i < indices.length; i++) {
float thisVal = Float.parseFloat(indices[i]);
//小于两个值的一半,则认为是匹配小的那个
if (val < (lastVal + (thisVal - lastVal) * .5f)) {
return i - 1;
}
lastVal = thisVal;
}
//没找到,那默认是最后一个
return indices.length - 1;
}
1.8.DisplayDensityUtils.java
>1.构造方法
public DisplayDensityUtils(Context context) {
//参考3.1
final int defaultDensity = DisplayDensityUtils.getDefaultDisplayDensity(
Display.DEFAULT_DISPLAY);
if (defaultDensity <= 0) {
mEntries = null;
mValues = null;
mDefaultDensity = 0;
mCurrentIndex = -1;
return;
}
final Resources res = context.getResources();
DisplayInfo info = new DisplayInfo();
context.getDisplayNoVerify().getDisplayInfo(info);
//系统当前的density
final int currentDensity = info.logicalDensityDpi;
int currentDensityIndex = -1;
//计算设备的最大,最小scale值
//宽高的最小像素大小
final int minDimensionPx = Math.min(info.logicalWidth, info.logicalHeight);
//160*min/320
final int maxDensity = DisplayMetrics.DENSITY_MEDIUM * minDimensionPx / MIN_DIMENSION_DP;
//读取配置里的最大scale值,见补充2
final float maxScaleDimen = context.getResources().getFraction(
R.fraction.display_density_max_scale, 1, 1);
// maxDensity /defaultDensity算出来的scale,根上边配置里读取的比较,取最小值
final float maxScale = Math.min(maxScaleDimen, maxDensity / (float) defaultDensity);
//读取配置里的最小scale值,见补充2
final float minScale = context.getResources().getFraction(
R.fraction.display_density_min_scale, 1, 1);
//读取配置里的最小scale间隔值,见补充2
final float minScaleInterval = context.getResources().getFraction(
R.fraction.display_density_min_scale_interval, 1, 1);
//计算下支持的放大次数
final int numLarger = (int) MathUtils.constrain((maxScale - 1) / minScaleInterval,
0, SUMMARIES_LARGER.length);//见补充3,这里是3
//计算下支持的缩小次数
final int numSmaller = (int) MathUtils.constrain((1 - minScale) / minScaleInterval,
0, SUMMARIES_SMALLER.length);//见补充3,这里是1
//放大次数+缩小次数+默认值
String[] entries = new String[1 + numSmaller + numLarger];
int[] values = new int[entries.length];
int curIndex = 0;
//下边就是计算数据了
//缩小的
if (numSmaller > 0) {
final float interval = (1 - minScale) / numSmaller;
for (int i = numSmaller - 1; i >= 0; i--) {
// Round down to a multiple of 2 by truncating the low bit.
final int density = ((int) (defaultDensity * (1 - (i + 1) * interval))) & ~1;
if (currentDensity == density) {
currentDensityIndex = curIndex;
}
entries[curIndex] = res.getString(SUMMARIES_SMALLER[i]);
values[curIndex] = density;
curIndex++;
}
}
//默认值
if (currentDensity == defaultDensity) {
currentDensityIndex = curIndex;
}
values[curIndex] = defaultDensity;
entries[curIndex] = res.getString(SUMMARY_DEFAULT);
curIndex++;
//放大的
if (numLarger > 0) {
final float interval = (maxScale - 1) / numLarger;
for (int i = 0; i < numLarger; i++) {
// Round down to a multiple of 2 by truncating the low bit.
final int density = ((int) (defaultDensity * (1 + (i + 1) * interval))) & ~1;
if (currentDensity == density) {
currentDensityIndex = curIndex;
}
values[curIndex] = density;
entries[curIndex] = res.getString(SUMMARIES_LARGER[i]);
curIndex++;
}
}
final int displayIndex;
if (currentDensityIndex >= 0) {
//系统当前的density有和我们数组里的数据匹配,那这里就设置对应的index
displayIndex = currentDensityIndex;
} else {
//走到这里,说明系统当前的density没有找到匹配的。
int newLength = values.length + 1;
values = Arrays.copyOf(values, newLength);
//数组长度加一,把系统当前的density放到数组末尾
values[curIndex] = currentDensity;
//同上,这里加的是summary
entries = Arrays.copyOf(entries, newLength);
entries[curIndex] = res.getString(SUMMARY_CUSTOM, currentDensity);
displayIndex = curIndex;
}
//默认的density
mDefaultDensity = defaultDensity;
//当前density的索引
mCurrentIndex = displayIndex;
//数组density对应的描述
mEntries = entries;
//支持的density数组
mValues = values;
}
>2.density最大最小值以及间隔
<!-- Minimum increment between density scales. -->
<fraction name="display_density_min_scale_interval">9%</fraction>
<!-- Maximum density scale. The actual scale used depends on the device. -->
<fraction name="display_density_max_scale">150%</fraction>
<!-- Minimum density scale. This is available on all devices. -->
<fraction name="display_density_min_scale">85%</fraction>
>3.常量
/**
* Summaries for scales smaller than "default" in order of smallest to
* largest. 缩小,最多支持下边一个
*/
private static final int[] SUMMARIES_SMALLER = new int[] {
R.string.screen_zoom_summary_small
};
/**
* Summaries for scales larger than "default" in order of smallest to
* largest. 放大,最多支持下边3个
*/
private static final int[] SUMMARIES_LARGER = new int[] {
R.string.screen_zoom_summary_large,
R.string.screen_zoom_summary_very_large,
R.string.screen_zoom_summary_extremely_large,
};
3.DisplayDensityConfiguration
3.1.getDefaultDisplayDensity
static int getDefaultDisplayDensity(int displayId) {
try {
final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
return wm.getInitialDisplayDensity(displayId);
} catch (RemoteException exc) {
return -1;
}
}
>1.WindowManagerService.java
public int getInitialDisplayDensity(int displayId) {
synchronized (mGlobalLock) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
return displayContent.mInitialDisplayDensity;
}
}
return -1;
}
3.2.clearForcedDisplayDensity
public static void clearForcedDisplayDensity(final int displayId) {
final int userId = UserHandle.myUserId();
AsyncTask.execute(
() -> {
try {
final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
//见4.1
wm.clearForcedDisplayDensityForUser(displayId, userId);
}
});
}
3.3.setForcedDisplayDensity
public static void setForcedDisplayDensity(final int displayId, final int density) {
final int userId = UserHandle.myUserId();
AsyncTask.execute(
() -> {
try {
final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
//见4.2
wm.setForcedDisplayDensityForUser(displayId, density, userId);
}
});
}
4.WindowManagerService
4.1.clearForcedDisplayDensityForUser
public void clearForcedDisplayDensityForUser(int displayId, int userId) {
//..
try {
synchronized (mGlobalLock) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
if (displayContent != null) {
//见5.1,可以看到,这里传了个默认值
displayContent.setForcedDensity(displayContent.mInitialDisplayDensity,
callingUserId);
}
}
//..
}
4.2.setForcedDisplayDensityForUser
public void setForcedDisplayDensityForUser(int displayId, int density, int userId) {
//..
try {
synchronized (mGlobalLock) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
if (displayContent != null) {
//见5.1,这里传递的density是外部传递过来的
displayContent.setForcedDensity(density, targetUserId);
}
}
//..
}
4.3.getInitialDisplayDensity
public int getInitialDisplayDensity(int displayId) {
synchronized (mGlobalLock) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
return displayContent.mInitialDisplayDensity;
}
}
return -1;
}
5.DisplayContent
5.1.setForcedDensity
void setForcedDensity(int density, int userId) {
mIsDensityForced = density != mInitialDisplayDensity;
final boolean updateCurrent = userId == UserHandle.USER_CURRENT;
if (mWmService.mCurrentUserId == userId || updateCurrent) {
mBaseDisplayDensity = density;//修改了这个值,
//见5.2,重新config
reconfigureDisplayLocked();
}
if (updateCurrent) {
// We are applying existing settings so no need to save it again.
return;
}
if (density == mInitialDisplayDensity) {
density = 0;
}
mWmService.mDisplayWindowSettings.setForcedDensity(this, density, userId);
}
5.2.reconfigureDisplayLocked
void reconfigureDisplayLocked() {
if (!isReady()) {
return;
}
configureDisplayPolicy();
setLayoutNeeded();
boolean configChanged = updateOrientation();
//获取旧的
final Configuration currentDisplayConfig = getConfiguration();
mTmpConfiguration.setTo(currentDisplayConfig);
//获取新的
computeScreenConfiguration(mTmpConfiguration);
//比较是否发生变化
final int changes = currentDisplayConfig.diff(mTmpConfiguration);
configChanged |= changes != 0;
if (configChanged) {
mWaitingForConfig = true;
if (mTransitionController.isShellTransitionsEnabled()) {
requestChangeTransitionIfNeeded(changes, null /* displayChange */);
} else if (mLastHasContent) {
mWmService.startFreezingDisplay(0 /* exitAnim */, 0 /* enterAnim */, this);
}
sendNewConfiguration();
}
mWmService.mWindowPlacerLocked.performSurfacePlacement();
}
>1.configureDisplayPolicy
void configureDisplayPolicy() {
mRootWindowContainer.updateDisplayImePolicyCache();
mDisplayPolicy.updateConfigurationAndScreenSizeDependentBehaviors();
mDisplayRotation.configure(mBaseDisplayWidth, mBaseDisplayHeight);
}
>2.setLayoutNeeded
void setLayoutNeeded() {
mLayoutNeeded = true;
}
>3.updateOrientation
boolean updateOrientation() {
return updateOrientation(false /* forceUpdate */);
}
private boolean updateOrientation(boolean forceUpdate) {
final int orientation = getOrientation();
// The last orientation source is valid only after getOrientation.
final WindowContainer orientationSource = getLastOrientationSource();
final ActivityRecord r =
orientationSource != null ? orientationSource.asActivityRecord() : null;
if (r != null) {
final Task task = r.getTask();
if (task != null && orientation != task.mLastReportedRequestedOrientation) {
task.mLastReportedRequestedOrientation = orientation;
mAtmService.getTaskChangeNotificationController()
.notifyTaskRequestedOrientationChanged(task.mTaskId, orientation);
}
// Currently there is no use case from non-activity.
if (handleTopActivityLaunchingInDifferentOrientation(r, true /* checkOpening */)) {
// Display orientation should be deferred until the top fixed rotation is finished.
return false;
}
}
return mDisplayRotation.updateOrientation(orientation, forceUpdate);
}
>4.computeScreenConfiguration
/**
* Compute display configuration based on display properties and policy settings.
* Do not call if mDisplayReady == false.
*/
void computeScreenConfiguration(Configuration config) {
final DisplayInfo displayInfo = updateDisplayAndOrientation(config.uiMode, config);
final int dw = displayInfo.logicalWidth;
final int dh = displayInfo.logicalHeight;
mTmpRect.set(0, 0, dw, dh);
config.windowConfiguration.setBounds(mTmpRect);
config.windowConfiguration.setMaxBounds(mTmpRect);
config.windowConfiguration.setWindowingMode(getWindowingMode());
config.windowConfiguration.setDisplayWindowingMode(getWindowingMode());
computeScreenAppConfiguration(config, dw, dh, displayInfo.rotation, config.uiMode,
displayInfo.displayCutout);
config.screenLayout = (config.screenLayout & ~Configuration.SCREENLAYOUT_ROUND_MASK)
| ((displayInfo.flags & Display.FLAG_ROUND) != 0
? Configuration.SCREENLAYOUT_ROUND_YES
: Configuration.SCREENLAYOUT_ROUND_NO);
config.densityDpi = displayInfo.logicalDensityDpi;
config.colorMode =
((displayInfo.isHdr() && mWmService.hasHdrSupport())
? Configuration.COLOR_MODE_HDR_YES
: Configuration.COLOR_MODE_HDR_NO)
| (displayInfo.isWideColorGamut() && mWmService.hasWideColorGamutSupport()
? Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_YES
: Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_NO);
// 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;
int keyboardPresence = 0;
int navigationPresence = 0;
final InputDevice[] devices = mWmService.mInputManager.getInputDevices();
final int len = devices != null ? devices.length : 0;
for (int i = 0; i < len; i++) {
InputDevice device = devices[i];
// Ignore virtual input device.
if (device.isVirtual()) {
continue;
}
// Check if input device can dispatch events to current display.
if (!mWmService.mInputManager.canDispatchToDisplay(device.getId(), mDisplayId)) {
continue;
}
final int sources = device.getSources();
final int presenceFlag = device.isExternal()
? WindowManagerPolicy.PRESENCE_EXTERNAL : WindowManagerPolicy.PRESENCE_INTERNAL;
if (mWmService.mIsTouchDevice) {
if ((sources & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN) {
config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
}
} else {
config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
}
if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
config.navigation = Configuration.NAVIGATION_TRACKBALL;
navigationPresence |= presenceFlag;
} else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
&& config.navigation == Configuration.NAVIGATION_NONAV) {
config.navigation = Configuration.NAVIGATION_DPAD;
navigationPresence |= presenceFlag;
}
if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
config.keyboard = Configuration.KEYBOARD_QWERTY;
keyboardPresence |= presenceFlag;
}
}
if (config.navigation == Configuration.NAVIGATION_NONAV && mWmService.mHasPermanentDpad) {
config.navigation = Configuration.NAVIGATION_DPAD;
navigationPresence |= WindowManagerPolicy.PRESENCE_INTERNAL;
}
// Determine whether a hard keyboard is available and enabled.
// TODO(multi-display): Should the hardware keyboard be tied to a display or to a device?
boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
if (hardKeyboardAvailable != mWmService.mHardKeyboardAvailable) {
mWmService.mHardKeyboardAvailable = hardKeyboardAvailable;
mWmService.mH.removeMessages(REPORT_HARD_KEYBOARD_STATUS_CHANGE);
mWmService.mH.sendEmptyMessage(REPORT_HARD_KEYBOARD_STATUS_CHANGE);
}
mDisplayPolicy.updateConfigurationAndScreenSizeDependentBehaviors();
// Let the policy update hidden states.
config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
mWmService.mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
}
6.DisplayWindowSettings.java
6.1.setForcedDensity
void setForcedDensity(DisplayContent displayContent, int density, int userId) {
if (displayContent.isDefaultDisplay) {
final String densityString = density == 0 ? "" : Integer.toString(density);
//修改
Settings.Secure.putStringForUser(mService.mContext.getContentResolver(),
Settings.Secure.DISPLAY_DENSITY_FORCED, densityString, userId);
}
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
final SettingsProvider.SettingsEntry overrideSettings =
mSettingsProvider.getOverrideSettings(displayInfo);
overrideSettings.mForcedDensity = density;
//这个最终就是把数据存储起来了
mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}