Initialize backup, when enabling it

For ApkBackup, we need to be initialized. If the system starts with app backup off, we would not initialize which would lead to issues when backing up the APKs.
This commit is contained in:
Torsten Grote 2024-02-27 14:51:02 -03:00
parent 2da989971b
commit ee581ee652
No known key found for this signature in database
GPG key ID: 3E5F77D92CF891FF
6 changed files with 60 additions and 14 deletions

View file

@ -2,6 +2,7 @@ package com.stevesoltys.seedvault.e2e
import android.content.pm.PackageInfo import android.content.pm.PackageInfo
import android.os.ParcelFileDescriptor import android.os.ParcelFileDescriptor
import androidx.test.uiautomator.Until
import com.stevesoltys.seedvault.e2e.io.BackupDataInputIntercept import com.stevesoltys.seedvault.e2e.io.BackupDataInputIntercept
import com.stevesoltys.seedvault.e2e.io.InputStreamIntercept import com.stevesoltys.seedvault.e2e.io.InputStreamIntercept
import com.stevesoltys.seedvault.e2e.screen.impl.BackupScreen import com.stevesoltys.seedvault.e2e.screen.impl.BackupScreen
@ -44,6 +45,11 @@ internal interface LargeBackupTestBase : LargeTestBase {
if (!backupManager.isBackupEnabled) { if (!backupManager.isBackupEnabled) {
backupSwitch.click() backupSwitch.click()
waitUntilIdle() waitUntilIdle()
BackupScreen {
device.wait(Until.hasObject(initializingText), 10000)
device.wait(Until.gone(initializingText), 120000)
}
} }
backupMenu.clickAndWaitForNewWindow() backupMenu.clickAndWaitForNewWindow()

View file

@ -57,7 +57,7 @@ open class App : Application() {
factory<IBackupManager> { IBackupManager.Stub.asInterface(getService(BACKUP_SERVICE)) } factory<IBackupManager> { IBackupManager.Stub.asInterface(getService(BACKUP_SERVICE)) }
factory { AppListRetriever(this@App, get(), get(), get()) } factory { AppListRetriever(this@App, get(), get(), get()) }
viewModel { SettingsViewModel(this@App, get(), get(), get(), get(), get(), get()) } viewModel { SettingsViewModel(this@App, get(), get(), get(), get(), get(), get(), get()) }
viewModel { RecoveryCodeViewModel(this@App, get(), get(), get(), get(), get(), get()) } viewModel { RecoveryCodeViewModel(this@App, get(), get(), get(), get(), get(), get()) }
viewModel { BackupStorageViewModel(this@App, get(), get(), get(), get()) } viewModel { BackupStorageViewModel(this@App, get(), get(), get(), get()) }
viewModel { RestoreStorageViewModel(this@App, get(), get()) } viewModel { RestoreStorageViewModel(this@App, get(), get()) }

View file

@ -10,6 +10,7 @@ import com.stevesoltys.seedvault.ui.RequireProvisioningActivity
import com.stevesoltys.seedvault.ui.RequireProvisioningViewModel import com.stevesoltys.seedvault.ui.RequireProvisioningViewModel
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
import com.stevesoltys.seedvault.ui.recoverycode.ARG_FOR_NEW_CODE import com.stevesoltys.seedvault.ui.recoverycode.ARG_FOR_NEW_CODE
import com.stevesoltys.seedvault.ui.storage.StorageCheckFragment
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
@ -36,6 +37,19 @@ class SettingsActivity : RequireProvisioningActivity(), OnPreferenceStartFragmen
if (intent?.action == ACTION_APP_STATUS_LIST) { if (intent?.action == ACTION_APP_STATUS_LIST) {
showFragment(AppStatusFragment(), true) showFragment(AppStatusFragment(), true)
} }
// observe initialization and show/remove init fragment
// this can happen when enabling backup and storage wasn't initialized
viewModel.initEvent.observeEvent(this) { show ->
val tag = "INIT"
if (show) {
val title = getString(R.string.storage_check_fragment_backup_title)
showFragment(StorageCheckFragment.newInstance(title), true, tag)
} else {
val f = supportFragmentManager.findFragmentByTag(tag)
if (f != null && f.isVisible) supportFragmentManager.popBackStack()
}
}
} }
@CallSuper @CallSuper

View file

@ -19,7 +19,6 @@ import androidx.preference.Preference
import androidx.preference.Preference.OnPreferenceChangeListener import androidx.preference.Preference.OnPreferenceChangeListener
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.TwoStatePreference import androidx.preference.TwoStatePreference
import androidx.work.ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE
import androidx.work.WorkInfo import androidx.work.WorkInfo
import com.stevesoltys.seedvault.R import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.permitDiskReads import com.stevesoltys.seedvault.permitDiskReads
@ -213,16 +212,10 @@ class SettingsFragment : PreferenceFragmentCompat() {
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
// TODO this should really get moved out off the UI layer
private fun trySetBackupEnabled(enabled: Boolean): Boolean { private fun trySetBackupEnabled(enabled: Boolean): Boolean {
return try { return try {
backupManager.isBackupEnabled = enabled backupManager.isBackupEnabled = enabled
if (enabled) { viewModel.onBackupEnabled(enabled)
viewModel.scheduleAppBackup(CANCEL_AND_REENQUEUE)
viewModel.enableCallLogBackup()
} else {
viewModel.cancelAppBackup()
}
backup.isChecked = enabled backup.isChecked = enabled
true true
} catch (e: RemoteException) { } catch (e: RemoteException) {

View file

@ -37,6 +37,9 @@ import com.stevesoltys.seedvault.permitDiskReads
import com.stevesoltys.seedvault.storage.StorageBackupJobService import com.stevesoltys.seedvault.storage.StorageBackupJobService
import com.stevesoltys.seedvault.storage.StorageBackupService import com.stevesoltys.seedvault.storage.StorageBackupService
import com.stevesoltys.seedvault.storage.StorageBackupService.Companion.EXTRA_START_APP_BACKUP import com.stevesoltys.seedvault.storage.StorageBackupService.Companion.EXTRA_START_APP_BACKUP
import com.stevesoltys.seedvault.transport.backup.BackupInitializer
import com.stevesoltys.seedvault.ui.LiveEvent
import com.stevesoltys.seedvault.ui.MutableLiveEvent
import com.stevesoltys.seedvault.ui.RequireProvisioningViewModel import com.stevesoltys.seedvault.ui.RequireProvisioningViewModel
import com.stevesoltys.seedvault.worker.AppBackupWorker import com.stevesoltys.seedvault.worker.AppBackupWorker
import com.stevesoltys.seedvault.worker.AppBackupWorker.Companion.UNIQUE_WORK_NAME import com.stevesoltys.seedvault.worker.AppBackupWorker.Companion.UNIQUE_WORK_NAME
@ -60,6 +63,7 @@ internal class SettingsViewModel(
private val appListRetriever: AppListRetriever, private val appListRetriever: AppListRetriever,
private val storageBackup: StorageBackup, private val storageBackup: StorageBackup,
private val backupManager: IBackupManager, private val backupManager: IBackupManager,
private val backupInitializer: BackupInitializer,
) : RequireProvisioningViewModel(app, settingsManager, keyManager) { ) : RequireProvisioningViewModel(app, settingsManager, keyManager) {
private val contentResolver = app.contentResolver private val contentResolver = app.contentResolver
@ -90,6 +94,9 @@ internal class SettingsViewModel(
private val _filesSummary = MutableLiveData<String>() private val _filesSummary = MutableLiveData<String>()
internal val filesSummary: LiveData<String> = _filesSummary internal val filesSummary: LiveData<String> = _filesSummary
private val _initEvent = MutableLiveEvent<Boolean>()
val initEvent: LiveEvent<Boolean> = _initEvent
private val storageObserver = object : ContentObserver(null) { private val storageObserver = object : ContentObserver(null) {
override fun onChange(selfChange: Boolean, uris: MutableCollection<Uri>, flags: Int) { override fun onChange(selfChange: Boolean, uris: MutableCollection<Uri>, flags: Int) {
onStoragePropertiesChanged() onStoragePropertiesChanged()
@ -230,6 +237,30 @@ internal class SettingsViewModel(
} }
} }
fun onBackupEnabled(enabled: Boolean) {
if (enabled) {
if (metadataManager.requiresInit) {
val onError: () -> Unit = {
viewModelScope.launch(Dispatchers.Main) {
val res = R.string.storage_check_fragment_backup_error
Toast.makeText(app, res, LENGTH_LONG).show()
}
}
viewModelScope.launch(Dispatchers.IO) {
backupInitializer.initialize(onError) {
_initEvent.postEvent(false)
scheduleAppBackup(CANCEL_AND_REENQUEUE)
}
_initEvent.postEvent(true)
}
}
// enable call log backups for existing installs (added end of 2020)
enableCallLogBackup()
} else {
cancelAppBackup()
}
}
/** /**
* Ensures that the call log will be included in backups. * Ensures that the call log will be included in backups.
* *

View file

@ -17,11 +17,13 @@ abstract class BackupActivity : AppCompatActivity() {
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
protected fun showFragment(f: Fragment, addToBackStack: Boolean = false) { protected fun showFragment(f: Fragment, addToBackStack: Boolean = false, tag: String? = null) {
val fragmentTransaction = supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction().apply {
.replace(R.id.fragment, f) if (tag == null) replace(R.id.fragment, f)
if (addToBackStack) fragmentTransaction.addToBackStack(null) else replace(R.id.fragment, f, tag)
fragmentTransaction.commit() if (addToBackStack) addToBackStack(null)
commit()
}
} }
} }