Don't leave the PreferencesActivity when importing a database

This commit is contained in:
Alexander Bakker 2018-05-10 14:50:47 +02:00
parent 002045c7c7
commit 246d3d634e
3 changed files with 147 additions and 95 deletions

View file

@ -33,7 +33,8 @@ public class MasterKey implements Serializable {
} catch (NoSuchPaddingException } catch (NoSuchPaddingException
| NoSuchAlgorithmException | NoSuchAlgorithmException
| InvalidAlgorithmParameterException | InvalidAlgorithmParameterException
| InvalidKeyException | BadPaddingException | InvalidKeyException
| BadPaddingException
| IllegalBlockSizeException e) { | IllegalBlockSizeException e) {
throw new MasterKeyException(e); throw new MasterKeyException(e);
} }

View file

@ -20,12 +20,7 @@ import android.widget.Toast;
import com.getbase.floatingactionbutton.FloatingActionsMenu; 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.lang.reflect.UndeclaredThrowableException;
import java.util.List;
import me.impy.aegis.AegisApplication; import me.impy.aegis.AegisApplication;
import me.impy.aegis.R; 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.DatabaseEntry;
import me.impy.aegis.db.DatabaseManager; import me.impy.aegis.db.DatabaseManager;
import me.impy.aegis.helpers.PermissionHelper; 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.KeyProfile;
import me.impy.aegis.ui.views.KeyProfileView; import me.impy.aegis.ui.views.KeyProfileView;
import me.impy.aegis.util.ByteInputStream;
public class MainActivity extends AegisActivity implements KeyProfileView.Listener { public class MainActivity extends AegisActivity implements KeyProfileView.Listener {
// activity request codes // 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_ENTER_KEYINFO = 3;
private static final int CODE_DO_INTRO = 4; private static final int CODE_DO_INTRO = 4;
private static final int CODE_DECRYPT = 5; private static final int CODE_DECRYPT = 5;
private static final int CODE_IMPORT = 6; private static final int CODE_PREFERENCES = 6;
private static final int CODE_PREFERENCES = 7; private static final int CODE_SLOTS = 7;
private static final int CODE_SLOTS = 8;
// permission request codes // permission request codes
private static final int CODE_PERM_EXPORT = 0; private static final int CODE_PERM_EXPORT = 0;
private static final int CODE_PERM_IMPORT = 1; private static final int CODE_PERM_CAMERA = 1;
private static final int CODE_PERM_CAMERA = 2;
private AegisApplication _app; private AegisApplication _app;
private DatabaseManager _db; private DatabaseManager _db;
@ -187,14 +177,12 @@ public class MainActivity extends AegisActivity implements KeyProfileView.Listen
case CODE_DECRYPT: case CODE_DECRYPT:
onDecryptResult(resultCode, data); onDecryptResult(resultCode, data);
break; break;
case CODE_IMPORT:
onImportResult(resultCode, data);
break;
case CODE_PREFERENCES: case CODE_PREFERENCES:
onPreferencesResult(resultCode, data); onPreferencesResult(resultCode, data);
break; break;
case CODE_SLOTS: case CODE_SLOTS:
onSlotManagerResult(resultCode, data); onSlotManagerResult(resultCode, data);
break;
} }
} }
@ -209,9 +197,6 @@ public class MainActivity extends AegisActivity implements KeyProfileView.Listen
case CODE_PERM_EXPORT: case CODE_PERM_EXPORT:
onExport(); onExport();
break; break;
case CODE_PERM_IMPORT:
onImport();
break;
case CODE_PERM_CAMERA: case CODE_PERM_CAMERA:
onScanKeyInfo(); onScanKeyInfo();
break; break;
@ -230,6 +215,12 @@ public class MainActivity extends AegisActivity implements KeyProfileView.Listen
private void onPreferencesResult(int resultCode, Intent data) { private void onPreferencesResult(int resultCode, Intent data) {
// refresh the entire key profile list if needed // 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)) { if (data.getBooleanExtra("needsRefresh", false)) {
boolean showIssuer = _app.getPreferences().getBoolean("pref_issuer", false); boolean showIssuer = _app.getPreferences().getBoolean("pref_issuer", false);
_keyProfileView.setShowIssuer(showIssuer); _keyProfileView.setShowIssuer(showIssuer);
@ -238,11 +229,6 @@ public class MainActivity extends AegisActivity implements KeyProfileView.Listen
// perform any pending actions // perform any pending actions
int action = data.getIntExtra("action", -1); int action = data.getIntExtra("action", -1);
switch (action) { switch (action) {
case PreferencesActivity.ACTION_IMPORT:
if (PermissionHelper.request(this, CODE_PERM_IMPORT, Manifest.permission.READ_EXTERNAL_STORAGE)) {
onImport();
}
break;
case PreferencesActivity.ACTION_EXPORT: case PreferencesActivity.ACTION_EXPORT:
onExport(); onExport();
break; break;
@ -296,71 +282,6 @@ public class MainActivity extends AegisActivity implements KeyProfileView.Listen
builder.show(); 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<DatabaseEntry> 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) { private void startEditProfileActivity(int requestCode, KeyProfile profile, boolean isNew) {
Intent intent = new Intent(this, EditProfileActivity.class); Intent intent = new Intent(this, EditProfileActivity.class);
if (profile != null) { if (profile != null) {

View file

@ -1,5 +1,6 @@
package me.impy.aegis.ui; package me.impy.aegis.ui;
import android.Manifest;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.preference.EditTextPreference; import android.preference.EditTextPreference;
@ -7,12 +8,34 @@ import android.preference.Preference;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.widget.Toast; 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.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 class PreferencesActivity extends AegisActivity {
public static final int ACTION_IMPORT = 0; // activity request codes
public static final int ACTION_EXPORT = 1; private static final int CODE_IMPORT = 0;
public static final int ACTION_SLOTS = 2;
// 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 @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -34,6 +57,8 @@ public class PreferencesActivity extends AegisActivity {
public static class PreferencesFragment extends PreferenceFragment { public static class PreferencesFragment extends PreferenceFragment {
private Intent _result = new Intent(); private Intent _result = new Intent();
private AegisApplication _app;
private DatabaseManager _db;
private void setResult() { private void setResult() {
getActivity().setResult(RESULT_OK, _result); getActivity().setResult(RESULT_OK, _result);
@ -48,6 +73,8 @@ public class PreferencesActivity extends AegisActivity {
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences); addPreferencesFromResource(R.xml.preferences);
_app = (AegisApplication) getActivity().getApplication();
_db = _app.getDatabaseManager();
// set the result intent in advance // set the result intent in advance
setResult(); setResult();
@ -65,8 +92,9 @@ public class PreferencesActivity extends AegisActivity {
exportPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { exportPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override @Override
public boolean onPreferenceClick(Preference preference) { public boolean onPreferenceClick(Preference preference) {
_result.putExtra("action", ACTION_IMPORT); if (PermissionHelper.request(getActivity(), CODE_PERM_IMPORT, Manifest.permission.READ_EXTERNAL_STORAGE)) {
finish(); onImport();
}
return true; 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<DatabaseEntry> 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();
}
} }
} }