Update progress notification now shows progress + fixes

such as trying to update all extensions while app is fully dead or it trying to install old extensions
Al
This commit is contained in:
Jays2Kings 2021-07-17 22:25:04 -04:00
parent ea0d8224b2
commit 31d16f421a
7 changed files with 43 additions and 15 deletions

View File

@ -47,6 +47,8 @@ object Notifications {
*/ */
const val CHANNEL_UPDATES_TO_EXTS = "updates_ext_channel" const val CHANNEL_UPDATES_TO_EXTS = "updates_ext_channel"
const val ID_UPDATES_TO_EXTS = -401 const val ID_UPDATES_TO_EXTS = -401
const val CHANNEL_EXT_PROGRESS = "ext_update_progress_channel"
const val ID_EXTENSION_PROGRESS = -402 const val ID_EXTENSION_PROGRESS = -402
private const val GROUP_BACKUP_RESTORE = "group_backup_restore" private const val GROUP_BACKUP_RESTORE = "group_backup_restore"
@ -136,5 +138,16 @@ object Notifications {
) )
) )
context.notificationManager.createNotificationChannels(channels) context.notificationManager.createNotificationChannels(channels)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val channel = NotificationChannel(
CHANNEL_EXT_PROGRESS,
context.getString(R.string.updating_extensions),
NotificationManager.IMPORTANCE_LOW
).apply {
setShowBadge(false)
setSound(null, null)
}
context.notificationManager.createNotificationChannel(channel)
}
} }
} }

View File

@ -50,12 +50,12 @@ class ExtensionInstallNotifier(private val context: Context) {
* @param current the current progress. * @param current the current progress.
* @param total the total progress. * @param total the total progress.
*/ */
fun showProgressNotification() { fun showProgressNotification(progress: Int, max: Int) {
context.notificationManager.notify( context.notificationManager.notify(
Notifications.ID_EXTENSION_PROGRESS, Notifications.ID_EXTENSION_PROGRESS,
progressNotificationBuilder progressNotificationBuilder
.setContentTitle(context.getString(R.string.updating_extensions)) .setContentTitle(context.getString(R.string.updating_extensions))
.setProgress(0, 0, true) .setProgress(max, progress, progress == 0)
.build() .build()
) )
} }

View File

@ -63,10 +63,19 @@ class ExtensionInstallService(
val list = intent.getParcelableArrayListExtra<ExtensionInfo>(KEY_EXTENSION) val list = intent.getParcelableArrayListExtra<ExtensionInfo>(KEY_EXTENSION)
?: return START_NOT_STICKY ?: return START_NOT_STICKY
var installed = 0
job = serviceScope.launch { job = serviceScope.launch {
val results = list.map { val results = list.map {
async { async {
installExtension(it) requestSemaphore.withPermit {
extensionManager.installExtension(it, serviceScope)
.collect {
if (it.first.isCompleted()) {
installed++
}
notifier.showProgressNotification(installed, list.size)
}
}
} }
} }
results.awaitAll() results.awaitAll()
@ -76,15 +85,6 @@ class ExtensionInstallService(
return START_REDELIVER_INTENT return START_REDELIVER_INTENT
} }
suspend fun installExtension(extension: ExtensionInfo) {
requestSemaphore.withPermit {
extensionManager.installExtension(extension, serviceScope)
.collect {
notifier.showProgressNotification()
}
}
}
/** /**
* Method called when the service is created. It injects dagger dependencies and acquire * Method called when the service is created. It injects dagger dependencies and acquire
* the wake lock. * the wake lock.

View File

@ -47,6 +47,7 @@ class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParam
private fun createUpdateNotification(extensions: List<Extension.Available>) { private fun createUpdateNotification(extensions: List<Extension.Available>) {
val preferences: PreferencesHelper by injectLazy() val preferences: PreferencesHelper by injectLazy()
preferences.extensionUpdatesCount().set(extensions.size) preferences.extensionUpdatesCount().set(extensions.size)
// Not doing this yet since users will get prompted while device is idle
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && preferences.autoUpdateExtensions()) { // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && preferences.autoUpdateExtensions()) {
// val intent = ExtensionInstallService.jobIntent(context, extensions) // val intent = ExtensionInstallService.jobIntent(context, extensions)
// context.startForegroundService(intent) // context.startForegroundService(intent)
@ -76,7 +77,7 @@ class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParam
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val intent = ExtensionInstallService.jobIntent(context, extensions) val intent = ExtensionInstallService.jobIntent(context, extensions)
val pendingIntent = val pendingIntent =
PendingIntent.getForegroundService(context, 0, intent, 0) PendingIntent.getForegroundService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
addAction( addAction(
R.drawable.ic_file_download_24dp, R.drawable.ic_file_download_24dp,
context.getString(R.string.update_all), context.getString(R.string.update_all),

View File

@ -1,9 +1,9 @@
package eu.kanade.tachiyomi.extension.model package eu.kanade.tachiyomi.extension.model
enum class InstallStep { enum class InstallStep {
Pending, Downloading, Loading, Installing, Installed, Error; Pending, Downloading, Loading, Installing, Installed, Error, Done;
fun isCompleted(): Boolean { fun isCompleted(): Boolean {
return this == Installed || this == Error return this == Installed || this == Error || this == Done
} }
} }

View File

@ -30,6 +30,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.transformWhile import kotlinx.coroutines.flow.transformWhile
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.takeWhile
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
@ -187,10 +188,21 @@ internal class ExtensionInstaller(private val context: Context) {
} }
delay(500) delay(500)
} }
}
.takeWhile {
val sessionId = downloadInstallerMap[id]
if (sessionId != null) {
context.packageManager.packageInstaller.getSessionInfo(sessionId) != null
} else {
true
}
} }
.catch { .catch {
Timber.e(it) Timber.e(it)
} }
.onCompletion {
emit(InstallStep.Done to null)
}
} }
/** /**

View File

@ -68,6 +68,7 @@ class ExtensionHolder(view: View, val adapter: ExtensionAdapter) :
@Suppress("ResourceType") @Suppress("ResourceType")
fun bindButton(item: ExtensionItem) = with(binding.extButton) { fun bindButton(item: ExtensionItem) = with(binding.extButton) {
if (item.installStep == InstallStep.Done) return@with
isEnabled = true isEnabled = true
isClickable = true isClickable = true
isActivated = false isActivated = false
@ -87,6 +88,7 @@ class ExtensionHolder(view: View, val adapter: ExtensionAdapter) :
InstallStep.Installing -> R.string.installing InstallStep.Installing -> R.string.installing
InstallStep.Installed -> R.string.installed InstallStep.Installed -> R.string.installed
InstallStep.Error -> R.string.retry InstallStep.Error -> R.string.retry
else -> return@with
} }
) )
if (installStep != InstallStep.Error) { if (installStep != InstallStep.Error) {