Android DisplayMetrics returns incorrect screen size in pixels on ICS
Asked Answered
H

6

24

I've tried this....

DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int fullscreenheight = metrics.heightPixels;
int fullscreenwidth = metrics.widthPixels;

and....

Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;

The Gnex has a display of 720×1280. The returned result for width/height (depending on orientation of course) is never 1280. I thought this might have something to do with the on screen navigation bar in Ice Cream Sandwich, so I hide that with :

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);

...and then started a thread which continuously logs the screen size height/width. Even after the ICS navigation bar was completely gone....the screen size would never report the 1280 value. I would get numbers like this:

width  = 720
height = 1184

How do you get the true device screen resolution in ICS?

The reason why I need this value is because my app plays video and I would like for the video to take up the entire screen when the device is in landscape orientation. Now I know what you're thinking, why not just give the videoview a value of "match_parent" for the height/width? The reason is because my videos have multiple aspect ratios and I'd like to be able to calculate the correct video size depending on the entire width of the screen.

Henbit answered 12/6, 2012 at 5:54 Comment(0)
H
20

I found this hidden treasure for ICS ONLY......if you're targeting API's higher than ICS see the comment by Chris Schmich below.

How to hide and display the navigation bar on Android ICS build

In case the link dies....here's how to get the actual device screen size.....

Display display = getWindowManager().getDefaultDisplay();     
Method mGetRawH = Display.class.getMethod("getRawHeight");
Method mGetRawW = Display.class.getMethod("getRawWidth");
int rawWidth = (Integer) mGetRawW.invoke(display);
int rawHeight = (Integer) mGetRawH.invoke(display);

EDIT (11/19/12)

The above code WILL NOT WORK on Android 4.2 and an exception will be thrown....I have yet to find a way to get the full screen size of a device in Android 4.2. When I do, I will edit this answer, but for now, you should code with contingency for android 4.2!!

Henbit answered 12/6, 2012 at 21:6 Comment(5)
- and why does Google have to make me go raw?Henbit
On Android 4.2 (API 17) and higher, you can use Display.getRealMetrics to get the actual physical display metrics. I confirmed that this works on my Samsung Galaxy Nexus with Jelly Bean (4.2.1). See developer.android.com/reference/android/view/…Counterreply
Note also that getRawHeight and getRawWidth are only available since API 14. So we can only use them for API 14, 15 and 16.Bromberg
I've written an answer on a different question that uses this and the other options to get the best display metrics possible on api 10+.Makeshift
Do not use reflection to access methods like this. Methods like this are hidden for a reason - there is no guarantee that they will exist in future releases or will return the same value between releases.Toleration
E
21

From the answer of Ahmed, this is full code without error:

    int width = 0, height = 0;
    final DisplayMetrics metrics = new DisplayMetrics();
    Display display = getWindowManager().getDefaultDisplay();
    Method mGetRawH = null, mGetRawW = null;

    try {
        // For JellyBean 4.2 (API 17) and onward
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
            display.getRealMetrics(metrics);

            width = metrics.widthPixels;
            height = metrics.heightPixels;
        } else {
            mGetRawH = Display.class.getMethod("getRawHeight");
            mGetRawW = Display.class.getMethod("getRawWidth");

            try {
                width = (Integer) mGetRawW.invoke(display);
                height = (Integer) mGetRawH.invoke(display);
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    } catch (NoSuchMethodException e3) {  
        e3.printStackTrace();
    }
Electrostatic answered 7/7, 2013 at 14:8 Comment(0)
H
20

I found this hidden treasure for ICS ONLY......if you're targeting API's higher than ICS see the comment by Chris Schmich below.

How to hide and display the navigation bar on Android ICS build

In case the link dies....here's how to get the actual device screen size.....

Display display = getWindowManager().getDefaultDisplay();     
Method mGetRawH = Display.class.getMethod("getRawHeight");
Method mGetRawW = Display.class.getMethod("getRawWidth");
int rawWidth = (Integer) mGetRawW.invoke(display);
int rawHeight = (Integer) mGetRawH.invoke(display);

EDIT (11/19/12)

The above code WILL NOT WORK on Android 4.2 and an exception will be thrown....I have yet to find a way to get the full screen size of a device in Android 4.2. When I do, I will edit this answer, but for now, you should code with contingency for android 4.2!!

Henbit answered 12/6, 2012 at 21:6 Comment(5)
- and why does Google have to make me go raw?Henbit
On Android 4.2 (API 17) and higher, you can use Display.getRealMetrics to get the actual physical display metrics. I confirmed that this works on my Samsung Galaxy Nexus with Jelly Bean (4.2.1). See developer.android.com/reference/android/view/…Counterreply
Note also that getRawHeight and getRawWidth are only available since API 14. So we can only use them for API 14, 15 and 16.Bromberg
I've written an answer on a different question that uses this and the other options to get the best display metrics possible on api 10+.Makeshift
Do not use reflection to access methods like this. Methods like this are hidden for a reason - there is no guarantee that they will exist in future releases or will return the same value between releases.Toleration
W
12

You can use getRealSize to get the screen resolution. It's officially supported in API 17 and higher, but it actually existed in the SDK since API 14. If you use the SDK platform for API 17 or higher, you can access the method normally and just bypass the warning about it only being available in API 17.

/**
 * Gets the device's native screen resolution rotated
 * based on the device's current screen orientation.
 */
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) //To remove warning about using
                                               //getRealSize prior to API 17
private Point screenResolution() {
    WindowManager windowManager =
        (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = windowManager.getDefaultDisplay();
    Point screenResolution = new Point();

    if (Build.VERSION.SDK_INT < 14)
        throw new RuntimeException("Unsupported Android version.");
    display.getRealSize(screenResolution);

    return screenResolution;    
}

I've tested this in a real Android 5.0.2 device and an emulator running 4.1.1 (and possibly others).

Thanks to benc for pointing this out in the comments.

Westmorland answered 28/2, 2015 at 11:23 Comment(1)
This method was deprecated in API level 31. You can use WindowManager#getCurrentWindowMetrics() insteadGuardian
W
6

Try this

    final DisplayMetrics metrics = new DisplayMetrics(); 
    Display display = getWindowManager().getDefaultDisplay();     
    Method mGetRawH = null,mGetRawW = null;

    try {
                    // For JellyBeans and onward
        if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN){
            display.getRealMetrics(metrics);

            realWidth = metrics.widthPixels;
            realHeight = metrics.heightPixels;
        }else{
            mGetRawH = Display.class.getMethod("getRawHeight");
            mGetRawW = Display.class.getMethod("getRawWidth");

            try {
                realWidth = (Integer) mGetRawW.invoke(display);
                realHeight = (Integer) mGetRawH.invoke(display);
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
Whitver answered 29/4, 2013 at 10:51 Comment(1)
In my limited testing so far, getRealMetrics() gives the correct results even on 4.0 devices, where you would expect it to crash. Also noteworthy is that getRealMetrics returns the correct DPI, where the other methods for getting a DisplayMetrics can return bogus data. (With the other methods, my S4 was claiming to be an mpdi device!)Governorship
C
3
public static Point getRealSize(Display display) {
        Point outPoint = new Point();
        Method mGetRawH;
        try {
            mGetRawH = Display.class.getMethod("getRawHeight");
            Method mGetRawW = Display.class.getMethod("getRawWidth");
            outPoint.x = (Integer) mGetRawW.invoke(display);
            outPoint.y = (Integer) mGetRawH.invoke(display);
            return outPoint;
        } catch (Throwable e) {
            return null;
        }
    }

    public static Point getSize(Display display) {
        if (Build.VERSION.SDK_INT >= 17) {
            Point outPoint = new Point();
            DisplayMetrics metrics = new DisplayMetrics();
            display.getRealMetrics(metrics);
            outPoint.x = metrics.widthPixels;
            outPoint.y = metrics.heightPixels;
            return outPoint;
        }
        if (Build.VERSION.SDK_INT >= 14) {
            Point outPoint = getRealSize(display);
            if (outPoint != null)
                return outPoint;
        }
        Point outPoint = new Point();
        if (Build.VERSION.SDK_INT >= 13) {
            display.getSize(outPoint);
        } else {
            outPoint.x = display.getWidth();
            outPoint.y = display.getHeight();
        }
        return outPoint;
    }
Constitution answered 12/2, 2014 at 19:0 Comment(0)
M
1

On some devices, e.g. tablets, the navigation bar can't be hidden at all (source, see section 'Controls for system UI visibility') because there's no hardware buttons as backup. If on your device you've managed to hide the bar though, you could make a full screen View and request its size with getWidth() and getHeight().

As far as I know, there isn't a reliable way to get the screen size on all ICS devices.

Magnitogorsk answered 12/6, 2012 at 6:13 Comment(4)
There HAS to be a way to do this. The youtube app for ICS is somehow blowing away the ICS navigation bar and getting the videoview to become the entire width of the screen.Henbit
This is device dependant, on tablets with ICS the bar is blacked out (the controls are hidden), but not gone.Magnitogorsk
Stuart, I can't confirm whether or not you can complete rid the screen of the OS navigation bar on a tablet running ICS, but even if what you say is true....that hiding the OS Navigation bar is device dependent....I don't know why Google intentionally hinder a developer from getting the exact dimensions of a device. What sense would that make? BTW....please don't take this as an attack at your answer. I appreciate the discussion!Henbit
Don't worry, I appreciate the discussion as well and I agree it would make sense for Android to offer a way to request the screen resolution. I've wanted to use this feature myself recently, but When I did a search on how to do it, I couldn't find how. I've added a link to my original answer for if you wish to verify that the navigation bar can't be hidden on some devices.Magnitogorsk

© 2022 - 2024 — McMap. All rights reserved.