diff --git a/.travis.yml b/.travis.yml
index aaa7fc6d..e9e1dda9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,8 +8,8 @@ android:
components:
- tools
- platform-tools
- - build-tools-29.0.3
- - android-29
+ - build-tools-30.0.0
+ - android-30
before_install:
- sdkmanager --list
diff --git a/app/build.gradle b/app/build.gradle
index e711f73e..8ca63080 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,11 +1,11 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 29
+ compileSdkVersion 30
defaultConfig {
minSdkVersion 16
- targetSdkVersion 29
+ targetSdkVersion 30
versionName "9.5.1"
versionCode = 225
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0a219c23..fbbb7dae 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -120,7 +120,8 @@
android:resizeableActivity="true"
android:launchMode="singleTask"
android:excludeFromRecents="true"
- android:theme="@style/StreamTheme">
+ android:theme="@style/StreamTheme"
+ android:preferMinimalPostProcessing="true">
diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java
index 345e0b9a..813b8ce3 100644
--- a/app/src/main/java/com/limelight/Game.java
+++ b/app/src/main/java/com/limelight/Game.java
@@ -63,6 +63,7 @@ import android.view.Display;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.View.OnGenericMotionListener;
@@ -212,11 +213,17 @@ public class Game extends Activity implements SurfaceHolder.Callback,
prefConfig = PreferenceConfiguration.readPreferences(this);
tombstonePrefs = Game.this.getSharedPreferences("DecoderTombstone", 0);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && prefConfig.stretchVideo) {
+ if (prefConfig.stretchVideo) {
// Allow the activity to layout under notches if the fill-screen option
// was turned on by the user
- getWindow().getAttributes().layoutInDisplayCutoutMode =
- WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ getWindow().getAttributes().layoutInDisplayCutoutMode =
+ WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ }
+ else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ getWindow().getAttributes().layoutInDisplayCutoutMode =
+ WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ }
}
// Listen for events on the game surface
@@ -609,29 +616,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
}
}
- // FIXME: Remove when Android R SDK is finalized
- private static void setPreferMinimalPostProcessingWithReflection(WindowManager.LayoutParams windowLayoutParams, boolean isPreferred) {
- // Build.VERSION.PREVIEW_SDK_INT was added in M
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q && Build.VERSION.PREVIEW_SDK_INT == 0) {
- // Don't attempt this reflection unless on Android R Developer Preview
- return;
- }
- }
- else {
- return;
- }
-
- try {
- Field field = windowLayoutParams.getClass().getDeclaredField("preferMinimalPostProcessing");
- field.set(windowLayoutParams, isPreferred);
- } catch (NoSuchFieldException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
- }
-
private float prepareDisplayForRendering() {
Display display = getWindowManager().getDefaultDisplay();
WindowManager.LayoutParams windowLayoutParams = getWindow().getAttributes();
@@ -709,7 +693,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
}
// Enable HDMI ALLM (game mode) on Android R
- setPreferMinimalPostProcessingWithReflection(windowLayoutParams, true);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ windowLayoutParams.preferMinimalPostProcessing = true;
+ }
// Apply the display mode change
getWindow().setAttributes(windowLayoutParams);
@@ -1693,6 +1679,11 @@ public class Game extends Activity implements SurfaceHolder.Callback,
@Override
public void surfaceCreated(SurfaceHolder holder) {
surfaceCreated = true;
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ // Tell the OS about our frame rate to allow it to adapt the display refresh rate appropriately
+ holder.getSurface().setFrameRate(prefConfig.fps, Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE);
+ }
}
@Override
diff --git a/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java b/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java
index e41fe541..15246ea4 100644
--- a/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java
+++ b/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java
@@ -318,8 +318,8 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
videoFormat.setInteger(MediaFormat.KEY_MAX_HEIGHT, height);
}
- if (lowLatency) {
- videoFormat.setInteger(MediaCodecHelper.KEY_LOW_LATENCY, 1);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && lowLatency) {
+ videoFormat.setInteger(MediaFormat.KEY_LOW_LATENCY, 1);
}
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Set the Qualcomm vendor low latency extension if the Android R option is unavailable
diff --git a/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java b/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java
index 54c52823..a9cac570 100644
--- a/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java
+++ b/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java
@@ -40,10 +40,6 @@ public class MediaCodecHelper {
private static final List blacklisted59FpsDecoderPrefixes;
private static final List qualcommDecoderPrefixes;
- // FIXME: Remove when Android R SDK is finalized
- public static final String FEATURE_LowLatency = "low-latency";
- public static final String KEY_LOW_LATENCY = "low-latency";
-
private static boolean isLowEndSnapdragon = false;
private static boolean initialized = false;
@@ -343,10 +339,9 @@ public class MediaCodecHelper {
}
public static boolean decoderSupportsLowLatency(MediaCodecInfo decoderInfo, String mimeType) {
- // KitKat added CodecCapabilities.isFeatureSupported()
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
try {
- if (decoderInfo.getCapabilitiesForType(mimeType).isFeatureSupported(FEATURE_LowLatency)) {
+ if (decoderInfo.getCapabilitiesForType(mimeType).isFeatureSupported(CodecCapabilities.FEATURE_LowLatency)) {
LimeLog.info("Low latency decoding mode supported (FEATURE_LowLatency)");
return true;
}
diff --git a/app/src/main/java/com/limelight/utils/HelpLauncher.java b/app/src/main/java/com/limelight/utils/HelpLauncher.java
index 9d99b68a..24402ae9 100644
--- a/app/src/main/java/com/limelight/utils/HelpLauncher.java
+++ b/app/src/main/java/com/limelight/utils/HelpLauncher.java
@@ -3,41 +3,22 @@ package com.limelight.utils;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.net.Uri;
import com.limelight.HelpActivity;
public class HelpLauncher {
-
- private static boolean isKnownBrowser(Context context, Intent i) {
- ResolveInfo resolvedActivity = context.getPackageManager().resolveActivity(i, PackageManager.MATCH_DEFAULT_ONLY);
- if (resolvedActivity == null) {
- // No browser
- return false;
- }
-
- String name = resolvedActivity.activityInfo.name;
- if (name == null) {
- return false;
- }
-
- name = name.toLowerCase();
- return name.contains("chrome") || name.contains("firefox");
- }
-
private static void launchUrl(Context context, String url) {
// Try to launch the default browser
try {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
- // Several Android TV devices will lie and say they do have a browser
- // even though the OS just shows an error dialog if we try to use it. We need to
- // be a bit more clever on these devices and detect if the browser is a legitimate
- // browser or just a fake error message activity.
- if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK) ||
- isKnownBrowser(context, i)) {
+ // Several Android TV devices will lie and say they do have a browser even though the OS
+ // just shows an error dialog if we try to use it. We used to try to be clever and check
+ // the package name of the resolved intent, but it's not worth it anymore with Android 11's
+ // package visibility changes. We'll just always use the WebView on Android TV.
+ if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
context.startActivity(i);
return;
}