From f27da5c95db561d709cdfac099db5b8e6bee0f1b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 18 Dec 2023 11:12:15 +0100 Subject: [PATCH] Fixed microphone & camera while app is in background on Android 14 if keep app alive setting is enabled --- .../compatibility/Api34Compatibility.kt | 34 +++++++++++++++++-- .../linphone/compatibility/Compatibility.kt | 14 ++++++-- .../notifications/NotificationsManager.kt | 26 ++++++++++++-- 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/linphone/compatibility/Api34Compatibility.kt b/app/src/main/java/org/linphone/compatibility/Api34Compatibility.kt index 777ab4607..79c164dea 100644 --- a/app/src/main/java/org/linphone/compatibility/Api34Compatibility.kt +++ b/app/src/main/java/org/linphone/compatibility/Api34Compatibility.kt @@ -97,12 +97,42 @@ class Api34Compatibility { } } - fun startDataSyncForegroundService(service: Service, notifId: Int, notif: Notification) { + fun startDataSyncForegroundService( + service: Service, + notifId: Int, + notif: Notification, + isCallActive: Boolean + ) { + val mask = if (isCallActive) { + Log.i( + "[Api34 Compatibility] Trying to start service as foreground using at least FOREGROUND_SERVICE_TYPE_PHONE_CALL or FOREGROUND_SERVICE_TYPE_DATA_SYNC" + ) + var computeMask = ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL or ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC + if (PermissionHelper.get().hasCameraPermission()) { + Log.i( + "[Api34 Compatibility] CAMERA permission has been granted, adding FOREGROUND_SERVICE_TYPE_CAMERA" + ) + computeMask = computeMask or ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA + } + if (PermissionHelper.get().hasRecordAudioPermission()) { + Log.i( + "[Api34 Compatibility] RECORD_AUDIO permission has been granted, adding FOREGROUND_SERVICE_TYPE_MICROPHONE" + ) + computeMask = computeMask or ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE + } + computeMask + } else { + Log.i( + "[Api34 Compatibility] Trying to start service as foreground using only FOREGROUND_SERVICE_TYPE_DATA_SYNC because no call at the time" + ) + ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC + } + try { service.startForeground( notifId, notif, - ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC + mask ) } catch (fssnae: ForegroundServiceStartNotAllowedException) { Log.e("[Api34 Compatibility] Can't start service as foreground! $fssnae") diff --git a/app/src/main/java/org/linphone/compatibility/Compatibility.kt b/app/src/main/java/org/linphone/compatibility/Compatibility.kt index 091f6d752..c0557bbcd 100644 --- a/app/src/main/java/org/linphone/compatibility/Compatibility.kt +++ b/app/src/main/java/org/linphone/compatibility/Compatibility.kt @@ -303,9 +303,19 @@ class Compatibility { } } - fun startDataSyncForegroundService(service: Service, notifId: Int, notif: Notification) { + fun startDataSyncForegroundService( + service: Service, + notifId: Int, + notif: Notification, + isCallActive: Boolean + ) { if (Version.sdkAboveOrEqual(Version.API34_ANDROID_14_UPSIDE_DOWN_CAKE)) { - Api34Compatibility.startDataSyncForegroundService(service, notifId, notif) + Api34Compatibility.startDataSyncForegroundService( + service, + notifId, + notif, + isCallActive + ) } else { startForegroundService(service, notifId, notif) } diff --git a/app/src/main/java/org/linphone/notifications/NotificationsManager.kt b/app/src/main/java/org/linphone/notifications/NotificationsManager.kt index 58b5ec334..a65995421 100644 --- a/app/src/main/java/org/linphone/notifications/NotificationsManager.kt +++ b/app/src/main/java/org/linphone/notifications/NotificationsManager.kt @@ -552,10 +552,22 @@ class NotificationsManager(private val context: Context) { "[Notifications Manager] Starting service as foreground [$currentForegroundServiceNotificationId]" ) + val core = coreContext.core + val isActiveCall = if (core.callsNb > 0) { + val currentCall = core.currentCall ?: core.calls.first() + when (currentCall.state) { + Call.State.IncomingReceived, Call.State.IncomingEarlyMedia, Call.State.OutgoingInit, Call.State.OutgoingProgress, Call.State.OutgoingRinging -> false + else -> true + } + } else { + false + } + Compatibility.startDataSyncForegroundService( coreService, currentForegroundServiceNotificationId, - notification + notification, + isActiveCall ) } @@ -864,11 +876,15 @@ class NotificationsManager(private val context: Context) { Log.i("[Notifications Manager] Notifying call notification [${notifiable.notificationId}]") notify(notifiable.notificationId, notification) - if (service != null && (currentForegroundServiceNotificationId == 0 || currentForegroundServiceNotificationId == notifiable.notificationId)) { + val coreService = service + if (coreService != null && (currentForegroundServiceNotificationId == 0 || currentForegroundServiceNotificationId == notifiable.notificationId)) { Log.i( "[Notifications Manager] Notifying call notification for foreground service [${notifiable.notificationId}]" ) startForeground(notifiable.notificationId, notification, isCallActive) + } else if (coreService != null && currentForegroundServiceNotificationId == SERVICE_NOTIF_ID) { + // To add microphone & camera foreground service use to foreground service if needed + startForeground(coreService, useAutoStartDescription = false) } } @@ -881,6 +897,12 @@ class NotificationsManager(private val context: Context) { } else { Log.w("[Notifications Manager] No notification found for call ${call.callLog.callId}") } + + // To remove microphone & camera foreground service use to foreground service if needed + val coreService = service + if (coreService != null && currentForegroundServiceNotificationId == SERVICE_NOTIF_ID) { + startForeground(coreService, useAutoStartDescription = false) + } } /* Chat related */