Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting 4K UHD screens on Android

I am trying to detect when a device is capable of outputting at 4K UHD (3840x2160) resolution. A number of devices such as the nVidia Shield TV and the Sony Xperia Z5 Premium will report that they are running at 1080p even though they are capable of UHD, because they default to 1080p output for non-video layouts. I need some way to detect if they are 4K capable to distinguish between them and non-4K devices like the Nexus Player.

Here is the code I'm using to determine the current resolution:

WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);

On the Shield TV, this returns 1920x1080 all the time, even when ExoPlayer reports that it's outputting video at 3840x2160.

like image 943
Cobar Avatar asked Sep 14 '15 04:09

Cobar


2 Answers

Should be using DisplayCompat.getSupportedModes as the TV may be running in FHD even if it support UHD. It is possible that UHD is only enabled during video playback.

fun isUhdDevice(context: Context) : Boolean {

    val displayManager = DisplayManagerCompat.getInstance(context)
    val defaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY)

    defaultDisplay?.let { display ->
        return DisplayCompat.getSupportedModes(context, display).any { it.physicalHeight >= 2160 && it.physicalWidth >= 3840 }
    }
    return false
}
like image 74
Fung LAM Avatar answered Sep 19 '22 11:09

Fung LAM


UPDATE: This has been fixed as of ExoPlayer 1.5.1 (see https://github.com/google/ExoPlayer/commit/79055066813123c939c29e5a5e223a5ff043b91e)


I followed up with ExoPlayer's developers and found the answer:

The only way to reliably detect 4K devices is using Device.Mode which is only available in api level 23+. See the Android M note on that here:

https://developer.android.com/preview/api-overview.html#4K-display

And the documentation for the class here:

https://developer.android.com/reference/android/view/Display.Mode.html#getPhysicalWidth()

As for ExoPlayer it does not implement this code, as of the current version (1.4.2) but that will probably change. See:

https://github.com/google/ExoPlayer/issues/800

And finally to answer the question, the right way to detect 4K right now is something like this:

/**
 * Used to check if the connected device support UHD (3840x2160)
 *
 * Note that this call will fail to identify UHD devices on api level bellow 23 (M)
 *
 * @return 1 if device is UHD, 0 otherwise
 */
public int isUHD(){
    Display display = getActivity().getWindowManager().getDefaultDisplay();
    Point displaySize = getDisplaySize(display);
    return (displaySize.x >= 3840 && displaySize.y >= 2160) ? 1 : 0;
}

/**
 * Convenience function that forks to the different ways to obatin the Display size across Android versions
 *
 * @param display Display instance to obtain information from
 *
 * @return Point a Point describing the Display size
 */
private static Point getDisplaySize(Display display) {
    Point displaySize = new Point();
    if(Util.SDK_INT >= 23){
        getDisplaySizeV23(display, displaySize);
    }else if(Util.SDK_INT >= 17) {
        getDisplaySizeV17(display, displaySize);
    } else if(Util.SDK_INT >= 16) {
        getDisplaySizeV16(display, displaySize);
    } else {
        getDisplaySizeV9(display, displaySize);
    }
    return displaySize;
}

@TargetApi(23)
private static void getDisplaySizeV23(Display display, Point outSize){
    Display.Mode[] modes = display.getSupportedModes();
    if(modes.length > 0){
        Display.Mode mode = modes[0];
        outSize.x = mode.getPhysicalWidth();
        outSize.y = mode.getPhysicalHeight();
    }
}

@TargetApi(17)
private static void getDisplaySizeV17(Display display, Point outSize) {
    display.getRealSize(outSize);
}

@TargetApi(16)
private static void getDisplaySizeV16(Display display, Point outSize) {
    display.getSize(outSize);
}

private static void getDisplaySizeV9(Display display, Point outSize) {
    outSize.x = display.getWidth();
    outSize.y = display.getHeight();
}

Which will give wrong results on api less than 23.

like image 37
Juan Carlos Ospina Gonzalez Avatar answered Sep 17 '22 11:09

Juan Carlos Ospina Gonzalez