From 637f424a70c30fcb084ba9a14413b40b9271c73b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 12 Dec 2023 18:22:11 +0100 Subject: [PATCH] Fixed foreground service types & use --- .../compatibility/Api29Compatibility.kt | 20 ------- .../compatibility/Api34Compatibility.kt | 19 +++++++ .../linphone/compatibility/Compatibility.kt | 4 +- .../notifications/NotificationsManager.kt | 57 ++++++++++++++++--- 4 files changed, 70 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/org/linphone/compatibility/Api29Compatibility.kt b/app/src/main/java/org/linphone/compatibility/Api29Compatibility.kt index de6159120..a3525ea92 100644 --- a/app/src/main/java/org/linphone/compatibility/Api29Compatibility.kt +++ b/app/src/main/java/org/linphone/compatibility/Api29Compatibility.kt @@ -19,36 +19,16 @@ */ package org.linphone.compatibility -import android.app.Notification -import android.app.Service import android.net.Uri import android.os.Build import android.provider.MediaStore import androidx.annotation.RequiresApi -import org.linphone.core.tools.Log @RequiresApi(Build.VERSION_CODES.Q) class Api29Compatibility { companion object { private const val TAG = "[API 29 Compatibility]" - fun startServiceForeground( - service: Service, - id: Int, - notification: Notification, - foregroundServiceType: Int - ) { - try { - service.startForeground( - id, - notification, - foregroundServiceType - ) - } catch (e: Exception) { - Log.e("$TAG Can't start service as foreground! $e") - } - } - fun getMediaCollectionUri(isImage: Boolean, isVideo: Boolean, isAudio: Boolean): Uri { return when { isImage -> { diff --git a/app/src/main/java/org/linphone/compatibility/Api34Compatibility.kt b/app/src/main/java/org/linphone/compatibility/Api34Compatibility.kt index 89f6ccf27..54bb077cf 100644 --- a/app/src/main/java/org/linphone/compatibility/Api34Compatibility.kt +++ b/app/src/main/java/org/linphone/compatibility/Api34Compatibility.kt @@ -19,7 +19,9 @@ */ package org.linphone.compatibility +import android.app.Notification import android.app.NotificationManager +import android.app.Service import android.content.Context import android.content.Intent import android.net.Uri @@ -34,6 +36,23 @@ class Api34Compatibility { companion object { private const val TAG = "[API 34 Compatibility]" + fun startServiceForeground( + service: Service, + id: Int, + notification: Notification, + foregroundServiceType: Int + ) { + try { + service.startForeground( + id, + notification, + foregroundServiceType + ) + } catch (e: Exception) { + Log.e("$TAG Can't start service as foreground! $e") + } + } + fun hasFullScreenIntentPermission(context: Context): Boolean { val notificationManager = context.getSystemService(NotificationManager::class.java) as NotificationManager // See https://developer.android.com/reference/android/app/NotificationManager#canUseFullScreenIntent%28%29 diff --git a/app/src/main/java/org/linphone/compatibility/Compatibility.kt b/app/src/main/java/org/linphone/compatibility/Compatibility.kt index b4c528f71..13f5f3a75 100644 --- a/app/src/main/java/org/linphone/compatibility/Compatibility.kt +++ b/app/src/main/java/org/linphone/compatibility/Compatibility.kt @@ -45,8 +45,8 @@ class Compatibility { notification: Notification, foregroundServiceType: Int ) { - if (Version.sdkAboveOrEqual(Version.API29_ANDROID_10)) { - Api29Compatibility.startServiceForeground( + if (Version.sdkAboveOrEqual(Version.API34_ANDROID_14_UPSIDE_DOWN_CAKE)) { + Api34Compatibility.startServiceForeground( service, id, notification, diff --git a/app/src/main/java/org/linphone/notifications/NotificationsManager.kt b/app/src/main/java/org/linphone/notifications/NotificationsManager.kt index b2809806b..fa79a4b9d 100644 --- a/app/src/main/java/org/linphone/notifications/NotificationsManager.kt +++ b/app/src/main/java/org/linphone/notifications/NotificationsManager.kt @@ -88,6 +88,8 @@ class NotificationsManager @MainThread constructor(private val context: Context) private const val MISSED_CALL_ID = 10 } + private var currentForegroundServiceNotificationId = -1 + private val notificationManager: NotificationManagerCompat by lazy { NotificationManagerCompat.from(context) } @@ -359,7 +361,8 @@ class NotificationsManager @MainThread constructor(private val context: Context) stopCallForeground() } else { Log.i("$TAG At least a call is still running") - startCallForeground() + val call = core.currentCall ?: core.calls.first() + startCallForeground(call) } } } @@ -405,6 +408,10 @@ class NotificationsManager @MainThread constructor(private val context: Context) isIncoming ) notify(notifiable.notificationId, notification) + + if (notifiable.notificationId == currentForegroundServiceNotificationId) { + startCallForeground(call) + } } @WorkerThread @@ -449,8 +456,8 @@ class NotificationsManager @MainThread constructor(private val context: Context) } @WorkerThread - private fun startCallForeground() { - Log.i("$TAG Trying to start foreground Service using call notification") + private fun startCallForeground(call: Call) { + Log.i("$TAG Trying to start/update foreground Service using call notification") val channelId = context.getString(R.string.notification_channel_call_id) val channel = notificationManager.getNotificationChannel(channelId) @@ -473,17 +480,48 @@ class NotificationsManager @MainThread constructor(private val context: Context) } Log.i("$TAG Found notification [${notification.id}] for current Call") + var mask = Compatibility.FOREGROUND_SERVICE_TYPE_PHONE_CALL + val callState = call.state + if (!LinphoneUtils.isCallIncoming(callState) && !LinphoneUtils.isCallOutgoing(callState) && !LinphoneUtils.isCallEnding( + callState + ) + ) { + if (ActivityCompat.checkSelfPermission( + context, + Manifest.permission.RECORD_AUDIO + ) == PackageManager.PERMISSION_GRANTED + ) { + mask = mask or Compatibility.FOREGROUND_SERVICE_TYPE_MICROPHONE + Log.i( + "$TAG RECORD_AUDIO permission has been granted, adding FOREGROUND_SERVICE_TYPE_MICROPHONE" + ) + } + if (call.currentParams.isVideoEnabled) { + if (ActivityCompat.checkSelfPermission( + context, + Manifest.permission.CAMERA + ) == PackageManager.PERMISSION_GRANTED + ) { + mask = mask or Compatibility.FOREGROUND_SERVICE_TYPE_CAMERA + Log.i( + "$TAG CAMERA permission has been granted, adding FOREGROUND_SERVICE_TYPE_CAMERA" + ) + } + } + } + val service = coreService if (service != null) { - Log.i("$TAG Service found, starting it as foreground using notification") + Log.i( + "$TAG Service found, starting it as foreground using notification ID [${notifiable.notificationId}] with type(s) [$mask]" + ) Compatibility.startServiceForeground( service, notifiable.notificationId, notification.notification, - Compatibility.FOREGROUND_SERVICE_TYPE_PHONE_CALL - or Compatibility.FOREGROUND_SERVICE_TYPE_MICROPHONE - or Compatibility.FOREGROUND_SERVICE_TYPE_CAMERA + mask ) + currentForegroundServiceNotificationId = notifiable.notificationId } else { Log.w("$TAG Core Foreground Service hasn't started yet...") } @@ -493,9 +531,12 @@ class NotificationsManager @MainThread constructor(private val context: Context) private fun stopCallForeground() { val service = coreService if (service != null) { - Log.i("$TAG Stopping foreground service") + Log.i( + "$TAG Stopping foreground service (was using notification ID [$currentForegroundServiceNotificationId])" + ) service.stopForeground(STOP_FOREGROUND_REMOVE) service.stopSelf() + currentForegroundServiceNotificationId = -1 } else { Log.w("$TAG Can't stop foreground service & notif, no service was found") }