系统设置中的显示大小调整的就是屏幕密度,调整的越小,屏幕显示的内容就越多。
在系统中都会有定义一个默认的屏幕密度
<Preference
android:key="font_size"
android:title="@string/title_font_size"
android:fragment="com.android.settings.display.ToggleFontSizePreferenceFragment"
settings:controller="com.android.settings.display.FontSizePreferenceController" />
<!-- 显示大小设置-->
<com.android.settings.display.ScreenZoomPreference
android:key="display_settings_screen_zoom"
android:title="@string/screen_zoom_title"
android:fragment="com.android.settings.display.ScreenZoomSettings"/>
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final DisplayDensityUtils density = new DisplayDensityUtils(getContext());
final int initialIndex = density.getCurrentIndex();
if (initialIndex < 0) {
// Failed to obtain default density, which means we failed to
// connect to the window manager service. Just use the current
// density and don't let the user change anything.
final int densityDpi = getResources().getDisplayMetrics().densityDpi;
mValues = new int[]{densityDpi};
mEntries = new String[]{getString(DisplayDensityUtils.SUMMARY_DEFAULT)};
mInitialIndex = 0;
mDefaultDensity = densityDpi;
} else {
mValues = density.getValues();
mEntries = density.getEntries();
mInitialIndex = initialIndex;
mDefaultDensity = density.getDefaultDensity();
}
getActivity().setTitle(R.string.screen_zoom_title);
}
@Override
protected Configuration createConfig(Configuration origConfig, int index) {
// Populate the sample layouts.
final Configuration config = new Configuration(origConfig);
config.densityDpi = mValues[index];
return config;
}
/**
* Persists the selected density and sends a configuration change.
*/
@Override
protected void commit() {
final int densityDpi = mValues[mCurrentIndex];
if (densityDpi == mDefaultDensity) {
DisplayDensityConfiguration.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY);
} else {
DisplayDensityConfiguration.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, densityDpi);
}
}
密度缩放等级描述"小,默认,大,较大,最大" mEntries和mValues 这些配置是从DisplayDensityUtils 中获取
设置显示大小后调用DisplayDensityConfiguration.setForcedDisplayDensity方法去配置
/**
* Utility methods for working with display density.
*/
public class DisplayDensityUtils {
private static final String LOG_TAG = "DisplayDensityUtils";
/** Minimum increment between density scales. */
private static final float MIN_SCALE_INTERVAL = 0.09f;
/** Minimum density scale. This is available on all devices. */
private static final float MIN_SCALE = 0.85f;
/** Maximum density scale. The actual scale used depends on the device. */
private static final float MAX_SCALE = 1.50f;
/** Summary used for "default" scale. */
public static final int SUMMARY_DEFAULT = R.string.screen_zoom_summary_default;
/** Summary used for "custom" scale. */
private static final int SUMMARY_CUSTOM = R.string.screen_zoom_summary_custom;
/**
* 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.
*/
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,
};
/**
* Minimum allowed screen dimension, corresponds to resource qualifiers
* "small" or "sw320dp". This value must be at least the minimum screen
* size required by the CDD so that we meet developer expectations.
*/
private static final int MIN_DIMENSION_DP = 320;
private final String[] mEntries;
private final int[] mValues;
private final int mDefaultDensity;
private final int mCurrentIndex;
public DisplayDensityUtils(Context context) {
// 获取默认的屏幕密度 ro.sf.lcd_density
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();
final DisplayMetrics metrics = new DisplayMetrics();
context.getDisplayNoVerify().getRealMetrics(metrics);
// 当前屏幕使用的密度值
final int currentDensity = metrics.densityDpi;
int currentDensityIndex = -1;
// Compute number of "larger" and "smaller" scales for this display.
final int minDimensionPx = Math.min(metrics.widthPixels, metrics.heightPixels);
// DisplayMetrics.DENSITY_MEDIUM = 160
// MIN_DIMENSION_DP = 320
final int maxDensity = DisplayMetrics.DENSITY_MEDIUM * minDimensionPx / MIN_DIMENSION_DP;
// 屏幕密度最大的缩放是1.5
final float maxScale = Math.min(MAX_SCALE, maxDensity / (float) defaultDensity);
// 屏幕密度最小缩放0.85
final float minScale = MIN_SCALE;
// 0~3
final int numLarger = (int) MathUtils.constrain((maxScale - 1) / MIN_SCALE_INTERVAL,
0, SUMMARIES_LARGER.length);
// 0~1
final int numSmaller = (int) MathUtils.constrain((1 - minScale) / MIN_SCALE_INTERVAL,
0, SUMMARIES_SMALLER.length);
// {小,默认,大,较大,最大}
// entries的内容根据numLarger和numSmaller的值来填充
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++;
}
}
// 如果numSmaller为0,entries{默认,..}
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) {
displayIndex = currentDensityIndex;
} else {
// We don't understand the current density. Must have been set by
// someone else. Make room for another entry...
int newLength = values.length + 1;
values = Arrays.copyOf(values, newLength);
values[curIndex] = currentDensity;
entries = Arrays.copyOf(entries, newLength);
entries[curIndex] = res.getString(SUMMARY_CUSTOM, currentDensity);
displayIndex = curIndex;
}
mDefaultDensity = defaultDensity;
mCurrentIndex = displayIndex;
mEntries = entries;
mValues = values;
}
public String[] getEntries() {
return mEntries;
}
public int[] getValues() {
return mValues;
}
首先读取ro.sf.lcd_density获得默认的屏幕密度值,然后通过metrics.densityDpi得到当前使用的屏幕密度值,根据屏幕宽高计算得到密度最大缩放值maxScale(最大为1.5);在通过计算得到numLarger和numSmaller的值然后对entries和values填充内容,得到我们看到的等级描述"小,默认,大,较大,最大"。
public static void setForcedDisplayDensity(final int displayId, final int density) {
final int userId = UserHandle.myUserId();
AsyncTask.execute(
() -> {
try {
final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
wm.setForcedDisplayDensityForUser(displayId, density, userId);
} catch (RemoteException exc) {
Log.w(LOG_TAG, "Unable to save forced display density setting");
}
});
}
@Override
public void setForcedDisplayDensityForUser(int displayId, int density, int userId) {
if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS);
}
final int targetUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, true, "setForcedDisplayDensityForUser",
null);
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
if (displayContent != null) {
displayContent.setForcedDensity(density, targetUserId);
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
void setForcedDensity(int density, int userId) {
final boolean updateCurrent = userId == UserHandle.USER_CURRENT;
if (mWmService.mCurrentUserId == userId || updateCurrent) {
// 重新赋值
mBaseDisplayDensity = density;
// 根据设置的值,重新计算显示配置
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);
}
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);
return;
}
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
final Entry entry = getOrCreateEntry(displayInfo);
entry.mForcedDensity = density;
writeSettingsIfNeeded(entry, displayInfo);
}
根据设置的屏幕密度值重新计算显示配置,最后修改Settings.Secure.DISPLAY_DENSITY_FORCED的值
private void loadSecureSettings(SQLiteDatabase db) {
SQLiteStatement stmt = null;
try {
stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
+ " VALUES(?,?);");
...
loadStringSetting(stmt, Settings.Secure.DISPLAY_DENSITY_FORCED,
R.string.def_display_density_forced);
<string name="def_display_density_forced">204</string>
这种修改方式是不改变默认的屏幕密度值ro.sf.lcd_density=240,在此基础上修改屏幕显示的密度。
修改之后使用adb命令查看
C:\Users\dell>adb shell wm density
Physical density: 240
Override density: 204
C:\Users\dell>
至于修改之后的值为什么可以覆盖默认的屏幕密度
final int defaultDensity = DisplayDensityUtils.getDefaultDisplayDensity(
Display.DEFAULT_DISPLAY)屏幕密度默认值的获取
final int currentDensity = metrics.densityDpi当前屏幕密度值得获取流程后面再更新。