Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit e34a7b61 authored by cketti's avatar cketti Committed by GitHub
Browse files

Merge pull request #6158 from thundernest/fix_notification_crash

Display an error notification when creating a notification fails
parents 465be90a 1ff327ed
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -18,7 +18,9 @@ val coreNotificationModule = module {
        )
    }
    single { NotificationManagerCompat.from(get()) }
    single { NotificationHelper(context = get(), notificationManager = get(), channelUtils = get()) }
    single {
        NotificationHelper(context = get(), notificationManager = get(), notificationChannelManager = get(), resourceProvider = get())
    }
    single {
        NotificationChannelManager(
            preferences = get(),
@@ -82,8 +84,7 @@ val coreNotificationModule = module {
            notificationHelper = get(),
            actionCreator = get(),
            resourceProvider = get(),
            lockScreenNotificationCreator = get(),
            notificationManager = get()
            lockScreenNotificationCreator = get()
        )
    }
    factory {
@@ -92,8 +93,7 @@ val coreNotificationModule = module {
            actionCreator = get(),
            lockScreenNotificationCreator = get(),
            singleMessageNotificationCreator = get(),
            resourceProvider = get(),
            notificationManager = get()
            resourceProvider = get()
        )
    }
    factory { LockScreenNotificationCreator(notificationHelper = get(), resourceProvider = get()) }
+62 −9
Original line number Diff line number Diff line
package com.fsck.k9.notification

import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.provider.Settings
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.fsck.k9.Account
import com.fsck.k9.K9
import com.fsck.k9.helper.PendingIntentCompat
import com.fsck.k9.notification.NotificationChannelManager.ChannelType
import timber.log.Timber

class NotificationHelper(
    private val context: Context,
    private val notificationManager: NotificationManagerCompat,
    private val channelUtils: NotificationChannelManager
    private val notificationChannelManager: NotificationChannelManager,
    private val resourceProvider: NotificationResourceProvider
) {
    fun getContext(): Context {
        return context
@@ -21,14 +29,59 @@ class NotificationHelper(
        return notificationManager
    }

    fun createNotificationBuilder(
        account: Account,
        channelType: NotificationChannelManager.ChannelType
    ): NotificationCompat.Builder {
        return NotificationCompat.Builder(
            context,
            channelUtils.getChannelIdFor(account, channelType)
        )
    fun createNotificationBuilder(account: Account, channelType: ChannelType): NotificationCompat.Builder {
        val notificationChannel = notificationChannelManager.getChannelIdFor(account, channelType)
        return NotificationCompat.Builder(context, notificationChannel)
    }

    fun notify(account: Account, notificationId: Int, notification: Notification) {
        try {
            notificationManager.notify(notificationId, notification)
        } catch (e: SecurityException) {
            // When importing settings from another device, we could end up with a NotificationChannel that references a
            // non-existing notification sound. In that case, we end up with a SecurityException with a message similar
            // to this:
            // UID 123 does not have permission to content://media/external_primary/audio/media/42?title=Coins&canonical=1 [user 0]
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
                e.message?.contains("does not have permission to") == true
            ) {
                Timber.e(e, "Failed to create a notification for a new message")
                showNotifyErrorNotification(account)
            } else {
                throw e
            }
        }
    }

    private fun showNotifyErrorNotification(account: Account) {
        val title = resourceProvider.notifyErrorTitle()
        val text = resourceProvider.notifyErrorText()

        val messagesNotificationChannelId = notificationChannelManager.getChannelIdFor(account, ChannelType.MESSAGES)
        val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS).apply {
            putExtra(Settings.EXTRA_CHANNEL_ID, messagesNotificationChannelId)
            putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
        }

        val notificationSettingsPendingIntent =
            PendingIntent.getActivity(context, account.accountNumber, intent, PendingIntentCompat.FLAG_IMMUTABLE)

        val notification = createNotificationBuilder(account, ChannelType.MISCELLANEOUS)
            .setSmallIcon(resourceProvider.iconWarning)
            .setColor(account.chipColor)
            .setWhen(System.currentTimeMillis())
            .setAutoCancel(true)
            .setTicker(title)
            .setContentTitle(title)
            .setContentText(text)
            .setContentIntent(notificationSettingsPendingIntent)
            .setStyle(NotificationCompat.BigTextStyle().bigText(text))
            .setCategory(NotificationCompat.CATEGORY_ERROR)
            .setErrorAppearance()
            .build()

        val notificationId = NotificationIds.getNewMailSummaryNotificationId(account)
        notificationManager.notify(notificationId, notification)
    }

    companion object {
+3 −0
Original line number Diff line number Diff line
@@ -24,6 +24,9 @@ interface NotificationResourceProvider {
    fun authenticationErrorTitle(): String
    fun authenticationErrorBody(accountName: String): String

    fun notifyErrorTitle(): String
    fun notifyErrorText(): String

    fun certificateErrorTitle(): String
    fun certificateErrorTitle(accountName: String): String
    fun certificateErrorBody(): String
+2 −4
Original line number Diff line number Diff line
@@ -3,7 +3,6 @@ package com.fsck.k9.notification
import android.app.PendingIntent
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationCompat.WearableExtender
import androidx.core.app.NotificationManagerCompat
import com.fsck.k9.notification.NotificationChannelManager.ChannelType
import timber.log.Timber
import androidx.core.app.NotificationCompat.Builder as NotificationBuilder
@@ -12,8 +11,7 @@ internal class SingleMessageNotificationCreator(
    private val notificationHelper: NotificationHelper,
    private val actionCreator: NotificationActionCreator,
    private val resourceProvider: NotificationResourceProvider,
    private val lockScreenNotificationCreator: LockScreenNotificationCreator,
    private val notificationManager: NotificationManagerCompat
    private val lockScreenNotificationCreator: LockScreenNotificationCreator
) {
    fun createSingleNotification(
        baseNotificationData: BaseNotificationData,
@@ -52,7 +50,7 @@ internal class SingleMessageNotificationCreator(
                notification
            )
        }
        notificationManager.notify(notificationId, notification)
        notificationHelper.notify(account, notificationId, notification)
    }

    private fun NotificationBuilder.setBigText(text: CharSequence) = apply {
+2 −4
Original line number Diff line number Diff line
@@ -3,7 +3,6 @@ package com.fsck.k9.notification
import android.app.PendingIntent
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationCompat.WearableExtender
import androidx.core.app.NotificationManagerCompat
import com.fsck.k9.Account
import com.fsck.k9.notification.NotificationChannelManager.ChannelType
import com.fsck.k9.notification.NotificationIds.getNewMailSummaryNotificationId
@@ -15,8 +14,7 @@ internal class SummaryNotificationCreator(
    private val actionCreator: NotificationActionCreator,
    private val lockScreenNotificationCreator: LockScreenNotificationCreator,
    private val singleMessageNotificationCreator: SingleMessageNotificationCreator,
    private val resourceProvider: NotificationResourceProvider,
    private val notificationManager: NotificationManagerCompat
    private val resourceProvider: NotificationResourceProvider
) {
    fun createSummaryNotification(
        baseNotificationData: BaseNotificationData,
@@ -75,7 +73,7 @@ internal class SummaryNotificationCreator(
            .build()

        Timber.v("Creating inbox-style summary notification (silent=%b): %s", notificationData.isSilent, notification)
        notificationManager.notify(notificationData.notificationId, notification)
        notificationHelper.notify(account, notificationData.notificationId, notification)
    }

    private fun buildInboxSummaryText(accountName: String, notificationData: SummaryInboxNotificationData): String {
Loading