Skip to content

Commit

Permalink
Show notification for backup running in the background
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
grote authored and chirayudesai committed Sep 11, 2020
1 parent a39f697 commit 43b24b5
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,25 @@ 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

/**
* @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)
Expand All @@ -43,6 +47,7 @@ class ConfigurableBackupTransportService : Service() {

override fun onDestroy() {
super.onDestroy()
notificationManager.onBackupBackgroundFinished()
transport = null
Log.d(TAG, "Service destroyed.")
}
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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)
}

/**
Expand Down Expand Up @@ -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) {
Expand All @@ -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)
Expand Down

0 comments on commit 43b24b5

Please sign in to comment.