From 94a1238f282fa530cc8d8ebbe26050875fe1e462 Mon Sep 17 00:00:00 2001 From: parneet-guraya Date: Wed, 10 Jan 2024 01:35:27 +0530 Subject: [PATCH 1/3] create notification group using summary notification Signed-off-by: parneet-guraya --- .../talk/jobs/UploadAndShareFilesWorker.kt | 34 ++++++++++++++++++- .../nextcloud/talk/utils/NotificationUtils.kt | 3 ++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt index 404352225..9a42ea03f 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt @@ -168,7 +168,7 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa } if (uploadSuccess) { - mNotifyManager?.cancel(notificationId) + cancelNotification() return Result.success() } else if (isStopped) { // since work is cancelled the result would be ignored anyways @@ -230,6 +230,7 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa .setOngoing(true) .setProgress(HUNDRED_PERCENT, ZERO_PERCENT, false) .setPriority(NotificationCompat.PRIORITY_LOW) + .setGroup(NotificationUtils.KEY_UPLOAD_GROUP) .setContentIntent(getIntentToOpenConversation()) .addAction( R.drawable.ic_cancel_white_24dp, getResourceString(context, R.string.nc_cancel), @@ -237,8 +238,39 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa ) .build() + notificationId = SystemClock.uptimeMillis().toInt() mNotifyManager!!.notify(notificationId, notification) + // only need one summary notification but multiple upload worker can call it more than once but it is safe + // because of the same notification object config and id. + makeSummaryNotification() + } + + private fun makeSummaryNotification() { + // summary notification encapsulating the group of notifications + val summaryNotification = NotificationCompat.Builder( + context, NotificationUtils.NotificationChannels + .NOTIFICATION_CHANNEL_UPLOADS.name + ).setSmallIcon(R.drawable.upload_white) + .setGroup(NotificationUtils.KEY_UPLOAD_GROUP) + .setGroupSummary(true) + .build() + + mNotifyManager?.notify(NotificationUtils.GROUP_SUMMARY_NOTIFICATION_ID, summaryNotification) + } + + private fun getActiveUploadNotifications(): Int? { + // filter out active notifications that are upload notifications using group + return mNotifyManager?.activeNotifications?.filter { notification.group == NotificationUtils.KEY_UPLOAD_GROUP }?.size + } + + private fun cancelNotification() { + mNotifyManager?.cancel(notificationId) + // summary notification would not get dismissed automatically if child notifications are cancelled programmatically + // so check if only 1 notification left if yes then cancel it because that would be summary notification + if(getActiveUploadNotifications() == 1){ + mNotifyManager?.cancel(NotificationUtils.GROUP_SUMMARY_NOTIFICATION_ID) + } } private fun getNotificationContentText(percentage: Int): String { diff --git a/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt index ef9d0400a..6b42cc4e2 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt @@ -68,6 +68,9 @@ object NotificationUtils { // RemoteInput key - used for replies sent directly from notification const val KEY_DIRECT_REPLY = "key_direct_reply" + // notification group keys + const val KEY_UPLOAD_GROUP = "com.nextcloud.talk.utils.KEY_UPLOAD_GROUP" + const val GROUP_SUMMARY_NOTIFICATION_ID = -1 @TargetApi(Build.VERSION_CODES.O) private fun createNotificationChannel( context: Context, From d6201cf796bd0071a2bfc3dcd6f6322f70cb27ed Mon Sep 17 00:00:00 2001 From: parneet-guraya Date: Wed, 10 Jan 2024 01:56:36 +0530 Subject: [PATCH 2/3] use new builder for failure notification Signed-off-by: parneet-guraya --- .../talk/jobs/UploadAndShareFilesWorker.kt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt index 9a42ea03f..1033d6722 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt @@ -268,7 +268,7 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa mNotifyManager?.cancel(notificationId) // summary notification would not get dismissed automatically if child notifications are cancelled programmatically // so check if only 1 notification left if yes then cancel it because that would be summary notification - if(getActiveUploadNotifications() == 1){ + if (getActiveUploadNotifications() == 1) { mNotifyManager?.cancel(NotificationUtils.GROUP_SUMMARY_NOTIFICATION_ID) } } @@ -321,17 +321,20 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa getResourceString(context, R.string.nc_upload_failed_notification_text), fileName ) - notification = mBuilder!! + val failureNotification = NotificationCompat.Builder( + context, NotificationUtils.NotificationChannels + .NOTIFICATION_CHANNEL_UPLOADS.name + ) .setContentTitle(failureTitle) .setContentText(failureText) .setSmallIcon(R.drawable.baseline_error_24) + .setGroup(NotificationUtils.KEY_UPLOAD_GROUP) .setOngoing(false) .build() - // Cancel original notification mNotifyManager?.cancel(notificationId) - // Then show information about failure - mNotifyManager!!.notify(SystemClock.uptimeMillis().toInt(), notification) + // update current notification with failure info + mNotifyManager!!.notify(SystemClock.uptimeMillis().toInt(), failureNotification) } private fun getResourceString(context: Context, resourceId: Int): String { From d63fc58a62bf5fbf0d7719aca4b27d09b697773b Mon Sep 17 00:00:00 2001 From: parneet-guraya Date: Wed, 10 Jan 2024 01:59:22 +0530 Subject: [PATCH 3/3] remove class level notification property Signed-off-by: parneet-guraya --- .../talk/jobs/UploadAndShareFilesWorker.kt | 35 +++++++++++-------- .../nextcloud/talk/utils/NotificationUtils.kt | 1 + 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt index 1033d6722..f171b8f62 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt @@ -2,7 +2,9 @@ * Nextcloud Talk application * * @author Marcel Hibbe + * @author Parneet Singh * Copyright (C) 2021-2022 Marcel Hibbe + * Copyright (C) 2024-2025 Parneet Singh * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,7 +24,6 @@ package com.nextcloud.talk.jobs import android.Manifest import android.app.Activity -import android.app.Notification import android.app.NotificationManager import android.app.PendingIntent import android.content.Context @@ -86,7 +87,6 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa private var mNotifyManager: NotificationManager? = null private var mBuilder: NotificationCompat.Builder? = null - private lateinit var notification: Notification private var notificationId: Int = 0 lateinit var roomToken: String @@ -196,12 +196,12 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa } override fun onTransferProgress(percentage: Int) { - notification = mBuilder!! + val progressUpdateNotification = mBuilder!! .setProgress(HUNDRED_PERCENT, percentage, false) .setContentText(getNotificationContentText(percentage)) .build() - mNotifyManager!!.notify(notificationId, notification) + mNotifyManager!!.notify(notificationId, progressUpdateNotification) } override fun onStopped() { @@ -223,8 +223,8 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa } private fun initNotificationWithPercentage() { - notification = mBuilder!! - .setContentTitle(getResourceString(context, R.string.nc_upload_in_progess)) + val initNotification = mBuilder!! + .setContentTitle(context.resources.getString(R.string.nc_upload_in_progess)) .setContentText(getNotificationContentText(ZERO_PERCENT)) .setSmallIcon(R.drawable.upload_white) .setOngoing(true) @@ -233,14 +233,14 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa .setGroup(NotificationUtils.KEY_UPLOAD_GROUP) .setContentIntent(getIntentToOpenConversation()) .addAction( - R.drawable.ic_cancel_white_24dp, getResourceString(context, R.string.nc_cancel), + R.drawable.ic_cancel_white_24dp, + getResourceString(context, R.string.nc_cancel), getCancelUploadIntent() ) .build() - notificationId = SystemClock.uptimeMillis().toInt() - mNotifyManager!!.notify(notificationId, notification) + mNotifyManager!!.notify(notificationId, initNotification) // only need one summary notification but multiple upload worker can call it more than once but it is safe // because of the same notification object config and id. makeSummaryNotification() @@ -249,7 +249,8 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa private fun makeSummaryNotification() { // summary notification encapsulating the group of notifications val summaryNotification = NotificationCompat.Builder( - context, NotificationUtils.NotificationChannels + context, + NotificationUtils.NotificationChannels .NOTIFICATION_CHANNEL_UPLOADS.name ).setSmallIcon(R.drawable.upload_white) .setGroup(NotificationUtils.KEY_UPLOAD_GROUP) @@ -261,13 +262,18 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa private fun getActiveUploadNotifications(): Int? { // filter out active notifications that are upload notifications using group - return mNotifyManager?.activeNotifications?.filter { notification.group == NotificationUtils.KEY_UPLOAD_GROUP }?.size + return mNotifyManager?.activeNotifications?.filter { + it.notification.group == NotificationUtils + .KEY_UPLOAD_GROUP + }?.size } private fun cancelNotification() { mNotifyManager?.cancel(notificationId) - // summary notification would not get dismissed automatically if child notifications are cancelled programmatically - // so check if only 1 notification left if yes then cancel it because that would be summary notification + // summary notification would not get dismissed automatically + // if child notifications are cancelled programmatically + // so check if only 1 notification left if yes + // then cancel it (which is summary notification) if (getActiveUploadNotifications() == 1) { mNotifyManager?.cancel(NotificationUtils.GROUP_SUMMARY_NOTIFICATION_ID) } @@ -322,7 +328,8 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa fileName ) val failureNotification = NotificationCompat.Builder( - context, NotificationUtils.NotificationChannels + context, + NotificationUtils.NotificationChannels .NOTIFICATION_CHANNEL_UPLOADS.name ) .setContentTitle(failureTitle) diff --git a/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt index 6b42cc4e2..82c987544 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt @@ -71,6 +71,7 @@ object NotificationUtils { // notification group keys const val KEY_UPLOAD_GROUP = "com.nextcloud.talk.utils.KEY_UPLOAD_GROUP" const val GROUP_SUMMARY_NOTIFICATION_ID = -1 + @TargetApi(Build.VERSION_CODES.O) private fun createNotificationChannel( context: Context,