Detecting Between a tablet and mobile

HI,

Is there a way to detect from a android Tablet and a Mobile phone from code ?

I use something like this.

Where 2 assumptions are made.

  1. If the highest dimension in pixels is less then 800, it is not a tablet.
  2. If it is smaller then 6.5 inches it is not a tablet.
    public static bool IsTablet(){
   
        float ssw;
        if(Screen.width>Screen.height){ssw=Screen.width;}else{ssw=Screen.height;}
       
        if(ssw<800) return false;
       
         if(Application.platform==RuntimePlatform.Android || Application.platform==RuntimePlatform.IPhonePlayer){
             float screenWidth = Screen.width / Screen.dpi;
             float screenHeight = Screen.height / Screen.dpi;
             float size = Mathf.Sqrt(Mathf.Pow(screenWidth, 2) + Mathf.Pow(screenHeight, 2));
             if(size >= 6.5f) return true;
         }
       
        return false;
    }
4 Likes

Thanks i will test it now on different tablets and mobiles.

Hi, how are you?

Wouldn’t it be enough with the second assumption?

Thank you

Well yes.
But at that time the 1st assumption made more sense.

1 Like

Ok, works great, thank you!

Through some beta testing on Android I’ve found there’s at least one phone out there that gets reported as a tablet with this code, the OnePlus GM1913. Its screen is 1080x2340 at 380 dpi. To restrict this a bit more, I added an aspect ratio test. I’m not aware of any tablet that has an aspect ratio greater than 2:1. Modify the snippet above like this:

var aspectRatio = Mathf.Max(Screen.width, Screen.height) / Mathf.Min(Screen.width, Screen.height)
if (size >= 6.5f && aspectRatio < 2f) return true;
5 Likes

Thanks for that @austinborden , iphone 8 plus not working for me hehe, so I added a iOS if for that.

I have a enum for the types so for other developers I put ENUMHERE so you can change it to the name you want

private float DeviceDiagonalSizeInInches()
{
    float screenWidth = Screen.width / Screen.dpi;
    float screenHeight = Screen.height / Screen.dpi;
    float diagonalInches =Mathf.Sqrt(Mathf.Pow(screenWidth, 2) + Mathf.Pow(screenHeight, 2));

    return diagonalInches;
}

public ENUMHERE GetDeviceType()
{
#if UNITY_IOS
    bool deviceIsIpad = UnityEngine.iOS.Device.generation.ToString().Contains("iPad");
            if (deviceIsIpad)
            {
                return ENUMHERE.Tablet;
            }

            bool deviceIsIphone = UnityEngine.iOS.Device.generation.ToString().Contains("iPhone");
            if (deviceIsIphone)
            {
                return ENUMHERE.Phone;
            }
#endif
          
            float aspectRatio = Mathf.Max(Screen.width, Screen.height) / Mathf.Min(Screen.width, Screen.height);
            bool isTablet = (DeviceDiagonalSizeInInches() > 6.5f && aspectRatio < 2f);

            if (isTablet)
            {
                return ENUMHERE.Tablet;
            }
            else
            {
                return ENUMHERE.Phone;
            }
        }
8 Likes

Nice work @wahnishjorge25 works perfectly.

So in the end I made it static and with the enums thanks to @wahnishjorge25 it became something like this:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public enum ENUM_Device_Type
{
    Tablet,
    Phone
}

public static class DeviceTypeChecker
{
    public static bool isTablet;
  
    private static float DeviceDiagonalSizeInInches()
    {
        float screenWidth = Screen.width / Screen.dpi;
        float screenHeight = Screen.height / Screen.dpi;
        float diagonalInches = Mathf.Sqrt(Mathf.Pow(screenWidth, 2) + Mathf.Pow(screenHeight, 2));

        return diagonalInches;
    }

    public static ENUM_Device_Type GetDeviceType()
    {
#if UNITY_IOS
    bool deviceIsIpad = UnityEngine.iOS.Device.generation.ToString().Contains("iPad");
            if (deviceIsIpad)
            {
                return ENUM_Device_Type.Tablet;
            }
            bool deviceIsIphone = UnityEngine.iOS.Device.generation.ToString().Contains("iPhone");
            if (deviceIsIphone)
            {
                return ENUM_Device_Type.Phone;
            }
#elif UNITY_ANDROID

        float aspectRatio = Mathf.Max(Screen.width, Screen.height) / Mathf.Min(Screen.width, Screen.height);
        bool isTablet = (DeviceDiagonalSizeInInches() > 6.5f && aspectRatio < 2f);

        if (isTablet)
        {
            return ENUM_Device_Type.Tablet;
        }
        else
        {
            return ENUM_Device_Type.Phone;
        }
#endif
    }
}

and this way you check it :

            if (DeviceTypeChecker.GetDeviceType() == ENUM_Device_Type.Phone)
            {
              
            }
12 Likes

Just a minor note that aspectRatio will be of type int. But the check aspectRatio < 2 is still valid.

I ran into a issue where there are 1920 x 1080 android tablets being detected as a phone.

Which models? What screen size do they have?

Can you try this script?

const int SCREENLAYOUT_SIZE_MASK = 0x0000000f;
const int SCREENLAYOUT_SIZE_LARGE = 0x00000003;
private static AndroidJavaObject s_context;

private static AndroidJavaObject GetUnityActivity()
        {
            if (s_context == null)
            {
                AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
                s_context = jc.GetStatic<AndroidJavaObject>("currentActivity");
            }
            return s_context;
        }


public static boolean IsTablet()
{
    AndroidJavaObject context = GetUnityActivity();
    int screenLayout = context.Call<AndroidJavaObject>("getResources").Call<int>("getConfiguration");
    return ((screenLayout & SCREENLAYOUT_SIZE_MASK) >= SCREENLAYOUT_SIZE_LARGE);
}

s_context is undefined when first used.

Thanks for the note. I just fixed it!

Kind of surprising unity doesn’t have some built in function for this, I am dealing with the same problem, it is easy to check ipad vs iphone but android tablet is difficult. Im confused why the aspect ration value threshold is 2, why wouldn’t it be lower?
Aren’t there going to be instances when this doesn’t work? Why not just check the screen diagnal, I am probably missing something.

Wouldnt it be better so use this info?

08-29 14:28:30.949 20228 20268 E Unity   : AndroidJavaException: java.lang.NoSuchFieldError: no "Landroid/app/Activity;" field "currentActivity" in class "Lcom/unity3d/player/UnityPlayer;" or its superclasses
08-29 14:28:30.949 20228 20268 E Unity   : java.lang.NoSuchFieldError: no "Landroid/app/Activity;" field "currentActivity" in class "Lcom/unity3d/player/UnityPlayer;" or its superclasses
08-29 14:28:30.949 20228 20268 E Unity   :      at com.unity3d.player.UnityPlayer.nativeRender(Native Method)
08-29 14:28:30.949 20228 20268 E Unity   :      at com.unity3d.player.UnityPlayer.access$300(Unknown Source:0)
08-29 14:28:30.949 20228 20268 E Unity   :      at com.unity3d.player.UnityPlayer$e$1.handleMessage(Unknown Source:95)
08-29 14:28:30.949 20228 20268 E Unity   :      at android.os.Handler.dispatchMessage(Handler.java:102)
08-29 14:28:30.949 20228 20268 E Unity   :      at android.os.Looper.loopOnce(Looper.java:210)
08-29 14:28:30.949 20228 20268 E Unity   :      at android.os.Looper.loop(Looper.java:299)
08-29 14:28:30.949 20228 20268 E Unity   :      at com.unity3d.player.UnityPlayer$e.run(Unknown Source:20)
08-29 14:28:30.949 20228 20268 E Unity   :   at UnityEngine.AndroidJNISafe.CheckException () [0x00000] in <00000000000000000000000000000000>:0
08-29 14:28:30.949 20228 20268 E Unity   :   at UnityEngine.AndroidJNISafe.GetFieldID (System.IntPtr clazz, System.String name, System.String sig) [0x00000] in <00000000000000000000000000000000>:0

Hello @Voxel-Busters when i run code it gives this error on device do you know why ?
Unity 2021.3.7 , my device is on android 12