From 32b132950ccfe4b162fd84e50437c5208ec53aff Mon Sep 17 00:00:00 2001 From: Milan Date: Fri, 15 Nov 2024 15:10:17 +0100 Subject: [PATCH] Address book android auto backup (#1641) * Address book android auto backup * Documentation update * Address book container folder added * Address book general error handling * Address book memory storage hotfix * Documentation update --------- Co-authored-by: Honza --- CHANGELOG.md | 1 + app/src/main/AndroidManifest.xml | 5 ++- app/src/main/res/xml/auto_backup_config.xml | 6 +++ .../res/xml/auto_backup_config_android_12.xml | 8 ++++ app/src/zcashmainnetDebug/AndroidManifest.xml | 1 - app/src/zcashtestnet/AndroidManifest.xml | 1 - app/src/zcashtestnetDebug/AndroidManifest.xml | 1 - docs/README.md | 9 +++- docs/whatsNew/WHATS_NEW_EN.md | 1 + docs/whatsNew/WHATS_NEW_ES.md | 1 + .../datasource/LocalAddressBookDataSource.kt | 45 ++++++++++--------- .../provider/AddressBookStorageProvider.kt | 37 +++++++++------ 12 files changed, 75 insertions(+), 41 deletions(-) create mode 100644 app/src/main/res/xml/auto_backup_config.xml create mode 100644 app/src/main/res/xml/auto_backup_config_android_12.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c8c6eb10..b3edf4a09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this application adheres to [Semantic Versioning](https://semver.org/spec/v2 ### Added - Address book encryption +- Android auto backup support for address book encryption - The device authentication feature on the Zashi app launch has been added - Zashi app now supports Spanish language. It can be changed in the System settings options. - The Flexa SDK has been adopted to enable payments using the embedded Flexa UI diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f504166dd..f4555d624 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,7 +4,10 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/xml/auto_backup_config_android_12.xml b/app/src/main/res/xml/auto_backup_config_android_12.xml new file mode 100644 index 000000000..481bbaea6 --- /dev/null +++ b/app/src/main/res/xml/auto_backup_config_android_12.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/zcashmainnetDebug/AndroidManifest.xml b/app/src/zcashmainnetDebug/AndroidManifest.xml index c4408c409..76538fc15 100644 --- a/app/src/zcashmainnetDebug/AndroidManifest.xml +++ b/app/src/zcashmainnetDebug/AndroidManifest.xml @@ -4,7 +4,6 @@ diff --git a/app/src/zcashtestnet/AndroidManifest.xml b/app/src/zcashtestnet/AndroidManifest.xml index 317015e2e..7e1b440d1 100644 --- a/app/src/zcashtestnet/AndroidManifest.xml +++ b/app/src/zcashtestnet/AndroidManifest.xml @@ -4,7 +4,6 @@ diff --git a/app/src/zcashtestnetDebug/AndroidManifest.xml b/app/src/zcashtestnetDebug/AndroidManifest.xml index beecfb955..4551b7489 100644 --- a/app/src/zcashtestnetDebug/AndroidManifest.xml +++ b/app/src/zcashtestnetDebug/AndroidManifest.xml @@ -4,7 +4,6 @@ diff --git a/docs/README.md b/docs/README.md index 31c0c9ef6..344d0b85d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,9 @@ # Documentation -Here you'll find documentation -TBD \ No newline at end of file +# Android auto backup testing + +To force the android system back up the app use the following commands: +``` + adb shell bmgr enable true + adb shell bmgr backupnow co.electriccoin.zcash.debug +``` diff --git a/docs/whatsNew/WHATS_NEW_EN.md b/docs/whatsNew/WHATS_NEW_EN.md index fde673660..1b9f22c7c 100644 --- a/docs/whatsNew/WHATS_NEW_EN.md +++ b/docs/whatsNew/WHATS_NEW_EN.md @@ -11,6 +11,7 @@ directly impact users rather than highlighting other key architectural updates.* ### Added - Address book encryption +- Android auto backup support for address book encryption - The device authentication feature on the Zashi app launch has been added - Zashi app now supports Spanish language. It can be changed in the System settings options. - The Flexa SDK has been adopted to enable payments using the embedded Flexa UI diff --git a/docs/whatsNew/WHATS_NEW_ES.md b/docs/whatsNew/WHATS_NEW_ES.md index d222098c2..315be7623 100644 --- a/docs/whatsNew/WHATS_NEW_ES.md +++ b/docs/whatsNew/WHATS_NEW_ES.md @@ -11,6 +11,7 @@ directly impact users rather than highlighting other key architectural updates.* ### Added - Address book encryption +- Android auto backup support for address book encryption - The device authentication feature on the Zashi app launch has been added - Zashi app now supports Spanish language. It can be changed in the System settings options. - The Flexa SDK has been adopted to enable payments using the embedded Flexa UI diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/common/datasource/LocalAddressBookDataSource.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/common/datasource/LocalAddressBookDataSource.kt index 3fe1d1733..479b7ee3d 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/common/datasource/LocalAddressBookDataSource.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/common/datasource/LocalAddressBookDataSource.kt @@ -11,8 +11,6 @@ import co.electriccoin.zcash.ui.common.serialization.addressbook.AddressBookKey import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import kotlinx.datetime.Clock -import java.io.IOException -import java.security.GeneralSecurityException interface LocalAddressBookDataSource { suspend fun getContacts(addressBookKey: AddressBookKey): AddressBook @@ -61,7 +59,9 @@ class LocalAddressBookDataSourceImpl( lastUpdated = Clock.System.now(), version = ADDRESS_BOOK_SERIALIZATION_V1, contacts = emptyList(), - ) + ).also { + this@LocalAddressBookDataSourceImpl.addressBook = it + } writeAddressBookToLocalStorage(newAddressBook, addressBookKey) } newAddressBook @@ -88,7 +88,9 @@ class LocalAddressBookDataSourceImpl( address = address, lastUpdated = lastUpdated, ), - ) + ).also { + addressBook = it + } writeAddressBookToLocalStorage(newAddressBook, addressBookKey) newAddressBook } @@ -118,7 +120,9 @@ class LocalAddressBookDataSourceImpl( ) } .toList(), - ) + ).also { + addressBook = it + } writeAddressBookToLocalStorage(newAddressBook, addressBookKey) newAddressBook } @@ -139,7 +143,9 @@ class LocalAddressBookDataSourceImpl( remove(addressBookContact) } .toList(), - ) + ).also { + addressBook = it + } writeAddressBookToLocalStorage(newAddressBook, addressBookKey) newAddressBook } @@ -158,22 +164,15 @@ class LocalAddressBookDataSourceImpl( @Suppress("ReturnCount") private suspend fun readLocalFileToAddressBook(addressBookKey: AddressBookKey): AddressBook? { - val encryptedFile = addressBookStorageProvider.getStorageFile(addressBookKey) - val unencryptedFile = addressBookStorageProvider.getLegacyUnencryptedStorageFile() + val encryptedFile = runCatching { addressBookStorageProvider.getStorageFile(addressBookKey) }.getOrNull() + val unencryptedFile = runCatching { addressBookStorageProvider.getLegacyUnencryptedStorageFile() }.getOrNull() if (encryptedFile != null) { - return try { - addressBookProvider.readAddressBookFromFile(encryptedFile, addressBookKey) - .also { - unencryptedFile?.deleteSuspend() - } - } catch (e: GeneralSecurityException) { - Twig.warn(e) { "Failed to decrypt address book" } - null - } catch (e: IOException) { - Twig.warn(e) { "Failed to decrypt address book" } - null - } + return runCatching { + addressBookProvider + .readAddressBookFromFile(encryptedFile, addressBookKey) + .also { unencryptedFile?.deleteSuspend() } + }.onFailure { e -> Twig.warn(e) { "Failed to decrypt address book" } }.getOrNull() } return if (unencryptedFile != null) { @@ -191,7 +190,9 @@ class LocalAddressBookDataSourceImpl( addressBook: AddressBook, addressBookKey: AddressBookKey ) { - val file = addressBookStorageProvider.getOrCreateStorageFile(addressBookKey) - addressBookProvider.writeAddressBookToFile(file, addressBook, addressBookKey) + runCatching { + val file = addressBookStorageProvider.getOrCreateStorageFile(addressBookKey) + addressBookProvider.writeAddressBookToFile(file, addressBook, addressBookKey) + }.onFailure { e -> Twig.warn(e) { "Failed to write address book" } } } } diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/common/provider/AddressBookStorageProvider.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/common/provider/AddressBookStorageProvider.kt index 69b8dcd61..05a417d4e 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/common/provider/AddressBookStorageProvider.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/common/provider/AddressBookStorageProvider.kt @@ -11,17 +11,17 @@ interface AddressBookStorageProvider { fun getOrCreateStorageFile(addressBookKey: AddressBookKey): File - /** - * Create a temporary file into which data from remote is written. This file is removed after usage. - */ - fun getOrCreateTempStorageFile(): File + // /** + // * Create a temporary file into which data from remote is written. This file is removed after usage. + // */ + // fun getOrCreateTempStorageFile(): File } class AddressBookStorageProviderImpl( private val context: Context ) : AddressBookStorageProvider { override fun getStorageFile(addressBookKey: AddressBookKey): File? { - return File(context.noBackupFilesDir, addressBookKey.fileIdentifier()) + return File(getOrCreateAddressBookDir(), addressBookKey.fileIdentifier()) .takeIf { it.exists() && it.isFile } } @@ -31,19 +31,30 @@ class AddressBookStorageProviderImpl( } override fun getOrCreateStorageFile(addressBookKey: AddressBookKey): File { - return getOrCreateFile(addressBookKey.fileIdentifier()) - } - - override fun getOrCreateTempStorageFile(): File = getOrCreateFile(REMOTE_ADDRESS_BOOK_FILE_NAME_LOCAL_COPY) - - private fun getOrCreateFile(name: String): File { - val file = File(context.noBackupFilesDir, name) + val file = File(getOrCreateAddressBookDir(), addressBookKey.fileIdentifier()) if (!file.exists()) { file.createNewFile() } return file } + + // override fun getOrCreateTempStorageFile(): File { + // val file = File(context.noBackupFilesDir, REMOTE_ADDRESS_BOOK_FILE_NAME_LOCAL_COPY) + // if (!file.exists()) { + // file.createNewFile() + // } + // return file + // } + + private fun getOrCreateAddressBookDir(): File { + val filesDir = context.filesDir + val addressBookDir = File(filesDir, "address_book") + if (!addressBookDir.exists()) { + addressBookDir.mkdir() + } + return addressBookDir + } } private const val LEGACY_UNENCRYPTED_ADDRESS_BOOK_FILE_NAME = "address_book" -private const val REMOTE_ADDRESS_BOOK_FILE_NAME_LOCAL_COPY = "address_book_temp" +// private const val REMOTE_ADDRESS_BOOK_FILE_NAME_LOCAL_COPY = "address_book_temp"