Save more information about current storage location
Show storage name in settings
This commit is contained in:
parent
c6f83647b2
commit
54ad762eb1
14 changed files with 80 additions and 57 deletions
|
@ -3,8 +3,8 @@ package com.stevesoltys.backup
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import androidx.test.runner.AndroidJUnit4
|
import androidx.test.runner.AndroidJUnit4
|
||||||
import com.stevesoltys.backup.settings.getBackupFolderUri
|
|
||||||
import com.stevesoltys.backup.settings.getBackupToken
|
import com.stevesoltys.backup.settings.getBackupToken
|
||||||
|
import com.stevesoltys.backup.settings.getStorage
|
||||||
import com.stevesoltys.backup.transport.backup.plugins.DocumentsStorage
|
import com.stevesoltys.backup.transport.backup.plugins.DocumentsStorage
|
||||||
import com.stevesoltys.backup.transport.backup.plugins.createOrGetFile
|
import com.stevesoltys.backup.transport.backup.plugins.createOrGetFile
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
|
@ -22,7 +22,7 @@ class DocumentsStorageTest {
|
||||||
|
|
||||||
private val context = InstrumentationRegistry.getInstrumentation().targetContext
|
private val context = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
private val token = getBackupToken(context)
|
private val token = getBackupToken(context)
|
||||||
private val folderUri = getBackupFolderUri(context)
|
private val folderUri = getStorage(context)
|
||||||
private val storage = DocumentsStorage(context, folderUri, token)
|
private val storage = DocumentsStorage(context, folderUri, token)
|
||||||
|
|
||||||
private lateinit var file: DocumentFile
|
private lateinit var file: DocumentFile
|
||||||
|
|
|
@ -31,7 +31,4 @@ class Backup : Application() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO fix
|
|
||||||
fun Uri.isOnExternalStorage() = authority == AUTHORITY_STORAGE
|
|
||||||
|
|
||||||
fun isDebugBuild() = Build.TYPE == "userdebug"
|
fun isDebugBuild() = Build.TYPE == "userdebug"
|
||||||
|
|
|
@ -18,9 +18,8 @@ import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
|
||||||
import static android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
|
import static android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
|
||||||
import static com.stevesoltys.backup.activity.MainActivity.OPEN_DOCUMENT_TREE_BACKUP_REQUEST_CODE;
|
import static com.stevesoltys.backup.activity.MainActivity.OPEN_DOCUMENT_TREE_BACKUP_REQUEST_CODE;
|
||||||
import static com.stevesoltys.backup.activity.MainActivity.OPEN_DOCUMENT_TREE_REQUEST_CODE;
|
import static com.stevesoltys.backup.activity.MainActivity.OPEN_DOCUMENT_TREE_REQUEST_CODE;
|
||||||
import static com.stevesoltys.backup.settings.SettingsManagerKt.getBackupFolderUri;
|
|
||||||
import static com.stevesoltys.backup.settings.SettingsManagerKt.getBackupPassword;
|
import static com.stevesoltys.backup.settings.SettingsManagerKt.getBackupPassword;
|
||||||
import static com.stevesoltys.backup.settings.SettingsManagerKt.setBackupFolderUri;
|
import static com.stevesoltys.backup.settings.SettingsManagerKt.getStorage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Soltys
|
* @author Steve Soltys
|
||||||
|
@ -31,7 +30,7 @@ public class MainActivityController {
|
||||||
public static final String DOCUMENT_MIME_TYPE = "application/octet-stream";
|
public static final String DOCUMENT_MIME_TYPE = "application/octet-stream";
|
||||||
|
|
||||||
void onBackupButtonClicked(Activity parent) {
|
void onBackupButtonClicked(Activity parent) {
|
||||||
Uri folderUri = getBackupFolderUri(parent);
|
Uri folderUri = null;
|
||||||
if (folderUri == null) {
|
if (folderUri == null) {
|
||||||
showChooseFolderActivity(parent, true);
|
showChooseFolderActivity(parent, true);
|
||||||
} else {
|
} else {
|
||||||
|
@ -42,7 +41,7 @@ public class MainActivityController {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isChangeBackupLocationButtonVisible(Activity parent) {
|
boolean isChangeBackupLocationButtonVisible(Activity parent) {
|
||||||
return getBackupFolderUri(parent) != null;
|
return getStorage(parent) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showChooseFolderActivity(Activity parent, boolean continueToBackup) {
|
private void showChooseFolderActivity(Activity parent, boolean continueToBackup) {
|
||||||
|
@ -75,7 +74,7 @@ public class MainActivityController {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean onAutomaticBackupsButtonClicked(Activity parent) {
|
boolean onAutomaticBackupsButtonClicked(Activity parent) {
|
||||||
if (getBackupFolderUri(parent) == null || getBackupPassword(parent) == null) {
|
if (getStorage(parent) == null || getBackupPassword(parent) == null) {
|
||||||
Toast.makeText(parent, "Please make at least one manual backup first.", Toast.LENGTH_SHORT).show();
|
Toast.makeText(parent, "Please make at least one manual backup first.", Toast.LENGTH_SHORT).show();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -103,9 +102,6 @@ public class MainActivityController {
|
||||||
(FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION);
|
(FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||||
parent.getContentResolver().takePersistableUriPermission(folderUri, takeFlags);
|
parent.getContentResolver().takePersistableUriPermission(folderUri, takeFlags);
|
||||||
|
|
||||||
// store backup folder location in settings
|
|
||||||
setBackupFolderUri(parent, folderUri);
|
|
||||||
|
|
||||||
if (!continueToBackup) return;
|
if (!continueToBackup) return;
|
||||||
|
|
||||||
showCreateBackupActivity(parent);
|
showCreateBackupActivity(parent);
|
||||||
|
|
|
@ -29,6 +29,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
private lateinit var backup: TwoStatePreference
|
private lateinit var backup: TwoStatePreference
|
||||||
private lateinit var autoRestore: TwoStatePreference
|
private lateinit var autoRestore: TwoStatePreference
|
||||||
|
private lateinit var backupLocation: Preference
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
setPreferencesFromResource(R.xml.settings, rootKey)
|
setPreferencesFromResource(R.xml.settings, rootKey)
|
||||||
|
@ -49,7 +50,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val backupLocation = findPreference<Preference>("backup_location")!!
|
backupLocation = findPreference<Preference>("backup_location")!!
|
||||||
backupLocation.setOnPreferenceClickListener {
|
backupLocation.setOnPreferenceClickListener {
|
||||||
viewModel.chooseBackupLocation()
|
viewModel.chooseBackupLocation()
|
||||||
true
|
true
|
||||||
|
@ -85,6 +86,10 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
val resolver = requireContext().contentResolver
|
val resolver = requireContext().contentResolver
|
||||||
autoRestore.isChecked = Settings.Secure.getInt(resolver, BACKUP_AUTO_RESTORE, 1) == 1
|
autoRestore.isChecked = Settings.Secure.getInt(resolver, BACKUP_AUTO_RESTORE, 1) == 1
|
||||||
|
|
||||||
|
// TODO add time of last backup here
|
||||||
|
val storageName = getStorage(requireContext())?.name
|
||||||
|
backupLocation.summary = storageName ?: getString(R.string.settings_backup_location_none )
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
|
|
@ -5,21 +5,34 @@ import android.net.Uri
|
||||||
import android.preference.PreferenceManager.getDefaultSharedPreferences
|
import android.preference.PreferenceManager.getDefaultSharedPreferences
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
private const val PREF_KEY_BACKUP_URI = "backupUri"
|
private const val PREF_KEY_STORAGE_URI = "storageUri"
|
||||||
|
private const val PREF_KEY_STORAGE_NAME = "storageName"
|
||||||
|
private const val PREF_KEY_STORAGE_EJECTABLE = "storageEjectable"
|
||||||
private const val PREF_KEY_BACKUP_TOKEN = "backupToken"
|
private const val PREF_KEY_BACKUP_TOKEN = "backupToken"
|
||||||
private const val PREF_KEY_BACKUP_PASSWORD = "backupLegacyPassword"
|
private const val PREF_KEY_BACKUP_PASSWORD = "backupLegacyPassword"
|
||||||
|
|
||||||
fun setBackupFolderUri(context: Context, uri: Uri) {
|
data class Storage(
|
||||||
|
val uri: Uri,
|
||||||
|
val name: String,
|
||||||
|
val ejectable: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
fun setStorage(context: Context, storage: Storage) {
|
||||||
getDefaultSharedPreferences(context)
|
getDefaultSharedPreferences(context)
|
||||||
.edit()
|
.edit()
|
||||||
.putString(PREF_KEY_BACKUP_URI, uri.toString())
|
.putString(PREF_KEY_STORAGE_URI, storage.uri.toString())
|
||||||
|
.putString(PREF_KEY_STORAGE_NAME, storage.name)
|
||||||
|
.putBoolean(PREF_KEY_STORAGE_EJECTABLE, storage.ejectable)
|
||||||
.apply()
|
.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getBackupFolderUri(context: Context): Uri? {
|
fun getStorage(context: Context): Storage? {
|
||||||
val uriStr = getDefaultSharedPreferences(context).getString(PREF_KEY_BACKUP_URI, null)
|
val prefs = getDefaultSharedPreferences(context)
|
||||||
?: return null
|
val uriStr = prefs.getString(PREF_KEY_STORAGE_URI, null) ?: return null
|
||||||
return Uri.parse(uriStr)
|
val uri = Uri.parse(uriStr)
|
||||||
|
val name = prefs.getString(PREF_KEY_STORAGE_NAME, null) ?: throw IllegalStateException()
|
||||||
|
val ejectable = prefs.getBoolean(PREF_KEY_STORAGE_EJECTABLE, false)
|
||||||
|
return Storage(uri, name, ejectable)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,8 +8,8 @@ import com.stevesoltys.backup.header.HeaderReaderImpl
|
||||||
import com.stevesoltys.backup.header.HeaderWriterImpl
|
import com.stevesoltys.backup.header.HeaderWriterImpl
|
||||||
import com.stevesoltys.backup.metadata.MetadataReaderImpl
|
import com.stevesoltys.backup.metadata.MetadataReaderImpl
|
||||||
import com.stevesoltys.backup.metadata.MetadataWriterImpl
|
import com.stevesoltys.backup.metadata.MetadataWriterImpl
|
||||||
import com.stevesoltys.backup.settings.getBackupFolderUri
|
|
||||||
import com.stevesoltys.backup.settings.getBackupToken
|
import com.stevesoltys.backup.settings.getBackupToken
|
||||||
|
import com.stevesoltys.backup.settings.getStorage
|
||||||
import com.stevesoltys.backup.transport.backup.BackupCoordinator
|
import com.stevesoltys.backup.transport.backup.BackupCoordinator
|
||||||
import com.stevesoltys.backup.transport.backup.FullBackup
|
import com.stevesoltys.backup.transport.backup.FullBackup
|
||||||
import com.stevesoltys.backup.transport.backup.InputFactory
|
import com.stevesoltys.backup.transport.backup.InputFactory
|
||||||
|
@ -26,7 +26,7 @@ class PluginManager(context: Context) {
|
||||||
|
|
||||||
// We can think about using an injection framework such as Dagger to simplify this.
|
// We can think about using an injection framework such as Dagger to simplify this.
|
||||||
|
|
||||||
private val storage = DocumentsStorage(context, getBackupFolderUri(context), getBackupToken(context))
|
private val storage = DocumentsStorage(context, getStorage(context), getBackupToken(context))
|
||||||
|
|
||||||
private val headerWriter = HeaderWriterImpl()
|
private val headerWriter = HeaderWriterImpl()
|
||||||
private val headerReader = HeaderReaderImpl()
|
private val headerReader = HeaderReaderImpl()
|
||||||
|
|
|
@ -2,9 +2,9 @@ package com.stevesoltys.backup.transport.backup.plugins
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageInfo
|
import android.content.pm.PackageInfo
|
||||||
import android.net.Uri
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
|
import com.stevesoltys.backup.settings.Storage
|
||||||
import com.stevesoltys.backup.settings.getAndSaveNewBackupToken
|
import com.stevesoltys.backup.settings.getAndSaveNewBackupToken
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
@ -19,10 +19,10 @@ private const val MIME_TYPE = "application/octet-stream"
|
||||||
|
|
||||||
private val TAG = DocumentsStorage::class.java.simpleName
|
private val TAG = DocumentsStorage::class.java.simpleName
|
||||||
|
|
||||||
class DocumentsStorage(private val context: Context, parentFolder: Uri?, token: Long) {
|
class DocumentsStorage(private val context: Context, storage: Storage?, token: Long) {
|
||||||
|
|
||||||
internal val rootBackupDir: DocumentFile? by lazy {
|
internal val rootBackupDir: DocumentFile? by lazy {
|
||||||
val folderUri = parentFolder ?: return@lazy null
|
val folderUri = storage?.uri ?: return@lazy null
|
||||||
// [fromTreeUri] should only return null when SDK_INT < 21
|
// [fromTreeUri] should only return null when SDK_INT < 21
|
||||||
val parent = DocumentFile.fromTreeUri(context, folderUri) ?: throw AssertionError()
|
val parent = DocumentFile.fromTreeUri(context, folderUri) ?: throw AssertionError()
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -3,15 +3,12 @@ package com.stevesoltys.backup.ui.storage
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.app.backup.BackupProgress
|
import android.app.backup.BackupProgress
|
||||||
import android.app.backup.IBackupObserver
|
import android.app.backup.IBackupObserver
|
||||||
import android.content.Intent
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.annotation.WorkerThread
|
import androidx.annotation.WorkerThread
|
||||||
import com.stevesoltys.backup.Backup
|
import com.stevesoltys.backup.Backup
|
||||||
import com.stevesoltys.backup.R
|
import com.stevesoltys.backup.R
|
||||||
import com.stevesoltys.backup.settings.getAndSaveNewBackupToken
|
import com.stevesoltys.backup.settings.getAndSaveNewBackupToken
|
||||||
import com.stevesoltys.backup.settings.setBackupFolderUri
|
|
||||||
import com.stevesoltys.backup.transport.ConfigurableBackupTransportService
|
|
||||||
import com.stevesoltys.backup.transport.TRANSPORT_ID
|
import com.stevesoltys.backup.transport.TRANSPORT_ID
|
||||||
|
|
||||||
private val TAG = BackupStorageViewModel::class.java.simpleName
|
private val TAG = BackupStorageViewModel::class.java.simpleName
|
||||||
|
@ -21,19 +18,11 @@ internal class BackupStorageViewModel(private val app: Application) : StorageVie
|
||||||
override val isRestoreOperation = false
|
override val isRestoreOperation = false
|
||||||
|
|
||||||
override fun onLocationSet(uri: Uri) {
|
override fun onLocationSet(uri: Uri) {
|
||||||
// store backup folder location in settings
|
saveStorage(uri)
|
||||||
setBackupFolderUri(app, uri)
|
|
||||||
|
|
||||||
// TODO also set the storage name
|
|
||||||
|
|
||||||
// stop backup service to be sure the old location will get updated
|
|
||||||
app.stopService(Intent(app, ConfigurableBackupTransportService::class.java))
|
|
||||||
|
|
||||||
// use a new backup token
|
// use a new backup token
|
||||||
getAndSaveNewBackupToken(app)
|
getAndSaveNewBackupToken(app)
|
||||||
|
|
||||||
Log.d(TAG, "New storage location chosen: $uri")
|
|
||||||
|
|
||||||
// initialize the new location
|
// initialize the new location
|
||||||
val observer = InitializationObserver()
|
val observer = InitializationObserver()
|
||||||
Backup.backupManager.initializeTransports(arrayOf(TRANSPORT_ID), observer)
|
Backup.backupManager.initializeTransports(arrayOf(TRANSPORT_ID), observer)
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
package com.stevesoltys.backup.ui.storage
|
package com.stevesoltys.backup.ui.storage
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Intent
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import com.stevesoltys.backup.R
|
import com.stevesoltys.backup.R
|
||||||
import com.stevesoltys.backup.settings.setBackupFolderUri
|
|
||||||
import com.stevesoltys.backup.transport.ConfigurableBackupTransportService
|
|
||||||
import com.stevesoltys.backup.transport.backup.plugins.DIRECTORY_ROOT
|
import com.stevesoltys.backup.transport.backup.plugins.DIRECTORY_ROOT
|
||||||
import com.stevesoltys.backup.transport.restore.plugins.DocumentsProviderRestorePlugin
|
import com.stevesoltys.backup.transport.restore.plugins.DocumentsProviderRestorePlugin
|
||||||
|
|
||||||
|
@ -19,13 +16,7 @@ internal class RestoreStorageViewModel(private val app: Application) : StorageVi
|
||||||
|
|
||||||
override fun onLocationSet(uri: Uri) {
|
override fun onLocationSet(uri: Uri) {
|
||||||
if (hasBackup(uri)) {
|
if (hasBackup(uri)) {
|
||||||
// store backup folder location in settings
|
saveStorage(uri)
|
||||||
setBackupFolderUri(app, uri)
|
|
||||||
|
|
||||||
// stop backup service to be sure the old location will get updated
|
|
||||||
app.stopService(Intent(app, ConfigurableBackupTransportService::class.java))
|
|
||||||
|
|
||||||
Log.d(TAG, "New storage location chosen: $uri")
|
|
||||||
|
|
||||||
mLocationChecked.setEvent(LocationResult())
|
mLocationChecked.setEvent(LocationResult())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -36,6 +36,10 @@ data class StorageRoot(
|
||||||
internal val supportsEject: Boolean,
|
internal val supportsEject: Boolean,
|
||||||
internal val enabled: Boolean = true) {
|
internal val enabled: Boolean = true) {
|
||||||
|
|
||||||
|
internal val uri: Uri by lazy {
|
||||||
|
DocumentsContract.buildTreeDocumentUri(authority, documentId)
|
||||||
|
}
|
||||||
|
|
||||||
fun isInternal(): Boolean {
|
fun isInternal(): Boolean {
|
||||||
return authority == AUTHORITY_STORAGE && !supportsEject
|
return authority == AUTHORITY_STORAGE && !supportsEject
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package com.stevesoltys.backup.ui.storage
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.Intent.*
|
import android.content.Intent.*
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.DocumentsContract
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.INVISIBLE
|
import android.view.View.INVISIBLE
|
||||||
|
@ -72,8 +71,9 @@ internal class StorageRootsFragment : Fragment(), StorageRootClickedListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onClick(root: StorageRoot) {
|
override fun onClick(root: StorageRoot) {
|
||||||
|
viewModel.onStorageRootChosen(root)
|
||||||
val intent = Intent(requireContext(), PermissionGrantActivity::class.java)
|
val intent = Intent(requireContext(), PermissionGrantActivity::class.java)
|
||||||
intent.data = DocumentsContract.buildTreeDocumentUri(root.authority, root.documentId)
|
intent.data = root.uri
|
||||||
intent.addFlags(FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
|
intent.addFlags(FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
|
||||||
FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION)
|
FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||||
startActivityForResult(intent, REQUEST_CODE_OPEN_DOCUMENT_TREE)
|
startActivityForResult(intent, REQUEST_CODE_OPEN_DOCUMENT_TREE)
|
||||||
|
|
|
@ -6,15 +6,21 @@ import android.content.Intent
|
||||||
import android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION
|
import android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
import android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
import android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import android.util.Log
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import com.stevesoltys.backup.isOnExternalStorage
|
import com.stevesoltys.backup.R
|
||||||
import com.stevesoltys.backup.settings.getBackupFolderUri
|
import com.stevesoltys.backup.settings.Storage
|
||||||
|
import com.stevesoltys.backup.settings.getStorage
|
||||||
|
import com.stevesoltys.backup.settings.setStorage
|
||||||
|
import com.stevesoltys.backup.transport.ConfigurableBackupTransportService
|
||||||
import com.stevesoltys.backup.ui.LiveEvent
|
import com.stevesoltys.backup.ui.LiveEvent
|
||||||
import com.stevesoltys.backup.ui.MutableLiveEvent
|
import com.stevesoltys.backup.ui.MutableLiveEvent
|
||||||
|
|
||||||
|
private val TAG = StorageViewModel::class.java.simpleName
|
||||||
|
|
||||||
internal abstract class StorageViewModel(private val app: Application) : AndroidViewModel(app), RemovableStorageListener {
|
internal abstract class StorageViewModel(private val app: Application) : AndroidViewModel(app), RemovableStorageListener {
|
||||||
|
|
||||||
private val mStorageRoots = MutableLiveData<List<StorageRoot>>()
|
private val mStorageRoots = MutableLiveData<List<StorageRoot>>()
|
||||||
|
@ -27,14 +33,15 @@ internal abstract class StorageViewModel(private val app: Application) : Android
|
||||||
internal val locationChecked: LiveEvent<LocationResult> get() = mLocationChecked
|
internal val locationChecked: LiveEvent<LocationResult> get() = mLocationChecked
|
||||||
|
|
||||||
private val storageRootFetcher by lazy { StorageRootFetcher(app) }
|
private val storageRootFetcher by lazy { StorageRootFetcher(app) }
|
||||||
|
private var storageRoot: StorageRoot? = null
|
||||||
|
|
||||||
abstract val isRestoreOperation: Boolean
|
abstract val isRestoreOperation: Boolean
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
internal fun validLocationIsSet(context: Context): Boolean {
|
internal fun validLocationIsSet(context: Context): Boolean {
|
||||||
val uri = getBackupFolderUri(context) ?: return false
|
val storage = getStorage(context) ?: return false
|
||||||
if (uri.isOnExternalStorage()) return true // TODO use ejectable instead
|
if (storage.ejectable) return true
|
||||||
val file = DocumentFile.fromTreeUri(context, uri) ?: return false
|
val file = DocumentFile.fromTreeUri(context, storage.uri) ?: return false
|
||||||
return file.isDirectory
|
return file.isDirectory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,6 +57,9 @@ internal abstract class StorageViewModel(private val app: Application) : Android
|
||||||
|
|
||||||
override fun onStorageChanged() = loadStorageRoots()
|
override fun onStorageChanged() = loadStorageRoots()
|
||||||
|
|
||||||
|
fun onStorageRootChosen(root: StorageRoot) {
|
||||||
|
storageRoot = root
|
||||||
|
}
|
||||||
|
|
||||||
internal fun onUriPermissionGranted(result: Intent?) {
|
internal fun onUriPermissionGranted(result: Intent?) {
|
||||||
val uri = result?.data ?: return
|
val uri = result?.data ?: return
|
||||||
|
@ -66,6 +76,23 @@ internal abstract class StorageViewModel(private val app: Application) : Android
|
||||||
|
|
||||||
abstract fun onLocationSet(uri: Uri)
|
abstract fun onLocationSet(uri: Uri)
|
||||||
|
|
||||||
|
protected fun saveStorage(uri: Uri) {
|
||||||
|
// store backup storage location in settings
|
||||||
|
val root = storageRoot ?: throw IllegalStateException()
|
||||||
|
val name = if (root.isInternal()) {
|
||||||
|
"${root.title} (${app.getString(R.string.settings_backup_location_internal)})"
|
||||||
|
} else {
|
||||||
|
root.title
|
||||||
|
}
|
||||||
|
val storage = Storage(uri, name, root.supportsEject)
|
||||||
|
setStorage(app, storage)
|
||||||
|
|
||||||
|
// stop backup service to be sure the old location will get updated
|
||||||
|
app.stopService(Intent(app, ConfigurableBackupTransportService::class.java))
|
||||||
|
|
||||||
|
Log.d(TAG, "New storage location saved: $uri")
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
storageRootFetcher.setRemovableStorageListener(null)
|
storageRootFetcher.setRemovableStorageListener(null)
|
||||||
super.onCleared()
|
super.onCleared()
|
||||||
|
|
|
@ -29,7 +29,8 @@
|
||||||
<string name="settings_backup_location_picker">Choose backup location</string>
|
<string name="settings_backup_location_picker">Choose backup location</string>
|
||||||
<string name="settings_backup_location_title">Backup Location</string>
|
<string name="settings_backup_location_title">Backup Location</string>
|
||||||
<string name="settings_backup_location_invalid">The chosen location can not be used.</string>
|
<string name="settings_backup_location_invalid">The chosen location can not be used.</string>
|
||||||
<string name="settings_backup_external_storage">External Storage</string>
|
<string name="settings_backup_location_none">None</string>
|
||||||
|
<string name="settings_backup_location_internal">Internal Storage</string>
|
||||||
<string name="settings_info">All backups are encrypted on your phone. To restore from backup you will need your 12-word recovery code.</string>
|
<string name="settings_info">All backups are encrypted on your phone. To restore from backup you will need your 12-word recovery code.</string>
|
||||||
<string name="settings_auto_restore_title">Automatic restore</string>
|
<string name="settings_auto_restore_title">Automatic restore</string>
|
||||||
<string name="settings_auto_restore_summary">When reinstalling an app, restore backed up settings and data</string>
|
<string name="settings_auto_restore_summary">When reinstalling an app, restore backed up settings and data</string>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
app:dependency="backup"
|
app:dependency="backup"
|
||||||
app:icon="@drawable/ic_storage"
|
app:icon="@drawable/ic_storage"
|
||||||
app:key="backup_location"
|
app:key="backup_location"
|
||||||
app:summary="@string/settings_backup_external_storage"
|
app:summary="@string/settings_backup_location_none"
|
||||||
app:title="@string/settings_backup_location" />
|
app:title="@string/settings_backup_location" />
|
||||||
|
|
||||||
<androidx.preference.SwitchPreferenceCompat
|
<androidx.preference.SwitchPreferenceCompat
|
||||||
|
|
Loading…
Reference in a new issue