rugo
rugo

Reputation: 71

Android screen density calculation

Can somebody tell me how Android counts the screen density?

My problem is I have a device (ODYS Space) with 480x800 resolution and with 7" diagonal screen. If I calculate its density I get a value 133 DPI but Android (2.2 and 2.3 too) reports it like "MEDIUM" density device (160 DPI).

I'm fighting with multiscreen support so I supposed 133 DPI will be rather reported like "LOW" than "MEDIUM" so now my screen layout looks quite stupid on this medium reported device.

I check the device with code like this:

DisplayMetrics dMetrics = new DisplayMetrics(); 
getWindowManager().getDefaultDisplay().getMetrics(dMetrics);  
int d=dMetrics.densityDpi;

If I run that code on a virtual device configured (480x800/7" and 133 DPI) then I got density=120.

On the real device why does it say 160 instead?

Upvotes: 6

Views: 11865

Answers (6)

Tyler
Tyler

Reputation: 18187

I have updated one of the other solutions for 2014.

Call this method in one of your Activities:

private void tellMeDensity() {
        DisplayMetrics dm = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        int dpiClassification = dm.densityDpi;

        float xDpi = dm.xdpi;
        float yDpi = dm.ydpi;

        Toast.makeText(this, "xdpi=" + xDpi, Toast.LENGTH_SHORT).show();
        Toast.makeText(this, "ydpi=" + yDpi, Toast.LENGTH_SHORT).show();

        switch(dpiClassification) {
           case DisplayMetrics.DENSITY_LOW:
               Toast.makeText(this, "low density", Toast.LENGTH_SHORT).show();
               break;    
           case DisplayMetrics.DENSITY_MEDIUM:
               Toast.makeText(this, "medium density", Toast.LENGTH_SHORT).show();
               break;                
           case DisplayMetrics.DENSITY_HIGH:
               Toast.makeText(this, "high density", Toast.LENGTH_SHORT).show();
               break;    
           case DisplayMetrics.DENSITY_XHIGH:
               Toast.makeText(this, "xhigh density", Toast.LENGTH_SHORT).show();
               break;                  
           case DisplayMetrics.DENSITY_XXHIGH:
               Toast.makeText(this, "xxhigh density", Toast.LENGTH_SHORT).show();
               break;                  
           case DisplayMetrics.DENSITY_XXXHIGH:
               Toast.makeText(this, "xxxhigh density", Toast.LENGTH_SHORT).show();
               break;      
        }
    }

Upvotes: 2

Simon
Simon

Reputation: 11190

The manufacturer chooses the density when it makes the ROM image for your device. It is not calculated at run-time.

If you take a look at the source: https://github.com/android/platform_frameworks_base/blob/master/core/java/android/util/DisplayMetrics.java#L294 you'll see the getDeviceDensity() function tries to use two system properties one is the qemu emulator value qemu.sf.lcd_density, and the other is the manufacturer set value ro.sf.lcd_density, and finally if the manufacturer forgot to set one the system falls back to the default. DENSITY_DEFAULT is set to DENSITY_MEDIUM which is set to 160.

You can verify the device property by plugging in your device and running this command:

adb shell getprop ro.sf.lcd_density

The properties are stored in /system/build.prop and are loaded on boot. You can look at the contents of the file with this command:

adb shell cat /system/build.prop

Upvotes: 0

Xavier Ducrohet
Xavier Ducrohet

Reputation: 28549

There are two different things here.

  1. The behavior in the emulator which is a combination of the AVD manager configuring the AVD itself and maybe using a device definition. The emulator system images have baked in values so that we can ship the same image for all device configurations. This baked in value is mdpi for density. When you create an AVD with a different density we inject just before boot time the new value. The injected value is converted to a density bucket value (ldpi, mdpi, hdpi, ...) based on basic rules (if you are past the half point between bucket value, you go in the next value).

So the half point between 120 and 160 is 140, and therefore 133dpi -> ldpi.

  1. Device do whatever they want. It's a manual process for any OEM to decide what their device's bucket value is, and this get set in a property. It is not dynamically computed based on the actual hardware screen size of the device. You can do a device that has a true screen density of 133 and yet put it in the xxdpi bucket if you want.

The end result is that you need to create a new device definition where you manually say your 7" 480x800 device is actually a medium density device, and it should work. If it doesn't, it's a bug on our side when we configure the emulator for a particular device-based AVD. It's not an issue on the Android platform itself which doesn't compute anything.

Upvotes: 4

Amey Haldankar
Amey Haldankar

Reputation: 2243

**dpi calculation programitically:**

public class SampleActivity extends Activity
{

   @Override
   public void onCreate(Bundle savedInstanceState)
    {
      super.onCreate(savedInstanceState);
       setContentView(R.layout.main);
       DisplayMetrics dm = new DisplayMetrics();
       getWindowManager().getDefaultDisplay().getMetrics(dm);
       int dpiClassification = dm.densityDpi;

    float xDpi = dm.xdpi;
    float yDpi = dm.ydpi;

    Toast.makeText(SampleActivity.this, "xdpi="+xDpi, Toast.LENGTH_SHORT).show();
    Toast.makeText(SampleActivity.this, "ydpi="+yDpi, Toast.LENGTH_SHORT).show();


    switch(dpiClassification)
    {
       case DisplayMetrics.DENSITY_LOW:
           Toast.makeText(SampleActivity.this, "low density",    
                   Toast.LENGTH_SHORT).show();

                 break;

       case DisplayMetrics.DENSITY_MEDIUM:
           Toast.makeText(SampleActivity.this, "low medium", 
                  Toast.LENGTH_SHORT).show();

                 break;
       case DisplayMetrics.DENSITY_HIGH:
           Toast.makeText(SampleActivity.this, "low high", 
                     Toast.LENGTH_SHORT).show();

                  break;



       case DisplayMetrics.DENSITY_XHIGH:
           Toast.makeText(SampleActivity.this, "low xhigh", 
                  Toast.LENGTH_SHORT).show();

                 break;
       }

    }
 }

Upvotes: 0

lulumeya
lulumeya

Reputation: 1628

I'm using same code and I have seen values 160, 240, 320 densityDpi values only. I thinks it's such a normalization on android os. It's my suggestion only I don't know detailed technical information.

Upvotes: 0

dmon
dmon

Reputation: 30168

If you check the docs (look for the "Using configuration qualifiers" section), a device is considered "low DPI" until you get around/below 120 DPI.

Upvotes: 0

Related Questions