From 822657972d90ef1de93009fa1754a7b18ccd2c56 Mon Sep 17 00:00:00 2001
From: edde746 <86283021+edde746@users.noreply.github.com>
Date: Mon, 13 Jul 2026 12:29:19 +0200
Subject: [PATCH] fix(android): enforce minSdk compatibility
---
.github/workflows/ci.yml | 4 ++++
android/app/build.gradle.kts | 6 ++++++
.../src/main/kotlin/com/edde746/plezy/MainActivity.kt | 3 +++
.../com/edde746/plezy/exoplayer/AssLatencyCalibrator.kt | 2 ++
.../kotlin/com/edde746/plezy/exoplayer/ExoPlayerCore.kt | 2 ++
.../main/kotlin/com/edde746/plezy/mpv/MpvPlayerCore.kt | 9 ++++++++-
.../kotlin/com/edde746/plezy/shared/MediaCodecQuery.kt | 7 +++----
android/app/src/main/res/values-night/styles.xml | 8 --------
android/app/src/main/res/values/styles.xml | 8 --------
android/gradle.properties | 4 +++-
10 files changed, 31 insertions(+), 22 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 01461e21..951f7ba3 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -176,6 +176,10 @@ jobs:
working-directory: android
run: ./gradlew :app:testDebugUnitTest :saf_util:testDebugUnitTest :libass:testDebugUnitTest -x :app:compileFlutterBuildDebug --continue
+ - name: Check Android API compatibility
+ working-directory: android
+ run: ./gradlew :app:lintDebug
+
native-format:
name: Native Formatting
runs-on: ubuntu-latest
diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts
index 18a23892..35822b94 100644
--- a/android/app/build.gradle.kts
+++ b/android/app/build.gradle.kts
@@ -166,6 +166,12 @@ android {
jniLibs.srcDir(File(mpvDir, "libcxx/jni"))
}
}
+
+ lint {
+ // Enforce the app-owned minSdk boundary without auditing upstream AndroidX.
+ checkDependencies = false
+ checkOnly += setOf("NewApi")
+ }
}
flutter {
diff --git a/android/app/src/main/kotlin/com/edde746/plezy/MainActivity.kt b/android/app/src/main/kotlin/com/edde746/plezy/MainActivity.kt
index f056fdf1..e67018f2 100644
--- a/android/app/src/main/kotlin/com/edde746/plezy/MainActivity.kt
+++ b/android/app/src/main/kotlin/com/edde746/plezy/MainActivity.kt
@@ -21,6 +21,7 @@ import android.view.WindowInsets
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import android.widget.FrameLayout
+import androidx.annotation.RequiresApi
import com.edde746.plezy.exoplayer.ExoPlayerPlugin
import com.edde746.plezy.mpv.MpvAudioPlayerPlugin
import com.edde746.plezy.mpv.MpvPlayerPlugin
@@ -676,6 +677,7 @@ class MainActivity : FlutterActivity() {
}
}
+ @RequiresApi(Build.VERSION_CODES.O)
private fun isPipPermissionGranted(): Boolean {
val appOpsManager = getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
return appOpsManager.checkOpNoThrow(
@@ -685,6 +687,7 @@ class MainActivity : FlutterActivity() {
) == AppOpsManager.MODE_ALLOWED
}
+ @RequiresApi(Build.VERSION_CODES.O)
private fun buildPipParams(width: Int, height: Int, autoEnterEnabled: Boolean? = null): PictureInPictureParams {
val (w, h) = if (width <= 0 || height <= 0) {
Pair(16, 9)
diff --git a/android/app/src/main/kotlin/com/edde746/plezy/exoplayer/AssLatencyCalibrator.kt b/android/app/src/main/kotlin/com/edde746/plezy/exoplayer/AssLatencyCalibrator.kt
index 48e151e0..27445749 100644
--- a/android/app/src/main/kotlin/com/edde746/plezy/exoplayer/AssLatencyCalibrator.kt
+++ b/android/app/src/main/kotlin/com/edde746/plezy/exoplayer/AssLatencyCalibrator.kt
@@ -3,6 +3,7 @@ package com.edde746.plezy.exoplayer
import android.os.Build
import android.view.SurfaceControl
import android.view.SurfaceView
+import androidx.annotation.RequiresApi
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
import kotlin.math.abs
@@ -101,6 +102,7 @@ internal class AssLatencyCalibrator(
/** Never called while holding [lock]: applyTransactionToFrame is a binder call and runs on the
* GL swap path. The native slot allocation is atomic, so concurrent callers are safe. */
+ @RequiresApi(34)
private fun attach(surface: SurfaceView, releaseTimeNs: Long, source: Int) {
try {
val tx = SurfaceControl.Transaction()
diff --git a/android/app/src/main/kotlin/com/edde746/plezy/exoplayer/ExoPlayerCore.kt b/android/app/src/main/kotlin/com/edde746/plezy/exoplayer/ExoPlayerCore.kt
index 517853fd..71854514 100644
--- a/android/app/src/main/kotlin/com/edde746/plezy/exoplayer/ExoPlayerCore.kt
+++ b/android/app/src/main/kotlin/com/edde746/plezy/exoplayer/ExoPlayerCore.kt
@@ -23,6 +23,7 @@ import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.widget.FrameLayout
import androidx.annotation.OptIn
+import androidx.annotation.RequiresApi
import androidx.media3.common.C
import androidx.media3.common.Format
import androidx.media3.common.MediaItem
@@ -2057,6 +2058,7 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener {
.build()
}
+ @RequiresApi(Build.VERSION_CODES.Q)
@Suppress("DEPRECATION")
private fun isDirectPlaybackSupportedApi29(
audioFormat: AudioFormat,
diff --git a/android/app/src/main/kotlin/com/edde746/plezy/mpv/MpvPlayerCore.kt b/android/app/src/main/kotlin/com/edde746/plezy/mpv/MpvPlayerCore.kt
index 55fc218f..6411d12f 100644
--- a/android/app/src/main/kotlin/com/edde746/plezy/mpv/MpvPlayerCore.kt
+++ b/android/app/src/main/kotlin/com/edde746/plezy/mpv/MpvPlayerCore.kt
@@ -5,6 +5,7 @@ import android.content.Context
import android.graphics.PixelFormat
import android.media.AudioAttributes
import android.media.ImageReader
+import android.os.Build
import android.os.Handler
import android.os.Looper
import android.util.Log
@@ -135,9 +136,15 @@ class MpvPlayerCore(
Log.d(TAG, "Created MPV placeholder surface")
}
+ @Suppress("DEPRECATION")
private fun currentDisplayFpsOverride(): String? {
if (audioOnly) return null
- val refreshRate = activity.display?.mode?.refreshRate ?: return null
+ val display = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ activity.display
+ } else {
+ activity.windowManager.defaultDisplay
+ }
+ val refreshRate = display?.mode?.refreshRate ?: return null
if (refreshRate <= 0f) return null
return refreshRate.toString()
}
diff --git a/android/app/src/main/kotlin/com/edde746/plezy/shared/MediaCodecQuery.kt b/android/app/src/main/kotlin/com/edde746/plezy/shared/MediaCodecQuery.kt
index 796a014a..f104a686 100644
--- a/android/app/src/main/kotlin/com/edde746/plezy/shared/MediaCodecQuery.kt
+++ b/android/app/src/main/kotlin/com/edde746/plezy/shared/MediaCodecQuery.kt
@@ -24,15 +24,14 @@ internal object MediaCodecQuery {
}
fun isHardwareAccelerated(info: MediaCodecInfo): Boolean {
- val sdkInt = Build.VERSION.SDK_INT
val name = info.name
- return if (sdkInt >= Build.VERSION_CODES.Q) {
- isHardwareAccelerated(sdkInt, info.isHardwareAccelerated, name)
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ isHardwareAccelerated(Build.VERSION.SDK_INT, info.isHardwareAccelerated, name)
} else {
// MediaCodecInfo.isHardwareAccelerated() does not exist before API 29.
// Keep the call inside the version gate so older Fire OS releases do not
// fail with NoSuchMethodError while initializing playback.
- isHardwareAccelerated(sdkInt, false, name)
+ isHardwareAccelerated(Build.VERSION.SDK_INT, false, name)
}
}
diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml
index 01337e8d..0e23f30d 100644
--- a/android/app/src/main/res/values-night/styles.xml
+++ b/android/app/src/main/res/values-night/styles.xml
@@ -3,8 +3,6 @@
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
index c927cb19..339e3091 100644
--- a/android/app/src/main/res/values/styles.xml
+++ b/android/app/src/main/res/values/styles.xml
@@ -3,8 +3,6 @@
diff --git a/android/gradle.properties b/android/gradle.properties
index 475a6280..ec8063fc 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,6 +1,8 @@
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
-android.enableJetifier=true
+# All bundled dependencies use AndroidX. Jetifier also cannot process modern
+# JVM-only test artifacts when Android lint builds dependency models.
+android.enableJetifier=false
# This builtInKotlin flag was added automatically by Flutter migrator
android.builtInKotlin=false
# This newDsl flag was added automatically by Flutter migrator