fix: guard foreground service start against missing RECORD_AUDIO permission
On SDK 36 starting a foreground service with type microphone requires RECORD_AUDIO to be granted at the moment startForeground() is called. When the permission isn't available (e.g. revoked between call start and peer connection) the service now falls back to a generic foreground type instead of crashing with a SecurityException. https://claude.ai/code/session_01WafqMofFQfWCQA5TcLvHRb
This commit is contained in:
+26
-10
@@ -20,17 +20,23 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.service.call
|
package com.vitorpamplona.amethyst.service.call
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
import android.content.pm.ServiceInfo
|
import android.content.pm.ServiceInfo
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.ServiceCompat
|
import androidx.core.app.ServiceCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
|
import com.vitorpamplona.quartz.utils.Log
|
||||||
|
|
||||||
|
private const val TAG = "CallForegroundService"
|
||||||
|
|
||||||
class CallForegroundService : Service() {
|
class CallForegroundService : Service() {
|
||||||
companion object {
|
companion object {
|
||||||
@@ -57,16 +63,26 @@ class CallForegroundService : Service() {
|
|||||||
ACTION_START -> {
|
ACTION_START -> {
|
||||||
val peerName = intent.getStringExtra(EXTRA_PEER_NAME) ?: "Unknown"
|
val peerName = intent.getStringExtra(EXTRA_PEER_NAME) ?: "Unknown"
|
||||||
val notification = buildNotification(peerName)
|
val notification = buildNotification(peerName)
|
||||||
ServiceCompat.startForeground(
|
val hasAudioPermission =
|
||||||
this,
|
ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) ==
|
||||||
NOTIFICATION_ID,
|
PackageManager.PERMISSION_GRANTED
|
||||||
notification,
|
try {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
val fgsType =
|
||||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE
|
if (hasAudioPermission && Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||||
} else {
|
ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE
|
||||||
0
|
} else {
|
||||||
},
|
0
|
||||||
)
|
}
|
||||||
|
ServiceCompat.startForeground(this, NOTIFICATION_ID, notification, fgsType)
|
||||||
|
} catch (e: SecurityException) {
|
||||||
|
Log.e(TAG, "Cannot start microphone foreground service, falling back", e)
|
||||||
|
try {
|
||||||
|
ServiceCompat.startForeground(this, NOTIFICATION_ID, notification, 0)
|
||||||
|
} catch (e2: Exception) {
|
||||||
|
Log.e(TAG, "Foreground service start failed entirely", e2)
|
||||||
|
stopSelf()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ACTION_STOP -> {
|
ACTION_STOP -> {
|
||||||
|
|||||||
Reference in New Issue
Block a user