What does DisplayMetrics.scaledDensity actually return in Android?
android
Solution
I was able to figure out this myself. After digging trough the Android source code I found that the `scaledDensity` property is calculated as `scaledDensity = density * fontScale` where fontScale depends on the system setting for font size. So this was just as I thought it should be.
The reason why `scaledDensity` always had the same value for me regardless of font size was because I was using the DisplayMetrics for the wrong Display. I got the DisplayMetrics from the default display and regarding this the documentation say:
Returns the Display upon which this WindowManager instance will create new windows.
Despite the name of this method, the display that is returned is not necessarily the primary display of the system (see DEFAULT_DISPLAY). The returned display could instead be a secondary display that this window manager instance is managing. Think of it as the display that this WindowManager instance uses by default.
In this case the default display is not the same display as the primary display of the system, so when I change the system font setting that setting is changed on the primary display and not on the default display. If I update my code to get the `DisplayMetrics` for the display that is actually used `scaledDensity` returns the expected values scaled according to the system font settings.
With the following updated code that uses `getResources().getDisplayMetrics()` everything works as expected:
DisplayMetrics metrics = getResources().getDisplayMetrics();
String result = "\n"
+ "density : " + metrics.density + " (24 dp = " + 24 * metrics.density + " px)\n"
+ "scaledDensity: " + metrics.scaledDensity + " (24 sp = " + 24 * metrics.scaledDensity + " px)\n" ;
((TextView) this.findViewById(R.id.label)).setText(result);
((TextView) this.findViewById(R.id.sp)).setTextSize(TypedValue.COMPLEX_UNIT_SP, 24);
((TextView) this.findViewById(R.id.dp)).setTextSize(TypedValue.COMPLEX_UNIT_DIP, 24);
With this way of getting the display metrics this is the result I get (observe how the scaled density changes with font size):
Problem
I'm trying to understand the sp unit in Android, but I can't really figure out how it works. The documentation say: sp Scale-independent Pixels - This is like the dp unit, but it is also scaled by the user's font size preference. It is recommend you use this unit when specifying font sizes, so they will be adjusted for both the screen density and the user's preference. Using DisplayMetrics it is possible to get the scaledDensity which is: A scaling factor for fonts displayed on the display. This is the same as density, except that it may be adjusted in smaller increments at runtime based on a user preference for the font size. So given this information I assume that the scaledDensity will change as I change the system font size and that I can use this information to know the ratio between 1dp and 1sp (`scaledDensity / density`). However when I'm testing this on my phone (Nexus 4) I am not getting the results I'm expecting. DisplayMetrics.scaledDensity always returns the same value (equal to DisplayMetrics.density) regardless of what font size I have set my phone to use (via `settings -> accessibility -> use large font` or `settings -> display -> font size`). When I change the font settings my sp specified fonts changes size, so the sp unit works as expected but the scaledDensity value doesn't change at all. The code I'm using to get the scaledDensity is: ``` DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); metrics.scaledDensity ``` Am I doing something wrong or have I misunderstood what DisplayMetrics.scaledDensity actually does? Update Here are three screenshots that illustrates what I mean: And this is the code for the application: ``` DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); String result = "\n" + "density : " + metrics.density + " (24 dp = " + 24 * metrics.density + " px)\n" + "scaledDensity: " + metrics.scaledDensity + " (24 sp = " + 24 * metrics.scaledDensity + " px)\n"; ((TextView) this.findViewById(R.id. label)).setText(result); ((TextView) this.findViewById(R.id. sp)).setTextSize(android.util.TypedValue. COMPLEX_UNIT_SP , 24); ((TextView) this.findViewById(R.id.dp )).setTextSize(android.util.TypedValue. COMPLEX_UNIT_DIP, 24); ``` I want to be able to calculate the amount of pixels needed y-wise to draw a certain string. If I specify the size of the string using dp I can easily calculate the required pixels using `displayMetrics.density`. But when I use sp and try to calculate the amount of pixels using `displayMetrics.scaledDensity` I do not get the correct values.