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

View file

@ -57,7 +57,7 @@ open class App : Application() {
factory<IBackupManager> { IBackupManager.Stub.asInterface(getService(BACKUP_SERVICE)) }
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 { BackupStorageViewModel(this@App, get(), get(), 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.notification.BackupNotificationManager
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.androidx.viewmodel.ext.android.viewModel
@ -36,6 +37,19 @@ class SettingsActivity : RequireProvisioningActivity(), OnPreferenceStartFragmen
if (intent?.action == ACTION_APP_STATUS_LIST) {
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

View file

@ -19,7 +19,6 @@ import androidx.preference.Preference
import androidx.preference.Preference.OnPreferenceChangeListener
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.TwoStatePreference
import androidx.work.ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE
import androidx.work.WorkInfo
import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.permitDiskReads
@ -213,16 +212,10 @@ class SettingsFragment : PreferenceFragmentCompat() {
else -> super.onOptionsItemSelected(item)
}
// TODO this should really get moved out off the UI layer
private fun trySetBackupEnabled(enabled: Boolean): Boolean {
return try {
backupManager.isBackupEnabled = enabled
if (enabled) {
viewModel.scheduleAppBackup(CANCEL_AND_REENQUEUE)
viewModel.enableCallLogBackup()
} else {
viewModel.cancelAppBackup()
}
viewModel.onBackupEnabled(enabled)
backup.isChecked = enabled
true
} 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.StorageBackupService
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.worker.AppBackupWorker
import com.stevesoltys.seedvault.worker.AppBackupWorker.Companion.UNIQUE_WORK_NAME
@ -60,6 +63,7 @@ internal class SettingsViewModel(
private val appListRetriever: AppListRetriever,
private val storageBackup: StorageBackup,
private val backupManager: IBackupManager,
private val backupInitializer: BackupInitializer,
) : RequireProvisioningViewModel(app, settingsManager, keyManager) {
private val contentResolver = app.contentResolver
@ -90,6 +94,9 @@ internal class SettingsViewModel(
private val _filesSummary = MutableLiveData<String>()
internal val filesSummary: LiveData<String> = _filesSummary
private val _initEvent = MutableLiveEvent<Boolean>()
val initEvent: LiveEvent<Boolean> = _initEvent
private val storageObserver = object : ContentObserver(null) {
override fun onChange(selfChange: Boolean, uris: MutableCollection<Uri>, flags: Int) {
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.
*

View file

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