fix(android): enforce minSdk compatibility
This commit is contained in:
@@ -176,6 +176,10 @@ jobs:
|
|||||||
working-directory: android
|
working-directory: android
|
||||||
run: ./gradlew :app:testDebugUnitTest :saf_util:testDebugUnitTest :libass:testDebugUnitTest -x :app:compileFlutterBuildDebug --continue
|
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:
|
native-format:
|
||||||
name: Native Formatting
|
name: Native Formatting
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -166,6 +166,12 @@ android {
|
|||||||
jniLibs.srcDir(File(mpvDir, "libcxx/jni"))
|
jniLibs.srcDir(File(mpvDir, "libcxx/jni"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lint {
|
||||||
|
// Enforce the app-owned minSdk boundary without auditing upstream AndroidX.
|
||||||
|
checkDependencies = false
|
||||||
|
checkOnly += setOf("NewApi")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flutter {
|
flutter {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import android.view.WindowInsets
|
|||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
import com.edde746.plezy.exoplayer.ExoPlayerPlugin
|
import com.edde746.plezy.exoplayer.ExoPlayerPlugin
|
||||||
import com.edde746.plezy.mpv.MpvAudioPlayerPlugin
|
import com.edde746.plezy.mpv.MpvAudioPlayerPlugin
|
||||||
import com.edde746.plezy.mpv.MpvPlayerPlugin
|
import com.edde746.plezy.mpv.MpvPlayerPlugin
|
||||||
@@ -676,6 +677,7 @@ class MainActivity : FlutterActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
private fun isPipPermissionGranted(): Boolean {
|
private fun isPipPermissionGranted(): Boolean {
|
||||||
val appOpsManager = getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
|
val appOpsManager = getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
|
||||||
return appOpsManager.checkOpNoThrow(
|
return appOpsManager.checkOpNoThrow(
|
||||||
@@ -685,6 +687,7 @@ class MainActivity : FlutterActivity() {
|
|||||||
) == AppOpsManager.MODE_ALLOWED
|
) == AppOpsManager.MODE_ALLOWED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
private fun buildPipParams(width: Int, height: Int, autoEnterEnabled: Boolean? = null): PictureInPictureParams {
|
private fun buildPipParams(width: Int, height: Int, autoEnterEnabled: Boolean? = null): PictureInPictureParams {
|
||||||
val (w, h) = if (width <= 0 || height <= 0) {
|
val (w, h) = if (width <= 0 || height <= 0) {
|
||||||
Pair(16, 9)
|
Pair(16, 9)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.edde746.plezy.exoplayer
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.view.SurfaceControl
|
import android.view.SurfaceControl
|
||||||
import android.view.SurfaceView
|
import android.view.SurfaceView
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import kotlin.math.abs
|
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
|
/** 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. */
|
* 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) {
|
private fun attach(surface: SurfaceView, releaseTimeNs: Long, source: Int) {
|
||||||
try {
|
try {
|
||||||
val tx = SurfaceControl.Transaction()
|
val tx = SurfaceControl.Transaction()
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import android.view.ViewGroup
|
|||||||
import android.view.ViewTreeObserver
|
import android.view.ViewTreeObserver
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.annotation.OptIn
|
import androidx.annotation.OptIn
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.media3.common.C
|
import androidx.media3.common.C
|
||||||
import androidx.media3.common.Format
|
import androidx.media3.common.Format
|
||||||
import androidx.media3.common.MediaItem
|
import androidx.media3.common.MediaItem
|
||||||
@@ -2057,6 +2058,7 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener {
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.Q)
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
private fun isDirectPlaybackSupportedApi29(
|
private fun isDirectPlaybackSupportedApi29(
|
||||||
audioFormat: AudioFormat,
|
audioFormat: AudioFormat,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.content.Context
|
|||||||
import android.graphics.PixelFormat
|
import android.graphics.PixelFormat
|
||||||
import android.media.AudioAttributes
|
import android.media.AudioAttributes
|
||||||
import android.media.ImageReader
|
import android.media.ImageReader
|
||||||
|
import android.os.Build
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
@@ -135,9 +136,15 @@ class MpvPlayerCore(
|
|||||||
Log.d(TAG, "Created MPV placeholder surface")
|
Log.d(TAG, "Created MPV placeholder surface")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
private fun currentDisplayFpsOverride(): String? {
|
private fun currentDisplayFpsOverride(): String? {
|
||||||
if (audioOnly) return null
|
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
|
if (refreshRate <= 0f) return null
|
||||||
return refreshRate.toString()
|
return refreshRate.toString()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,15 +24,14 @@ internal object MediaCodecQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun isHardwareAccelerated(info: MediaCodecInfo): Boolean {
|
fun isHardwareAccelerated(info: MediaCodecInfo): Boolean {
|
||||||
val sdkInt = Build.VERSION.SDK_INT
|
|
||||||
val name = info.name
|
val name = info.name
|
||||||
return if (sdkInt >= Build.VERSION_CODES.Q) {
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
isHardwareAccelerated(sdkInt, info.isHardwareAccelerated, name)
|
isHardwareAccelerated(Build.VERSION.SDK_INT, info.isHardwareAccelerated, name)
|
||||||
} else {
|
} else {
|
||||||
// MediaCodecInfo.isHardwareAccelerated() does not exist before API 29.
|
// MediaCodecInfo.isHardwareAccelerated() does not exist before API 29.
|
||||||
// Keep the call inside the version gate so older Fire OS releases do not
|
// Keep the call inside the version gate so older Fire OS releases do not
|
||||||
// fail with NoSuchMethodError while initializing playback.
|
// fail with NoSuchMethodError while initializing playback.
|
||||||
isHardwareAccelerated(sdkInt, false, name)
|
isHardwareAccelerated(Build.VERSION.SDK_INT, false, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
<item name="android:windowBackground">@color/splash_background</item>
|
<item name="android:windowBackground">@color/splash_background</item>
|
||||||
<!-- Disable Android's default green focus highlight that appears during d-pad/keyboard navigation -->
|
|
||||||
<item name="android:defaultFocusHighlightEnabled">false</item>
|
|
||||||
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
||||||
</style>
|
</style>
|
||||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||||
@@ -15,30 +13,24 @@
|
|||||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
<item name="android:windowBackground">@color/splash_background</item>
|
<item name="android:windowBackground">@color/splash_background</item>
|
||||||
<!-- Disable Android's default green focus highlight that appears during d-pad/keyboard navigation -->
|
|
||||||
<item name="android:defaultFocusHighlightEnabled">false</item>
|
|
||||||
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- Splash theme variants for setSplashScreenTheme -->
|
<!-- Splash theme variants for setSplashScreenTheme -->
|
||||||
<style name="SplashTheme.Dark" parent="@android:style/Theme.Black.NoTitleBar">
|
<style name="SplashTheme.Dark" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
<item name="android:windowBackground">@color/splash_dark</item>
|
<item name="android:windowBackground">@color/splash_dark</item>
|
||||||
<item name="android:defaultFocusHighlightEnabled">false</item>
|
|
||||||
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
||||||
</style>
|
</style>
|
||||||
<style name="SplashTheme.Oled" parent="@android:style/Theme.Black.NoTitleBar">
|
<style name="SplashTheme.Oled" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
<item name="android:windowBackground">@color/splash_oled</item>
|
<item name="android:windowBackground">@color/splash_oled</item>
|
||||||
<item name="android:defaultFocusHighlightEnabled">false</item>
|
|
||||||
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
||||||
</style>
|
</style>
|
||||||
<style name="SplashTheme.Light" parent="@android:style/Theme.Black.NoTitleBar">
|
<style name="SplashTheme.Light" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
<item name="android:windowBackground">@color/splash_light</item>
|
<item name="android:windowBackground">@color/splash_light</item>
|
||||||
<item name="android:defaultFocusHighlightEnabled">false</item>
|
|
||||||
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
||||||
</style>
|
</style>
|
||||||
<style name="SplashTheme.System" parent="@android:style/Theme.Black.NoTitleBar">
|
<style name="SplashTheme.System" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
<item name="android:windowBackground">@color/splash_background</item>
|
<item name="android:windowBackground">@color/splash_background</item>
|
||||||
<item name="android:defaultFocusHighlightEnabled">false</item>
|
|
||||||
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||||
<item name="android:windowBackground">@color/splash_background</item>
|
<item name="android:windowBackground">@color/splash_background</item>
|
||||||
<!-- Disable Android's default green focus highlight that appears during d-pad/keyboard navigation -->
|
|
||||||
<item name="android:defaultFocusHighlightEnabled">false</item>
|
|
||||||
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
||||||
</style>
|
</style>
|
||||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||||
@@ -15,30 +13,24 @@
|
|||||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||||
<item name="android:windowBackground">@color/splash_background</item>
|
<item name="android:windowBackground">@color/splash_background</item>
|
||||||
<!-- Disable Android's default green focus highlight that appears during d-pad/keyboard navigation -->
|
|
||||||
<item name="android:defaultFocusHighlightEnabled">false</item>
|
|
||||||
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- Splash theme variants for setSplashScreenTheme -->
|
<!-- Splash theme variants for setSplashScreenTheme -->
|
||||||
<style name="SplashTheme.Dark" parent="@android:style/Theme.Light.NoTitleBar">
|
<style name="SplashTheme.Dark" parent="@android:style/Theme.Light.NoTitleBar">
|
||||||
<item name="android:windowBackground">@color/splash_dark</item>
|
<item name="android:windowBackground">@color/splash_dark</item>
|
||||||
<item name="android:defaultFocusHighlightEnabled">false</item>
|
|
||||||
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
||||||
</style>
|
</style>
|
||||||
<style name="SplashTheme.Oled" parent="@android:style/Theme.Light.NoTitleBar">
|
<style name="SplashTheme.Oled" parent="@android:style/Theme.Light.NoTitleBar">
|
||||||
<item name="android:windowBackground">@color/splash_oled</item>
|
<item name="android:windowBackground">@color/splash_oled</item>
|
||||||
<item name="android:defaultFocusHighlightEnabled">false</item>
|
|
||||||
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
||||||
</style>
|
</style>
|
||||||
<style name="SplashTheme.Light" parent="@android:style/Theme.Light.NoTitleBar">
|
<style name="SplashTheme.Light" parent="@android:style/Theme.Light.NoTitleBar">
|
||||||
<item name="android:windowBackground">@color/splash_light</item>
|
<item name="android:windowBackground">@color/splash_light</item>
|
||||||
<item name="android:defaultFocusHighlightEnabled">false</item>
|
|
||||||
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
||||||
</style>
|
</style>
|
||||||
<style name="SplashTheme.System" parent="@android:style/Theme.Light.NoTitleBar">
|
<style name="SplashTheme.System" parent="@android:style/Theme.Light.NoTitleBar">
|
||||||
<item name="android:windowBackground">@color/splash_background</item>
|
<item name="android:windowBackground">@color/splash_background</item>
|
||||||
<item name="android:defaultFocusHighlightEnabled">false</item>
|
|
||||||
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
<item name="android:colorControlHighlight">@android:color/transparent</item>
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
||||||
android.useAndroidX=true
|
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
|
# This builtInKotlin flag was added automatically by Flutter migrator
|
||||||
android.builtInKotlin=false
|
android.builtInKotlin=false
|
||||||
# This newDsl flag was added automatically by Flutter migrator
|
# This newDsl flag was added automatically by Flutter migrator
|
||||||
|
|||||||
Reference in New Issue
Block a user