WorkManager keep notification after work is done
Asked Answered
I

2

8

I want to display a notification while a Worker is running in the background. I can do that with something like the code below:

override suspend fun doWork(): Result {
    val manager = NotificationManagerCompat.from(applicationContext)
    val channel = "some_channel"
    val id = 15
    val builder = NotificationCompat.Builder(applicationContext, channel)

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
        manager.createNotificationChannel(NotificationChannel(channel, "DefaultName", NotificationManager.IMPORTANCE_LOW))

    builder
        .setOnlyAlertOnce(true)
        .setOngoing(true)
        .setAutoCancel(false)
        .setPriority(NotificationCompat.PRIORITY_HIGH)
        .setSmallIcon(android.R.drawable.ic_dialog_alert)
        .setTicker("Background Task")
        .setContentText("Starting")
        .setProgress(0, 0, true)

    setForeground(ForegroundInfo(id, builder.build()))

    delay(500)

    manager.notify(id, builder.setContentText("Progress A").setProgress(20, 0, false).build())
    for (i in 1..20) {
        delay(100)
        manager.notify(id, builder.setProgress(20, i, false).build())
    }

    delay(500)

    manager.notify(id, builder.setContentText("Progress B").setProgress(2, 0, false).build())
    delay(1000)
    manager.notify(id, builder.setProgress(2, 1, false).build())
    delay(1000)
    manager.notify(id, builder.setProgress(2, 2, false).build())

    delay(1000)

    manager.notify(id, builder.setContentText("Done!").setProgress(0, 0, false).build())

    delay(500)

    return Result.success()
}

But I also want to display the result of the worker in the notification and keep it until the user sees and clears it, yet the notification is always cleared at the end of the work.

How can I keep the notification alive? .setOngoing(true) and .setAutoCancel(false) didn't help.

Inflexed answered 15/3, 2020 at 14:15 Comment(0)
I
7

A much simpler way I think I found is to either notify the final notification with a different id (use .setOngoing(false)):

manager.notify(
    id + 1,
    builder.setContentText("Done!")
        .setAutoCancel(true)
        .setOngoing(false)
        .build()
)
return Result.success()

Or, send it after a bit of delay:

CoroutineScope(Main).launch {
    delay(200)
    manager.notify(
        id,
        builder.setContentText("Done!")
            .setAutoCancel(true)
            .setOngoing(false)
            .build()
    )
}
return Result.success()
Inflexed answered 23/3, 2020 at 21:52 Comment(0)
I
0

A workaround that I found, is to have a BroadcastReceiver that takes the final notification and shows it. This is possible because Notification extends Parcelable. Note: have the NotificationReceiver use a different notification id than the one your Worker is using, otherwise the Worker will close the notification.

class NotificationReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        if (intent.action == ACTION_SEND_NOTIFICATION) {
            val notification = intent.getParcelableExtra<Notification>(EXTRA_NOTIFICATION)
            val id = intent.getIntExtra(EXTRA_ID, DEFAULT_ID)
            if (notification == null)
                Log.e(TAG, "EXTRA_NOTIFICATION ($EXTRA_NOTIFICATION) was not provided!")
            else
                NotificationManagerCompat.from(context).notify(id, notification)
        }
    }

    companion object {
        const val TAG = "NotificationReceiver"

        const val ACTION_SEND_NOTIFICATION = "intent.action.SEND_NOTIFICATION"

        const val EXTRA_NOTIFICATION = "notification_parcel"
        const val EXTRA_ID = "notification_id"
        const val DEFAULT_ID = 1010
    }

}
<receiver android:name=".NotificationReceiver" android:enabled="true" />
    // At the end of doWork, before returning
    applicationContext.sendBroadcast(
        Intent(applicationContext, NotificationReceiver::class.java).setAction(
            NotificationReceiver.ACTION_SEND_NOTIFICATION
        ).putExtra(NotificationReceiver.EXTRA_NOTIFICATION, builder.build())
    )
Inflexed answered 16/3, 2020 at 17:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.