Show one single progress bar in the notification
Also don't show individual package results, but a single dismissible status notification in the end. Closes #59, #61
This commit is contained in:
parent
2bcf82d607
commit
6ed522bfb7
5 changed files with 67 additions and 18 deletions
|
@ -63,6 +63,8 @@ class BackupNotificationManager(private val context: Context) {
|
|||
val notification = observerBuilder.apply {
|
||||
setContentTitle(context.getString(R.string.notification_title))
|
||||
setContentText(app)
|
||||
setOngoing(true)
|
||||
setShowWhen(false)
|
||||
setWhen(System.currentTimeMillis())
|
||||
setProgress(expected, transferred, false)
|
||||
priority = if (userInitiated) PRIORITY_DEFAULT else PRIORITY_LOW
|
||||
|
@ -79,14 +81,33 @@ class BackupNotificationManager(private val context: Context) {
|
|||
val notification = observerBuilder.apply {
|
||||
setContentTitle(title)
|
||||
setContentText(app)
|
||||
setOngoing(true)
|
||||
setShowWhen(false)
|
||||
setWhen(System.currentTimeMillis())
|
||||
priority = if (userInitiated) PRIORITY_DEFAULT else PRIORITY_LOW
|
||||
}.build()
|
||||
nm.notify(NOTIFICATION_ID_OBSERVER, notification)
|
||||
}
|
||||
|
||||
fun onBackupFinished() {
|
||||
nm.cancel(NOTIFICATION_ID_OBSERVER)
|
||||
fun onBackupFinished(success: Boolean, notBackedUp: Int?, userInitiated: Boolean) {
|
||||
if (!userInitiated) {
|
||||
nm.cancel(NOTIFICATION_ID_OBSERVER)
|
||||
return
|
||||
}
|
||||
val titleRes = if (success) R.string.notification_success_title else R.string.notification_failed_title
|
||||
val contentText = if (notBackedUp == null) null else {
|
||||
context.getString(R.string.notification_success_num_not_backed_up, notBackedUp)
|
||||
}
|
||||
val notification = observerBuilder.apply {
|
||||
setContentTitle(context.getString(titleRes))
|
||||
setContentText(contentText)
|
||||
setOngoing(false)
|
||||
setShowWhen(true)
|
||||
setWhen(System.currentTimeMillis())
|
||||
setProgress(0, 0, false)
|
||||
priority = PRIORITY_LOW
|
||||
}.build()
|
||||
nm.notify(NOTIFICATION_ID_OBSERVER, notification)
|
||||
}
|
||||
|
||||
fun onBackupError() {
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.content.pm.PackageManager.NameNotFoundException
|
|||
import android.util.Log
|
||||
import android.util.Log.INFO
|
||||
import android.util.Log.isLoggable
|
||||
import com.stevesoltys.seedvault.metadata.MetadataManager
|
||||
import org.koin.core.KoinComponent
|
||||
import org.koin.core.inject
|
||||
|
||||
|
@ -14,9 +15,18 @@ private val TAG = NotificationBackupObserver::class.java.simpleName
|
|||
|
||||
class NotificationBackupObserver(
|
||||
private val context: Context,
|
||||
private val expectedPackages: Int,
|
||||
private val userInitiated: Boolean) : IBackupObserver.Stub(), KoinComponent {
|
||||
|
||||
private val nm: BackupNotificationManager by inject()
|
||||
private val metadataManager: MetadataManager by inject()
|
||||
private var currentPackage: String? = null
|
||||
private var numPackages: Int = 0
|
||||
|
||||
init {
|
||||
// we need to show this manually as [onUpdate] isn't called for first @pm@ package
|
||||
nm.onBackupUpdate(getAppName(MAGIC_PACKAGE_MANAGER), 0, expectedPackages, userInitiated)
|
||||
}
|
||||
|
||||
/**
|
||||
* This method could be called several times for packages with full data backup.
|
||||
|
@ -26,10 +36,7 @@ class NotificationBackupObserver(
|
|||
* @param backupProgress Current progress of backup for the package.
|
||||
*/
|
||||
override fun onUpdate(currentBackupPackage: String, backupProgress: BackupProgress) {
|
||||
val transferred = backupProgress.bytesTransferred.toInt()
|
||||
val expected = backupProgress.bytesExpected.toInt()
|
||||
val app = getAppName(currentBackupPackage)
|
||||
nm.onBackupUpdate(app, transferred, expected, userInitiated)
|
||||
showProgressNotification(currentBackupPackage)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,7 +53,8 @@ class NotificationBackupObserver(
|
|||
if (isLoggable(TAG, INFO)) {
|
||||
Log.i(TAG, "Completed. Target: $target, status: $status")
|
||||
}
|
||||
nm.onBackupResult(getAppName(target), status, userInitiated)
|
||||
// often [onResult] gets called right away without any [onUpdate] call
|
||||
showProgressNotification(target)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,9 +66,23 @@ class NotificationBackupObserver(
|
|||
*/
|
||||
override fun backupFinished(status: Int) {
|
||||
if (isLoggable(TAG, INFO)) {
|
||||
Log.i(TAG, "Backup finished. Status: $status")
|
||||
Log.i(TAG, "Backup finished $numPackages/$expectedPackages. Status: $status")
|
||||
}
|
||||
nm.onBackupFinished()
|
||||
val success = status == 0
|
||||
val notBackedUp = if (success) metadataManager.getPackagesNumNotBackedUp() else null
|
||||
nm.onBackupFinished(success, notBackedUp, userInitiated)
|
||||
}
|
||||
|
||||
private fun showProgressNotification(packageName: String) {
|
||||
if (currentPackage == packageName) return
|
||||
|
||||
if (isLoggable(TAG, INFO)) {
|
||||
Log.i(TAG, "Showing progress notification for $currentPackage $numPackages/$expectedPackages")
|
||||
}
|
||||
currentPackage = packageName
|
||||
val app = getAppName(packageName)
|
||||
numPackages += 1
|
||||
nm.onBackupUpdate(app, numPackages, expectedPackages, userInitiated)
|
||||
}
|
||||
|
||||
private fun getAppName(packageId: String): CharSequence = getAppName(context, packageId)
|
||||
|
|
|
@ -178,6 +178,13 @@ class MetadataManager(
|
|||
return metadata.packageMetadataMap[packageName]?.copy()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun getPackagesNumNotBackedUp(): Int {
|
||||
return metadata.packageMetadataMap.filter { (_, packageMetadata) ->
|
||||
!packageMetadata.system && packageMetadata.state != APK_AND_DATA
|
||||
}.count()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
@VisibleForTesting
|
||||
private fun getMetadataFromCache(): BackupMetadata? {
|
||||
|
|
|
@ -15,7 +15,6 @@ import androidx.annotation.WorkerThread
|
|||
import com.stevesoltys.seedvault.BackupMonitor
|
||||
import com.stevesoltys.seedvault.BackupNotificationManager
|
||||
import com.stevesoltys.seedvault.NotificationBackupObserver
|
||||
import com.stevesoltys.seedvault.R
|
||||
import com.stevesoltys.seedvault.transport.backup.PackageService
|
||||
import org.koin.core.context.GlobalContext.get
|
||||
|
||||
|
@ -52,19 +51,16 @@ class ConfigurableBackupTransportService : Service() {
|
|||
|
||||
@WorkerThread
|
||||
fun requestBackup(context: Context) {
|
||||
// show notification
|
||||
val nm: BackupNotificationManager = get().koin.get()
|
||||
nm.onBackupUpdate(context.getString(R.string.notification_backup_starting), 0, 1, true)
|
||||
|
||||
val packageService: PackageService = get().koin.get()
|
||||
val observer = NotificationBackupObserver(context, true)
|
||||
val flags = FLAG_NON_INCREMENTAL_BACKUP or FLAG_USER_INITIATED
|
||||
val packages = packageService.eligiblePackages
|
||||
|
||||
val observer = NotificationBackupObserver(context, packages.size, true)
|
||||
val result = try {
|
||||
val backupManager: IBackupManager = get().koin.get()
|
||||
backupManager.requestBackup(packages, observer, BackupMonitor(), flags)
|
||||
backupManager.requestBackup(packages, observer, BackupMonitor(), FLAG_USER_INITIATED)
|
||||
} catch (e: RemoteException) {
|
||||
Log.e(TAG, "Error during backup: ", e)
|
||||
val nm: BackupNotificationManager = get().koin.get()
|
||||
nm.onBackupError()
|
||||
}
|
||||
if (result == BackupManager.SUCCESS) {
|
||||
|
|
|
@ -70,11 +70,14 @@
|
|||
<!-- Notification -->
|
||||
<string name="notification_channel_title">Backup Notification</string>
|
||||
<string name="notification_title">Backup running</string>
|
||||
<string name="notification_backup_starting">Starting Backup…</string>
|
||||
<string name="notification_backup_result_complete">Backup complete</string>
|
||||
<string name="notification_backup_result_rejected">Not backed up</string>
|
||||
<string name="notification_backup_result_error">Backup failed</string>
|
||||
|
||||
<string name="notification_success_title">Backup finished</string>
|
||||
<string name="notification_success_num_not_backed_up">%1$d apps could not get backed up</string>
|
||||
<string name="notification_failed_title">Backup failed</string>
|
||||
|
||||
<string name="notification_error_channel_title">Error Notification</string>
|
||||
<string name="notification_error_title">Backup Error</string>
|
||||
<string name="notification_error_text">A device backup failed to run.</string>
|
||||
|
|
Loading…
Reference in a new issue