From edeb95aee02b070d77242a033f65de24d68d33c2 Mon Sep 17 00:00:00 2001 From: Sylvia van Os Date: Tue, 21 May 2024 21:01:42 +0200 Subject: [PATCH] Run Import/Export on non-UI thread This seems to fix Android sometimes throwing NetworkOnMainThreadException when importing bit files through the Nextcloud app. I'm not sure if this is necessary for the export too, but it doesn't seem to break anything so for consistency it makes sense to also wrap the exporter into a thread. This change is suboptimal because it will still block the UI with a ProgressDialog (which is deprecated) and force the user to wait until the import/export completes (and will kill the import/export if the app gets backgrounded) but it should at least fix the most common crash for most users. --- CHANGELOG.md | 1 + .../card_locker/ImportExportActivity.java | 47 ++++++++++++------- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab120020f..ba502dea0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Support for creating a card when sharing plain text - Display image type instead of barcode below images +- Fix possible crash when trying to import a backup from the Nextcloud app ## v2.29.1 - 135 (2024-05-19) diff --git a/app/src/main/java/protect/card_locker/ImportExportActivity.java b/app/src/main/java/protect/card_locker/ImportExportActivity.java index 6335902df..50e7b41e1 100644 --- a/app/src/main/java/protect/card_locker/ImportExportActivity.java +++ b/app/src/main/java/protect/card_locker/ImportExportActivity.java @@ -80,15 +80,21 @@ public class ImportExportActivity extends CatimaAppCompatActivity { Log.e(TAG, "Activity returned NULL uri"); return; } - try { - OutputStream writer = getContentResolver().openOutputStream(uri); - Log.e(TAG, "Starting file export with: " + result.toString()); - startExport(writer, uri, exportPassword.toCharArray(), true); - } catch (IOException e) { - Log.e(TAG, "Failed to export file: " + result.toString(), e); - onExportComplete(new ImportExportResult(ImportExportResultType.GenericFailure, result.toString()), uri); - } - + // Running this in a thread prevents Android from throwing a NetworkOnMainThreadException for large files + // FIXME: This is still suboptimal, because showing that the export started is delayed until the network request finishes + new Thread() { + @Override + public void run() { + try { + OutputStream writer = getContentResolver().openOutputStream(uri); + Log.e(TAG, "Starting file export with: " + result); + startExport(writer, uri, exportPassword.toCharArray(), true); + } catch (IOException e) { + Log.e(TAG, "Failed to export file: " + result, e); + onExportComplete(new ImportExportResult(ImportExportResultType.GenericFailure, result.toString()), uri); + } + } + }.start(); }); fileOpenLauncher = registerForActivityResult(new ActivityResultContracts.GetContent(), result -> { if (result == null) { @@ -160,14 +166,21 @@ public class ImportExportActivity extends CatimaAppCompatActivity { } private void openFileForImport(Uri uri, char[] password) { - try { - InputStream reader = getContentResolver().openInputStream(uri); - Log.e(TAG, "Starting file import with: " + uri.toString()); - startImport(reader, uri, importDataFormat, password, true); - } catch (IOException e) { - Log.e(TAG, "Failed to import file: " + uri.toString(), e); - onImportComplete(new ImportExportResult(ImportExportResultType.GenericFailure, e.toString()), uri, importDataFormat); - } + // Running this in a thread prevents Android from throwing a NetworkOnMainThreadException for large files + // FIXME: This is still suboptimal, because showing that the import started is delayed until the network request finishes + new Thread() { + @Override + public void run() { + try { + InputStream reader = getContentResolver().openInputStream(uri); + Log.e(TAG, "Starting file import with: " + uri); + startImport(reader, uri, importDataFormat, password, true); + } catch (IOException e) { + Log.e(TAG, "Failed to import file: " + uri, e); + onImportComplete(new ImportExportResult(ImportExportResultType.GenericFailure, e.toString()), uri, importDataFormat); + } + } + }.start(); } private void chooseImportType(boolean choosePicker,