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.
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
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With