Determine if the device is a smartphone or tablet? [duplicate]
Asked Answered
P

9

319

I would like to get info about a device to see if it's a smartphone or tablet. How can I do it?

I would like to show different web pages from resources based on the type of device:

String s="Debug-infos:";
s += "\n OS Version: " + System.getProperty("os.version") + "(" +    android.os.Build.VERSION.INCREMENTAL + ")";
s += "\n OS API Level: " + android.os.Build.VERSION.SDK;
s += "\n Device: " + android.os.Build.DEVICE;
s += "\n Model (and Product): " + android.os.Build.MODEL + " ("+ android.os.Build.PRODUCT + ")";

However, it seems useless for my case.


This solution works for me now:

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

if (SharedCode.width > 1023 || SharedCode.height > 1023){
   //code for big screen (like tablet)
}else{
   //code for small screen (like smartphone)
}
Paschal answered 14/2, 2012 at 14:58 Comment(7)
using displaymetris get your screen size and do it.Cruck
Find the screensize is the only way. You can't really think of it in terms of "smartphone" and "tablet". In the end, screensize is what you want anyway.Conviction
https://mcmap.net/q/57346/-distinguish-between-tablet-and-smart-phone-on-icsCioffi
are your differences only layout-based? or do you plan to give completely different contents? Multiple layouts and Activities vs. Fragments are your way.Boon
Using physical pixels is a horrible idea, as devices are getting more and more pixel-dense. At least you should use dp as unit.Buchanan
You generally don't need to know if the device is a phone or tablet. Just provide different resource files for different screen sizes and let the system determine it for you. See this answer for more.Ruy
The official Android Developers blog posted a blog entry with the title 'Detecting device type – How to know if a device is foldable or a tablet'. This should answer this question as they clarify how to check if a device is a phone, a tablet or a foldable. SPOILER: As of June 2023 they check if at least one display has a sw >= 600 dp. Then it's a tablet or a foldable, otherwise it's classisfied as a phone. android-developers.googleblog.com/2023/06/…Guideline
M
854

This subject is discussed in the Android Training:

Use the Smallest-width Qualifier

If you read the entire topic, they explain how to set a boolean value in a specific value file (as res/values-sw600dp/attrs.xml):

<resources>
    <bool name="isTablet">true</bool>
</resources>

Because the sw600dp qualifier is only valid for platforms above android 3.2. If you want to make sure this technique works on all platforms (before 3.2), create the same file in res/values-xlarge folder:

<resources>
    <bool name="isTablet">true</bool>
</resources>

Then, in the "standard" value file (as res/values/attrs.xml), you set the boolean to false:

<resources>
    <bool name="isTablet">false</bool>
</resources>

Then in you activity, you can get this value and check if you are running in a tablet size device:

boolean tabletSize = getResources().getBoolean(R.bool.isTablet);
if (tabletSize) {
    // do something
} else {
    // do something else
}
Monophyletic answered 16/2, 2012 at 9:5 Comment(14)
This answer is good but possibly a bit dated since values-xlarge is now being deprecated.Using /res/values and /res/values-sw600 as the folders to store these values in may be a better solution. sw600 means "smallest width 600". If the size of the smallest dimension of the screen is greater than or equal to 600dp, the value in that folder will be chosen. A good reference for values and layout buckets (folders) is here: android-developers.blogspot.com/2012/07/….Morning
You are right, now you have to use the sw600 qualifier instead of xlarge. But to keep compatibility with versions below android 3.2, you need to keep the boolean value in the xlarge resources folder. I added the precision in the answer. Thanks.Monophyletic
Better values-large than values-xlarge. The old "large" is move equivalent to the new "sw600dp", to my understanding.Buchanan
this may not work as effective any more as many smartphones now have minimum width>600, for example Samsung galaxy s3 which has min width of 720 pixels, thanks to the ever increasing pixel density.Political
@Political note the "dp" in the "sw600dp", this means that this does not compare to real pixels but to density independent pixels. So although S3 has 720px, it still has way less then 600dp.Clydeclydebank
As @Clydeclydebank says, nothing to do with pixels. We are talking with dp. You can see this like available space to display things. A tablet has more available space than a phone. Independently of the resolution. A sw600dp device has at least 600dp (7" screen). A sw720dp has at least 720dp (10" screens). A phone, like a Nexus S has a smallest width of 320dp and a Nexus 4, a sw384 and a GS5 will have bearly the same (sw360). So this technique works also with modern full HD phones.Monophyletic
How do you differentiate for launch? There's only 1 AndroidManifest.xml file, isn't there?Dumortierite
@GuyKogus this works if you want to use the same Activity for phones and tablets. If you want to start different Activity for phones and tablets, have a look to the Google IO source code (github.com/google/iosched) they activate/deactivate the components at run-time with a "ConfigActivity". Like this they can use easily one Activity or an other with the sames Intent.Monophyletic
Note: it's very important to include the isTablet value in the standard value file. If you don't include this you will get a ResourceNotFoundException when boolean tabletSize = getResources().getBoolean(R.bool.isTablet); is executed.Awestricken
When you try upload apk in google play, you'll have more errors good luck :DMouton
the dp-based solutions (layout-sw600dp etc) are getting useless as long as new smartphones have more dpis than most tablets in the market. For example, a Samsung Galaxy S4 or S5 will show the tablet layout, which is not the expected result.Cafard
dpi and pixels are not the same. As @Clydeclydebank explains above, even if you have a 1920x1080 pixel phone as a S4 or S5, it their smallest width will not be 600dp. It will be 360dp (smallest width 1080px, it's in the xxhdpi x3 category. so 1080/3 = 360dp). So the sw600dp will work independently of the actual pixel resolution.Monophyletic
This method is not working because if you start the app when you are in "landscape" mode in phones, d600p is passed so device think it is tablet.Barbur
@MertSerimer it works because I use sw600dp. It means the smallest width of both X and Y. So the orientation will have no impact. In the official documentation : "indicated by the shortest dimension of the available screen area" and "You can use this qualifier to ensure that, regardless of the screen's current orientation" developer.android.com/guide/practices/…Monophyletic
F
99

I consider a tablet to have at least a 6.5 inch screen. This is how to compute it, based on Nolf's answer above.

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

float yInches= metrics.heightPixels/metrics.ydpi;
float xInches= metrics.widthPixels/metrics.xdpi;
double diagonalInches = Math.sqrt(xInches*xInches + yInches*yInches);
if (diagonalInches>=6.5){
    // 6.5inch device or bigger
}else{
    // smaller device
}
Fuegian answered 11/7, 2014 at 15:15 Comment(2)
Not working for me. I gives 4.89 for 10 inch Nexus 10 and 5.88 for 5 inch Galaxy S2.Precipitation
[Years later] IMHO, diagonal dimension is not as useful as smallest dimension, because there are now some very tall phone screens. Should not categorize these as tablets, because the ones I'm referring to are still quite narrow.Berwickupontweed
R
41

My assumption is that when you define 'Mobile/Phone' you wish to know whether you can make a phone call on the device which cannot be done on something that would be defined as a 'Tablet'. The way to verify this is below. If you wish to know something based on sensors, screen size, etc then this is really a different question.

Also, while using screen resolution, or the resource managements large vs xlarge, may have been a valid approach in the past new 'Mobile' devices are now coming with such large screens and high resolutions that they are blurring this line while if you really wish to know phone call vs no phone call capability the below is 'best'.

TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
        if(manager.getPhoneType() == TelephonyManager.PHONE_TYPE_NONE){
            return "Tablet";
        }else{
            return "Mobile";
        }
Revis answered 14/6, 2012 at 21:35 Comment(6)
Problem with this approach is that some telephony devices may have large screenHierarchy
Given the influx of phone-tabs, I used a combination of the two solutions. True = tablet, false = not TelephonyManager manager = (TelephonyManager) activity.getSystemService(Context.TELEPHONY_SERVICE); /*if no telephony, it's a tablet. Otherwise, chack boolean file*/ boolean tablet = manager.getPhoneType() == TelephonyManager.PHONE_TYPE_NONE || activity.getResources().getBoolean(R.bool.isTablet); Hydantoin
I just tried that with a Samsung Tab 7 and it returns PHONE_TYPE_GSM. I guess because of the SIM-card module init. So absolutely not reliable.Gabriel
Did you test it on a phone (handset device) without a SIM card in it?Bimolecular
Not future proof. Breaks as soon as someone makes a tablet that can make calls.Quevedo
In nexus 4, Android 5. it returns false during the bootup.Teasley
D
35

I like Ol_v_er's solution and it's simplicity however, I've found that it's not always that simple, what with new devices and displays constantly coming out, and I want to be a little more "granular" in trying to figure out the actual screen size. One other solution that I found here by John uses a String resource, instead of a boolean, to specify the tablet size. So, instead of just putting true in a /res/values-sw600dp/screen.xml file (assuming this is where your layouts are for small tablets) you would put:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string name="screen_type">7-inch-tablet</string>
</resources>

Reference it as follows and then do what you need based on the result:

String screenType = getResources().getString(R.string.screen_type);
if (screenType.equals("7-inch-tablet")) {
    // do something
} else {
    // do something else
}

Sean O'Toole's answer for Detect 7 inch and 10 inch tablet programmatically was also what I was looking for. You might want to check that out if the answers here don't allow you to be as specific as you'd like. He does a great job of explaining how to calculate different metrics to figure out what you're actually dealing with.

UPDATE

In looking at the Google I/O 2013 app source code, I ran across the following that they use to identify if the device is a tablet or not, so I figured I'd add it. The above gives you a little more "control" over it, but if you just want to know if it's a tablet, the following is pretty simple:

public static boolean isTablet(Context context) {
    return (context.getResources().getConfiguration().screenLayout
            & Configuration.SCREENLAYOUT_SIZE_MASK)
            >= Configuration.SCREENLAYOUT_SIZE_LARGE;
}
Driftwood answered 22/8, 2013 at 18:17 Comment(6)
Your isTablet solution is e.g. not working on a Emulator with API 18 and Nexus 7 1200 x 1920 xhdpi !Kickoff
@Kickoff Not sure what you mean by not working, but I just fired up a test project using Eclipse and Android Studio and it worked correctly for both on a Nexus 7 1200 x 1920: xhdpi AVD. Are you getting errors in the IDE? Does the app compile? Does isTablet return false? What values are returned for the SCREENLAYOUT sizes? How are you calling isTablet? You really don't have any info that allows someone to try to help you. If you're really stuck, you might try posting an actual question with code examples so it will be easier to help.Driftwood
Yes "isTablet(Context context)" returns false. Did you use API 18?Kickoff
Yes, I used API 18, sorry I left that out. I had compileSDKVersion and targetSDKVersion set to 21 in Android studio and both set to 18 in Eclipse. I'd make sure those are both set to at least 18. minSDKVersion was set to 18 for both as well. I would suggest that you post a question with example code if you need additional help.Driftwood
Doesn't work in Nexus 5Bastian
This isTablet method does not work on Redmi Note 10Walley
P
15

I use this method in all my apps, and it works successfully:

public static boolean isTablet(Context ctx){    
    return (ctx.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE; 
}
Prophecy answered 24/9, 2014 at 23:11 Comment(6)
This solution is e.g. not working on a Emulator with API 18 and Nexus 7 1200 x 1920 xhdpi !Kickoff
Hey, one of my testing devices is a Nexus 7 and works perfect, Im wondering why isn[t working on your Emulator. >`Prophecy
I dont know what is wrong in your code. But I have tested on Emulator and the result of "isTablet(Context ctx) was false. Try by self on Emulator.Kickoff
It's decrepated. That's why.Allseed
Are you sure that this is deprecated? do you have info about it? import android.content.res.Configuration; I have targetSDK = 21 and it Works.Prophecy
it's not deprecated but not working right on smartphones are bigger than 6"Swarm
I
7

Since tablet are in general bigger than smartphones and since a low res tablet may have the same number of pixels as a high res smartphone, one way to solve this is to calculate the physical SIZE (not resolution) of a device:

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

    float yInches= metrics.heightPixels/metrics.ydpi;
    float xInches= metrics.widthPixels/metrics.xdpi;

   if (yInches> smallestTabletSize|| xInches > smallestTabletSize)
    {
                  //We are on a 
    }
Itu answered 3/5, 2013 at 6:25 Comment(1)
The if test used here results in largest dimension being used to determine whether is tablet. This is not a good idea; phones can be quite tall yet too narrow to be treated as a tablet. Better to use smallest dimension: if (Math.Min(xInches, yInches) > largestPhoneWidth) // is a "tablet".Berwickupontweed
F
5

The best option I found and the less intrusive, is to set a tag param in your xml, like

PHONE XML LAYOUT

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:tag="phone"/>

TABLET XML LAYOUT

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:tag="tablet">

    ...

</RelativeLayout>

and then call this in your activity class:

View viewPager = findViewById(R.id.pager);
Log.d(getClass().getSimpleName(), String.valueOf(viewPager.getTag()));

Hope it works for u.

Flautist answered 6/5, 2014 at 0:33 Comment(0)
C
2

The solution that I use is to define two layouts. One with the layout folder set to for example layout-sw600dp I use this to provide a menu button for my tablet users and to hide this for the phone users. That way I do not (yet) have to implement the ActionBar for my existing apps ...

See this post for more details.

Colossians answered 8/2, 2013 at 7:41 Comment(0)
A
1

Re: the tangent above on how to tell a phone from a non-phone: as far as I know, only a phone has a 15-digit IMEI (International Mobile Station Equipment Identity), so the following code will definitively distinguish a phone from a non-phone:

    TelephonyManager manager = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
    String deviceInfo = "";
    deviceInfo += manager.getDeviceId(); // the IMEI
    Log.d(TAG, "IMEI or unique ID is " + deviceInfo);

    if (manager.getDeviceId() == null) {
        Log.d(TAG, "This device is NOT a phone");
    } else {
        Log.d(TAG, "This device is a phone.");
    }

I have found that on a Nook emulator getPhoneType() returns a phoneType of "GSM" for some reason, so it appears checking for phone type is unreliable. Likewise, getNetworkType() will return 0 for a phone in airplane mode. In fact, airplane mode will cause getLine1Number() and the getSim* methods to return null too. But even in airplane mode, the IMEI of a phone persists.

Agone answered 22/3, 2014 at 23:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.