From b9ffe2c03ee5f2ca4e9a3656c52bd731c2e39967 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Fri, 4 Sep 2020 14:51:20 -0300 Subject: [PATCH] Show notification for backup running in the background The system triggers backup jobs periodically or when a package is announcing that its data has changed. So far we were not showing notifications for those. This commit shows a notification with an indeterminate progress bar as we don't have any information about how many packages will get backed up. --- .../ConfigurableBackupTransportService.kt | 11 ++- .../notification/BackupNotificationManager.kt | 80 ++++++++++--------- .../NotificationBackupObserver.kt | 9 +-- 3 files changed, 56 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/ConfigurableBackupTransportService.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/ConfigurableBackupTransportService.kt index d5f10b6b..499311c2 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/transport/ConfigurableBackupTransportService.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/transport/ConfigurableBackupTransportService.kt @@ -13,10 +13,12 @@ import android.os.RemoteException import android.util.Log import androidx.annotation.WorkerThread import com.stevesoltys.seedvault.BackupMonitor +import com.stevesoltys.seedvault.transport.backup.PackageService import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager import com.stevesoltys.seedvault.ui.notification.NotificationBackupObserver -import com.stevesoltys.seedvault.transport.backup.PackageService +import org.koin.core.KoinComponent import org.koin.core.context.GlobalContext.get +import org.koin.core.inject private val TAG = ConfigurableBackupTransportService::class.java.simpleName @@ -24,10 +26,12 @@ private val TAG = ConfigurableBackupTransportService::class.java.simpleName * @author Steve Soltys * @author Torsten Grote */ -class ConfigurableBackupTransportService : Service() { +class ConfigurableBackupTransportService : Service(), KoinComponent { private var transport: ConfigurableBackupTransport? = null + private val notificationManager: BackupNotificationManager by inject() + override fun onCreate() { super.onCreate() transport = ConfigurableBackupTransport(applicationContext) @@ -43,6 +47,7 @@ class ConfigurableBackupTransportService : Service() { override fun onDestroy() { super.onDestroy() + notificationManager.onBackupBackgroundFinished() transport = null Log.d(TAG, "Service destroyed.") } @@ -55,7 +60,7 @@ fun requestBackup(context: Context) { val packages = packageService.eligiblePackages val appTotals = packageService.expectedAppTotals - val observer = NotificationBackupObserver(context, packages.size, appTotals, true) + val observer = NotificationBackupObserver(context, packages.size, appTotals) val result = try { val backupManager: IBackupManager = get().koin.get() backupManager.requestBackup(packages, observer, BackupMonitor(), FLAG_USER_INITIATED) diff --git a/app/src/main/java/com/stevesoltys/seedvault/ui/notification/BackupNotificationManager.kt b/app/src/main/java/com/stevesoltys/seedvault/ui/notification/BackupNotificationManager.kt index c98a0171..7225c5db 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/ui/notification/BackupNotificationManager.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/ui/notification/BackupNotificationManager.kt @@ -31,6 +31,7 @@ private const val CHANNEL_ID_RESTORE_ERROR = "NotificationRestoreError" private const val NOTIFICATION_ID_OBSERVER = 1 private const val NOTIFICATION_ID_ERROR = 2 private const val NOTIFICATION_ID_RESTORE_ERROR = 3 +private const val NOTIFICATION_ID_BACKGROUND = 4 private val TAG = BackupNotificationManager::class.java.simpleName @@ -71,14 +72,12 @@ internal class BackupNotificationManager(private val context: Context) { */ fun onBackupStarted( expectedPackages: Int, - appTotals: ExpectedAppTotals, - userInitiated: Boolean + appTotals: ExpectedAppTotals ) { updateBackupNotification( infoText = "", // This passes quickly, no need to show something here transferred = 0, - expected = expectedPackages, - userInitiated = userInitiated + expected = expectedPackages ) expectedApps = expectedPackages expectedOptOutApps = appTotals.appsOptOut @@ -89,57 +88,55 @@ internal class BackupNotificationManager(private val context: Context) { * This is expected to get called before [onOptOutAppBackup] and [onBackupUpdate]. */ fun onPmKvBackup(packageName: String, transferred: Int, expected: Int) { + val text = "@pm@ record for $packageName" if (expectedApps == null) { - Log.d(TAG, "Expected number of apps unknown. Not showing @pm@ notification.") - return + updateBackgroundBackupNotification(text) + } else { + val addend = (expectedOptOutApps ?: 0) + (expectedApps ?: 0) + updateBackupNotification( + infoText = text, + transferred = transferred, + expected = expected + addend + ) + expectedPmRecords = expected } - val addend = (expectedOptOutApps ?: 0) + (expectedApps ?: 0) - updateBackupNotification( - infoText = "@pm@ record for $packageName", - transferred = transferred, - expected = expected + addend, - userInitiated = false - ) - expectedPmRecords = expected } /** * This should get called after [onPmKvBackup], but before [onBackupUpdate]. */ fun onOptOutAppBackup(packageName: String, transferred: Int, expected: Int) { + val text = "Opt-out APK for $packageName" if (expectedApps == null) { - Log.d(TAG, "Expected number of apps unknown. Not showing APK notification.") - return + updateBackgroundBackupNotification(text) + } else { + updateBackupNotification( + infoText = text, + transferred = transferred + (expectedPmRecords ?: 0), + expected = expected + (expectedApps ?: 0) + (expectedPmRecords ?: 0) + ) + expectedOptOutApps = expected } - updateBackupNotification( - infoText = "Opt-out APK for $packageName", - transferred = transferred + (expectedPmRecords ?: 0), - expected = expected + (expectedApps ?: 0) + (expectedPmRecords ?: 0), - userInitiated = false - ) - expectedOptOutApps = expected } /** * In the series of notification updates, * this type is is expected to get called after [onOptOutAppBackup] and [onPmKvBackup]. */ - fun onBackupUpdate(app: CharSequence, transferred: Int, userInitiated: Boolean) { + fun onBackupUpdate(app: CharSequence, transferred: Int) { val expected = expectedApps ?: error("expectedApps is null") val addend = (expectedOptOutApps ?: 0) + (expectedPmRecords ?: 0) updateBackupNotification( infoText = app, transferred = transferred + addend, - expected = expected + addend, - userInitiated = userInitiated + expected = expected + addend ) } private fun updateBackupNotification( infoText: CharSequence, transferred: Int, - expected: Int, - userInitiated: Boolean + expected: Int ) { @Suppress("MagicNumber") val percentage = (transferred.toFloat() / expected) * 100 @@ -149,22 +146,33 @@ internal class BackupNotificationManager(private val context: Context) { setSmallIcon(R.drawable.ic_cloud_upload) setContentTitle(context.getString(R.string.notification_title)) setContentText(percentageStr) - setTicker(infoText) setOngoing(true) setShowWhen(false) setWhen(System.currentTimeMillis()) setProgress(expected, transferred, false) - priority = if (userInitiated) PRIORITY_DEFAULT else PRIORITY_LOW + priority = PRIORITY_DEFAULT }.build() nm.notify(NOTIFICATION_ID_OBSERVER, notification) } - fun onBackupFinished(success: Boolean, numBackedUp: Int?, userInitiated: Boolean) { - if (!userInitiated) { - // don't show permanent finished notification if backup was not triggered by user - nm.cancel(NOTIFICATION_ID_OBSERVER) - return - } + private fun updateBackgroundBackupNotification(infoText: CharSequence) { + Log.i(TAG, "$infoText") + val notification = Builder(context, CHANNEL_ID_OBSERVER).apply { + setSmallIcon(R.drawable.ic_cloud_upload) + setContentTitle(context.getString(R.string.notification_title)) + setShowWhen(false) + setWhen(System.currentTimeMillis()) + setProgress(0, 0, true) + priority = PRIORITY_LOW + }.build() + nm.notify(NOTIFICATION_ID_BACKGROUND, notification) + } + + fun onBackupBackgroundFinished() { + nm.cancel(NOTIFICATION_ID_BACKGROUND) + } + + fun onBackupFinished(success: Boolean, numBackedUp: Int?) { val titleRes = if (success) R.string.notification_success_title else R.string.notification_failed_title val total = expectedAppTotals?.appsTotal diff --git a/app/src/main/java/com/stevesoltys/seedvault/ui/notification/NotificationBackupObserver.kt b/app/src/main/java/com/stevesoltys/seedvault/ui/notification/NotificationBackupObserver.kt index 4a22c063..b4a30cf1 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/ui/notification/NotificationBackupObserver.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/ui/notification/NotificationBackupObserver.kt @@ -19,8 +19,7 @@ private val TAG = NotificationBackupObserver::class.java.simpleName internal class NotificationBackupObserver( private val context: Context, private val expectedPackages: Int, - appTotals: ExpectedAppTotals, - private val userInitiated: Boolean + appTotals: ExpectedAppTotals ) : IBackupObserver.Stub(), KoinComponent { private val nm: BackupNotificationManager by inject() @@ -31,7 +30,7 @@ internal class NotificationBackupObserver( init { // Inform the notification manager that a backup has started // and inform about the expected numbers, so it can compute a total. - nm.onBackupStarted(expectedPackages, appTotals, userInitiated) + nm.onBackupStarted(expectedPackages, appTotals) } /** @@ -79,7 +78,7 @@ internal class NotificationBackupObserver( } val success = status == 0 val numBackedUp = if (success) metadataManager.getPackagesNumBackedUp() else null - nm.onBackupFinished(success, numBackedUp, userInitiated) + nm.onBackupFinished(success, numBackedUp) } private fun showProgressNotification(packageName: String) { @@ -93,7 +92,7 @@ internal class NotificationBackupObserver( currentPackage = packageName val app = getAppName(packageName) numPackages += 1 - nm.onBackupUpdate(app, numPackages, userInitiated) + nm.onBackupUpdate(app, numPackages) } private fun getAppName(packageId: String): CharSequence = getAppName(context, packageId)