View Issue Details

IDProjectCategoryView StatusLast Update
0012090Talerwallet (Android App)public2026-11-11 01:44
Reporterbot-cg [agent] Assigned ToResolution deadline
ImplementerReviewer 
Release signed byDeployed by 
VerifierCommunicatorCM_7  
Data protection authority notification requiredNo  
CSIRT notification requiredNo  
Estimated effort (hours)Actual effort (hours)0 
Fast-trackNo
Work packagenone
PrioritynormalSeverityminorReproducibilityhave not tried
Status newResolutionopen 
Summary0012090: Android: database export/import and the app version are only visible in developer mode (app version: regression of 0008536) -- iOS and the WebExtension offer backup/restore to everybody (patch attached)
DescriptionOn Android, a user who has not switched on developer mode can neither back up the wallet database (Export database / Import database) nor see which app version is installed. All of these rows sit inside the developer-mode block of Settings. iOS offers "Backup / Restore" (More settings) and shows "App Version" and "Wallet-Core Version" under "About GNU Taler" to everybody; the WebExtension offers "Database export and import" in its normal settings.

For the app version this is a regression of 0008536 ("show version info even when not in developer mode", fixed in b3119118: app version shown by default, wallet-core version developer-only). The Compose migration (2cede292, 2026-04-22) moved the app version into the developer block; before it, settings_main.xml had pref_version_app with isPreferenceVisible="true" and it was not in SettingsFragment's devPrefs list. Export/import were already developer-only then.

What the user sees (developer mode off):
- Android: Payment services, Bank accounts, Tax-deductible donations, Protect access to wallet, Developer mode, and nothing else (before-android-1.png). The export/import/version rows appear only with developer mode on, next to "Reset Wallet (dangerous!)" and the integration test (before-android-2.png).
- iOS: Settings starts with "About GNU Taler" (App Version 1.6.18, Wallet-Core Version 1.6.49), More > "Backup / Restore" with "Create JSON backup" / restore list (before-ios-1.png .. before-ios-4.png).
- WebExtension: Settings > "Database export and import" with a warning that exports contain sensitive data (before-web-1.png).

Why it matters: the wallet holds money, and uninstalling or losing the phone loses it (0010681). The only backup the Android app has is hidden behind a switch labelled "Shows more information intended for debugging". Support also cannot ask an ordinary user for the app version.

Code (origin/master 4c483527):
- wallet/src/main/java/net/taler/wallet/settings/SettingsScreen.kt:240 `if (devModeEnabled) {`, then :310-316 Export database, :324-338 Import database, :348-358 App version / Wallet Core version; the export confirmation dialog (pendingDbExport, :408-433) is also inside the block.

The patch (android-F408-backup-and-version-visible.patch, SettingsScreen.kt only): moves "Export database" (JSON, with its existing "sensitive data" confirmation), "Import database" (with its existing confirmation) and "App version" above the Developer mode switch, and moves the export confirmation dialog out of the developer block so it also works with developer mode off. Raw SQLite export, the wallet-core and protocol versions (as decided in 0008536), integration test and reset stay developer-only. No new strings.

Verified: :wallet:assembleFdroidSim and :wallet:testFdroidSimUnitTest pass; after-android-1.png (Export/Import database and App version visible with developer mode off) and after-android-2.png (export confirmation dialog with developer mode off).

Related, not changed here: 0011037 (Android lacks the diagnostics export iOS and web have), 0011844 (DD92 backup & sync UI).

Assisted by LLM
Steps To Reproduce1. Fresh install, developer mode off.
2. Settings: no Export/Import database, no App version.
3. Switch on Developer mode: the rows appear.
TagsNo tags attached.
Attached Files
before-android-1.png (160,091 bytes)   
before-android-1.png (160,091 bytes)   
before-android-2.png (186,235 bytes)   
before-android-2.png (186,235 bytes)   
before-ios-1.png (276,676 bytes)
before-ios-2.png (217,358 bytes)   
before-ios-2.png (217,358 bytes)   
before-ios-3.png (253,097 bytes)   
before-ios-3.png (253,097 bytes)   
before-ios-4.png (300,310 bytes)
before-web-1.png (157,313 bytes)   
before-web-1.png (157,313 bytes)   
after-android-1.png (201,724 bytes)   
after-android-1.png (201,724 bytes)   
after-android-2.png (198,747 bytes)   
after-android-2.png (198,747 bytes)   
android-F408-backup-and-version-visible.patch (7,122 bytes)   
diff --git a/wallet/src/main/java/net/taler/wallet/settings/SettingsScreen.kt b/wallet/src/main/java/net/taler/wallet/settings/SettingsScreen.kt
index 05923069..9e9a2f30 100644
--- a/wallet/src/main/java/net/taler/wallet/settings/SettingsScreen.kt
+++ b/wallet/src/main/java/net/taler/wallet/settings/SettingsScreen.kt
@@ -227,6 +227,36 @@ fun SettingsContent(
             }
         )
 
+        SettingsItem(
+            title = stringResource(R.string.settings_db_export),
+            summary = stringResource(R.string.settings_db_export_summary),
+            icon = ImageVector.vectorResource(R.drawable.ic_unarchive),
+            onClick = { pendingDbExport = DbExportType.Json }
+        )
+
+        SettingsItem(
+            title = stringResource(R.string.settings_db_import),
+            summary = stringResource(R.string.settings_db_import_summary),
+            icon = ImageVector.vectorResource(R.drawable.ic_archive),
+            onClick = {
+                MaterialAlertDialogBuilder(context)
+                    .setMessage(R.string.settings_dialog_import_message)
+                    .setNegativeButton(R.string.import_db) { _, _ ->
+                        dbImportLauncher.launch(arrayOf("application/json"))
+                    }
+                    .setPositiveButton(R.string.cancel) { _, _ ->
+                        scope.launch { snackbarHostState.showSnackbar(importCanceledMessage) }
+                    }
+                    .show()
+            }
+        )
+
+        SettingsItem(
+            title = stringResource(R.string.settings_version_app),
+            summary = "${BuildConfig.VERSION_NAME} (${BuildConfig.FLAVOR} ${BuildConfig.VERSION_CODE})",
+            icon = ImageVector.vectorResource(R.drawable.ic_account_balance_wallet),
+        )
+
         SettingsSwitchItem(
             title = stringResource(R.string.settings_dev_mode),
             summary = stringResource(R.string.settings_dev_mode_summary),
@@ -308,13 +338,6 @@ fun SettingsContent(
                 onClick = { onNavigate(WalletDestination.AliasRegistration, false) }
             )
 
-            SettingsItem(
-                title = stringResource(R.string.settings_db_export),
-                summary = stringResource(R.string.settings_db_export_summary),
-                icon = ImageVector.vectorResource(R.drawable.ic_unarchive),
-                onClick = { pendingDbExport = DbExportType.Json }
-            )
-
             SettingsItem(
                 title = stringResource(R.string.settings_db_export_raw),
                 summary = stringResource(R.string.settings_db_export_raw_summary),
@@ -322,23 +345,6 @@ fun SettingsContent(
                 onClick = { pendingDbExport = DbExportType.Raw }
             )
 
-            SettingsItem(
-                title = stringResource(R.string.settings_db_import),
-                summary = stringResource(R.string.settings_db_import_summary),
-                icon = ImageVector.vectorResource(R.drawable.ic_archive),
-                onClick = {
-                    MaterialAlertDialogBuilder(context)
-                        .setMessage(R.string.settings_dialog_import_message)
-                        .setNegativeButton(R.string.import_db) { _, _ ->
-                            dbImportLauncher.launch(arrayOf("application/json"))
-                        }
-                        .setPositiveButton(R.string.cancel) { _, _ ->
-                            scope.launch { snackbarHostState.showSnackbar(importCanceledMessage) }
-                        }
-                        .show()
-                }
-            )
-
             if (databaseBackend == WalletDatabaseBackend.IndexedDB) SettingsItem(
                 title = stringResource(R.string.settings_migrate_db),
                 summary = stringResource(R.string.settings_migrate_db_summary),
@@ -346,12 +352,6 @@ fun SettingsContent(
                 onClick = model::offerDatabaseMigration,
             )
 
-            SettingsItem(
-                title = stringResource(R.string.settings_version_app),
-                summary = "${BuildConfig.VERSION_NAME} (${BuildConfig.FLAVOR} ${BuildConfig.VERSION_CODE})",
-                icon = ImageVector.vectorResource(R.drawable.ic_account_balance_wallet),
-            )
-
             SettingsItem(
                 title = stringResource(R.string.settings_version_core),
                 summary = "$walletVersion ($walletVersionHash)",
@@ -404,32 +404,32 @@ fun SettingsContent(
                         .show()
                 }
             )
+        }
 
-            pendingDbExport?.let { exportType ->
-                AlertDialog(
-                    onDismissRequest = { pendingDbExport = null },
-                    title = { Text(stringResource(R.string.wallet_export_database)) },
-                    text = { Text(stringResource(R.string.wallet_export_database_warning)) },
-                    confirmButton = {
-                        Button(onClick = {
-                            pendingDbExport = null
-                            when (exportType) {
-                                DbExportType.Json ->
-                                    dbExportLauncher.launch("taler-wallet-db-${System.currentTimeMillis()}.json")
-                                DbExportType.Raw ->
-                                    rawDbExportLauncher.launch("taler-wallet-db-${System.currentTimeMillis()}.sqlite3")
-                            }
-                        }) {
-                            Text(stringResource(R.string.wallet_export_database_confirm))
-                        }
-                    },
-                    dismissButton = {
-                        TextButton(onClick = { pendingDbExport = null }) {
-                            Text(stringResource(R.string.cancel))
+        pendingDbExport?.let { exportType ->
+            AlertDialog(
+                onDismissRequest = { pendingDbExport = null },
+                title = { Text(stringResource(R.string.wallet_export_database)) },
+                text = { Text(stringResource(R.string.wallet_export_database_warning)) },
+                confirmButton = {
+                    Button(onClick = {
+                        pendingDbExport = null
+                        when (exportType) {
+                            DbExportType.Json ->
+                                dbExportLauncher.launch("taler-wallet-db-${System.currentTimeMillis()}.json")
+                            DbExportType.Raw ->
+                                rawDbExportLauncher.launch("taler-wallet-db-${System.currentTimeMillis()}.sqlite3")
                         }
+                    }) {
+                        Text(stringResource(R.string.wallet_export_database_confirm))
                     }
-                )
-            }
+                },
+                dismissButton = {
+                    TextButton(onClick = { pendingDbExport = null }) {
+                        Text(stringResource(R.string.cancel))
+                    }
+                }
+            )
         }
 
         BottomInsetsSpacer()

Required notifications

Address or linkRemarkAdded byNotifiedActions

Relationships

related to 0008536 closedgrote show version info even when not in developer mode 

Activities

Issue History

Date ModifiedUsernameFieldChange
2026-11-11 01:44bot-cgNew Issue
2026-11-11 01:44bot-cgRelationship addedrelated to 0008536
2026-11-11 01:44bot-cgFile Added: before-android-1.png
2026-11-11 01:44bot-cgFile Added: before-android-2.png
2026-11-11 01:44bot-cgFile Added: before-ios-1.png
2026-11-11 01:44bot-cgFile Added: before-ios-2.png
2026-11-11 01:44bot-cgFile Added: before-ios-3.png
2026-11-11 01:44bot-cgFile Added: before-ios-4.png
2026-11-11 01:44bot-cgFile Added: before-web-1.png
2026-11-11 01:44bot-cgFile Added: after-android-1.png
2026-11-11 01:44bot-cgFile Added: after-android-2.png
2026-11-11 01:44bot-cgFile Added: android-F408-backup-and-version-visible.patch