134
votes

How can I find out my screen size programmatically, in the units used by touch events and View measurement/layout? In other words, I want the coordinates of the bottom-right corner of the screen, in the coordinate system used by touch events' getRawX()/getRawY() and View.getLocationOnScreen().

I'm hesitant to call the desired event/view units "pixels" since evidently there are several notions of "pixels" on my phone in various modes, and they're not adding up to a consistent story.

I see this has been asked and answered a lot on stackoverflow and elsewhere, but none of the answers actually work on my phone (droid 4, android 4.1.2) in all modes:

(wow!)

This is for library code that needs to work regardless of whether the app is in "screen compatibility mode" (i.e. targetSdkVersion<=10 in the manifest) or not, and I also don't want to make any assumptions about the position, size, or existence of the status bar or any other similar screen decorations.


Here are the facts:

  1. my phone (a droid 4 running android 4.1.2) has 540x960 physical pixels, i.e. little colored glowing dots.

  2. the size of the screen in the desired units, from looking at touch events and View measurements, is 360x640 when the app is in screen compat mode, 540x960 when the app is not in screen compat mode. These are the numbers I need to find programmatically, without mucking with touch events or Views to find them, but I'm having extreme difficulty finding any API that will return these numbers.

  3. Display and DisplayMetrics objects obtained in various ways all claim the screen size is 540x960 "pixels" (whether in screen compat mode or not). To be specific, the following all say 540x960 all the time: DisplayMetrics.{width,height}Pixels, Display.getSize(), Display.getRealSize(), Display.get{Width,Height}(),

  4. Configuration objects obtained in various ways all say screen{Width,Height}Dp = 360x614 (whether in screen compat mode or not). I don't believe that represents the whole screen, since the aspect ratio is wrong. (I think it's the whole screen minus the status bar; I need the whole screen.) I think it's safe to say that the whole screen is 360x640 dp, though I don't know any API that returns that 640.

  5. DisplayMetrics obtained in various ways say the "density" is 1.0f when in screen compat mode, 1.5f when not in screen compat mode.

  6. The activity's getWindow().getAttributes().{width,height} isn't helpful since it typically contains MATCH_PARENT rather than actual sizes. But I can apparently get the desired answer from an activity's getWindow().getDecorView().getMeasured{Width,Height}() (which is actually surprising since the activity's window's decorView doesn't look like it's taking up the whole screen; it looks like it's taking up the screen minus the status bar). But I don't want to rely on this because if the window ever gets resized (soft keyboard appearing? someone calling window.setAttributes()? or maybe I'm not in an Activity at all), this is clearly going to be all wrong.

I understand the following formula is supposed to hold: pixels = dp * density That seems to agree with all the reported numbers ((3),(4),(5) above) when not in screen compatibility mode: 540x960 = 360x640 * 1.5 But in screen compatibility mode it doesn't add up: 540x960 != 360x640 * 1 So, something is awry.

The simplest explanation, I think, is that the methods listed in (3) above are simply giving the wrong answer for "pixels" when in screen compat mode-- that is, they were intended to return 360x640 "pixels" but they are wrongly returning 540x960 instead. But there may be other ways of looking at it.

In any case, getting the desired numbers regardless of mode, from the above puzzle pieces, is certainly a tricky puzzle. I have found a way that seems to work on my phone in both modes, but it is extremely circuitous, and it relies on two assumptions that still seem rather shaky (as described in the code comments below).

Here is my recipe:

/** get screen size in "pixels", i.e. touchevent/view units.
* on my droid 4, this is 360x640 or 540x960
* depending on whether the app is in screen compatibility mode
* (i.e. targetSdkVersion<=10 in the manifest) or not. */
public void getScreenSizePixels(int widthHeightInPixels[/*2*/])
{
    Resources resources = getResources();
    Configuration config = resources.getConfiguration();
    DisplayMetrics dm = resources.getDisplayMetrics();
    // Note, screenHeightDp isn't reliable
    // (it seems to be too small by the height of the status bar),
    // but we assume screenWidthDp is reliable.
    // Note also, dm.widthPixels,dm.heightPixels aren't reliably pixels
    // (they get confused when in screen compatibility mode, it seems),
    // but we assume their ratio is correct.
    double screenWidthInPixels = (double)config.screenWidthDp * dm.density;
    double screenHeightInPixels = screenWidthInPixels * dm.heightPixels / dm.widthPixels;
    widthHeightInPixels[0] = (int)(screenWidthInPixels + .5);
    widthHeightInPixels[1] = (int)(screenHeightInPixels + .5);
}

Is there any better/cleaner way to find the size of the screen??

10
+1 Great question, and shows a lot of research effort.Alex Gittemeier
@Don In docs, it is explained that compatibility mode will stop doing "zoom to fit" operation on older setups. However it is not clearly explained "how it works", from your observations, I think they simply turn off density scaling, i.e: 1px becomes 1dp. It may be that this change is in only the rendering part, and DisplayMetrics is never updated of such changes. There are issues like this already filed.S.D.
@user117 - interesting. Well part of DisplayMetrics got updated at least-- density changed to 1.0. But widthPixels/heightPixels didn't get changed to match, it seems. Regarding the issue cited, it looks like the behavior reverted to the 3.1 behavior (i.e. I'm seeing heightPixels include the status bar... but in the wrong units it seems)Don Hatch
@DonHatch Thanks, kindly -- I was actually trying to give a praise to a thoughtful question of sorts strangely not so welcome on StackExchange -- note how the question being more than "real" gets nothing in the answers, speaking of the (low) quality of the audience's knowledge on the topic. Now, I may be traumatized by my own questions being closed one after another for being "not real", and the sense of humor may be failing me, but it starts looking like questions for which there're "nicey" recipish answers are really what this all becomes about here... And Of course, I upvoted yours :)mlvljr
btw! here's something along the lines of my suspicions: michael.richter.name/blogs/… (esp. see his (1) point, the one on quickly crafted answers -- actually just the case with this Q!). Happy NY, anyways (mine comes in 11 minutes)! :)mlvljr

10 Answers

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

Now you can measure your screen size in pixel which is a better measurement unit than centimeter because all the buttons ,textviews etc.. are measured in this unit. That what I use normally

9
votes

By using the DisplayMetrics you can get height and width of the screen of any device. Note that width and height are sensitive to rotation. here is the code.

DisplayMetrics metrics; 
int width = 0, height = 0;

In your onCreate Method

 metrics = new DisplayMetrics();        
 getWindowManager().getDefaultDisplay().getMetrics(metrics);

 height = Math.min(metrics.widthPixels, metrics.heightPixels); //height
 width = Math.max(metrics.widthPixels, metrics.heightPixels); //width

Try this.

8
votes

In your #6, you note that the DecorView seems to provide what you want, but you don't think it is realiable. I believe that is as close as you can come. According to the documentation for Window.getDecorView:

Retrieve the top-level window decor view (containing the standard window frame/decorations and the client's content inside of that), which can be added as a window to the window manager.

The status bar is part of the window decoration mentioned there. Software keyboards and other overlays will receive their own window, so they shouldn't interfere with the relevant values. It is correct that isn't precisely the display metrics, but if your application is full screen it should always be the full screen size filtered through the compatibility translator. Other applications won't have access to your application's Window, so there is no need to worry about some other app changing the attributes while you aren't looking.

Hope that helps.

5
votes

I should put this as a comment but I don't have the rep for that.
This may not be a totally correct answer but I got my dimensions when I switched the height and width in the DisplayMetrics method.

    DisplayMetrics metrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(metrics);   
    width = metrics.heightPixels;
    height = metrics.widthPixels;

as I said this may not be correct but I don't know why but it worked for me.

3
votes

If you are using api level 17 or higher check out getRealMetrics and getRealSize in Display

For api level 14,15 & 16 look here

3
votes

I've used Pythagoras theorem to find the diagonal size of Android phone/tablet screen, same principal can be applied to iPhone or Blackberry screen.

DisplayMetrics met = new DisplayMetrics();                
this.getWindowManager().getDefaultDisplay().getMetrics(met);// get display metrics object
String strSize = 
new DecimalFormat("##.##").format(Math.sqrt(((met.widthPixels / met.xdpi) *
(met.widthPixels / met.xdpi)) +
((met.heightPixels / met.ydpi) * (met.heightPixels / met.ydpi))));
// using Dots per inches with width and height

Pythagoras must have been a genios, he knew smart phone programming so many years ago :p

1
votes

I use the below method to get the width of the device :

public static int getDeviceWidth(Context context){
    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();
    int width=display.getWidth();
    return width;
}
0
votes

I think this function will help you to simply get the width and height of your android screen size. The function returns the width and height as an array of integers as shown below

private int[] getScreenSIze(){
        DisplayMetrics displaymetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
        int h = displaymetrics.heightPixels;
        int w = displaymetrics.widthPixels;

        int[] size={w,h};
        return size;

    }

and on your create method output your width and height as shown below

 int[] screenSize= getScreenSIze();
        int width=screenSize[0];
        int height=screenSize[1];
        screenSizes.setText("Phone Screen sizes \n\n  width = "+width+" \n Height = "+height);

Download source code and test it on your android studio

0
votes

This works for me:

int width = Resources.getSystem().getDisplayMetrics().widthPixels;

int height = Resources.getSystem().getDisplayMetrics().heightPixels;

I used this to update width of my items in a horizontal recycler view.(according to my requirement) Hope it helps someone!

-1
votes

For this solution in Kotlin, try this:

private fun yourFunction(){
   val metrics = DisplayMetrics()
   windowManager.defaultDisplay.getMetrics(metrics)
   val width = metrics.widthPixels
   val height = metrics.heightPixels
}