Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Lint shows warning when using in (inch) or mm (millimeter) units as dimension?

Documentation clearly says that mm and in are screen size dependent.

mm
Millimeters - Based on the physical size of the screen.

in
Inches - Based on the physical size of the screen.

But when I use them, Lint says:

Avoid using "mm" as units (it does not work accurately on all devices); use "dp" instead

Is documentation wrong? And why Lint doesn't warn when using pt?

pt
Points - 1/72 of an inch based on the physical size of the screen.

like image 257
M-WaJeEh Avatar asked Dec 17 '13 10:12

M-WaJeEh


1 Answers

To be able to give a good answer to your question I first have to give an explanation on how DPI works in Android, so this answer is a bit long.

TL;DR: The documentation is correct, however the warning from Lint is also correct. That is there are some (buggy?) devices where mm, in and pt doesn't work correctly.

DPI in Android

In Android there are two different kinds of density measures that can be accessed from the DisplayMetrics class:

  • densityDpi - The screen density expressed as dots-per-inch. This value is always set to one of the generalized density buckets available in Android (e.g. Medium/160, High/240, Extra High/320).
  • xdpi / ydpi - The exact physical pixels per inch of the screen in the X/Y dimension. It is not uncommon that this value is slightly different than densityDpi depending on what screen size and resolution the device have.

The dp unit is calculated based on the densityDpi metric while the mm, in and pt units are all calculated based on xdpi/ydpi instead.

Reported values

It is possible to divide devices into four different categories depending on what values they report for densityDpi and xdpi / ydpi:

  1. densityDpi is almost the same, or the same as xdpi / ydpi.
  2. densityDpi is noticeably smaller than xdpi / ydpi
  3. densityDpi is noticeably larger than xdpi / ydpi
  4. the xdpi / ydpi values are completely wrong.

Category 1 (densityDpi is the same as xdpi / ydpi)

Example devices: Samsung Galaxy Trend, Nexus 4, Nexus 7.

For these devices there it doesn't really matter if you use in, mm, or dp. If you draw a square with sides 1 in and one with 160 dp they will be the same and both will be about 1 inch on the actual screen.

Category 2 & 3 (densityDpi is different than xdpi / ydpi)

Category 2 example devices: HTC One S, Sony Xperia V, Sony Xperia Z Ultra.
Category 3 example devices: Samsung Galaxy S4, Sony Xperia Z1, Nexus 5.

For these devices the densityDpi and xdpi / ydpi differs because the densityDpi must be set to one of the available density buckets. So the true physical dpi is rounded to match the nearest bucket and this is what is reported as densityDPI value. This is illustrated by Figure 1 in the Supporting Multiple Screens document.

This means that if you draw a square with side 1 in and one with 160 dp they will have slightly different size. For category 2 devices the 160 dp square will be slightly smaller and for category 3 devices it will instead by slightly larger. If you take out a ruler and physically measure the squares on the screen of the phone you will see that the 1 in square is 1 inch while the 160 dp square is a bit smaller or bigger depending on category.

This is a natural consequence of the density buckets system in Android, but unless you have a deeper understanding of how this works it may be a bit surprising that things drawn with a fixed dp measure may look different on different phones.

Category 4 (incorrect xdpi / ydpi values)

Example devices: Samsung Galaxy Mini, Samsung Galaxy S3 Mini.

These devices are more problematic, they have a good value for densityDpi (their true dpi rounded to the nearest bucket), but they report bogus values for xdpi / ydpi.

For example Samsung Galaxy S3 Mini reports an xdpi of 160 and densityDpi of 240. The screen 480 px wide so if 160 dpi was correct this would mean a screen width of 3 inch, but in reality the screen with is 2.05 inch. Based on these numbers the actual xdpi value that the phone should be reporting is 234.

Another example is the Samsung Galaxy Mini which also reports an xdpi of 160, but has densityDpi set to 120. That screen is 240 px wide so that would give a physical width of 1.5 inch, but in reality the screen is 1.9 inch (actual xdpi of 126).

So on these types of devices it is not possible to trust the in, mm, pt units since they will result in things being way too small or way too big.

Examples

Category 1-3

Comparison of category 1-3 devices

This is three screenshots of a test app I've made taken on devices from category 1, 2 and 3. The green square is drawn to be 1 inch big based on using the xdpi and ydpi values while the red square is drawn to be 1 inch big using dp (160 dp).

When physically measuring the result with a ruler the green square was inch big in all these examples while the red square size differed somewhat as it's visible on the screenshots.

Category 4

Screenshot from category 4 device

This is a screenshot from a category 4 device. The green and red squares are the same as in the previous example, but here I have also added two more squares, a yellow square that is 1 in and a blue square that is 72 pt. As visible on the screenshot all squares except the red square are of equal size.

When physically measuring the result with a ruler the red square is about one inch big while the rest of the squares are only about 0.67 inch big.

The answer to the question

The warning from Lint refers to category 4 type devices that return incorrect values for xdpi and ydpi. Since xdpi / ydpi can not be trusted on these devices the units (mm, in, pt) that depend on them can not be trusted either.

Is documentation wrong?

No the documentation is correct, these units are based on the physical size of the screen. However some problematic devices report wrong values for the physical size of the screen (xdpi / ydpi) to Android and then these units will be wrong as well.

And why Lint doesn't warn when using pt?

The Lint developers probably just forgot about pt, it is just as problematic as in and mm.

The reason Lint recommends using dp instead is because this is a unit that is used extremely frequently in Android so if any device had broken dp units pretty much all applications would look horrible and it would be fixed before the device was ever released to market.

like image 148
nibarius Avatar answered Nov 03 '22 01:11

nibarius