From 5d5b641c1dec222eb4e504391fc021c35d73f6fd Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Fri, 28 Sep 2018 13:33:23 -0700 Subject: [PATCH] Extend physical display size workaround for ATVs Extend Sony workaround up to and including Oreo. Due to a platform issue the Display API couldn't report 1080p UI and 4k SurfaceView support until Oreo. Since Oreo it is still common for devices to misreport their display sizes via Display, so this change switches to using system properties up to and including Pie. On Pie treble may prevent writing sys.display-size so check for vendor.display-size instead. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=214987203 --- .../audio/MediaCodecAudioRenderer.java | 22 ++--- .../google/android/exoplayer2/util/Util.java | 86 ++++++++++++------- 2 files changed, 61 insertions(+), 47 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java index 89d2ee16b2..a68ee5b727 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java @@ -18,7 +18,6 @@ package com.google.android.exoplayer2.audio; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.Context; -import android.content.pm.PackageManager; import android.media.MediaCodec; import android.media.MediaCrypto; import android.media.MediaFormat; @@ -707,21 +706,12 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media * be determined. */ private int getCodecMaxInputSize(MediaCodecInfo codecInfo, Format format) { - if (Util.SDK_INT < 24 && "OMX.google.raw.decoder".equals(codecInfo.name)) { - // OMX.google.raw.decoder didn't resize its output buffers correctly prior to N, so there's no - // point requesting a non-default input size. Doing so may cause a native crash, where-as not - // doing so will cause a more controlled failure when attempting to fill an input buffer. See: - // https://github.com/google/ExoPlayer/issues/4057. - boolean needsRawDecoderWorkaround = true; - if (Util.SDK_INT == 23) { - PackageManager packageManager = context.getPackageManager(); - if (packageManager != null - && packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) { - // The workaround is not required for AndroidTV devices running M. - needsRawDecoderWorkaround = false; - } - } - if (needsRawDecoderWorkaround) { + if ("OMX.google.raw.decoder".equals(codecInfo.name)) { + // OMX.google.raw.decoder didn't resize its output buffers correctly prior to N, except on + // Android TV running M, so there's no point requesting a non-default input size. Doing so may + // cause a native crash, whereas not doing so will cause a more controlled failure when + // attempting to fill an input buffer. See: https://github.com/google/ExoPlayer/issues/4057. + if (Util.SDK_INT < 24 && !(Util.SDK_INT == 23 && Util.isAndroidTv(context))) { return Format.NO_VALUE; } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java index eafb05226c..33c8dc5643 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java @@ -1728,6 +1728,18 @@ public final class Util { } } + /** + * Returns whether the device is an Android TV. + * + * @param context Any context. + * @return Whether the device is an Android TV. + */ + public static boolean isAndroidTv(Context context) { + PackageManager packageManager = context.getPackageManager(); + return packageManager != null + && packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK); + } + /** * Gets the physical size of the default display, in pixels. * @@ -1747,43 +1759,42 @@ public final class Util { * @return The physical display size, in pixels. */ public static Point getPhysicalDisplaySize(Context context, Display display) { - if (Util.SDK_INT < 25 && display.getDisplayId() == Display.DEFAULT_DISPLAY) { - // Before API 25 the Display object does not provide a working way to identify Android TVs - // that can show 4k resolution in a SurfaceView, so check for supported devices here. - if ("Sony".equals(Util.MANUFACTURER) && Util.MODEL.startsWith("BRAVIA") + if (Util.SDK_INT <= 28 + && display.getDisplayId() == Display.DEFAULT_DISPLAY + && Util.isAndroidTv(context)) { + // On Android TVs it is common for the UI to be configured for a lower resolution than + // SurfaceViews can output. Before API 26 the Display object does not provide a way to + // identify this case, and up to and including API 28 many devices still do not correctly set + // their hardware compositor output size. + + // Sony Android TVs advertise support for 4k output via a system feature. + if ("Sony".equals(Util.MANUFACTURER) + && Util.MODEL.startsWith("BRAVIA") && context.getPackageManager().hasSystemFeature("com.sony.dtv.hardware.panel.qfhd")) { return new Point(3840, 2160); - } else if (("NVIDIA".equals(Util.MANUFACTURER) && Util.MODEL.contains("SHIELD")) - || ("philips".equals(Util.toLowerInvariant(Util.MANUFACTURER)) - && (Util.MODEL.startsWith("QM1") - || Util.MODEL.equals("QV151E") - || Util.MODEL.equals("TPM171E")))) { - // Attempt to read sys.display-size. - String sysDisplaySize = null; + } + + // Otherwise check the system property for display size. From API 28 treble may prevent the + // system from writing sys.display-size so we check vendor.display-size instead. + String displaySize = + Util.SDK_INT < 28 + ? getSystemProperty("sys.display-size") + : getSystemProperty("vendor.display-size"); + // If we managed to read the display size, attempt to parse it. + if (!TextUtils.isEmpty(displaySize)) { try { - @SuppressLint("PrivateApi") - Class systemProperties = Class.forName("android.os.SystemProperties"); - Method getMethod = systemProperties.getMethod("get", String.class); - sysDisplaySize = (String) getMethod.invoke(systemProperties, "sys.display-size"); - } catch (Exception e) { - Log.e(TAG, "Failed to read sys.display-size", e); - } - // If we managed to read sys.display-size, attempt to parse it. - if (!TextUtils.isEmpty(sysDisplaySize)) { - try { - String[] sysDisplaySizeParts = split(sysDisplaySize.trim(), "x"); - if (sysDisplaySizeParts.length == 2) { - int width = Integer.parseInt(sysDisplaySizeParts[0]); - int height = Integer.parseInt(sysDisplaySizeParts[1]); - if (width > 0 && height > 0) { - return new Point(width, height); - } + String[] displaySizeParts = split(displaySize.trim(), "x"); + if (displaySizeParts.length == 2) { + int width = Integer.parseInt(displaySizeParts[0]); + int height = Integer.parseInt(displaySizeParts[1]); + if (width > 0 && height > 0) { + return new Point(width, height); } - } catch (NumberFormatException e) { - // Do nothing. } - Log.e(TAG, "Invalid sys.display-size: " + sysDisplaySize); + } catch (NumberFormatException e) { + // Do nothing. } + Log.e(TAG, "Invalid display size: " + displaySize); } } @@ -1800,6 +1811,19 @@ public final class Util { return displaySize; } + @Nullable + private static String getSystemProperty(String name) { + try { + @SuppressLint("PrivateApi") + Class systemProperties = Class.forName("android.os.SystemProperties"); + Method getMethod = systemProperties.getMethod("get", String.class); + return (String) getMethod.invoke(systemProperties, name); + } catch (Exception e) { + Log.e(TAG, "Failed to read system property " + name, e); + return null; + } + } + @TargetApi(23) private static void getDisplaySizeV23(Display display, Point outSize) { Display.Mode mode = display.getMode();