Support notification channels. Fixes #995

This commit is contained in:
inorichi 2017-10-10 14:15:41 +02:00
parent deec65446f
commit d97aff85b3
11 changed files with 91 additions and 36 deletions

View File

@ -7,6 +7,7 @@ import android.support.multidex.MultiDex
import com.evernote.android.job.JobManager import com.evernote.android.job.JobManager
import eu.kanade.tachiyomi.data.backup.BackupCreatorJob import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.data.updater.UpdateCheckerJob import eu.kanade.tachiyomi.data.updater.UpdateCheckerJob
import eu.kanade.tachiyomi.util.LocaleHelper import eu.kanade.tachiyomi.util.LocaleHelper
import org.acra.ACRA import org.acra.ACRA
@ -34,6 +35,7 @@ open class App : Application() {
setupAcra() setupAcra()
setupJobManager() setupJobManager()
setupNotificationChannels()
LocaleHelper.updateConfiguration(this, resources.configuration) LocaleHelper.updateConfiguration(this, resources.configuration)
} }
@ -65,4 +67,8 @@ open class App : Application() {
} }
} }
protected open fun setupNotificationChannels() {
Notifications.createChannels(this)
}
} }

View File

@ -1,10 +0,0 @@
package eu.kanade.tachiyomi
object Constants {
const val NOTIFICATION_LIBRARY_PROGRESS_ID = 1
const val NOTIFICATION_LIBRARY_RESULT_ID = 2
const val NOTIFICATION_UPDATER_ID = 3
const val NOTIFICATION_DOWNLOAD_CHAPTER_ID = 4
const val NOTIFICATION_DOWNLOAD_CHAPTER_ERROR_ID = 5
const val NOTIFICATION_DOWNLOAD_IMAGE_ID = 6
}

View File

@ -3,12 +3,12 @@ package eu.kanade.tachiyomi.data.download
import android.content.Context import android.content.Context
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.support.v4.app.NotificationCompat import android.support.v4.app.NotificationCompat
import eu.kanade.tachiyomi.Constants
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.download.model.DownloadQueue import eu.kanade.tachiyomi.data.download.model.DownloadQueue
import eu.kanade.tachiyomi.data.notification.NotificationHandler import eu.kanade.tachiyomi.data.notification.NotificationHandler
import eu.kanade.tachiyomi.data.notification.NotificationReceiver import eu.kanade.tachiyomi.data.notification.NotificationReceiver
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.util.chop import eu.kanade.tachiyomi.util.chop
import eu.kanade.tachiyomi.util.notificationManager import eu.kanade.tachiyomi.util.notificationManager
import java.util.regex.Pattern import java.util.regex.Pattern
@ -23,7 +23,7 @@ internal class DownloadNotifier(private val context: Context) {
* Notification builder. * Notification builder.
*/ */
private val notification by lazy { private val notification by lazy {
NotificationCompat.Builder(context) NotificationCompat.Builder(context, Notifications.CHANNEL_DOWNLOADER)
.setLargeIcon(BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher)) .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher))
} }
@ -69,7 +69,7 @@ internal class DownloadNotifier(private val context: Context) {
* *
* @param id the id of the notification. * @param id the id of the notification.
*/ */
private fun NotificationCompat.Builder.show(id: Int = Constants.NOTIFICATION_DOWNLOAD_CHAPTER_ID) { private fun NotificationCompat.Builder.show(id: Int = Notifications.ID_DOWNLOAD_CHAPTER) {
context.notificationManager.notify(id, build()) context.notificationManager.notify(id, build())
} }
@ -86,7 +86,7 @@ internal class DownloadNotifier(private val context: Context) {
* those can only be dismissed by the user. * those can only be dismissed by the user.
*/ */
fun dismiss() { fun dismiss() {
context.notificationManager.cancel(Constants.NOTIFICATION_DOWNLOAD_CHAPTER_ID) context.notificationManager.cancel(Notifications.ID_DOWNLOAD_CHAPTER)
} }
/** /**
@ -262,7 +262,7 @@ internal class DownloadNotifier(private val context: Context) {
setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context)) setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context))
setProgress(0, 0, false) setProgress(0, 0, false)
} }
notification.show(Constants.NOTIFICATION_DOWNLOAD_CHAPTER_ERROR_ID) notification.show(Notifications.ID_DOWNLOAD_CHAPTER_ERROR)
// Reset download information // Reset download information
errorThrown = true errorThrown = true

View File

@ -10,7 +10,6 @@ import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.os.PowerManager import android.os.PowerManager
import android.support.v4.app.NotificationCompat import android.support.v4.app.NotificationCompat
import eu.kanade.tachiyomi.Constants
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
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
@ -20,6 +19,7 @@ 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.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.NotificationReceiver
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.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
@ -80,7 +80,7 @@ class LibraryUpdateService(
/** /**
* Cached progress notification to avoid creating a lot. * Cached progress notification to avoid creating a lot.
*/ */
private val progressNotification by lazy { NotificationCompat.Builder(this) private val progressNotification by lazy { NotificationCompat.Builder(this, Notifications.CHANNEL_LIBRARY)
.setSmallIcon(R.drawable.ic_refresh_white_24dp_img) .setSmallIcon(R.drawable.ic_refresh_white_24dp_img)
.setLargeIcon(notificationBitmap) .setLargeIcon(notificationBitmap)
.setOngoing(true) .setOngoing(true)
@ -417,7 +417,7 @@ class LibraryUpdateService(
* @param total the total progress. * @param total the total progress.
*/ */
private fun showProgressNotification(manga: Manga, current: Int, total: Int) { private fun showProgressNotification(manga: Manga, current: Int, total: Int) {
notificationManager.notify(Constants.NOTIFICATION_LIBRARY_PROGRESS_ID, progressNotification notificationManager.notify(Notifications.ID_LIBRARY_PROGRESS, progressNotification
.setContentTitle(manga.title) .setContentTitle(manga.title)
.setProgress(total, current, false) .setProgress(total, current, false)
.build()) .build())
@ -434,7 +434,7 @@ class LibraryUpdateService(
// Append new chapters from a previous, existing notification // Append new chapters from a previous, existing notification
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val previousNotification = notificationManager.activeNotifications val previousNotification = notificationManager.activeNotifications
.find { it.id == Constants.NOTIFICATION_LIBRARY_RESULT_ID } .find { it.id == Notifications.ID_LIBRARY_RESULT }
if (previousNotification != null) { if (previousNotification != null) {
val oldUpdates = previousNotification.notification.extras val oldUpdates = previousNotification.notification.extras
@ -446,7 +446,7 @@ class LibraryUpdateService(
} }
} }
notificationManager.notify(Constants.NOTIFICATION_LIBRARY_RESULT_ID, notification { notificationManager.notify(Notifications.ID_LIBRARY_RESULT, notification(Notifications.CHANNEL_LIBRARY) {
setSmallIcon(R.drawable.ic_book_white_24dp) setSmallIcon(R.drawable.ic_book_white_24dp)
setLargeIcon(notificationBitmap) setLargeIcon(notificationBitmap)
setContentTitle(getString(R.string.notification_new_chapters)) setContentTitle(getString(R.string.notification_new_chapters))
@ -466,7 +466,7 @@ class LibraryUpdateService(
* Cancels the progress notification. * Cancels the progress notification.
*/ */
private fun cancelProgressNotification() { private fun cancelProgressNotification() {
notificationManager.cancel(Constants.NOTIFICATION_LIBRARY_PROGRESS_ID) notificationManager.cancel(Notifications.ID_LIBRARY_PROGRESS)
} }
/** /**

View File

@ -5,7 +5,6 @@ import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Handler import android.os.Handler
import eu.kanade.tachiyomi.Constants
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Chapter
@ -50,7 +49,7 @@ class NotificationReceiver : BroadcastReceiver() {
ACTION_DELETE_IMAGE -> deleteImage(context, intent.getStringExtra(EXTRA_FILE_LOCATION), ACTION_DELETE_IMAGE -> deleteImage(context, intent.getStringExtra(EXTRA_FILE_LOCATION),
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)) intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1))
// Cancel library update and dismiss notification // Cancel library update and dismiss notification
ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context, Constants.NOTIFICATION_LIBRARY_PROGRESS_ID) ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context, Notifications.ID_LIBRARY_PROGRESS)
// Open reader activity // Open reader activity
ACTION_OPEN_CHAPTER -> { ACTION_OPEN_CHAPTER -> {
openChapter(context, intent.getLongExtra(EXTRA_MANGA_ID, -1), openChapter(context, intent.getLongExtra(EXTRA_MANGA_ID, -1),

View File

@ -0,0 +1,54 @@
package eu.kanade.tachiyomi.data.notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.os.Build
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.notificationManager
/**
* Class to manage the basic information of all the notifications used in the app.
*/
object Notifications {
/**
* Common notification channel and ids used anywhere.
*/
const val CHANNEL_COMMON = "common_channel"
const val ID_UPDATER = 1
const val ID_DOWNLOAD_IMAGE = 2
/**
* Notification channel and ids used by the library updater.
*/
const val CHANNEL_LIBRARY = "library_channel"
const val ID_LIBRARY_PROGRESS = 101
const val ID_LIBRARY_RESULT = 102
/**
* Notification channel and ids used by the downloader.
*/
const val CHANNEL_DOWNLOADER = "downloader_channel"
const val ID_DOWNLOAD_CHAPTER = 201
const val ID_DOWNLOAD_CHAPTER_ERROR = 202
/**
* Creates the notification channels introduced in Android Oreo.
*
* @param context The application context.
*/
fun createChannels(context: Context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
val channels = listOf(
NotificationChannel(CHANNEL_COMMON, context.getString(R.string.channel_common),
NotificationManager.IMPORTANCE_DEFAULT),
NotificationChannel(CHANNEL_LIBRARY, context.getString(R.string.channel_library),
NotificationManager.IMPORTANCE_DEFAULT),
NotificationChannel(CHANNEL_DOWNLOADER, context.getString(R.string.channel_downloader),
NotificationManager.IMPORTANCE_DEFAULT)
)
context.notificationManager.createNotificationChannels(channels)
}
}

View File

@ -6,8 +6,8 @@ import android.support.v4.app.NotificationCompat
import com.evernote.android.job.Job import com.evernote.android.job.Job
import com.evernote.android.job.JobManager import com.evernote.android.job.JobManager
import com.evernote.android.job.JobRequest import com.evernote.android.job.JobRequest
import eu.kanade.tachiyomi.Constants.NOTIFICATION_UPDATER_ID
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.util.notificationManager import eu.kanade.tachiyomi.util.notificationManager
class UpdateCheckerJob : Job() { class UpdateCheckerJob : Job() {
@ -23,7 +23,7 @@ class UpdateCheckerJob : Job() {
putExtra(UpdateDownloaderService.EXTRA_DOWNLOAD_URL, url) putExtra(UpdateDownloaderService.EXTRA_DOWNLOAD_URL, url)
} }
NotificationCompat.Builder(context).update { NotificationCompat.Builder(context, Notifications.CHANNEL_COMMON).update {
setContentTitle(context.getString(R.string.app_name)) setContentTitle(context.getString(R.string.app_name))
setContentText(context.getString(R.string.update_check_notification_update_available)) setContentText(context.getString(R.string.update_check_notification_update_available))
setSmallIcon(android.R.drawable.stat_sys_download_done) setSmallIcon(android.R.drawable.stat_sys_download_done)
@ -43,7 +43,7 @@ class UpdateCheckerJob : Job() {
fun NotificationCompat.Builder.update(block: NotificationCompat.Builder.() -> Unit) { fun NotificationCompat.Builder.update(block: NotificationCompat.Builder.() -> Unit) {
block() block()
context.notificationManager.notify(NOTIFICATION_UPDATER_ID, build()) context.notificationManager.notify(Notifications.ID_UPDATER, build())
} }
companion object { companion object {

View File

@ -4,10 +4,10 @@ import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.support.v4.app.NotificationCompat import android.support.v4.app.NotificationCompat
import eu.kanade.tachiyomi.Constants
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.notification.NotificationHandler import eu.kanade.tachiyomi.data.notification.NotificationHandler
import eu.kanade.tachiyomi.data.notification.NotificationReceiver import eu.kanade.tachiyomi.data.notification.NotificationReceiver
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.util.notificationManager import eu.kanade.tachiyomi.util.notificationManager
import java.io.File import java.io.File
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
@ -49,7 +49,7 @@ internal class UpdateDownloaderReceiver(val context: Context) : BroadcastReceive
/** /**
* Notification shown to user * Notification shown to user
*/ */
private val notification = NotificationCompat.Builder(context) private val notification = NotificationCompat.Builder(context, Notifications.CHANNEL_COMMON)
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
when (intent.getStringExtra(EXTRA_ACTION)) { when (intent.getStringExtra(EXTRA_ACTION)) {
@ -105,7 +105,7 @@ internal class UpdateDownloaderReceiver(val context: Context) : BroadcastReceive
// Cancel action // Cancel action
addAction(R.drawable.ic_clear_grey_24dp_img, addAction(R.drawable.ic_clear_grey_24dp_img,
context.getString(R.string.action_cancel), context.getString(R.string.action_cancel),
NotificationReceiver.dismissNotificationPendingBroadcast(context, Constants.NOTIFICATION_UPDATER_ID)) NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER))
} }
notification.show() notification.show()
} }
@ -128,7 +128,7 @@ internal class UpdateDownloaderReceiver(val context: Context) : BroadcastReceive
// Cancel action // Cancel action
addAction(R.drawable.ic_clear_grey_24dp_img, addAction(R.drawable.ic_clear_grey_24dp_img,
context.getString(R.string.action_cancel), context.getString(R.string.action_cancel),
NotificationReceiver.dismissNotificationPendingBroadcast(context, Constants.NOTIFICATION_UPDATER_ID)) NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER))
} }
notification.show() notification.show()
} }
@ -138,7 +138,7 @@ internal class UpdateDownloaderReceiver(val context: Context) : BroadcastReceive
* *
* @param id the id of the notification. * @param id the id of the notification.
*/ */
private fun NotificationCompat.Builder.show(id: Int = Constants.NOTIFICATION_UPDATER_ID) { private fun NotificationCompat.Builder.show(id: Int = Notifications.ID_UPDATER) {
context.notificationManager.notify(id, build()) context.notificationManager.notify(id, build())
} }
} }

View File

@ -5,10 +5,10 @@ import android.graphics.Bitmap
import android.support.v4.app.NotificationCompat import android.support.v4.app.NotificationCompat
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy
import eu.kanade.tachiyomi.Constants
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.notification.NotificationHandler import eu.kanade.tachiyomi.data.notification.NotificationHandler
import eu.kanade.tachiyomi.data.notification.NotificationReceiver import eu.kanade.tachiyomi.data.notification.NotificationReceiver
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.util.notificationManager import eu.kanade.tachiyomi.util.notificationManager
import java.io.File import java.io.File
@ -19,13 +19,13 @@ class SaveImageNotifier(private val context: Context) {
/** /**
* Notification builder. * Notification builder.
*/ */
private val notificationBuilder = NotificationCompat.Builder(context) private val notificationBuilder = NotificationCompat.Builder(context, Notifications.CHANNEL_COMMON)
/** /**
* Id of the notification. * Id of the notification.
*/ */
private val notificationId: Int private val notificationId: Int
get() = Constants.NOTIFICATION_DOWNLOAD_IMAGE_ID get() = Notifications.ID_DOWNLOAD_IMAGE
/** /**
* Called when image download/copy is complete. This method must be called in a background * Called when image download/copy is complete. This method must be called in a background

View File

@ -40,11 +40,12 @@ fun Context.toast(text: String?, duration: Int = Toast.LENGTH_SHORT) {
/** /**
* Helper method to create a notification. * Helper method to create a notification.
* *
* @param id the channel id.
* @param func the function that will execute inside the builder. * @param func the function that will execute inside the builder.
* @return a notification to be displayed or updated. * @return a notification to be displayed or updated.
*/ */
inline fun Context.notification(func: NotificationCompat.Builder.() -> Unit): Notification { inline fun Context.notification(channelId: String, func: NotificationCompat.Builder.() -> Unit): Notification {
val builder = NotificationCompat.Builder(this) val builder = NotificationCompat.Builder(this, channelId)
builder.func() builder.func()
return builder.build() return builder.build()
} }

View File

@ -439,4 +439,9 @@
<string name="download_notifier_text_only_wifi">No wifi connection available</string> <string name="download_notifier_text_only_wifi">No wifi connection available</string>
<string name="download_notifier_no_network">No network connection available</string> <string name="download_notifier_no_network">No network connection available</string>
<string name="download_notifier_download_paused">Download paused</string> <string name="download_notifier_download_paused">Download paused</string>
<!-- Notification channels -->
<string name="channel_common">Common</string>
<string name="channel_library">Library</string>
<string name="channel_downloader">Downloader</string>
</resources> </resources>