mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 18:56:44 -04:00
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:
parent
d5943856cd
commit
a48f90422a
@ -18,30 +18,44 @@
|
|||||||
|
|
||||||
package org.kiwix.kiwixmobile.core.downloader.downloadManager
|
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.app.Service
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
import com.tonyodev.fetch2.Download
|
import com.tonyodev.fetch2.Download
|
||||||
import com.tonyodev.fetch2.Error
|
import com.tonyodev.fetch2.Error
|
||||||
import com.tonyodev.fetch2.Fetch
|
import com.tonyodev.fetch2.Fetch
|
||||||
import com.tonyodev.fetch2.FetchListener
|
import com.tonyodev.fetch2.FetchListener
|
||||||
|
import com.tonyodev.fetch2.R
|
||||||
import com.tonyodev.fetch2.Status
|
import com.tonyodev.fetch2.Status
|
||||||
|
import com.tonyodev.fetch2.util.DEFAULT_NOTIFICATION_TIMEOUT_AFTER_RESET
|
||||||
import com.tonyodev.fetch2core.DownloadBlock
|
import com.tonyodev.fetch2core.DownloadBlock
|
||||||
import io.reactivex.Observable
|
|
||||||
import io.reactivex.disposables.Disposable
|
import io.reactivex.disposables.Disposable
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
import io.reactivex.subjects.PublishSubject
|
import io.reactivex.subjects.PublishSubject
|
||||||
import org.kiwix.kiwixmobile.core.CoreApp
|
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.dao.DownloadRoomDao
|
||||||
import org.kiwix.kiwixmobile.core.utils.files.Log
|
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
|
||||||
import java.util.concurrent.TimeUnit
|
import org.kiwix.kiwixmobile.core.utils.DOWNLOAD_NOTIFICATION_CHANNEL_ID
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class DownloadMonitorService : Service() {
|
class DownloadMonitorService : Service() {
|
||||||
private val updater = PublishSubject.create<() -> Unit>()
|
private val updater = PublishSubject.create<() -> Unit>()
|
||||||
private var updaterDisposable: Disposable? = null
|
private var updaterDisposable: Disposable? = null
|
||||||
private var monitoringDisposable: 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
|
@Inject
|
||||||
lateinit var fetch: Fetch
|
lateinit var fetch: Fetch
|
||||||
@ -60,42 +74,10 @@ class DownloadMonitorService : Service() {
|
|||||||
.inject(this)
|
.inject(this)
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
setupUpdater()
|
setupUpdater()
|
||||||
startMonitoringDownloads()
|
|
||||||
fetch.addListener(fetchListener, true)
|
fetch.addListener(fetchListener, true)
|
||||||
setForegroundNotification()
|
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() {
|
private fun setupUpdater() {
|
||||||
updaterDisposable = updater.subscribeOn(Schedulers.io()).observeOn(Schedulers.io()).subscribe(
|
updaterDisposable = updater.subscribeOn(Schedulers.io()).observeOn(Schedulers.io()).subscribe(
|
||||||
{ it.invoke() },
|
{ it.invoke() },
|
||||||
@ -203,8 +185,19 @@ class DownloadMonitorService : Service() {
|
|||||||
update(download)
|
update(download)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun update(download: Download, shouldSetForegroundNotification: Boolean = false) {
|
private fun update(
|
||||||
updater.onNext { downloadRoomDao.update(download) }.also {
|
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) {
|
if (shouldSetForegroundNotification) {
|
||||||
setForegroundNotification()
|
setForegroundNotification()
|
||||||
}
|
}
|
||||||
@ -212,12 +205,91 @@ class DownloadMonitorService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun delete(download: Download) {
|
private fun delete(download: Download) {
|
||||||
updater.onNext { downloadRoomDao.delete(download) }.also {
|
updater.onNext {
|
||||||
|
downloadRoomDao.delete(download)
|
||||||
setForegroundNotification()
|
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.
|
* Stops the foreground service, disposes of resources, and removes the Fetch listener.
|
||||||
*/
|
*/
|
||||||
@ -225,7 +297,7 @@ class DownloadMonitorService : Service() {
|
|||||||
monitoringDisposable?.dispose()
|
monitoringDisposable?.dispose()
|
||||||
updaterDisposable?.dispose()
|
updaterDisposable?.dispose()
|
||||||
fetch.removeListener(fetchListener)
|
fetch.removeListener(fetchListener)
|
||||||
stopForeground(STOP_FOREGROUND_REMOVE)
|
stopForeground(STOP_FOREGROUND_DETACH)
|
||||||
stopSelf()
|
stopSelf()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ const val EXTRA_IS_WIDGET_VOICE = "isWidgetVoice"
|
|||||||
const val HOTSPOT_SERVICE_CHANNEL_ID = "hotspotService"
|
const val HOTSPOT_SERVICE_CHANNEL_ID = "hotspotService"
|
||||||
const val OLD_PROVIDER_DOMAIN = "org.kiwix.zim.base"
|
const val OLD_PROVIDER_DOMAIN = "org.kiwix.zim.base"
|
||||||
const val READ_ALOUD_SERVICE_CHANNEL_ID = "readAloudService"
|
const val READ_ALOUD_SERVICE_CHANNEL_ID = "readAloudService"
|
||||||
|
const val DOWNLOAD_NOTIFICATION_CHANNEL_ID = "kiwixDownloadNotificationChannel"
|
||||||
|
|
||||||
// For Storage select dialog
|
// For Storage select dialog
|
||||||
const val INTERNAL_SELECT_POSITION = 0
|
const val INTERNAL_SELECT_POSITION = 0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user