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
This commit is contained in:
andrewlewis 2018-09-28 13:33:23 -07:00 committed by Oliver Woodman
parent 5c8dabade6
commit 5d5b641c1d
2 changed files with 61 additions and 47 deletions

View File

@ -18,7 +18,6 @@ package com.google.android.exoplayer2.audio;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.media.MediaCrypto; import android.media.MediaCrypto;
import android.media.MediaFormat; import android.media.MediaFormat;
@ -707,21 +706,12 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
* be determined. * be determined.
*/ */
private int getCodecMaxInputSize(MediaCodecInfo codecInfo, Format format) { private int getCodecMaxInputSize(MediaCodecInfo codecInfo, Format format) {
if (Util.SDK_INT < 24 && "OMX.google.raw.decoder".equals(codecInfo.name)) { if ("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 // OMX.google.raw.decoder didn't resize its output buffers correctly prior to N, except on
// point requesting a non-default input size. Doing so may cause a native crash, where-as not // Android TV running M, so there's no point requesting a non-default input size. Doing so may
// doing so will cause a more controlled failure when attempting to fill an input buffer. See: // cause a native crash, whereas not doing so will cause a more controlled failure when
// https://github.com/google/ExoPlayer/issues/4057. // attempting to fill an input buffer. See: https://github.com/google/ExoPlayer/issues/4057.
boolean needsRawDecoderWorkaround = true; if (Util.SDK_INT < 24 && !(Util.SDK_INT == 23 && Util.isAndroidTv(context))) {
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) {
return Format.NO_VALUE; return Format.NO_VALUE;
} }
} }

View File

@ -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. * 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. * @return The physical display size, in pixels.
*/ */
public static Point getPhysicalDisplaySize(Context context, Display display) { public static Point getPhysicalDisplaySize(Context context, Display display) {
if (Util.SDK_INT < 25 && display.getDisplayId() == Display.DEFAULT_DISPLAY) { if (Util.SDK_INT <= 28
// Before API 25 the Display object does not provide a working way to identify Android TVs && display.getDisplayId() == Display.DEFAULT_DISPLAY
// that can show 4k resolution in a SurfaceView, so check for supported devices here. && Util.isAndroidTv(context)) {
if ("Sony".equals(Util.MANUFACTURER) && Util.MODEL.startsWith("BRAVIA") // 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")) { && context.getPackageManager().hasSystemFeature("com.sony.dtv.hardware.panel.qfhd")) {
return new Point(3840, 2160); 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") // Otherwise check the system property for display size. From API 28 treble may prevent the
|| Util.MODEL.equals("QV151E") // system from writing sys.display-size so we check vendor.display-size instead.
|| Util.MODEL.equals("TPM171E")))) { String displaySize =
// Attempt to read sys.display-size. Util.SDK_INT < 28
String sysDisplaySize = null; ? 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 { try {
@SuppressLint("PrivateApi") String[] displaySizeParts = split(displaySize.trim(), "x");
Class<?> systemProperties = Class.forName("android.os.SystemProperties"); if (displaySizeParts.length == 2) {
Method getMethod = systemProperties.getMethod("get", String.class); int width = Integer.parseInt(displaySizeParts[0]);
sysDisplaySize = (String) getMethod.invoke(systemProperties, "sys.display-size"); int height = Integer.parseInt(displaySizeParts[1]);
} catch (Exception e) { if (width > 0 && height > 0) {
Log.e(TAG, "Failed to read sys.display-size", e); return new Point(width, height);
}
// 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);
}
} }
} 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; 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) @TargetApi(23)
private static void getDisplaySizeV23(Display display, Point outSize) { private static void getDisplaySizeV23(Display display, Point outSize) {
Display.Mode mode = display.getMode(); Display.Mode mode = display.getMode();