Compare commits

...

6 Commits

Author SHA1 Message Date
Fredrik Burmester
24d04c1003 fix: BOOT_COMPLETED runtime protection 2026-01-05 21:32:41 +01:00
Fredrik Burmester
7da52441ab chore: version 2026-01-05 21:32:41 +01:00
Fredrik Burmester
70268e6120 fix: use vlc build with 16kb page size 2026-01-05 21:32:41 +01:00
Fredrik Burmester
96fbb9fe1f fix: target version 35 2026-01-05 21:32:40 +01:00
Fredrik Burmester
3b104b91fc chore: version 2026-01-05 21:32:40 +01:00
Fredrik Burmester
e4134d6f9a fix: item content header button colors 2026-01-05 21:32:40 +01:00
5 changed files with 66 additions and 12 deletions

View File

@@ -34,7 +34,7 @@
},
"android": {
"jsEngine": "hermes",
"versionCode": 89,
"versionCode": 91,
"adaptiveIcon": {
"foregroundImage": "./assets/images/icon-android-plain.png",
"monochromeImage": "./assets/images/icon-android-themed.png",
@@ -63,7 +63,7 @@
"android": {
"buildArchs": ["arm64-v8a", "x86_64"],
"compileSdkVersion": 36,
"targetSdkVersion": 34,
"targetSdkVersion": 35,
"buildToolsVersion": "35.0.0",
"kotlinVersion": "2.0.21",
"minSdkVersion": 24,

View File

@@ -16,6 +16,7 @@ export const AddToFavorites: FC<Props> = ({ item, ...props }) => {
<RoundButton
size='large'
icon={isFavorite ? "heart" : "heart-outline"}
color={isFavorite ? "purple" : "white"}
onPress={toggleFavorite}
/>
</View>

View File

@@ -104,7 +104,7 @@ export const RoundButton: React.FC<PropsWithChildren<Props>> = ({
<Ionicons
name={icon}
size={size === "large" ? 22 : 18}
color={"white"}
color={color === "white" ? "white" : "#9334E9"}
/>
) : null}
{children ? children : null}

View File

@@ -5,42 +5,92 @@ import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Intent
import android.content.pm.ServiceInfo
import android.os.Binder
import android.os.Build
import android.os.IBinder
import android.os.SystemClock
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.app.ServiceCompat
class DownloadService : Service() {
private val TAG = "DownloadService"
private val NOTIFICATION_ID = 1001
private val CHANNEL_ID = "download_channel"
// Time threshold to detect if we're in boot context (10 minutes after boot)
private val BOOT_THRESHOLD_MS = 10 * 60 * 1000L
private val binder = DownloadServiceBinder()
private var activeDownloadCount = 0
private var currentDownloadTitle = "Preparing download..."
private var currentProgress = 0
private var isForegroundStarted = false
inner class DownloadServiceBinder : Binder() {
fun getService(): DownloadService = this@DownloadService
}
override fun onCreate() {
super.onCreate()
Log.d(TAG, "DownloadService created")
createNotificationChannel()
}
override fun onBind(intent: Intent?): IBinder {
Log.d(TAG, "DownloadService bound")
return binder
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d(TAG, "DownloadService started")
startForeground(NOTIFICATION_ID, createNotification())
// On Android 15+, dataSync foreground services cannot be started from BOOT_COMPLETED context
// Check if we're likely in a boot context and skip foreground start if so
if (Build.VERSION.SDK_INT >= 35 && isLikelyBootContext()) {
Log.w(TAG, "Skipping foreground start - likely boot context on Android 15+")
stopSelf()
return START_NOT_STICKY
}
startForegroundSafely()
return START_STICKY
}
/**
* Check if we're likely in a boot context by checking system uptime.
* If the system has been up for less than the threshold, we might be in boot context.
*/
private fun isLikelyBootContext(): Boolean {
val uptimeMs = SystemClock.elapsedRealtime()
return uptimeMs < BOOT_THRESHOLD_MS
}
/**
* Start foreground service safely with proper service type for Android 14+
*/
private fun startForegroundSafely() {
if (isForegroundStarted) return
try {
if (Build.VERSION.SDK_INT >= 34) {
ServiceCompat.startForeground(
this,
NOTIFICATION_ID,
createNotification(),
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
)
} else {
startForeground(NOTIFICATION_ID, createNotification())
}
isForegroundStarted = true
} catch (e: Exception) {
Log.e(TAG, "Failed to start foreground service", e)
// If we can't start foreground, stop the service
stopSelf()
}
}
override fun onDestroy() {
Log.d(TAG, "DownloadService destroyed")
@@ -86,7 +136,7 @@ class DownloadService : Service() {
activeDownloadCount++
Log.d(TAG, "Download started, active count: $activeDownloadCount")
if (activeDownloadCount == 1) {
startForeground(NOTIFICATION_ID, createNotification())
startForegroundSafely()
}
}
@@ -94,7 +144,10 @@ class DownloadService : Service() {
activeDownloadCount = maxOf(0, activeDownloadCount - 1)
Log.d(TAG, "Download stopped, active count: $activeDownloadCount")
if (activeDownloadCount == 0) {
stopForeground(STOP_FOREGROUND_REMOVE)
if (isForegroundStarted) {
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
isForegroundStarted = false
}
stopSelf()
}
}

View File

@@ -35,7 +35,7 @@ android {
}
dependencies {
implementation 'org.videolan.android:libvlc-all:3.6.0'
implementation 'io.github.mengzhidaren:vlc-android-sdk:3.6.3'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
}