Repository: thundernest/k-9
Issue: App crashes when creating a notification

### Checklist

- [X] I have used the search function to see if someone else has already submitted the same bug report.
- [X] I will describe the problem with as much detail as possible.

### App version

5.915

### Where did you get the app from?

Google Play

### Android version

Android 11 & 12

### Device model

 POCO F2 Pro, ZTE Z839V

### Steps to reproduce

Unknown. Probably configure a custom ringtone the app doesn't have permission to access.

### Expected behavior

No crash

### Actual behavior

Crash

### Logs

Stack trace retrieved via Google Play Developer console:

```text
java.lang.SecurityException: 
  at android.os.Parcel.createExceptionOrNull (Parcel.java:2376)
  at android.os.Parcel.createException (Parcel.java:2360)
  at android.os.Parcel.readException (Parcel.java:2343)
  at android.os.Parcel.readException (Parcel.java:2285)
  at android.app.INotificationManager$Stub$Proxy.enqueueNotificationWithTag (INotificationManager.java:3201)
  at android.app.NotificationManager.notifyAsUser (NotificationManager.java:584)
  at android.app.NotificationManager.notify (NotificationManager.java:534)
  at androidx.core.app.NotificationManagerCompat.notify (NotificationManagerCompat.java:223)
  at androidx.core.app.NotificationManagerCompat.notify (NotificationManagerCompat.java:205)
  at com.fsck.k9.notification.SingleMessageNotificationCreator.createSingleNotification (SingleMessageNotificationCreator.kt:55)
  at com.fsck.k9.notification.SingleMessageNotificationCreator.createSingleNotification$default (SingleMessageNotificationCreator.kt:18)
  at com.fsck.k9.notification.NewMailNotificationController.createSingleNotification (NewMailNotificationController.kt:79)
  at com.fsck.k9.notification.NewMailNotificationController.processNewMailNotificationData (NewMailNotificationController.kt:61)
  at com.fsck.k9.notification.NewMailNotificationController.restoreNewMailNotifications (NewMailNotificationController.kt:22)
  at com.fsck.k9.notification.NotificationController.restoreNewMailNotifications (NotificationController.kt:60)
  at com.fsck.k9.Core$restoreNotifications$1.invokeSuspend (Core.kt:85)
  at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33)
  at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.kt:106)
  at kotlinx.coroutines.internal.LimitedDispatcher.run (LimitedDispatcher.kt:39)
  at kotlinx.coroutines.scheduling.TaskImpl.run (Tasks.kt:95)
  at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely (CoroutineScheduler.kt:571)
  at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask (CoroutineScheduler.kt:750)
  at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker (CoroutineScheduler.kt:678)
  at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run (CoroutineScheduler.kt:665)
Caused by: android.os.RemoteException: 
  at com.android.server.uri.UriGrantsManagerService.checkGrantUriPermissionUnlocked (UriGrantsManagerService.java:1254)
  at com.android.server.uri.UriGrantsManagerService.checkGrantUriPermissionUnlocked (UriGrantsManagerService.java:1268)
  at com.android.server.uri.UriGrantsManagerService.access$900 (UriGrantsManagerService.java:118)
  at com.android.server.uri.UriGrantsManagerService$LocalService.checkGrantUriPermission (UriGrantsManagerService.java:1414)
  at com.android.server.notification.NotificationRecord.visitGrantableUri (NotificationRecord.java:1310)
```

Changed files:
app/core/src/main/java/com/fsck/k9/notification/SyncNotificationController.kt
app/core/src/main/java/com/fsck/k9/notification/CertificateErrorNotificationController.kt
app/core/src/main/java/com/fsck/k9/notification/SendFailedNotificationController.kt
app/core/src/main/java/com/fsck/k9/notification/AuthenticationErrorNotificationController.kt
app/core/src/main/java/com/fsck/k9/notification/NotificationHelper.kt

diff --git a/app/core/src/main/java/com/fsck/k9/notification/AuthenticationErrorNotificationController.kt b/app/core/src/main/java/com/fsck/k9/notification/AuthenticationErrorNotificationController.kt
index 2231a3fd3..332c7dbb4 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/AuthenticationErrorNotificationController.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/AuthenticationErrorNotificationController.kt
@@ -30,15 +30,7 @@ internal open class AuthenticationErrorNotificationController(
             .setStyle(NotificationCompat.BigTextStyle().bigText(text))
             .setPublicVersion(createLockScreenNotification(account))
             .setCategory(NotificationCompat.CATEGORY_ERROR)
-
-        notificationHelper.configureNotification(
-            builder = notificationBuilder,
-            ringtone = null,
-            vibrationPattern = null,
-            ledColor = NotificationHelper.NOTIFICATION_LED_FAILURE_COLOR,
-            ledSpeed = NotificationHelper.NOTIFICATION_LED_BLINK_FAST,
-            ringAndVibrate = true
-        )
+            .setErrorAppearance()
 
         notificationManager.notify(notificationId, notificationBuilder.build())
     }
diff --git a/app/core/src/main/java/com/fsck/k9/notification/CertificateErrorNotificationController.kt b/app/core/src/main/java/com/fsck/k9/notification/CertificateErrorNotificationController.kt
index ba657a240..bae4f7e45 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/CertificateErrorNotificationController.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/CertificateErrorNotificationController.kt
@@ -30,15 +30,7 @@ internal open class CertificateErrorNotificationController(
             .setStyle(NotificationCompat.BigTextStyle().bigText(text))
             .setPublicVersion(createLockScreenNotification(account))
             .setCategory(NotificationCompat.CATEGORY_ERROR)
-
-        notificationHelper.configureNotification(
-            builder = notificationBuilder,
-            ringtone = null,
-            vibrationPattern = null,
-            ledColor = NotificationHelper.NOTIFICATION_LED_FAILURE_COLOR,
-            ledSpeed = NotificationHelper.NOTIFICATION_LED_BLINK_FAST,
-            ringAndVibrate = true
-        )
+            .setErrorAppearance()
 
         notificationManager.notify(notificationId, notificationBuilder.build())
     }
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationHelper.kt b/app/core/src/main/java/com/fsck/k9/notification/NotificationHelper.kt
index 4b85b884c..c51736c6c 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/NotificationHelper.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/NotificationHelper.kt
@@ -2,7 +2,7 @@ package com.fsck.k9.notification
 
 import android.content.Context
 import android.net.Uri
-import android.text.TextUtils
+import android.os.Build
 import androidx.core.app.NotificationCompat
 import androidx.core.app.NotificationManagerCompat
 import com.fsck.k9.Account
@@ -13,47 +13,6 @@ class NotificationHelper(
     private val notificationManager: NotificationManagerCompat,
     private val channelUtils: NotificationChannelManager
 ) {
-    fun configureNotification(
-        builder: NotificationCompat.Builder,
-        ringtone: String?,
-        vibrationPattern: LongArray?,
-        ledColor: Int?,
-        ledSpeed: Int,
-        ringAndVibrate: Boolean
-    ) {
-
-        if (K9.isQuietTime) {
-            builder.setNotificationSilent()
-            return
-        }
-
-        if (ringAndVibrate) {
-            if (ringtone != null && !TextUtils.isEmpty(ringtone)) {
-                builder.setSound(Uri.parse(ringtone))
-            }
-
-            if (vibrationPattern != null) {
-                builder.setVibrate(vibrationPattern)
-            }
-        } else {
-            builder.setNotificationSilent()
-        }
-
-        if (ledColor != null) {
-            val ledOnMS: Int
-            val ledOffMS: Int
-            if (ledSpeed == NOTIFICATION_LED_BLINK_SLOW) {
-                ledOnMS = NOTIFICATION_LED_ON_TIME
-                ledOffMS = NOTIFICATION_LED_OFF_TIME
-            } else {
-                ledOnMS = NOTIFICATION_LED_FAST_ON_TIME
-                ledOffMS = NOTIFICATION_LED_FAST_OFF_TIME
-            }
-
-            builder.setLights(ledColor, ledOnMS, ledOffMS)
-        }
-    }
-
     fun getContext(): Context {
         return context
     }
@@ -75,12 +34,22 @@ class NotificationHelper(
     companion object {
         internal const val NOTIFICATION_LED_ON_TIME = 500
         internal const val NOTIFICATION_LED_OFF_TIME = 2000
-        private const val NOTIFICATION_LED_FAST_ON_TIME = 100
-        private const val NOTIFICATION_LED_FAST_OFF_TIME = 100
+        internal const val NOTIFICATION_LED_FAST_ON_TIME = 100
+        internal const val NOTIFICATION_LED_FAST_OFF_TIME = 100
 
-        internal const val NOTIFICATION_LED_BLINK_SLOW = 0
-        internal const val NOTIFICATION_LED_BLINK_FAST = 1
-        internal const val NOTIFICATION_LED_FAILURE_COLOR = -0x10000
+        internal const val NOTIFICATION_LED_FAILURE_COLOR = 0xFFFF0000L.toInt()
+    }
+}
+
+internal fun NotificationCompat.Builder.setErrorAppearance(): NotificationCompat.Builder = apply {
+    setSilent(true)
+
+    if (!K9.isQuietTime) {
+        setLights(
+            NotificationHelper.NOTIFICATION_LED_FAILURE_COLOR,
+            NotificationHelper.NOTIFICATION_LED_FAST_ON_TIME,
+            NotificationHelper.NOTIFICATION_LED_FAST_OFF_TIME
+        )
     }
 }
 
@@ -90,7 +59,7 @@ internal fun NotificationCompat.Builder.setAppearance(
 ): NotificationCompat.Builder = apply {
     if (silent) {
         setSilent(true)
-    } else {
+    } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
         if (!appearance.ringtone.isNullOrEmpty()) {
             setSound(Uri.parse(appearance.ringtone))
         }
diff --git a/app/core/src/main/java/com/fsck/k9/notification/SendFailedNotificationController.kt b/app/core/src/main/java/com/fsck/k9/notification/SendFailedNotificationController.kt
index a75b73f5a..3dd80b75e 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/SendFailedNotificationController.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/SendFailedNotificationController.kt
@@ -42,15 +42,7 @@ internal class SendFailedNotificationController(
             .setStyle(NotificationCompat.BigTextStyle().bigText(text))
             .setPublicVersion(createLockScreenNotification(account))
             .setCategory(NotificationCompat.CATEGORY_ERROR)
-
-        notificationHelper.configureNotification(
-            builder = notificationBuilder,
-            ringtone = null,
-            vibrationPattern = null,
-            ledColor = NotificationHelper.NOTIFICATION_LED_FAILURE_COLOR,
-            ledSpeed = NotificationHelper.NOTIFICATION_LED_BLINK_FAST,
-            ringAndVibrate = true
-        )
+            .setErrorAppearance()
 
         notificationManager.notify(notificationId, notificationBuilder.build())
     }
diff --git a/app/core/src/main/java/com/fsck/k9/notification/SyncNotificationController.kt b/app/core/src/main/java/com/fsck/k9/notification/SyncNotificationController.kt
index fa318ffa9..3140fb813 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/SyncNotificationController.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/SyncNotificationController.kt
@@ -6,8 +6,6 @@ import androidx.core.app.NotificationManagerCompat
 import com.fsck.k9.Account
 import com.fsck.k9.mailstore.LocalFolder
 
-private const val NOTIFICATION_LED_WHILE_SYNCING = false
-
 internal class SyncNotificationController(
     private val notificationHelper: NotificationHelper,
     private val actionBuilder: NotificationActionCreator,
@@ -36,17 +34,6 @@ internal class SyncNotificationController(
             .setContentIntent(showMessageListPendingIntent)
             .setPublicVersion(createSendingLockScreenNotification(account))
 
-        if (NOTIFICATION_LED_WHILE_SYNCING) {
-            notificationHelper.configureNotification(
-                builder = notificationBuilder,
-                ringtone = null,
-                vibrationPattern = null,
-                ledColor = account.notificationSettings.light.toColor(account),
-                ledSpeed = NotificationHelper.NOTIFICATION_LED_BLINK_FAST,
-                ringAndVibrate = true
-            )
-        }
-
         notificationManager.notify(notificationId, notificationBuilder.build())
     }
 
@@ -83,17 +70,6 @@ internal class SyncNotificationController(
             .setPublicVersion(createFetchingMailLockScreenNotification(account))
             .setCategory(NotificationCompat.CATEGORY_SERVICE)
 
-        if (NOTIFICATION_LED_WHILE_SYNCING) {
-            notificationHelper.configureNotification(
-                builder = notificationBuilder,
-                ringtone = null,
-                vibrationPattern = null,
-                ledColor = account.notificationSettings.light.toColor(account),
-                ledSpeed = NotificationHelper.NOTIFICATION_LED_BLINK_FAST,
-                ringAndVibrate = true
-            )
-        }
-
         notificationManager.notify(notificationId, notificationBuilder.build())
     }
 
@@ -113,17 +89,6 @@ internal class SyncNotificationController(
             .setPublicVersion(createFetchingMailLockScreenNotification(account))
             .setCategory(NotificationCompat.CATEGORY_SERVICE)
 
-        if (NOTIFICATION_LED_WHILE_SYNCING) {
-            notificationHelper.configureNotification(
-                builder = notificationBuilder,
-                ringtone = null,
-                vibrationPattern = null,
-                ledColor = account.notificationSettings.light.toColor(account),
-                ledSpeed = NotificationHelper.NOTIFICATION_LED_BLINK_FAST,
-                ringAndVibrate = true
-            )
-        }
-
         notificationManager.notify(notificationId, notificationBuilder.build())
     }