Move notification logic out of LibraryUpdateService

This commit is contained in:
arkon 2020-05-10 18:14:43 -04:00
parent dd1b5c7ea7
commit 530daeaa3a
5 changed files with 286 additions and 265 deletions

View File

@ -70,11 +70,11 @@ class BackupCreateService : Service() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
notifier = BackupNotifier(this) notifier = BackupNotifier(this)
wakeLock = acquireWakeLock(javaClass.name)
startForeground(Notifications.ID_BACKUP_PROGRESS, notifier.showBackupProgress().build()) startForeground(Notifications.ID_BACKUP_PROGRESS, notifier.showBackupProgress().build())
wakeLock = acquireWakeLock(javaClass.name)
} }
override fun stopService(name: Intent?): Boolean { override fun stopService(name: Intent?): Boolean {

View File

@ -124,11 +124,11 @@ class BackupRestoreService : Service() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
notifier = BackupNotifier(this) notifier = BackupNotifier(this)
wakeLock = acquireWakeLock(javaClass.name)
startForeground(Notifications.ID_RESTORE_PROGRESS, notifier.showRestoreProgress().build()) startForeground(Notifications.ID_RESTORE_PROGRESS, notifier.showRestoreProgress().build())
wakeLock = acquireWakeLock(javaClass.name)
} }
override fun stopService(name: Intent?): Boolean { override fun stopService(name: Intent?): Boolean {

View File

@ -0,0 +1,268 @@
package eu.kanade.tachiyomi.data.library
import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.bumptech.glide.Glide
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.util.lang.chop
import eu.kanade.tachiyomi.util.system.notification
import eu.kanade.tachiyomi.util.system.notificationBuilder
import eu.kanade.tachiyomi.util.system.notificationManager
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import uy.kohesive.injekt.injectLazy
class LibraryUpdateNotifier(private val context: Context) {
private val preferences: PreferencesHelper by injectLazy()
/**
* Pending intent of action that cancels the library update
*/
private val cancelIntent by lazy {
NotificationReceiver.cancelLibraryUpdatePendingBroadcast(context)
}
/**
* Bitmap of the app for notifications.
*/
private val notificationBitmap by lazy {
BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher)
}
/**
* Cached progress notification to avoid creating a lot.
*/
val progressNotificationBuilder by lazy {
context.notificationBuilder(Notifications.CHANNEL_LIBRARY) {
setContentTitle(context.getString(R.string.app_name))
setSmallIcon(R.drawable.ic_refresh_24dp)
setLargeIcon(notificationBitmap)
setOngoing(true)
setOnlyAlertOnce(true)
addAction(R.drawable.ic_close_24dp, context.getString(android.R.string.cancel), cancelIntent)
}
}
/**
* Shows the notification containing the currently updating manga and the progress.
*
* @param manga the manga that's being updated.
* @param current the current progress.
* @param total the total progress.
*/
fun showProgressNotification(manga: Manga, current: Int, total: Int) {
val title = if (preferences.hideNotificationContent()) {
context.getString(R.string.notification_check_updates)
} else {
manga.title
}
context.notificationManager.notify(
Notifications.ID_LIBRARY_PROGRESS,
progressNotificationBuilder
.setContentTitle(title)
.setProgress(total, current, false)
.build()
)
}
/**
* Shows the notification containing the result of the update done by the service.
*
* @param updates a list of manga with new updates.
*/
fun showUpdateNotifications(updates: List<Pair<Manga, Array<Chapter>>>) {
if (updates.isEmpty()) {
return
}
NotificationManagerCompat.from(context).apply {
// Parent group notification
notify(
Notifications.ID_NEW_CHAPTERS,
context.notification(Notifications.CHANNEL_NEW_CHAPTERS) {
setContentTitle(context.getString(R.string.notification_new_chapters))
if (updates.size == 1 && !preferences.hideNotificationContent()) {
setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN))
} else {
setContentText(context.resources.getQuantityString(R.plurals.notification_new_chapters_summary, updates.size, updates.size))
if (!preferences.hideNotificationContent()) {
setStyle(
NotificationCompat.BigTextStyle().bigText(
updates.joinToString("\n") {
it.first.title.chop(NOTIF_TITLE_MAX_LEN)
}
)
)
}
}
setSmallIcon(R.drawable.ic_tachi)
setLargeIcon(notificationBitmap)
setGroup(Notifications.GROUP_NEW_CHAPTERS)
setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY)
setGroupSummary(true)
priority = NotificationCompat.PRIORITY_HIGH
setContentIntent(getNotificationIntent())
setAutoCancel(true)
}
)
// Per-manga notification
if (!preferences.hideNotificationContent()) {
updates.forEach {
val (manga, chapters) = it
notify(manga.id.hashCode(), createNewChaptersNotification(manga, chapters))
}
}
}
}
private fun createNewChaptersNotification(manga: Manga, chapters: Array<Chapter>): Notification {
return context.notification(Notifications.CHANNEL_NEW_CHAPTERS) {
setContentTitle(manga.title)
val description = getNewChaptersDescription(chapters)
setContentText(description)
setStyle(NotificationCompat.BigTextStyle().bigText(description))
setSmallIcon(R.drawable.ic_tachi)
val icon = getMangaIcon(manga)
if (icon != null) {
setLargeIcon(icon)
}
setGroup(Notifications.GROUP_NEW_CHAPTERS)
setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY)
priority = NotificationCompat.PRIORITY_HIGH
// Open first chapter on tap
setContentIntent(NotificationReceiver.openChapterPendingActivity(context, manga, chapters.first()))
setAutoCancel(true)
// Mark chapters as read action
addAction(
R.drawable.ic_glasses_black_24dp, context.getString(R.string.action_mark_as_read),
NotificationReceiver.markAsReadPendingBroadcast(
context,
manga, chapters, Notifications.ID_NEW_CHAPTERS
)
)
// View chapters action
addAction(
R.drawable.ic_book_24dp, context.getString(R.string.action_view_chapters),
NotificationReceiver.openChapterPendingActivity(
context,
manga, Notifications.ID_NEW_CHAPTERS
)
)
}
}
/**
* Cancels the progress notification.
*/
fun cancelProgressNotification() {
context.notificationManager.cancel(Notifications.ID_LIBRARY_PROGRESS)
}
private fun getMangaIcon(manga: Manga): Bitmap? {
return try {
Glide.with(context)
.asBitmap()
.load(manga.toMangaThumbnail())
.dontTransform()
.centerCrop()
.circleCrop()
.override(
NOTIF_ICON_SIZE,
NOTIF_ICON_SIZE
)
.submit()
.get()
} catch (e: Exception) {
null
}
}
private fun getNewChaptersDescription(chapters: Array<Chapter>): String {
val formatter = DecimalFormat(
"#.###",
DecimalFormatSymbols()
.apply { decimalSeparator = '.' }
)
val displayableChapterNumbers = chapters
.filter { it.isRecognizedNumber }
.sortedBy { it.chapter_number }
.map { formatter.format(it.chapter_number) }
.toSet()
return when (displayableChapterNumbers.size) {
// No sensible chapter numbers to show (i.e. no chapters have parsed chapter number)
0 -> {
// "1 new chapter" or "5 new chapters"
context.resources.getQuantityString(R.plurals.notification_chapters_generic, chapters.size, chapters.size)
}
// Only 1 chapter has a parsed chapter number
1 -> {
val remaining = chapters.size - displayableChapterNumbers.size
if (remaining == 0) {
// "Chapter 2.5"
context.resources.getString(R.string.notification_chapters_single, displayableChapterNumbers.first())
} else {
// "Chapter 2.5 and 10 more"
context.resources.getString(R.string.notification_chapters_single_and_more, displayableChapterNumbers.first(), remaining)
}
}
// Everything else (i.e. multiple parsed chapter numbers)
else -> {
val shouldTruncate = displayableChapterNumbers.size > NOTIF_MAX_CHAPTERS
if (shouldTruncate) {
// "Chapters 1, 2.5, 3, 4, 5 and 10 more"
val remaining = displayableChapterNumbers.size - NOTIF_MAX_CHAPTERS
val joinedChapterNumbers = displayableChapterNumbers.take(NOTIF_MAX_CHAPTERS).joinToString(", ")
context.resources.getQuantityString(R.plurals.notification_chapters_multiple_and_more, remaining, joinedChapterNumbers, remaining)
} else {
// "Chapters 1, 2.5, 3"
context.resources.getString(R.string.notification_chapters_multiple, displayableChapterNumbers.joinToString(", "))
}
}
}
}
/**
* Returns an intent to open the main activity.
*/
private fun getNotificationIntent(): PendingIntent {
val intent = Intent(context, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
action = MainActivity.SHORTCUT_RECENTLY_UPDATED
}
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
companion object {
private const val NOTIF_MAX_CHAPTERS = 5
private const val NOTIF_TITLE_MAX_LEN = 45
private const val NOTIF_ICON_SIZE = 192
}
}

View File

@ -1,20 +1,11 @@
package eu.kanade.tachiyomi.data.library package eu.kanade.tachiyomi.data.library
import android.app.Notification
import android.app.PendingIntent
import android.app.Service import android.app.Service
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Build import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.os.PowerManager import android.os.PowerManager
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationCompat.GROUP_ALERT_SUMMARY
import androidx.core.app.NotificationManagerCompat
import com.bumptech.glide.Glide
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
@ -23,26 +14,17 @@ import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.DownloadService import eu.kanade.tachiyomi.data.download.DownloadService
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.data.library.LibraryUpdateRanker.rankingScheme import eu.kanade.tachiyomi.data.library.LibraryUpdateRanker.rankingScheme
import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Companion.start import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Companion.start
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
import eu.kanade.tachiyomi.data.notification.Notifications import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
import eu.kanade.tachiyomi.util.lang.chop
import eu.kanade.tachiyomi.util.prepUpdateCover import eu.kanade.tachiyomi.util.prepUpdateCover
import eu.kanade.tachiyomi.util.system.acquireWakeLock import eu.kanade.tachiyomi.util.system.acquireWakeLock
import eu.kanade.tachiyomi.util.system.isServiceRunning import eu.kanade.tachiyomi.util.system.isServiceRunning
import eu.kanade.tachiyomi.util.system.notification
import eu.kanade.tachiyomi.util.system.notificationBuilder
import eu.kanade.tachiyomi.util.system.notificationManager
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import java.util.ArrayList import java.util.ArrayList
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import rx.Observable import rx.Observable
@ -74,39 +56,13 @@ class LibraryUpdateService(
*/ */
private lateinit var wakeLock: PowerManager.WakeLock private lateinit var wakeLock: PowerManager.WakeLock
private lateinit var notifier: LibraryUpdateNotifier
/** /**
* Subscription where the update is done. * Subscription where the update is done.
*/ */
private var subscription: Subscription? = null private var subscription: Subscription? = null
/**
* Pending intent of action that cancels the library update
*/
private val cancelIntent by lazy {
NotificationReceiver.cancelLibraryUpdatePendingBroadcast(this)
}
/**
* Bitmap of the app for notifications.
*/
private val notificationBitmap by lazy {
BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
}
/**
* Cached progress notification to avoid creating a lot.
*/
private val progressNotificationBuilder by lazy {
notificationBuilder(Notifications.CHANNEL_LIBRARY) {
setContentTitle(getString(R.string.app_name))
setSmallIcon(R.drawable.ic_refresh_24dp)
setLargeIcon(notificationBitmap)
setOngoing(true)
setOnlyAlertOnce(true)
addAction(R.drawable.ic_close_24dp, getString(android.R.string.cancel), cancelIntent)
}
}
/** /**
* Defines what should be updated within a service execution. * Defines what should be updated within a service execution.
*/ */
@ -128,10 +84,6 @@ class LibraryUpdateService(
*/ */
const val KEY_TARGET = "target" const val KEY_TARGET = "target"
private const val NOTIF_MAX_CHAPTERS = 5
private const val NOTIF_TITLE_MAX_LEN = 45
private const val NOTIF_ICON_SIZE = 192
/** /**
* Returns the status of the service. * Returns the status of the service.
* *
@ -186,9 +138,10 @@ class LibraryUpdateService(
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
startForeground(Notifications.ID_LIBRARY_PROGRESS, progressNotificationBuilder.build()) notifier = LibraryUpdateNotifier(this)
wakeLock = acquireWakeLock(javaClass.name) wakeLock = acquireWakeLock(javaClass.name)
startForeground(Notifications.ID_LIBRARY_PROGRESS, notifier.progressNotificationBuilder.build())
} }
/** /**
@ -316,7 +269,7 @@ class LibraryUpdateService(
{ bySource -> { bySource ->
bySource bySource
// Notify manga that will update. // Notify manga that will update.
.doOnNext { showProgressNotification(it, count.andIncrement, mangaToUpdate.size) } .doOnNext { notifier.showProgressNotification(it, count.andIncrement, mangaToUpdate.size) }
.concatMap { manga -> .concatMap { manga ->
updateManga(manga) updateManga(manga)
// If there's any error, return empty update and continue. // If there's any error, return empty update and continue.
@ -358,7 +311,7 @@ class LibraryUpdateService(
// Notify result of the overall update. // Notify result of the overall update.
.doOnCompleted { .doOnCompleted {
if (newUpdates.isNotEmpty()) { if (newUpdates.isNotEmpty()) {
showUpdateNotifications(newUpdates) notifier.showUpdateNotifications(newUpdates)
if (downloadNew && hasDownloads) { if (downloadNew && hasDownloads) {
DownloadService.start(this) DownloadService.start(this)
} }
@ -368,7 +321,7 @@ class LibraryUpdateService(
Timber.e("Failed updating: ${failedUpdates.map { it.title }}") Timber.e("Failed updating: ${failedUpdates.map { it.title }}")
} }
cancelProgressNotification() notifier.cancelProgressNotification()
} }
.map { manga -> manga.first } .map { manga -> manga.first }
} }
@ -415,14 +368,14 @@ class LibraryUpdateService(
var count = 0 var count = 0
return Observable.from(mangaToUpdate) return Observable.from(mangaToUpdate)
.doOnNext { showProgressNotification(it, count++, mangaToUpdate.size) } .doOnNext { notifier.showProgressNotification(it, count++, mangaToUpdate.size) }
.map { manga -> .map { manga ->
manga.prepUpdateCover(coverCache) manga.prepUpdateCover(coverCache)
db.insertManga(manga).executeAsBlocking() db.insertManga(manga).executeAsBlocking()
manga manga
} }
.doOnCompleted { .doOnCompleted {
cancelProgressNotification() notifier.cancelProgressNotification()
} }
} }
@ -439,7 +392,7 @@ class LibraryUpdateService(
// Emit each manga and update it sequentially. // Emit each manga and update it sequentially.
return Observable.from(mangaToUpdate) return Observable.from(mangaToUpdate)
// Notify manga that will update. // Notify manga that will update.
.doOnNext { showProgressNotification(it, count++, mangaToUpdate.size) } .doOnNext { notifier.showProgressNotification(it, count++, mangaToUpdate.size) }
// Update the tracking details. // Update the tracking details.
.concatMap { manga -> .concatMap { manga ->
val tracks = db.getTracks(manga).executeAsBlocking() val tracks = db.getTracks(manga).executeAsBlocking()
@ -458,207 +411,7 @@ class LibraryUpdateService(
.map { manga } .map { manga }
} }
.doOnCompleted { .doOnCompleted {
cancelProgressNotification() notifier.cancelProgressNotification()
} }
} }
/**
* Shows the notification containing the currently updating manga and the progress.
*
* @param manga the manga that's being updated.
* @param current the current progress.
* @param total the total progress.
*/
private fun showProgressNotification(manga: Manga, current: Int, total: Int) {
val title = if (preferences.hideNotificationContent()) {
getString(R.string.notification_check_updates)
} else {
manga.title
}
notificationManager.notify(
Notifications.ID_LIBRARY_PROGRESS,
progressNotificationBuilder
.setContentTitle(title)
.setProgress(total, current, false)
.build()
)
}
/**
* Shows the notification containing the result of the update done by the service.
*
* @param updates a list of manga with new updates.
*/
private fun showUpdateNotifications(updates: List<Pair<Manga, Array<Chapter>>>) {
if (updates.isEmpty()) {
return
}
NotificationManagerCompat.from(this).apply {
// Parent group notification
notify(
Notifications.ID_NEW_CHAPTERS,
notification(Notifications.CHANNEL_NEW_CHAPTERS) {
setContentTitle(getString(R.string.notification_new_chapters))
if (updates.size == 1 && !preferences.hideNotificationContent()) {
setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN))
} else {
setContentText(resources.getQuantityString(R.plurals.notification_new_chapters_summary, updates.size, updates.size))
if (!preferences.hideNotificationContent()) {
setStyle(
NotificationCompat.BigTextStyle().bigText(
updates.joinToString("\n") {
it.first.title.chop(NOTIF_TITLE_MAX_LEN)
}
)
)
}
}
setSmallIcon(R.drawable.ic_tachi)
setLargeIcon(notificationBitmap)
setGroup(Notifications.GROUP_NEW_CHAPTERS)
setGroupAlertBehavior(GROUP_ALERT_SUMMARY)
setGroupSummary(true)
priority = NotificationCompat.PRIORITY_HIGH
setContentIntent(getNotificationIntent())
setAutoCancel(true)
}
)
// Per-manga notification
if (!preferences.hideNotificationContent()) {
updates.forEach {
val (manga, chapters) = it
notify(manga.id.hashCode(), createNewChaptersNotification(manga, chapters))
}
}
}
}
private fun createNewChaptersNotification(manga: Manga, chapters: Array<Chapter>): Notification {
return notification(Notifications.CHANNEL_NEW_CHAPTERS) {
setContentTitle(manga.title)
val description = getNewChaptersDescription(chapters)
setContentText(description)
setStyle(NotificationCompat.BigTextStyle().bigText(description))
setSmallIcon(R.drawable.ic_tachi)
val icon = getMangaIcon(manga)
if (icon != null) {
setLargeIcon(icon)
}
setGroup(Notifications.GROUP_NEW_CHAPTERS)
setGroupAlertBehavior(GROUP_ALERT_SUMMARY)
priority = NotificationCompat.PRIORITY_HIGH
// Open first chapter on tap
setContentIntent(NotificationReceiver.openChapterPendingActivity(this@LibraryUpdateService, manga, chapters.first()))
setAutoCancel(true)
// Mark chapters as read action
addAction(
R.drawable.ic_glasses_black_24dp, getString(R.string.action_mark_as_read),
NotificationReceiver.markAsReadPendingBroadcast(
this@LibraryUpdateService,
manga, chapters, Notifications.ID_NEW_CHAPTERS
)
)
// View chapters action
addAction(
R.drawable.ic_book_24dp, getString(R.string.action_view_chapters),
NotificationReceiver.openChapterPendingActivity(
this@LibraryUpdateService,
manga, Notifications.ID_NEW_CHAPTERS
)
)
}
}
/**
* Cancels the progress notification.
*/
private fun cancelProgressNotification() {
notificationManager.cancel(Notifications.ID_LIBRARY_PROGRESS)
}
private fun getMangaIcon(manga: Manga): Bitmap? {
return try {
Glide.with(this)
.asBitmap()
.load(manga.toMangaThumbnail())
.dontTransform()
.centerCrop()
.circleCrop()
.override(NOTIF_ICON_SIZE, NOTIF_ICON_SIZE)
.submit()
.get()
} catch (e: Exception) {
null
}
}
private fun getNewChaptersDescription(chapters: Array<Chapter>): String {
val formatter = DecimalFormat(
"#.###",
DecimalFormatSymbols()
.apply { decimalSeparator = '.' }
)
val displayableChapterNumbers = chapters
.filter { it.isRecognizedNumber }
.sortedBy { it.chapter_number }
.map { formatter.format(it.chapter_number) }
.toSet()
return when (displayableChapterNumbers.size) {
// No sensible chapter numbers to show (i.e. no chapters have parsed chapter number)
0 -> {
// "1 new chapter" or "5 new chapters"
resources.getQuantityString(R.plurals.notification_chapters_generic, chapters.size, chapters.size)
}
// Only 1 chapter has a parsed chapter number
1 -> {
val remaining = chapters.size - displayableChapterNumbers.size
if (remaining == 0) {
// "Chapter 2.5"
resources.getString(R.string.notification_chapters_single, displayableChapterNumbers.first())
} else {
// "Chapter 2.5 and 10 more"
resources.getString(R.string.notification_chapters_single_and_more, displayableChapterNumbers.first(), remaining)
}
}
// Everything else (i.e. multiple parsed chapter numbers)
else -> {
val shouldTruncate = displayableChapterNumbers.size > NOTIF_MAX_CHAPTERS
if (shouldTruncate) {
// "Chapters 1, 2.5, 3, 4, 5 and 10 more"
val remaining = displayableChapterNumbers.size - NOTIF_MAX_CHAPTERS
val joinedChapterNumbers = displayableChapterNumbers.take(NOTIF_MAX_CHAPTERS).joinToString(", ")
resources.getQuantityString(R.plurals.notification_chapters_multiple_and_more, remaining, joinedChapterNumbers, remaining)
} else {
// "Chapters 1, 2.5, 3"
resources.getString(R.string.notification_chapters_multiple, displayableChapterNumbers.joinToString(", "))
}
}
}
}
/**
* Returns an intent to open the main activity.
*/
private fun getNotificationIntent(): PendingIntent {
val intent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
action = MainActivity.SHORTCUT_RECENTLY_UPDATED
}
return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
} }

View File

@ -37,11 +37,11 @@ class UpdaterService : Service() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
notifier = UpdaterNotifier(this) notifier = UpdaterNotifier(this)
wakeLock = acquireWakeLock(javaClass.name)
startForeground(Notifications.ID_UPDATER, notifier.onDownloadStarted().build()) startForeground(Notifications.ID_UPDATER, notifier.onDownloadStarted().build())
wakeLock = acquireWakeLock(javaClass.name)
} }
/** /**