20

I want to determine whether the current device has a small, medium, large or xlarge screen in code. I can't find anything in the SDK docs that would help me get to that information. All the methods / classes I have looked at provide only absolute values (i.e. screen size in pixels, screen density, etc.).

Is there a way to tell what kind of screen I'm running on in code?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Felix
  • 88,392
  • 43
  • 149
  • 167
  • 2
    i'm not sure what you are doing but it may be worth saying that you should try to avoid such behavior. If you can, just create the various resources and let android figure out which resource it should load. – Ian Sep 02 '11 at 14:16
  • @Ian I know this is something to be avoided, but in this case I have no alternative. I need to set different window flags for a dialog depending on the screen size. – Felix Sep 02 '11 at 14:34
  • ok. good. I just wanted to throw that out there. – Ian Sep 02 '11 at 14:34
  • 1
    possible duplicate of [How to determine device screen size category (small, normal, large, xlarge) using code?](http://stackoverflow.com/questions/5015094/how-to-determine-device-screen-size-category-small-normal-large-xlarge-usin) – Pang Jan 02 '15 at 05:32

9 Answers9

58

I ended up using bool resources placed in the different bucket folders. I only needed to differentiate between normal (small / medium) and large (large / xlarge) screens, so I did this:

values/bools.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="screen_large">false</bool>
</resources>

values-large/bools.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="screen_large">true</bool>
</resources>

Then, I just call getBoolean(R.bool.screen_large) to tell whether the screen is large or not. This way it's 100% up to the platform decide what screen the device has.

Felix
  • 88,392
  • 43
  • 149
  • 167
7

There is a difference between Density and screen type. enter image description here

Since you can get the pixels and the density you can always have a static Helper class that determines that.

You can transofm pixels to dp with that

public static float dpFromPixels(int pixels) {
        float dp = (float) ((pixels) / Density.scale);
        return dp;
    }

I think that you might want to add or subtract .5f from the pixels since getting pixels from dp comes from that code.

public static int pixelsFromDp(float dps) {
        int pixels = (int) (dps * Density.scale + 0.5f);
        return pixels;
    }

From the documentation

xlarge screens are at least 960dp x 720dp

large screens are at least 640dp x 480dp

normal screens are at least 470dp x 320dp

small screens are at least 426dp x 320dp

weakwire
  • 9,284
  • 8
  • 53
  • 78
  • it's worth noting that the smallest dimension is what is regarded when putting the screen in a bucket size. – Ian Sep 02 '11 at 14:15
  • 1
    +1, good solution, I forgot they actually posted the dimensions. However, I went with a less hard-coded solution, check out my answer :) – Felix Sep 02 '11 at 14:30
  • 1
    You cannot use the above classification as it does not clearly specify the screen size boundaries. – Ron Sep 02 '11 at 14:34
  • Felix mentioned that he can access "screen size in pixels, screen density, etc". Giving that he can determine the screen type. – weakwire Sep 02 '11 at 14:37
  • So where does `Density.scale` come from? – Qwertie Jun 27 '12 at 22:38
6
public static boolean isLargeScreen(Context context) {
  int screenSize = context.getResources().getConfiguration().screenLayout
    & Configuration.SCREENLAYOUT_SIZE_MASK;
  return screenSize >= Configuration.SCREENLAYOUT_SIZE_LARGE;
}
Mikhail Kadan
  • 556
  • 1
  • 5
  • 15
5

I agree that Felix answer is pretty elegant. But I think the way I found in this post might be even easier How to determine device screen size category (small, normal, large, xlarge) using code?

Community
  • 1
  • 1
Bilthon
  • 2,461
  • 8
  • 36
  • 44
1

I use this method in my code to differeniate between "Large Screens" (What I consider tablets) and "Small Screens" (What I consider phones).

public static boolean isLargeScreen(Configuration toCheckConfig) {  
    int screenSizeBucket = toCheckConfig.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
    if (screenSizeBucket >= Configuration.SCREENLAYOUT_SIZE_LARGE) {
        return true;
    }
    else return false;
}       

The Configuration object also contains SCREENLAYOUT_SIZE_SMALL, SCREENLAYOUT_SIZE_XLARGE etc. (if you specifically need to test for size buckets).

This also works well with these two util functions:

public static int getPixelsFromDp(Context context, int dpValue) {
    return (int) (context.getResources().getDisplayMetrics().density * dpValue);
}

public static int getDpfromPixels(Context context, int pixels) {
    return (int) (pixels / context.getResources().getDisplayMetrics().density);
}

Where context.getResources().getDisplayMetrics().density is equal to 1.0, 1.5, 2.0 (mdpi, hdpi, xhdpi respectively).

Graeme
  • 25,714
  • 24
  • 124
  • 186
1

Just as a complement to the Felix's answer, you can use the following code to get the ScreenSize without creating any folder for values-XXX :

int screenSize = getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
        Log.d(TAG, "screenSize = "+screenSize);

        switch(screenSize) {
            case Configuration.SCREENLAYOUT_SIZE_LARGE:
                Log.d(TAG, "Large Screen");
                break;
            case Configuration.SCREENLAYOUT_SIZE_NORMAL:
                Log.d(TAG, "Normal Screen");
                break;
            case Configuration.SCREENLAYOUT_SIZE_SMALL:
                Log.d(TAG, "Small Screen");
                break;
            case Configuration.SCREENLAYOUT_SIZE_XLARGE : 
                Log.d(TAG, "XLarge Screen");
                break;
            default:
                Log.d(TAG,  "Screen size is neither large, normal or small or xlarge");
        }
Houcine
  • 24,001
  • 13
  • 56
  • 83
1

Use the DisplayMetrics class...

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

// DENSITY_LOW, DENSITY_MEDIUM, DENSITY_HIGH, or DENSITY_XHIGH
int density = dm.densityDpi;

Small = DisplayMetrics.DENSITY_LOW

Medium = DisplayMetrics.DENSITY_MEDIUM

Large = DisplayMetrics.DENSITY_HIGH

XLarge = DisplayMetrics.DENSITY_XHIGH

DRiFTy
  • 11,269
  • 11
  • 61
  • 77
  • Gotta love it when people down vote and don't explain themselves... I use this for displaying specific layouts all the time, and works great. – DRiFTy Sep 02 '11 at 14:25
  • 1
    I downvoted because it does not answer my question. This gives me the screen **density**, not size. You might want to read up on the difference between the two. – Felix Sep 02 '11 at 14:31
  • 1
    `DisplayMetrics` does give the size in pixels. Probably you got to reverse your vote. – Ron Sep 02 '11 at 14:37
  • @user7777777777, I think he either asked a question that was different than what he was going for or didn't bother trying any of our answers to solve his problem. – DRiFTy Sep 02 '11 at 14:40
  • @Kieran: Your mapping of density to screen sizes is wrong as its possible that a xlarge screen could have a high density. – Ron Sep 02 '11 at 14:41
  • @Kieran: Yes, could be the case. We should just move on. – Ron Sep 02 '11 at 14:43
  • I do agree with you that a xlarge screen could have high density, and that is a good point to bring up. I think what I use this for is just different than what he (or you) would use it for. Whenever I need to do something that is extremely screen dependent I just get the width and height in pixels. – DRiFTy Sep 02 '11 at 14:45
0

Other solutions here classify device screens into 4 buckets (small, normal, large, x-large).

For those looking to classify the device into the 6 drawable buckets instead, the following approach can be used.

The advantage of this approach is that it is not required to perform screen density calculations, which may differ from the way the OS does it. This solution instead relies purely on the OS to decide the density bucket. The disadvantage of this solution is that it requires creating redundant drawable resources, which is not elegant.

The are 6 screen density buckets:

  1. drawable-ldpi
  2. drawable-mdpi
  3. drawable-hdpi
  4. drawable-xhdpi
  5. drawable-xxhdpi
  6. drawable-xxxhdpi

The solution requires creating 6 drawables, and placing a copy into the density folders, so that each density folder is missing the correspondingly named resource. For example, pixel_not_ldpi.png, should be placed into all folders, except the drawable-ldpi folder.

resources

  1. pixel_not_ldpi.png // copy to the 5 folders, except drawable-ldpi
  2. pixel_not_mdpi.png // copy to the 5 folders, except drawable-mdpi
  3. pixel_not_hdpi.png // etc..
  4. pixel_not_xdpi.png // etc..
  5. pixel_not_xxdpi.png // etc..
  6. pixel_not_xxxdpi.png // etc..

Notes:

  1. Do not place any of these resources inside the general 'drawable' folder.
  2. It's best to create a 1x1 pixel png image, which is only 68kb, and is smaller than a 1x1 jpeg image. Also make sure to strip meta data from these images to save space.

Once the images are placed, write a helper method which attempts to load each of these resources using 6 try/catch blocks. Catch the Resources.NotFoundException. Whichever resource throws the exception, that is the screen density of the device. This works with Android App Bundles.

It's not an ideal solution, but it answers the question comprehensively, and unlike other solutions, which involve arithmetic, it relies purely on the OS to determine density.

Edge Case: incorrect side-loading of App Bundle

Some users side-load their apps, by downloading them from outside the play store, or otherwise, and can make the mistake of downloading only a part of the resources present in the whole app bundle. Such users are able to install and launch the app, but some resources might be missing, which would cause a resource not found exception to fire inside one of our try/catch blocks above, making it impossible to determine whether the resource was missing intentionally, or unintentionally (due to an incomplete app bundle).

To differentiate the two cases, simply use the same approach. Place another resource, pixel.png into all 6 density drawable folders, and try to load it using a try/catch. If it throws, then the app was downloaded incorrectly.

Enjoy

Alexei Fando
  • 666
  • 5
  • 13
-1

The DisplayMetrics has got all that you need. To get it

 DisplayMetrics metrics = new DisplayMetrics();
 getWindowManager().getDefaultDisplay().getMetrics(metrics);
Ron
  • 24,175
  • 8
  • 56
  • 97
  • 1
    DisplayMetrics only sais what density is the screen. It doesn't actually tell you what kind of screen is that. Correct me if i'm wrong – weakwire Sep 02 '11 at 14:09
  • You wrong. Its also got the `heightPixels` and `widthPixels` which give the absolute height and width of the display in pixels. – Ron Sep 02 '11 at 14:30
  • Well yeah it provides other info as well.My point was you didn't give any workaround for his problem. Sure he will use DisplayMetrics to get the pixel num the density but these values alone can't decide the screen type. Also od what is worth , if you u downVoted me cause you think i downvoted you , that's not the case. – weakwire Sep 02 '11 at 14:48
  • @weakwire: I didn't. And I know its the owner who downvoted or unvoted. – Ron Sep 02 '11 at 14:55