Add prompt to re-enable local backups post restore.

This commit is contained in:
Cody Henthorne
2025-09-08 16:34:06 -04:00
committed by Greyson Parrelli
parent bdf2ef5a05
commit 2792b9e676

View File

@@ -5,11 +5,18 @@
package org.thoughtcrime.securesms.restore.restorelocalbackup
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.widget.EditText
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import androidx.core.widget.doOnTextChanged
@@ -25,6 +32,7 @@ import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.LoggingFragment
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.backup.BackupEvent
import org.thoughtcrime.securesms.backup.BackupPassphrase
import org.thoughtcrime.securesms.components.ViewBinderDelegate
import org.thoughtcrime.securesms.databinding.FragmentRestoreLocalBackupBinding
import org.thoughtcrime.securesms.keyvalue.SignalStore
@@ -32,6 +40,7 @@ import org.thoughtcrime.securesms.registration.fragments.RegistrationViewDelegat
import org.thoughtcrime.securesms.restore.RestoreActivity
import org.thoughtcrime.securesms.restore.RestoreRepository
import org.thoughtcrime.securesms.restore.RestoreViewModel
import org.thoughtcrime.securesms.service.LocalBackupListener
import org.thoughtcrime.securesms.util.BackupUtil
import org.thoughtcrime.securesms.util.DateUtils
import org.thoughtcrime.securesms.util.ViewModelFactory
@@ -50,6 +59,34 @@ class RestoreLocalBackupFragment : LoggingFragment(R.layout.fragment_restore_loc
RestoreLocalBackupViewModel(fileBackupUri)
}
)
private val selectBackupDirectory = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
when (val resultCode = result.resultCode) {
Activity.RESULT_OK -> {
val backupDirectoryUri: Uri? = result.data?.data
if (backupDirectoryUri != null) {
Log.i(TAG, "Re-enabling backups with new directory")
val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
SignalStore.settings.setSignalBackupDirectory(backupDirectoryUri)
requireContext().contentResolver.takePersistableUriPermission(backupDirectoryUri, takeFlags)
enableLocalBackups(requireContext())
resumeRegistrationAfterLocalBackupRestore()
} else {
Log.w(TAG, "Backup directory URI is null, reshowing dialog to re-enable")
onLocalBackupRestoreCompletedSuccessfully()
}
}
Activity.RESULT_CANCELED -> {
Log.w(TAG, "Backup directory selection canceled, reshowing dialog to re-enable")
onLocalBackupRestoreCompletedSuccessfully()
}
else -> Log.w(TAG, "Backup directory selection activity ended with unknown result code: $resultCode")
}
}
private val binding: FragmentRestoreLocalBackupBinding by ViewBinderDelegate(FragmentRestoreLocalBackupBinding::bind)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -72,7 +109,7 @@ class RestoreLocalBackupFragment : LoggingFragment(R.layout.fragment_restore_loc
if (SignalStore.settings.isBackupEnabled) {
Log.i(TAG, "Backups enabled, so a backup must have been previously restored.")
onBackupCompletedSuccessfully()
onLocalBackupRestoreCompletedSuccessfully()
return
}
@@ -98,7 +135,7 @@ class RestoreLocalBackupFragment : LoggingFragment(R.layout.fragment_restore_loc
restoreLocalBackupViewModel.importResult.observe(viewLifecycleOwner) { importResult ->
when (importResult) {
null -> Unit
RestoreRepository.BackupImportResult.SUCCESS -> onBackupCompletedSuccessfully()
RestoreRepository.BackupImportResult.SUCCESS -> onLocalBackupRestoreCompletedSuccessfully()
else -> {
handleBackupImportError(importResult)
restoreLocalBackupViewModel.backupImportErrorShown()
@@ -109,12 +146,56 @@ class RestoreLocalBackupFragment : LoggingFragment(R.layout.fragment_restore_loc
restoreLocalBackupViewModel.prepareRestore(requireContext())
}
private fun onBackupCompletedSuccessfully() {
private fun onLocalBackupRestoreCompletedSuccessfully() {
Log.d(TAG, "onBackupCompletedSuccessfully()")
if (BackupUtil.isUserSelectionRequired(requireContext()) && !BackupUtil.canUserAccessBackupDirectory(requireContext())) {
displayConfirmationDialog(requireContext())
} else {
enableLocalBackups(requireContext())
resumeRegistrationAfterLocalBackupRestore()
}
}
private fun resumeRegistrationAfterLocalBackupRestore() {
val activity = requireActivity() as RestoreActivity
activity.onBackupCompletedSuccessfully()
}
@RequiresApi(29)
private fun displayConfirmationDialog(context: Context) {
Log.d(TAG, "Showing continue using local backups dialog")
MaterialAlertDialogBuilder(context)
.setTitle(R.string.RestoreBackupFragment__restore_complete)
.setMessage(R.string.RestoreBackupFragment__to_continue_using_backups_please_choose_a_folder)
.setPositiveButton(R.string.RestoreBackupFragment__choose_folder) { _, _ ->
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
try {
Log.d(TAG, "Showing external file picker for new backup directory")
selectBackupDirectory.launch(intent)
} catch (_: ActivityNotFoundException) {
Log.w(TAG, "No external activity found")
Toast.makeText(context, R.string.BackupDialog_no_file_picker_available, Toast.LENGTH_LONG).show()
BackupPassphrase.set(context, null)
resumeRegistrationAfterLocalBackupRestore()
}
}
.setNegativeButton(R.string.RestoreBackupFragment__not_now) { _, _ ->
BackupPassphrase.set(context, null)
resumeRegistrationAfterLocalBackupRestore()
}
.setCancelable(false)
.show()
}
private fun enableLocalBackups(context: Context) {
if (BackupUtil.canUserAccessBackupDirectory(context)) {
LocalBackupListener.setNextBackupTimeToIntervalFromNow(context)
SignalStore.settings.isBackupEnabled = true
LocalBackupListener.schedule(context)
}
}
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)