diff --git a/composeApp/src/androidMain/AndroidManifest.xml b/composeApp/src/androidMain/AndroidManifest.xml index b396cd3..58fb629 100644 --- a/composeApp/src/androidMain/AndroidManifest.xml +++ b/composeApp/src/androidMain/AndroidManifest.xml @@ -8,7 +8,7 @@ - + @@ -59,7 +59,7 @@ android:name=".NostrForegroundService" android:enabled="true" android:exported="false" - android:foregroundServiceType="dataSync" /> + android:foregroundServiceType="remoteMessaging" /> \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/su/reya/coop/NostrForegroundService.kt b/composeApp/src/androidMain/kotlin/su/reya/coop/NostrForegroundService.kt index 0efbd5b..abb13ad 100644 --- a/composeApp/src/androidMain/kotlin/su/reya/coop/NostrForegroundService.kt +++ b/composeApp/src/androidMain/kotlin/su/reya/coop/NostrForegroundService.kt @@ -22,6 +22,8 @@ import kotlinx.coroutines.cancel import kotlinx.coroutines.launch import java.io.File +private const val GROUP_KEY_MESSAGES = "su.reya.coop.MESSAGES" + class NostrForegroundService : Service() { private val serviceScope = CoroutineScope(Dispatchers.IO + SupervisorJob()) private val nostr by lazy { NostrManager.instance } @@ -29,26 +31,26 @@ class NostrForegroundService : Service() { override fun onBind(intent: Intent?): IBinder? = null - private fun isUserInApp(): Boolean { - return ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED) - } - override fun onCreate() { super.onCreate() - createNotificationChannel() - val notification = createNotification() - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { - startForeground(1, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC) - } else { - startForeground(1, notification) - } + startAsForeground() } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + if (intent?.action == "STOP_SERVICE") { + stopForeground(STOP_FOREGROUND_REMOVE) + stopSelf() + return START_NOT_STICKY + } + + // Start the nostr service in the foreground + startAsForeground() + + // Check if the service is already running if (notificationJob?.isActive == true) return START_STICKY + // Start the Nostr client notificationJob = serviceScope.launch { try { Log.d("Coop", "Starting Nostr in background") @@ -93,6 +95,26 @@ class NostrForegroundService : Service() { return START_STICKY } + private fun isUserInApp(): Boolean { + return ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED) + } + + private fun startAsForeground() { + val notification = createNotification() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + startForeground(1, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING) + } else { + startForeground(1, notification) + } + } + + private fun getStopServicePendingIntent(): PendingIntent { + val intent = Intent(this, NostrForegroundService::class.java).apply { + action = "STOP_SERVICE" + } + return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_IMMUTABLE) + } + private fun createNotificationChannel() { val manager = getSystemService(NotificationManager::class.java) @@ -115,10 +137,12 @@ class NostrForegroundService : Service() { private fun createNotification(content: String? = null): Notification { val builder = NotificationCompat.Builder(this, "nostr_service") + .setGroup(GROUP_KEY_MESSAGES) .setSmallIcon(R.drawable.ic_notification) .setOngoing(true) .setPriority(NotificationCompat.PRIORITY_MIN) .setCategory(Notification.CATEGORY_SERVICE) + .addAction(R.drawable.ic_notification, "Stop", getStopServicePendingIntent()) if (content != null) { builder.setContentTitle("Coop")