From ec3076ecb771276b0eb4e5df828b4f49d32cad3e Mon Sep 17 00:00:00 2001 From: Ambarish Manna Date: Thu, 27 Feb 2025 21:48:59 +0530 Subject: [PATCH 1/2] #4236 Improved download notification strings replacing default Fetch's string --- .../FetchDownloadNotificationManager.kt | 14 ++++++++++++++ core/src/main/res/values-qq/strings.xml | 5 +++++ core/src/main/res/values/strings.xml | 5 +++++ 3 files changed, 24 insertions(+) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/downloadManager/FetchDownloadNotificationManager.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/downloadManager/FetchDownloadNotificationManager.kt index 6c64661ec3..2eed6a6b19 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/downloadManager/FetchDownloadNotificationManager.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/downloadManager/FetchDownloadNotificationManager.kt @@ -111,6 +111,20 @@ class FetchDownloadNotificationManager @Inject constructor( } } + override fun getSubtitleText( + context: Context, + downloadNotification: DownloadNotification + ): String { + return when { + downloadNotification.isCompleted -> context.getString(R.string.fetch_notification_download_complete) + downloadNotification.isFailed -> context.getString(R.string.fetch_notification_download_failed) + downloadNotification.isPaused -> context.getString(R.string.fetch_notification_download_paused) + downloadNotification.isQueued -> context.getString(R.string.fetch_notification_download_resuming) + downloadNotification.etaInMilliSeconds < 0 -> context.getString(R.string.fetch_notification_download_downloading) + else -> super.getSubtitleText(context, downloadNotification) + } + } + @RequiresApi(Build.VERSION_CODES.O) private fun createChannel(channelId: String, context: Context) = NotificationChannel( diff --git a/core/src/main/res/values-qq/strings.xml b/core/src/main/res/values-qq/strings.xml index c07eefb559..a1359d0028 100644 --- a/core/src/main/res/values-qq/strings.xml +++ b/core/src/main/res/values-qq/strings.xml @@ -329,4 +329,9 @@ This is a text label, by clicking on this text user navigates to the app settings on their device. This message appears in the “Android Dialog” as an information message. When the user tries to run any functionality which requires notification access but the app does not have that access, then this message shows to the user to give notification access. {{Ignored}} + This appears in the "Android Notification" as a notification description message indicating the download is complete. + This appears in the "Android Notification" as a notification description message indicating the download failed. + This appears in the "Android Notification" as a notification description message indicating the download has been paused. + This appears in the "Android Notification" as a notification description message indicating a paused download is resuming. + This appears in the "Android Notification" as a notification description message indicating that a download is in progress. diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index e3c0d20111..328db5beff 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -402,4 +402,9 @@ Donate Today %s needs your help. Make a donation + Complete + Failed + Paused + Resuming + Downloading From 4a1da8b81e861291d5331737f4cb39037a8f6033 Mon Sep 17 00:00:00 2001 From: Ambarish Manna Date: Fri, 28 Feb 2025 20:37:56 +0530 Subject: [PATCH 2/2] #4236 Improved download notification strings replacing default Fetch's string --- .../downloadManager/DownloadMonitorService.kt | 11 +++-- .../FetchDownloadNotificationManager.kt | 48 ++++++++++++------- core/src/main/res/values-qq/strings.xml | 8 ++-- core/src/main/res/values/strings.xml | 12 ++--- 4 files changed, 47 insertions(+), 32 deletions(-) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/downloadManager/DownloadMonitorService.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/downloadManager/DownloadMonitorService.kt index a52b9fbb97..1532b338c2 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/downloadManager/DownloadMonitorService.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/downloadManager/DownloadMonitorService.kt @@ -33,7 +33,6 @@ import com.tonyodev.fetch2.Download import com.tonyodev.fetch2.Error import com.tonyodev.fetch2.Fetch import com.tonyodev.fetch2.FetchListener -import com.tonyodev.fetch2.R import com.tonyodev.fetch2.Status import com.tonyodev.fetch2.util.DEFAULT_NOTIFICATION_TIMEOUT_AFTER_RESET import com.tonyodev.fetch2core.DownloadBlock @@ -48,6 +47,8 @@ import org.kiwix.kiwixmobile.core.main.CoreMainActivity import org.kiwix.kiwixmobile.core.utils.DOWNLOAD_NOTIFICATION_CHANNEL_ID import javax.inject.Inject +const val THIRTY_TREE = 33 + class DownloadMonitorService : Service() { private val updater = PublishSubject.create<() -> Unit>() private var updaterDisposable: Disposable? = null @@ -265,7 +266,6 @@ class DownloadMonitorService : Service() { } } - @Suppress("MagicNumber") private fun showDownloadCompletedNotification(download: Download) { downloadNotificationChannel() val notificationBuilder = getNotificationBuilder(download.id) @@ -275,7 +275,7 @@ class DownloadMonitorService : Service() { notificationBuilder.setPriority(NotificationCompat.PRIORITY_DEFAULT) .setSmallIcon(android.R.drawable.stat_sys_download_done) .setContentTitle(notificationTitle) - .setContentText(getString(R.string.fetch_notification_download_complete)) + .setContentText(getString(string.complete)) .setOngoing(false) .setGroup(download.id.toString()) .setGroupSummary(false) @@ -287,7 +287,10 @@ class DownloadMonitorService : Service() { // notification. If we use the same ID, changing the foreground notification for another // ongoing download cancels the previous notification for that id, preventing the download // complete notification from being displayed. - val downloadCompleteNotificationId = download.id + 33 + val downloadCompleteNotificationId = download.id + THIRTY_TREE + // Cancel the complete download notification if already shown due to the application's + // lifecycle fetch. See #4237 for more details. + cancelNotificationForId(download.id - THIRTY_TREE) notificationManager.notify(downloadCompleteNotificationId, notificationBuilder.build()) } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/downloadManager/FetchDownloadNotificationManager.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/downloadManager/FetchDownloadNotificationManager.kt index 2eed6a6b19..d628ca86f4 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/downloadManager/FetchDownloadNotificationManager.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/downloadManager/FetchDownloadNotificationManager.kt @@ -58,10 +58,7 @@ import com.tonyodev.fetch2.R.drawable import com.tonyodev.fetch2.R.string import com.tonyodev.fetch2.Status import com.tonyodev.fetch2.util.DEFAULT_NOTIFICATION_TIMEOUT_AFTER_RESET -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.kiwix.kiwixmobile.core.CoreApp import org.kiwix.kiwixmobile.core.Intents @@ -116,11 +113,11 @@ class FetchDownloadNotificationManager @Inject constructor( downloadNotification: DownloadNotification ): String { return when { - downloadNotification.isCompleted -> context.getString(R.string.fetch_notification_download_complete) - downloadNotification.isFailed -> context.getString(R.string.fetch_notification_download_failed) - downloadNotification.isPaused -> context.getString(R.string.fetch_notification_download_paused) - downloadNotification.isQueued -> context.getString(R.string.fetch_notification_download_resuming) - downloadNotification.etaInMilliSeconds < 0 -> context.getString(R.string.fetch_notification_download_downloading) + downloadNotification.isCompleted -> context.getString(R.string.complete) + downloadNotification.isFailed -> context.getString(R.string.download_failed_state) + downloadNotification.isPaused -> context.getString(R.string.paused_state) + downloadNotification.isQueued -> context.getString(R.string.resuming_state) + downloadNotification.etaInMilliSeconds < 0 -> context.getString(R.string.downloading_state) else -> super.getSubtitleText(context, downloadNotification) } } @@ -198,6 +195,28 @@ class FetchDownloadNotificationManager @Inject constructor( else -> notificationBuilder.setTimeoutAfter(DEFAULT_NOTIFICATION_TIMEOUT_AFTER_RESET) } notificationCustomisation(downloadNotification, notificationBuilder, context) + // Remove the already shown notification if any, because fetch now pushes a + // download complete notification. + removeNotificationIfAlreadyShowingForCompletedDownload(downloadNotification) + } + + /** + * We are adding 33 to the groupId (which is the download ID) because the download + * complete notification is shown by DownloadMonitorService. If the application resumes + * just before the download completes, Fetch in the application might also push a + * download complete notification. + * + * To avoid duplicate notifications, we clear the previous notification if it is already shown. + * See #4237 for more information. + * + * @see DownloadMonitorService.showDownloadCompletedNotification + */ + private fun removeNotificationIfAlreadyShowingForCompletedDownload( + downloadNotification: DownloadNotification + ) { + if (downloadNotification.isCompleted) { + downloadNotificationManager.cancel(downloadNotification.groupId + THIRTY_TREE) + } } @SuppressLint("UnspecifiedImmutableFlag") @@ -226,14 +245,11 @@ class FetchDownloadNotificationManager @Inject constructor( fun showDownloadPauseNotification( fetch: Fetch, - download: Download, - dispatcher: CoroutineDispatcher = Dispatchers.IO + download: Download ) { - CoroutineScope(dispatcher).launch { - val notificationBuilder = getNotificationBuilder(download.id, download.id) - val cancelNotification = getCancelNotification(fetch, download, notificationBuilder) - downloadNotificationManager.notify(download.id, cancelNotification) - } + val notificationBuilder = getNotificationBuilder(download.id, download.id) + val cancelNotification = getCancelNotification(fetch, download, notificationBuilder) + downloadNotificationManager.notify(download.id, cancelNotification) } @Suppress("InjectDispatcher") @@ -251,7 +267,7 @@ class FetchDownloadNotificationManager @Inject constructor( return notificationBuilder.setPriority(NotificationCompat.PRIORITY_DEFAULT) .setSmallIcon(android.R.drawable.stat_sys_download_done) .setContentTitle(notificationTitle) - .setContentText(context.getString(string.fetch_notification_download_paused)) + .setContentText(context.getString(R.string.paused_state)) // Set the ongoing true so that could not cancel the pause notification. // However, on Android 14 and above user can cancel the notification by swipe right so we // can't control that see https://developer.android.com/about/versions/14/behavior-changes-all#non-dismissable-notifications diff --git a/core/src/main/res/values-qq/strings.xml b/core/src/main/res/values-qq/strings.xml index a1359d0028..be846b3ca7 100644 --- a/core/src/main/res/values-qq/strings.xml +++ b/core/src/main/res/values-qq/strings.xml @@ -329,9 +329,7 @@ This is a text label, by clicking on this text user navigates to the app settings on their device. This message appears in the “Android Dialog” as an information message. When the user tries to run any functionality which requires notification access but the app does not have that access, then this message shows to the user to give notification access. {{Ignored}} - This appears in the "Android Notification" as a notification description message indicating the download is complete. - This appears in the "Android Notification" as a notification description message indicating the download failed. - This appears in the "Android Notification" as a notification description message indicating the download has been paused. - This appears in the "Android Notification" as a notification description message indicating a paused download is resuming. - This appears in the "Android Notification" as a notification description message indicating that a download is in progress. + This text is shown to inform the user that the current state of download is resuming. + This text is shown to inform the user that the current state of download is actively in progress. + This text is shown to inform the user when a download has been failed. diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 328db5beff..d695ed7bff 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -177,7 +177,7 @@ Warn when entering external links Display popup to warn about additional costs or not working in offline links. Entering External Link! - You are entering an external link. This could lead to additional costs for data transfer or will just not work when you are offline. Do you want to continue? + You are entering an external link. This could lead to additional costs for data transfer or will just not work when you are offline.\nDo you want to continue? Do not ask anymore Selected languages: Other languages: @@ -335,7 +335,7 @@ Move Copying ZIM file… Moving ZIM file… - Kiwix requires the ZIM file to be in its own data directory. Do you want to copy or move it there? + Kiwix requires the ZIM file to be in its own data directory.\nDo you want to copy or move it there? Error in copying the ZIM file: %s. Be cautious: Ensure all ZIM chunks have been properly moved/copied! You can verify them inside “Android/media/org.kiwix…/” folder.\nOnce done, refresh the library screen by swiping down. The split ZIM file will then appear in your library. @@ -402,9 +402,7 @@ Donate Today %s needs your help. Make a donation - Complete - Failed - Paused - Resuming - Downloading + Resuming + Downloading + Failed