From 246d3d634ec3c874d1522184a7a0e288a89c1f5d Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Thu, 10 May 2018 14:50:47 +0200 Subject: [PATCH] Don't leave the PreferencesActivity when importing a database --- .../java/me/impy/aegis/crypto/MasterKey.java | 3 +- .../java/me/impy/aegis/ui/MainActivity.java | 99 ++----------- .../me/impy/aegis/ui/PreferencesActivity.java | 140 +++++++++++++++++- 3 files changed, 147 insertions(+), 95 deletions(-) diff --git a/app/src/main/java/me/impy/aegis/crypto/MasterKey.java b/app/src/main/java/me/impy/aegis/crypto/MasterKey.java index 29c859b3..c41d1e30 100644 --- a/app/src/main/java/me/impy/aegis/crypto/MasterKey.java +++ b/app/src/main/java/me/impy/aegis/crypto/MasterKey.java @@ -33,7 +33,8 @@ public class MasterKey implements Serializable { } catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidAlgorithmParameterException - | InvalidKeyException | BadPaddingException + | InvalidKeyException + | BadPaddingException | IllegalBlockSizeException e) { throw new MasterKeyException(e); } diff --git a/app/src/main/java/me/impy/aegis/ui/MainActivity.java b/app/src/main/java/me/impy/aegis/ui/MainActivity.java index f8a3efe8..4c3fb912 100644 --- a/app/src/main/java/me/impy/aegis/ui/MainActivity.java +++ b/app/src/main/java/me/impy/aegis/ui/MainActivity.java @@ -20,12 +20,7 @@ import android.widget.Toast; import com.getbase.floatingactionbutton.FloatingActionsMenu; -import java.io.ByteArrayOutputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; import java.lang.reflect.UndeclaredThrowableException; -import java.util.List; import me.impy.aegis.AegisApplication; import me.impy.aegis.R; @@ -35,11 +30,8 @@ import me.impy.aegis.db.slots.SlotCollection; import me.impy.aegis.db.DatabaseEntry; import me.impy.aegis.db.DatabaseManager; import me.impy.aegis.helpers.PermissionHelper; -import me.impy.aegis.importers.DatabaseImporter; -import me.impy.aegis.importers.DatabaseImporterException; import me.impy.aegis.ui.views.KeyProfile; import me.impy.aegis.ui.views.KeyProfileView; -import me.impy.aegis.util.ByteInputStream; public class MainActivity extends AegisActivity implements KeyProfileView.Listener { // activity request codes @@ -49,14 +41,12 @@ public class MainActivity extends AegisActivity implements KeyProfileView.Listen private static final int CODE_ENTER_KEYINFO = 3; private static final int CODE_DO_INTRO = 4; private static final int CODE_DECRYPT = 5; - private static final int CODE_IMPORT = 6; - private static final int CODE_PREFERENCES = 7; - private static final int CODE_SLOTS = 8; + private static final int CODE_PREFERENCES = 6; + private static final int CODE_SLOTS = 7; // permission request codes private static final int CODE_PERM_EXPORT = 0; - private static final int CODE_PERM_IMPORT = 1; - private static final int CODE_PERM_CAMERA = 2; + private static final int CODE_PERM_CAMERA = 1; private AegisApplication _app; private DatabaseManager _db; @@ -187,14 +177,12 @@ public class MainActivity extends AegisActivity implements KeyProfileView.Listen case CODE_DECRYPT: onDecryptResult(resultCode, data); break; - case CODE_IMPORT: - onImportResult(resultCode, data); - break; case CODE_PREFERENCES: onPreferencesResult(resultCode, data); break; case CODE_SLOTS: onSlotManagerResult(resultCode, data); + break; } } @@ -209,9 +197,6 @@ public class MainActivity extends AegisActivity implements KeyProfileView.Listen case CODE_PERM_EXPORT: onExport(); break; - case CODE_PERM_IMPORT: - onImport(); - break; case CODE_PERM_CAMERA: onScanKeyInfo(); break; @@ -230,6 +215,12 @@ public class MainActivity extends AegisActivity implements KeyProfileView.Listen private void onPreferencesResult(int resultCode, Intent data) { // refresh the entire key profile list if needed + if (data.getBooleanExtra("needsReload", false)) { + _keyProfileView.clearKeys(); + for (DatabaseEntry entry : _db.getKeys()) { + _keyProfileView.addKey(new KeyProfile(entry)); + } + } if (data.getBooleanExtra("needsRefresh", false)) { boolean showIssuer = _app.getPreferences().getBoolean("pref_issuer", false); _keyProfileView.setShowIssuer(showIssuer); @@ -238,11 +229,6 @@ public class MainActivity extends AegisActivity implements KeyProfileView.Listen // perform any pending actions int action = data.getIntExtra("action", -1); switch (action) { - case PreferencesActivity.ACTION_IMPORT: - if (PermissionHelper.request(this, CODE_PERM_IMPORT, Manifest.permission.READ_EXTERNAL_STORAGE)) { - onImport(); - } - break; case PreferencesActivity.ACTION_EXPORT: onExport(); break; @@ -296,71 +282,6 @@ public class MainActivity extends AegisActivity implements KeyProfileView.Listen builder.show(); } - private void onImport() { - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.setType("*/*"); - startActivityForResult(intent, CODE_IMPORT); - } - - private void onImportResult(int resultCode, Intent data) { - if (resultCode != RESULT_OK) { - return; - } - - InputStream fileStream = null; - try { - try { - fileStream = getContentResolver().openInputStream(data.getData()); - } catch (FileNotFoundException e) { - Toast.makeText(this, "Error: File not found", Toast.LENGTH_SHORT).show(); - return; - } - - ByteInputStream stream; - try { - int read; - byte[] buf = new byte[4096]; - ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - while ((read = fileStream.read(buf, 0, buf.length)) != -1) { - outStream.write(buf, 0, read); - } - stream = new ByteInputStream(outStream.toByteArray()); - } catch (IOException e) { - Toast.makeText(this, "An error occurred while trying to read the file", Toast.LENGTH_SHORT).show(); - return; - } - - List entries = null; - for (DatabaseImporter converter : DatabaseImporter.create(stream)) { - try { - entries = converter.convert(); - break; - } catch (DatabaseImporterException e) { - stream.reset(); - } - } - - if (entries == null) { - Toast.makeText(this, "An error occurred while trying to parse the file", Toast.LENGTH_SHORT).show(); - return; - } - - for (DatabaseEntry entry : entries) { - addKey(new KeyProfile(entry)); - } - } finally { - if (fileStream != null) { - try { - fileStream.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - saveDatabase(); - } - private void startEditProfileActivity(int requestCode, KeyProfile profile, boolean isNew) { Intent intent = new Intent(this, EditProfileActivity.class); if (profile != null) { diff --git a/app/src/main/java/me/impy/aegis/ui/PreferencesActivity.java b/app/src/main/java/me/impy/aegis/ui/PreferencesActivity.java index 61ca224f..f9fd3a44 100644 --- a/app/src/main/java/me/impy/aegis/ui/PreferencesActivity.java +++ b/app/src/main/java/me/impy/aegis/ui/PreferencesActivity.java @@ -1,5 +1,6 @@ package me.impy.aegis.ui; +import android.Manifest; import android.content.Intent; import android.os.Bundle; import android.preference.EditTextPreference; @@ -7,12 +8,34 @@ import android.preference.Preference; import android.preference.PreferenceFragment; import android.widget.Toast; +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.Locale; + +import me.impy.aegis.AegisApplication; import me.impy.aegis.R; +import me.impy.aegis.db.DatabaseEntry; +import me.impy.aegis.db.DatabaseManager; +import me.impy.aegis.db.DatabaseManagerException; +import me.impy.aegis.helpers.PermissionHelper; +import me.impy.aegis.importers.DatabaseImporter; +import me.impy.aegis.importers.DatabaseImporterException; +import me.impy.aegis.ui.views.KeyProfile; +import me.impy.aegis.util.ByteInputStream; public class PreferencesActivity extends AegisActivity { - public static final int ACTION_IMPORT = 0; - public static final int ACTION_EXPORT = 1; - public static final int ACTION_SLOTS = 2; + // activity request codes + private static final int CODE_IMPORT = 0; + + // permission request codes + private static final int CODE_PERM_IMPORT = 0; + + // action codes + public static final int ACTION_EXPORT = 0; + public static final int ACTION_SLOTS = 1; @Override protected void onCreate(Bundle savedInstanceState) { @@ -34,6 +57,8 @@ public class PreferencesActivity extends AegisActivity { public static class PreferencesFragment extends PreferenceFragment { private Intent _result = new Intent(); + private AegisApplication _app; + private DatabaseManager _db; private void setResult() { getActivity().setResult(RESULT_OK, _result); @@ -48,6 +73,8 @@ public class PreferencesActivity extends AegisActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); + _app = (AegisApplication) getActivity().getApplication(); + _db = _app.getDatabaseManager(); // set the result intent in advance setResult(); @@ -65,8 +92,9 @@ public class PreferencesActivity extends AegisActivity { exportPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { - _result.putExtra("action", ACTION_IMPORT); - finish(); + if (PermissionHelper.request(getActivity(), CODE_PERM_IMPORT, Manifest.permission.READ_EXTERNAL_STORAGE)) { + onImport(); + } return true; } }); @@ -111,5 +139,107 @@ public class PreferencesActivity extends AegisActivity { } }); } + + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + if (!PermissionHelper.checkResults(grantResults)) { + Toast.makeText(getActivity(), "Permission denied", Toast.LENGTH_SHORT).show(); + return; + } + + switch (requestCode) { + case CODE_PERM_IMPORT: + onImport(); + break; + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (data == null) { + return; + } + + switch (requestCode) { + case CODE_IMPORT: + onImportResult(resultCode, data); + break; + } + } + + private void onImport() { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType("*/*"); + startActivityForResult(intent, CODE_IMPORT); + } + + private void onImportResult(int resultCode, Intent data) { + if (resultCode != RESULT_OK) { + return; + } + + InputStream fileStream = null; + List entries = null; + + try { + try { + fileStream = getActivity().getContentResolver().openInputStream(data.getData()); + } catch (FileNotFoundException e) { + Toast.makeText(getActivity(), "Error: File not found", Toast.LENGTH_SHORT).show(); + return; + } + + ByteInputStream stream; + try { + int read; + byte[] buf = new byte[4096]; + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + while ((read = fileStream.read(buf, 0, buf.length)) != -1) { + outStream.write(buf, 0, read); + } + stream = new ByteInputStream(outStream.toByteArray()); + } catch (IOException e) { + Toast.makeText(getActivity(), "An error occurred while trying to read the file", Toast.LENGTH_SHORT).show(); + return; + } + + for (DatabaseImporter converter : DatabaseImporter.create(stream)) { + try { + entries = converter.convert(); + break; + } catch (DatabaseImporterException e) { + stream.reset(); + } + } + } finally { + if (fileStream != null) { + try { + fileStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + if (entries == null) { + Toast.makeText(getActivity(), "An error occurred while trying to parse the file", Toast.LENGTH_SHORT).show(); + return; + } + + for (DatabaseEntry entry : entries) { + _db.addKey(entry); + } + + try { + _db.save(); + } catch (DatabaseManagerException e) { + e.printStackTrace(); + Toast.makeText(getActivity(), "An error occurred while trying to save the database", Toast.LENGTH_LONG).show(); + return; + } + + _result.putExtra("needsReload", true); + Toast.makeText(getActivity(), String.format(Locale.getDefault(), "Imported %d entries", entries.size()), Toast.LENGTH_SHORT).show(); + } } }