Fixed: The ZIM file was not opening when clicking on the download notification while the application was not running in the background.

This commit is contained in:
MohitMaliFtechiz 2024-12-24 16:36:19 +05:30
parent d5943856cd
commit a48f90422a
2 changed files with 113 additions and 40 deletions

View File

@ -18,30 +18,44 @@
package org.kiwix.kiwixmobile.core.downloader.downloadManager
import android.annotation.SuppressLint
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
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
import io.reactivex.Observable
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import io.reactivex.subjects.PublishSubject
import org.kiwix.kiwixmobile.core.CoreApp
import org.kiwix.kiwixmobile.core.Intents
import org.kiwix.kiwixmobile.core.R.string
import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao
import org.kiwix.kiwixmobile.core.utils.files.Log
import java.util.concurrent.TimeUnit
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
import org.kiwix.kiwixmobile.core.utils.DOWNLOAD_NOTIFICATION_CHANNEL_ID
import javax.inject.Inject
class DownloadMonitorService : Service() {
private val updater = PublishSubject.create<() -> Unit>()
private var updaterDisposable: Disposable? = null
private var monitoringDisposable: Disposable? = null
private val lock = Any()
private val notificationManager: NotificationManager by lazy {
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
}
private val downloadNotificationsBuilderMap = mutableMapOf<Int, NotificationCompat.Builder>()
@Inject
lateinit var fetch: Fetch
@ -60,42 +74,10 @@ class DownloadMonitorService : Service() {
.inject(this)
super.onCreate()
setupUpdater()
startMonitoringDownloads()
fetch.addListener(fetchListener, true)
setForegroundNotification()
}
/**
* Periodically checks if there are active downloads.
* If no downloads are active, it stops the foreground service.
*/
private fun startMonitoringDownloads() {
// Check if monitoring is already active. If it is, do nothing.
if (monitoringDisposable?.isDisposed == false) return
monitoringDisposable = Observable.interval(ZERO.toLong(), FIVE.toLong(), TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(
{
try {
synchronized(lock) {
fetch.hasActiveDownloads(includeAddedDownloads = true) {
if (!it) {
stopForegroundServiceForDownloads()
}
}
}
} catch (ignore: Exception) {
Log.e(
"DOWNLOAD_MONITOR",
"Couldn't get the downloads update. Original exception = $ignore"
)
}
},
Throwable::printStackTrace
)
}
private fun setupUpdater() {
updaterDisposable = updater.subscribeOn(Schedulers.io()).observeOn(Schedulers.io()).subscribe(
{ it.invoke() },
@ -203,8 +185,19 @@ class DownloadMonitorService : Service() {
update(download)
}
private fun update(download: Download, shouldSetForegroundNotification: Boolean = false) {
updater.onNext { downloadRoomDao.update(download) }.also {
private fun update(
download: Download,
shouldSetForegroundNotification: Boolean = false
) {
updater.onNext {
downloadRoomDao.update(download)
if (download.status == Status.COMPLETED) {
downloadRoomDao.getEntityForDownloadId(download.id.toLong())?.let {
showDownloadCompletedNotification(download)
// to move these downloads in NewBookDao.
downloadRoomDao.downloads().blockingFirst()
}
}
if (shouldSetForegroundNotification) {
setForegroundNotification()
}
@ -212,12 +205,91 @@ class DownloadMonitorService : Service() {
}
private fun delete(download: Download) {
updater.onNext { downloadRoomDao.delete(download) }.also {
updater.onNext {
downloadRoomDao.delete(download)
setForegroundNotification()
}
}
}
private fun showDownloadCompletedNotification(download: Download) {
downloadNotificationChannel()
val notificationBuilder = getNotificationBuilder(download.id)
val notificationTitle =
downloadRoomDao.getEntityForFileName(getDownloadNotificationTitle(download))?.title
?: download.file
notificationBuilder.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setSmallIcon(android.R.drawable.stat_sys_download_done)
.setContentTitle(notificationTitle)
.setContentText(getString(R.string.fetch_notification_download_complete))
.setOngoing(false)
.setGroup(download.id.toString())
.setGroupSummary(false)
.setProgress(ZERO, ZERO, false)
.setTimeoutAfter(DEFAULT_NOTIFICATION_TIMEOUT_AFTER_RESET)
.setContentIntent(getPendingIntentForDownloadedNotification(download))
.setAutoCancel(true)
notificationManager.notify(download.id, notificationBuilder.build())
}
private fun getPendingIntentForDownloadedNotification(download: Download): PendingIntent {
val internal = Intents.internal(CoreMainActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
putExtra(DOWNLOAD_NOTIFICATION_TITLE, getDownloadNotificationTitle(download))
}
return PendingIntent.getActivity(
this,
download.id,
internal,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
}
private fun downloadNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (notificationManager.getNotificationChannel(DOWNLOAD_NOTIFICATION_CHANNEL_ID) == null) {
notificationManager.createNotificationChannel(createChannel())
}
}
}
@RequiresApi(Build.VERSION_CODES.O)
private fun createChannel() =
NotificationChannel(
DOWNLOAD_NOTIFICATION_CHANNEL_ID,
getString(string.download_notification_channel_name),
NotificationManager.IMPORTANCE_HIGH
).apply {
setSound(null, null)
enableVibration(false)
}
@SuppressLint("RestrictedApi")
private fun getNotificationBuilder(notificationId: Int): NotificationCompat.Builder {
synchronized(downloadNotificationsBuilderMap) {
val notificationBuilder = downloadNotificationsBuilderMap[notificationId]
?: NotificationCompat.Builder(this, DOWNLOAD_NOTIFICATION_CHANNEL_ID)
downloadNotificationsBuilderMap[notificationId] = notificationBuilder
notificationBuilder
.setGroup("$notificationId")
.setStyle(null)
.setProgress(ZERO, ZERO, false)
.setContentTitle(null)
.setContentText(null)
.setContentIntent(null)
.setGroupSummary(false)
.setTimeoutAfter(DEFAULT_NOTIFICATION_TIMEOUT_AFTER_RESET)
.setOngoing(false)
.setOnlyAlertOnce(true)
.setSmallIcon(android.R.drawable.stat_sys_download_done)
.mActions.clear()
return@getNotificationBuilder notificationBuilder
}
}
private fun getDownloadNotificationTitle(download: Download): String =
fetchDownloadNotificationManager.getDownloadNotificationTitle(download)
/**
* Stops the foreground service, disposes of resources, and removes the Fetch listener.
*/
@ -225,7 +297,7 @@ class DownloadMonitorService : Service() {
monitoringDisposable?.dispose()
updaterDisposable?.dispose()
fetch.removeListener(fetchListener)
stopForeground(STOP_FOREGROUND_REMOVE)
stopForeground(STOP_FOREGROUND_DETACH)
stopSelf()
}

View File

@ -39,6 +39,7 @@ const val EXTRA_IS_WIDGET_VOICE = "isWidgetVoice"
const val HOTSPOT_SERVICE_CHANNEL_ID = "hotspotService"
const val OLD_PROVIDER_DOMAIN = "org.kiwix.zim.base"
const val READ_ALOUD_SERVICE_CHANNEL_ID = "readAloudService"
const val DOWNLOAD_NOTIFICATION_CHANNEL_ID = "kiwixDownloadNotificationChannel"
// For Storage select dialog
const val INTERNAL_SELECT_POSITION = 0