赞
踩
系统设置中的显示大小调整的就是屏幕密度,调整的越小,屏幕显示的内容就越多。
在系统中都会有定义一个默认的屏幕密度
<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>
public void displayReady() { synchronized (mGlobalLock) { if (mMaxUiWidth > 0) { mRoot.forAllDisplays(displayContent -> displayContent.setMaxUiWidth(mMaxUiWidth)); } applyForcedPropertiesForDefaultDisplay(); mAnimator.ready(); mDisplayReady = true; ... } /** The global settings only apply to default display. */ private boolean applyForcedPropertiesForDefaultDisplay() { boolean changed = false; final DisplayContent displayContent = getDefaultDisplayContentLocked(); ... // Display density. final int density = getForcedDisplayDensityForUserLocked(mCurrentUserId); if (density != 0 && density != displayContent.mBaseDisplayDensity) { displayContent.mBaseDisplayDensity = density; changed = true; } ... } /** * @param userId the ID of the user * @return the forced display density for the specified user, if set, or * {@code 0} if not set */ private int getForcedDisplayDensityForUserLocked(int userId) { String densityStr = Settings.Secure.getStringForUser(mContext.getContentResolver(), Settings.Secure.DISPLAY_DENSITY_FORCED, userId); if (densityStr == null || densityStr.length() == 0) { // String DENSITY_OVERRIDE = "ro.config.density_override"; densityStr = SystemProperties.get(DENSITY_OVERRIDE, null); } if (densityStr != null && densityStr.length() > 0) { try { return Integer.parseInt(densityStr); } catch (NumberFormatException ex) { } } return 0; }
在WindowManagerService启动之后,调用getForcedDisplayDensityForUserLocked方法获取强制设置的屏幕显示密度,如果有强制设置,将获取到的值赋给mBaseDisplayDensity,系统将以Settings.Secure.DISPLAY_DENSITY_FORCED的值这个密度显示。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。