diff --git a/app/src/main/java/com/stevesoltys/seedvault/UsbIntentReceiver.kt b/app/src/main/java/com/stevesoltys/seedvault/UsbIntentReceiver.kt index a4738fdc..8f175a3f 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/UsbIntentReceiver.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/UsbIntentReceiver.kt @@ -19,6 +19,7 @@ import com.stevesoltys.seedvault.metadata.MetadataManager import com.stevesoltys.seedvault.settings.FlashDrive import com.stevesoltys.seedvault.settings.SettingsManager import com.stevesoltys.seedvault.storage.StorageBackupService +import com.stevesoltys.seedvault.storage.StorageBackupService.Companion.EXTRA_START_APP_BACKUP import com.stevesoltys.seedvault.transport.requestBackup import com.stevesoltys.seedvault.ui.storage.AUTHORITY_STORAGE import org.koin.core.context.KoinContextHandler.get @@ -57,14 +58,15 @@ class UsbIntentReceiver : UsbMonitor() { override fun onStatusChanged(context: Context, action: String, device: UsbDevice) { if (settingsManager.isStorageBackupEnabled()) { - // TODO is it safe to start this at the same time as app backup? val i = Intent(context, StorageBackupService::class.java) + // this starts an app backup afterwards + i.putExtra(EXTRA_START_APP_BACKUP, true) startForegroundService(context, i) + } else { + Thread { + requestBackup(context) + }.start() } - - Thread { - requestBackup(context) - }.start() } } diff --git a/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsViewModel.kt b/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsViewModel.kt index 1179c804..e393a7df 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsViewModel.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsViewModel.kt @@ -3,6 +3,7 @@ package com.stevesoltys.seedvault.settings import android.app.Application import android.app.job.JobInfo.NETWORK_TYPE_NONE import android.app.job.JobInfo.NETWORK_TYPE_UNMETERED +import android.content.Intent import android.database.ContentObserver import android.net.ConnectivityManager import android.net.Network @@ -14,6 +15,7 @@ import android.util.Log import android.widget.Toast import android.widget.Toast.LENGTH_LONG import androidx.annotation.UiThread +import androidx.core.content.ContextCompat.startForegroundService import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Transformations.switchMap @@ -25,6 +27,8 @@ import com.stevesoltys.seedvault.crypto.KeyManager import com.stevesoltys.seedvault.metadata.MetadataManager import com.stevesoltys.seedvault.permitDiskReads import com.stevesoltys.seedvault.storage.StorageBackupJobService +import com.stevesoltys.seedvault.storage.StorageBackupService +import com.stevesoltys.seedvault.storage.StorageBackupService.Companion.EXTRA_START_APP_BACKUP import com.stevesoltys.seedvault.transport.requestBackup import com.stevesoltys.seedvault.ui.RequireProvisioningViewModel import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager @@ -32,7 +36,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.calyxos.backup.storage.api.StorageBackup import org.calyxos.backup.storage.backup.BackupJobService -import org.calyxos.backup.storage.backup.NotificationBackupObserver import java.util.concurrent.TimeUnit.HOURS private const val TAG = "SettingsViewModel" @@ -156,10 +159,13 @@ internal class SettingsViewModel( Toast.makeText(app, R.string.notification_backup_already_running, LENGTH_LONG).show() } else viewModelScope.launch(Dispatchers.IO) { if (settingsManager.isStorageBackupEnabled()) { - val backupObserver = NotificationBackupObserver(app) - storageBackup.runBackup(backupObserver) + val i = Intent(app, StorageBackupService::class.java) + // this starts an app backup afterwards + i.putExtra(EXTRA_START_APP_BACKUP, true) + startForegroundService(app, i) + } else { + requestBackup(app) } - requestBackup(app) } } diff --git a/app/src/main/java/com/stevesoltys/seedvault/storage/Services.kt b/app/src/main/java/com/stevesoltys/seedvault/storage/Services.kt index 5f55caec..1c54beb2 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/storage/Services.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/storage/Services.kt @@ -1,5 +1,7 @@ package com.stevesoltys.seedvault.storage +import android.content.Intent +import com.stevesoltys.seedvault.transport.requestBackup import org.calyxos.backup.storage.api.BackupObserver import org.calyxos.backup.storage.api.RestoreObserver import org.calyxos.backup.storage.api.StorageBackup @@ -24,12 +26,23 @@ force running with: internal class StorageBackupJobService : BackupJobService(StorageBackupService::class.java) internal class StorageBackupService : BackupService() { + + companion object { + internal const val EXTRA_START_APP_BACKUP = "startAppBackup" + } + override val storageBackup: StorageBackup by inject() // use lazy delegate because context isn't available during construction time override val backupObserver: BackupObserver by lazy { NotificationBackupObserver(applicationContext) } + + override fun onBackupFinished(intent: Intent, success: Boolean) { + if (intent.getBooleanExtra(EXTRA_START_APP_BACKUP, false)) { + requestBackup(applicationContext) + } + } } internal class StorageRestoreService : RestoreService() { diff --git a/storage/demo/src/main/java/de/grobox/storagebackuptester/MainViewModel.kt b/storage/demo/src/main/java/de/grobox/storagebackuptester/MainViewModel.kt index d68d76cf..777247b4 100644 --- a/storage/demo/src/main/java/de/grobox/storagebackuptester/MainViewModel.kt +++ b/storage/demo/src/main/java/de/grobox/storagebackuptester/MainViewModel.kt @@ -68,6 +68,8 @@ class MainViewModel(application: Application) : BackupContentViewModel(applicati viewModelScope.launch(Dispatchers.IO) { val text = storageBackup.getUriSummaryString() _backupLog.postValue(BackupProgress(0, 0, "Scanning: $text\n")) + // FIXME: This might get killed if we navigate away from the activity. + // A foreground service would avoid that. if (storageBackup.runBackup(backupObserver)) { // only prune old backups when backup run was successful storageBackup.pruneOldBackups(backupObserver) diff --git a/storage/lib/src/main/java/org/calyxos/backup/storage/backup/BackupService.kt b/storage/lib/src/main/java/org/calyxos/backup/storage/backup/BackupService.kt index 17b772eb..318bcbdf 100644 --- a/storage/lib/src/main/java/org/calyxos/backup/storage/backup/BackupService.kt +++ b/storage/lib/src/main/java/org/calyxos/backup/storage/backup/BackupService.kt @@ -21,14 +21,15 @@ public abstract class BackupService : Service() { protected abstract val storageBackup: StorageBackup protected abstract val backupObserver: BackupObserver? - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { Log.d(TAG, "onStartCommand $intent $flags $startId") startForeground( NOTIFICATION_ID_BACKUP, n.getBackupNotification(R.string.notification_backup_scanning) ) GlobalScope.launch { - if (storageBackup.runBackup(backupObserver)) { + val success = storageBackup.runBackup(backupObserver) + if (success) { // only prune old backups when backup run was successful startForeground( NOTIFICATION_ID_PRUNE, @@ -36,11 +37,15 @@ public abstract class BackupService : Service() { ) storageBackup.pruneOldBackups(backupObserver) } + onBackupFinished(intent, success) stopSelf(startId) } return super.onStartCommand(intent, flags, startId) } + protected open fun onBackupFinished(intent: Intent, success: Boolean) { + } + override fun onBind(intent: Intent?): IBinder? { return null }