diff --git a/app/src/main/java/protect/card_locker/ImportExportActivity.java b/app/src/main/java/protect/card_locker/ImportExportActivity.java index bbd4eba9a..c2f7c959d 100644 --- a/app/src/main/java/protect/card_locker/ImportExportActivity.java +++ b/app/src/main/java/protect/card_locker/ImportExportActivity.java @@ -10,15 +10,14 @@ import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; -import android.os.Environment; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; -import androidx.core.content.FileProvider; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; + import android.util.Log; import android.view.MenuItem; import android.view.View; @@ -28,7 +27,9 @@ import android.widget.Toast; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.InputStream; +import java.io.OutputStream; import java.util.List; public class ImportExportActivity extends AppCompatActivity @@ -36,13 +37,11 @@ public class ImportExportActivity extends AppCompatActivity private static final String TAG = "LoyaltyCardLocker"; private static final int PERMISSIONS_EXTERNAL_STORAGE = 1; - private static final int CHOOSE_EXPORT_FILE = 2; + private static final int CHOOSE_EXPORT_LOCATION = 2; + private static final int CHOOSE_EXPORTED_FILE = 3; private ImportExportTask importExporter; - private final File sdcardDir = Environment.getExternalStorageDirectory(); - private final File exportFile = new File(sdcardDir, "LoyaltyCardKeychain.csv"); - @Override protected void onCreate(Bundle savedInstanceState) { @@ -70,6 +69,11 @@ public class ImportExportActivity extends AppCompatActivity PERMISSIONS_EXTERNAL_STORAGE); } + // Check that there is a file manager available + final Intent intentCreateDocumentAction = new Intent(Intent.ACTION_CREATE_DOCUMENT); + intentCreateDocumentAction.addCategory(Intent.CATEGORY_OPENABLE); + intentCreateDocumentAction.setType("text/csv"); + intentCreateDocumentAction.putExtra(Intent.EXTRA_TITLE, "LoyaltyCardKeychain.csv"); Button exportButton = findViewById(R.id.exportButton); exportButton.setOnClickListener(new View.OnClickListener() @@ -77,7 +81,7 @@ public class ImportExportActivity extends AppCompatActivity @Override public void onClick(View v) { - startExport(); + chooseFileWithIntent(intentCreateDocumentAction, CHOOSE_EXPORT_LOCATION); } }); @@ -86,14 +90,13 @@ public class ImportExportActivity extends AppCompatActivity intentGetContentAction.addCategory(Intent.CATEGORY_OPENABLE); intentGetContentAction.setType("*/*"); - Button importFilesystem = findViewById(R.id.importOptionFilesystemButton); importFilesystem.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - chooseFileWithIntent(intentGetContentAction); + chooseFileWithIntent(intentGetContentAction, CHOOSE_EXPORTED_FILE); } }); @@ -114,7 +117,7 @@ public class ImportExportActivity extends AppCompatActivity @Override public void onClick(View v) { - chooseFileWithIntent(intentPickAction); + chooseFileWithIntent(intentPickAction, CHOOSE_EXPORTED_FILE); } }); @@ -125,28 +128,6 @@ public class ImportExportActivity extends AppCompatActivity findViewById(R.id.importOptionApplicationExplanation).setVisibility(View.GONE); importApplication.setVisibility(View.GONE); } - - // This option, to import from the fixed location, should always be present - - Button importButton = findViewById(R.id.importOptionFixedButton); - importButton.setOnClickListener(new View.OnClickListener() - { - @Override - public void onClick(View v) - { - Uri uri = Uri.fromFile(exportFile); - try - { - FileInputStream stream = new FileInputStream(exportFile); - startImport(stream, uri); - } - catch(FileNotFoundException e) - { - Log.e(TAG, "Could not import file " + exportFile.getAbsolutePath(), e); - onImportComplete(false, uri); - } - } - }); } private void startImport(final InputStream target, final Uri targetUri) @@ -165,19 +146,19 @@ public class ImportExportActivity extends AppCompatActivity importExporter.execute(); } - private void startExport() + private void startExport(final OutputStream target, final Uri targetUri) { ImportExportTask.TaskCompleteListener listener = new ImportExportTask.TaskCompleteListener() { @Override public void onTaskComplete(boolean success) { - onExportComplete(success, exportFile); + onExportComplete(success, targetUri); } }; importExporter = new ImportExportTask(ImportExportActivity.this, - DataFormat.CSV, exportFile, listener); + DataFormat.CSV, target, listener); importExporter.execute(); } @@ -265,7 +246,7 @@ public class ImportExportActivity extends AppCompatActivity builder.create().show(); } - private void onExportComplete(boolean success, final File path) + private void onExportComplete(boolean success, final Uri path) { AlertDialog.Builder builder = new AlertDialog.Builder(this); @@ -281,7 +262,11 @@ public class ImportExportActivity extends AppCompatActivity int messageId = success ? R.string.exportedTo : R.string.exportFailed; final String template = getResources().getString(messageId); - final String message = String.format(template, path.getAbsolutePath()); + + // Get the filename of the file being imported + String filename = path.toString(); + + final String message = String.format(template, filename); builder.setMessage(message); builder.setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() { @@ -301,9 +286,8 @@ public class ImportExportActivity extends AppCompatActivity @Override public void onClick(DialogInterface dialog, int which) { - Uri outputUri = FileProvider.getUriForFile(ImportExportActivity.this, BuildConfig.APPLICATION_ID, path); Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_STREAM, outputUri); + sendIntent.putExtra(Intent.EXTRA_STREAM, path); sendIntent.setType("text/csv"); // set flag to give temporary permission to external app to use the FileProvider @@ -345,11 +329,11 @@ public class ImportExportActivity extends AppCompatActivity return false; } - private void chooseFileWithIntent(Intent intent) + private void chooseFileWithIntent(Intent intent, int requestCode) { try { - startActivityForResult(intent, CHOOSE_EXPORT_FILE); + startActivityForResult(intent, requestCode); } catch (ActivityNotFoundException e) { @@ -362,7 +346,7 @@ public class ImportExportActivity extends AppCompatActivity { super.onActivityResult(requestCode, resultCode, data); - if (resultCode != RESULT_OK || requestCode != CHOOSE_EXPORT_FILE) + if (resultCode != RESULT_OK || (requestCode != CHOOSE_EXPORT_LOCATION && requestCode != CHOOSE_EXPORTED_FILE)) { Log.w(TAG, "Failed onActivityResult(), result=" + resultCode); return; @@ -377,24 +361,48 @@ public class ImportExportActivity extends AppCompatActivity try { - InputStream reader; - - if(uri.getScheme() != null) + if (requestCode == CHOOSE_EXPORT_LOCATION) { - reader = getContentResolver().openInputStream(uri); + OutputStream writer; + if (uri.getScheme() != null) + { + writer = getContentResolver().openOutputStream(uri); + } + else + { + writer = new FileOutputStream(new File(uri.toString())); + } + + Log.e(TAG, "Starting file export with: " + uri.toString()); + startExport(writer, uri); } else { - reader = new FileInputStream(new File(uri.toString())); - } + InputStream reader; + if(uri.getScheme() != null) + { + reader = getContentResolver().openInputStream(uri); + } + else + { + reader = new FileInputStream(new File(uri.toString())); + } - Log.e(TAG, "Starting file import with: " + uri.toString()); - startImport(reader, uri); + Log.e(TAG, "Starting file export with: " + uri.toString()); + startImport(reader, uri); + } } catch(FileNotFoundException e) { - Log.e(TAG, "Failed to import file: " + uri.toString(), e); - onImportComplete(false, uri); + Log.e(TAG, "Failed to import/export file: " + uri.toString(), e); + if (requestCode == CHOOSE_EXPORT_LOCATION) + { + onExportComplete(false, uri); + } + else + { + onImportComplete(false, uri); + } } } } \ No newline at end of file diff --git a/app/src/main/java/protect/card_locker/ImportExportTask.java b/app/src/main/java/protect/card_locker/ImportExportTask.java index 839e7c36d..ab54c9ef3 100644 --- a/app/src/main/java/protect/card_locker/ImportExportTask.java +++ b/app/src/main/java/protect/card_locker/ImportExportTask.java @@ -4,16 +4,12 @@ import android.app.Activity; import android.app.ProgressDialog; import android.content.DialogInterface; import android.os.AsyncTask; -import android.os.Environment; import android.util.Log; -import android.widget.Toast; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; import java.io.OutputStreamWriter; import java.nio.charset.Charset; @@ -24,7 +20,7 @@ class ImportExportTask extends AsyncTask private Activity activity; private boolean doImport; private DataFormat format; - private File target; + private OutputStream outputStream; private InputStream inputStream; private TaskCompleteListener listener; @@ -33,14 +29,14 @@ class ImportExportTask extends AsyncTask /** * Constructor which will setup a task for exporting to the given file */ - ImportExportTask(Activity activity, DataFormat format, File target, + ImportExportTask(Activity activity, DataFormat format, OutputStream output, TaskCompleteListener listener) { super(); this.activity = activity; this.doImport = false; this.format = format; - this.target = target; + this.outputStream = output; this.listener = listener; } @@ -78,14 +74,13 @@ class ImportExportTask extends AsyncTask return result; } - private boolean performExport(File exportFile, DBHelper db) + private boolean performExport(OutputStream stream, DBHelper db) { boolean result = false; try { - FileOutputStream fileWriter = new FileOutputStream(exportFile); - OutputStreamWriter writer = new OutputStreamWriter(fileWriter, Charset.forName("UTF-8")); + OutputStreamWriter writer = new OutputStreamWriter(stream, Charset.forName("UTF-8")); result = MultiFormatExporter.exportData(db, writer, format); writer.close(); } @@ -94,7 +89,7 @@ class ImportExportTask extends AsyncTask Log.e(TAG, "Unable to export file", e); } - Log.i(TAG, "Export of '" + exportFile.getAbsolutePath() + "' result: " + result); + Log.i(TAG, "Export result: " + result); return result; } @@ -127,7 +122,7 @@ class ImportExportTask extends AsyncTask } else { - result = performExport(target, db); + result = performExport(outputStream, db); } return result; diff --git a/app/src/main/res/layout/import_export_activity.xml b/app/src/main/res/layout/import_export_activity.xml index 464b3657e..5d4d7fdf5 100644 --- a/app/src/main/res/layout/import_export_activity.xml +++ b/app/src/main/res/layout/import_export_activity.xml @@ -99,7 +99,6 @@ android:layout_marginTop="8dp" android:text="@string/importOptionFilesystemButton" /> - - - - - - - - -