在 Android 上检测 4K UHD 屏幕

问题描述 投票:0回答:3

我正在尝试检测设备何时能够以 4K UHD (3840x2160) 分辨率输出。 nVidia Shield TV 和 Sony Xperia Z5 Premium 等许多设备即使支持 UHD,也会报告以 1080p 运行,因为它们默认为非视频布局的 1080p 输出。我需要某种方法来检测它们是否支持 4K,以区分它们和 Nexus Player 等非 4K 设备。

这是我用来确定当前分辨率的代码:

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

在 Shield TV 上,它始终返回 1920x1080,即使 ExoPlayer 报告它正在以 3840x2160 输出视频。

android android-tv
3个回答
5
投票

更新:此问题已从 ExoPlayer 1.5.1 开始修复(请参阅 https://github.com/google/ExoPlayer/commit/79055066813123c939c29e5a5e223a5ff043b91e


我跟踪ExoPlayer的开发者并找到了答案:

可靠检测 4K 设备的唯一方法是使用

Device.Mode
,它仅在 api 级别 23+ 中可用。请参阅此处的 Android M 注释:

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

这里还有该课程的文档:

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

至于

ExoPlayer
,从当前版本(1.4.2)开始,它没有实现此代码,但这可能会改变。参见:

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

最后回答一下这个问题,目前检测4K的正确方法是这样的:

/**
 * 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();
}

这会在 api 小于 23 上给出错误的结果。


1
投票

应使用 DisplayCompat.getSupportedModes,因为电视即使支持 UHD,也可能以 FHD 运行。 UHD 可能仅在视频播放期间启用。

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
}

0
投票

@冯 这实际上适用于准确检测 4K,即使在索尼 Bravia 电视上也是如此,其他方法返回 1080p。

这就是我现在用来返回 4K 的:

 private fun getViewportSize(): Point {
    val display: Display?
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        display = this.display
    } else {
        @Suppress("DEPRECATION")
        display = windowManager.defaultDisplay
    }
    return getDisplaySize(display!!)
}

private fun getDisplaySize(display: Display): Point {
    val displaySize = Point()
    getDisplaySizeActual(display, displaySize)
    return displaySize
}

private fun getDisplaySizeActual(display: Display, outSize: Point) {
    val modes = DisplayCompat.getSupportedModes(this, display)
    if (modes.isNotEmpty()) {
        val mode = modes[0]
        outSize.x = mode.physicalWidth
        outSize.y = mode.physicalHeight
    }
}

private fun isUhdDevice() : Boolean {

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

    defaultDisplay?.let { display ->
        return DisplayCompat.getSupportedModes(this, display).any { it.physicalHeight >= 2160 && it.physicalWidth >= 3840 }
    }
    return false
}

要使用只需致电:

 if (isUhdDevice()){
        getViewportSize()
    }

谢谢

© www.soinside.com 2019 - 2024. All rights reserved.