Disable automatic backups when a removable USB flash drive is used

as storage location.

The backup backoff time is not reliable for this as the system still
attempts to backup the magic @pm@ package without checking for the
backoff value.
This commit is contained in:
Torsten Grote 2019-09-19 16:29:53 -03:00
parent 2c4d44c5b9
commit 26f23e95fe
No known key found for this signature in database
GPG key ID: 3E5F77D92CF891FF
8 changed files with 59 additions and 19 deletions

View file

@ -19,6 +19,11 @@
android:name="android.permission.MANAGE_USB"
tools:ignore="ProtectedPermissions" />
<!-- This is needed to change system backup settings -->
<uses-permission
android:name="android.permission.WRITE_SECURE_SETTINGS"
tools:ignore="ProtectedPermissions" />
<application
android:name=".Backup"
android:allowBackup="false"

View file

@ -50,7 +50,7 @@ class RestoreProgressFragment : Fragment() {
// success
currentPackageView.text = getString(R.string.restore_finished_success)
val settingsManager = (requireContext().applicationContext as Backup).settingsManager
warningView.text = if (settingsManager.getStorage()?.ejectable == true) {
warningView.text = if (settingsManager.getStorage()?.isUsb == true) {
getString(R.string.restore_finished_warning_only_installed, getString(R.string.restore_finished_warning_ejectable))
} else {
getString(R.string.restore_finished_warning_only_installed, null)

View file

@ -0,0 +1,30 @@
package com.stevesoltys.backup.settings
import android.content.ContentResolver
import android.provider.Settings
private val SETTING = Settings.Secure.BACKUP_MANAGER_CONSTANTS
private const val DELIMITER = ','
private const val KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS = "key_value_backup_interval_milliseconds"
private const val FULL_BACKUP_INTERVAL_MILLISECONDS = "full_backup_interval_milliseconds"
object BackupManagerSettings {
fun enableAutomaticBackups(resolver: ContentResolver) {
// setting this to null will cause the BackupManagerConstants to use default values
setSettingValue(resolver, null)
}
fun disableAutomaticBackups(resolver: ContentResolver) {
val value = Long.MAX_VALUE
val kv = "$KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS=$value"
val full = "$FULL_BACKUP_INTERVAL_MILLISECONDS=$value"
setSettingValue(resolver, "$kv$DELIMITER$full")
}
private fun setSettingValue(resolver: ContentResolver, value: String?) {
Settings.Secure.putString(resolver, SETTING, value)
}
}

View file

@ -9,7 +9,7 @@ import java.util.*
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_STORAGE_IS_USB = "storageIsUsb"
private const val PREF_KEY_FLASH_DRIVE_NAME = "flashDriveName"
private const val PREF_KEY_FLASH_DRIVE_SERIAL_NUMBER = "flashSerialNumber"
@ -28,7 +28,7 @@ class SettingsManager(context: Context) {
prefs.edit()
.putString(PREF_KEY_STORAGE_URI, storage.uri.toString())
.putString(PREF_KEY_STORAGE_NAME, storage.name)
.putBoolean(PREF_KEY_STORAGE_EJECTABLE, storage.ejectable)
.putBoolean(PREF_KEY_STORAGE_IS_USB, storage.isUsb)
.apply()
}
@ -36,8 +36,8 @@ class SettingsManager(context: Context) {
val uriStr = prefs.getString(PREF_KEY_STORAGE_URI, null) ?: return null
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)
val isUsb = prefs.getBoolean(PREF_KEY_STORAGE_IS_USB, false)
return Storage(uri, name, isUsb)
}
fun setFlashDrive(usb: FlashDrive?) {
@ -86,9 +86,9 @@ class SettingsManager(context: Context) {
/**
* Sets the last backup time to "now".
*/
fun saveNewBackupTime() {
fun saveNewBackupTime(millis: Long = Date().time) {
prefs.edit()
.putLong(PREF_KEY_BACKUP_TIME, Date().time)
.putLong(PREF_KEY_BACKUP_TIME, millis)
.apply()
}
@ -118,7 +118,7 @@ class SettingsManager(context: Context) {
data class Storage(
val uri: Uri,
val name: String,
val ejectable: Boolean) {
val isUsb: Boolean) {
fun getDocumentFile(context: Context) = DocumentFile.fromTreeUri(context, uri)
?: throw AssertionError("Should only happen on API < 21.")
}

View file

@ -199,7 +199,7 @@ class BackupCoordinator(
// back off if there's no storage set
val storage = settingsManager.getStorage() ?: return defaultBackoff
// don't back off if storage is not ejectable or available right now
return if (!storage.ejectable || storage.getDocumentFile(context).isDirectory) noBackoff
return if (!storage.isUsb || storage.getDocumentFile(context).isDirectory) noBackoff
// otherwise back off
else defaultBackoff
}

View file

@ -33,7 +33,7 @@ data class StorageRoot(
internal val title: String,
internal val summary: String?,
internal val availableBytes: Long?,
internal val supportsEject: Boolean,
internal val isUsb: Boolean,
internal val enabled: Boolean = true) {
internal val uri: Uri by lazy {
@ -41,7 +41,7 @@ data class StorageRoot(
}
fun isInternal(): Boolean {
return authority == AUTHORITY_STORAGE && !supportsEject
return authority == AUTHORITY_STORAGE && !isUsb
}
}
@ -122,7 +122,6 @@ internal class StorageRootFetcher(private val context: Context) {
if (!supportsCreate || !supportsIsChild) return null
val rootId = cursor.getString(COLUMN_ROOT_ID)!!
if (authority == AUTHORITY_STORAGE && rootId == ROOT_ID_HOME) return null
val supportsEject = flags and FLAG_SUPPORTS_EJECT != 0
return StorageRoot(
authority = authority,
rootId = rootId,
@ -131,13 +130,13 @@ internal class StorageRootFetcher(private val context: Context) {
title = cursor.getString(COLUMN_TITLE)!!,
summary = cursor.getString(COLUMN_SUMMARY),
availableBytes = cursor.getLong(COLUMN_AVAILABLE_BYTES),
supportsEject = supportsEject
isUsb = flags and FLAG_REMOVABLE_USB != 0
)
}
private fun checkOrAddUsbRoot(roots: ArrayList<StorageRoot>) {
for (root in roots) {
if (root.authority == AUTHORITY_STORAGE && root.supportsEject) return
if (root.authority == AUTHORITY_STORAGE && root.isUsb) return
}
val root = StorageRoot(
authority = AUTHORITY_STORAGE,
@ -147,7 +146,7 @@ internal class StorageRootFetcher(private val context: Context) {
title = context.getString(R.string.storage_fake_drive_title),
summary = context.getString(R.string.storage_fake_drive_summary),
availableBytes = null,
supportsEject = true,
isUsb = true,
enabled = false
)
roots.add(root)

View file

@ -15,6 +15,7 @@ import androidx.lifecycle.MutableLiveData
import com.stevesoltys.backup.Backup
import com.stevesoltys.backup.R
import com.stevesoltys.backup.isMassStorage
import com.stevesoltys.backup.settings.BackupManagerSettings
import com.stevesoltys.backup.settings.FlashDrive
import com.stevesoltys.backup.settings.Storage
import com.stevesoltys.backup.transport.ConfigurableBackupTransportService
@ -45,7 +46,7 @@ internal abstract class StorageViewModel(private val app: Application) : Android
internal fun validLocationIsSet(context: Context): Boolean {
val settingsManager = (context.applicationContext as Backup).settingsManager
val storage = settingsManager.getStorage() ?: return false
if (storage.ejectable) return true
if (storage.isUsb) return true
return storage.getDocumentFile(context).isDirectory
}
}
@ -88,16 +89,20 @@ internal abstract class StorageViewModel(private val app: Application) : Android
} else {
root.title
}
val storage = Storage(uri, name, root.supportsEject)
val storage = Storage(uri, name, root.isUsb)
settingsManager.setStorage(storage)
// reset time of last backup to "Never"
settingsManager.resetBackupTime()
if (storage.ejectable) {
if (storage.isUsb) {
val wasSaved = saveUsbDevice()
// reset stored flash drive, if we did not update it
if (!wasSaved) settingsManager.setFlashDrive(null)
BackupManagerSettings.disableAutomaticBackups(app.contentResolver)
} else {
settingsManager.setFlashDrive(null)
BackupManagerSettings.enableAutomaticBackups(app.contentResolver)
}
// stop backup service to be sure the old location will get updated
@ -114,7 +119,7 @@ internal abstract class StorageViewModel(private val app: Application) : Android
return true
}
}
Log.w(TAG, "No USB device found for ejectable storage.")
Log.e(TAG, "No USB device found even though we were expecting one.")
return false
}

View file

@ -3,5 +3,6 @@
<privapp-permissions package="com.stevesoltys.backup">
<permission name="android.permission.BACKUP"/>
<permission name="android.permission.MANAGE_USB"/>
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
</privapp-permissions>
</permissions>