Merge pull request #389 from alexbakker/edit-entry-fix

Write entries to the vault directly in EditEntryActivity
This commit is contained in:
Michael Schättgen 2020-05-09 14:11:59 +02:00 committed by GitHub
commit 0bbc413423
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 116 additions and 84 deletions

View file

@ -8,13 +8,14 @@ import android.provider.Settings;
import android.view.WindowManager;
import android.widget.Toast;
import androidx.annotation.CallSuper;
import androidx.appcompat.app.AppCompatActivity;
import com.beemdevelopment.aegis.AegisApplication;
import com.beemdevelopment.aegis.Preferences;
import com.beemdevelopment.aegis.R;
import com.beemdevelopment.aegis.Theme;
import androidx.annotation.CallSuper;
import androidx.appcompat.app.AppCompatActivity;
import com.beemdevelopment.aegis.vault.VaultManagerException;
import java.util.Locale;
@ -126,6 +127,16 @@ public abstract class AegisActivity extends AppCompatActivity implements AegisAp
this.getResources().updateConfiguration(config, this.getResources().getDisplayMetrics());
}
protected boolean saveVault() {
try {
getApp().getVaultManager().save();
return true;
} catch (VaultManagerException e) {
Toast.makeText(this, getString(R.string.saving_error), Toast.LENGTH_LONG).show();
return false;
}
}
/**
* Reports whether this Activity has been resumed. (i.e. onResume was called)
*/

View file

@ -31,7 +31,6 @@ import androidx.appcompat.app.AlertDialog;
import com.amulyakhare.textdrawable.TextDrawable;
import com.avito.android.krop.KropView;
import com.beemdevelopment.aegis.R;
import com.beemdevelopment.aegis.vault.VaultEntry;
import com.beemdevelopment.aegis.encoding.Base32;
import com.beemdevelopment.aegis.encoding.EncodingException;
import com.beemdevelopment.aegis.helpers.EditTextHelper;
@ -43,16 +42,18 @@ import com.beemdevelopment.aegis.otp.OtpInfoException;
import com.beemdevelopment.aegis.otp.SteamInfo;
import com.beemdevelopment.aegis.otp.TotpInfo;
import com.beemdevelopment.aegis.util.Cloner;
import com.beemdevelopment.aegis.vault.VaultEntry;
import com.beemdevelopment.aegis.vault.VaultManager;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import java.io.ByteArrayOutputStream;
import java.text.Collator;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
import de.hdodenhof.circleimageview.CircleImageView;
@ -89,22 +90,28 @@ public class EditEntryActivity extends AegisActivity {
private RelativeLayout _advancedSettingsHeader;
private RelativeLayout _advancedSettings;
private VaultManager _vault;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_entry);
_vault = getApp().getVaultManager();
_groups = _vault.getGroups();
ActionBar bar = getSupportActionBar();
bar.setHomeAsUpIndicator(R.drawable.ic_close);
bar.setDisplayHomeAsUpEnabled(true);
// retrieve info from the calling activity
Intent intent = getIntent();
_origEntry = (VaultEntry) intent.getSerializableExtra("entry");
_isNew = intent.getBooleanExtra("isNew", false);
_groups = new TreeSet<>(Collator.getInstance());
_groups.addAll(intent.getStringArrayListExtra("groups"));
if (_isNew) {
UUID entryUUID = (UUID) intent.getSerializableExtra("entryUUID");
if (entryUUID != null) {
_origEntry = _vault.getEntryByUUID(entryUUID);
} else {
_origEntry = (VaultEntry) intent.getSerializableExtra("newEntry");
_isNew = true;
setTitle(R.string.add_new_entry);
}
@ -185,9 +192,8 @@ public class EditEntryActivity extends AegisActivity {
_spinnerType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String type = _spinnerType.getSelectedItem().toString();
switch (type.toLowerCase()) {
String type = _spinnerType.getSelectedItem().toString().toLowerCase();
switch (type) {
case TotpInfo.ID:
case SteamInfo.ID:
_rowCounter.setVisibility(View.GONE);
@ -251,7 +257,6 @@ public class EditEntryActivity extends AegisActivity {
// automatically open advanced settings since 'Secret' is required.
if (_isNew) {
openAdvancedSettings();
setGroup(selectedGroup);
}
}
@ -264,6 +269,7 @@ public class EditEntryActivity extends AegisActivity {
int pos = _groups.contains(groupName) ? _groups.headSet(groupName).size() : -1;
_spinnerGroup.setSelection(pos + 1, false);
}
private void openAdvancedSettings() {
Animation fadeOut = new AlphaAnimation(1, 0);
fadeOut.setInterpolator(new AccelerateInterpolator());
@ -344,7 +350,7 @@ public class EditEntryActivity extends AegisActivity {
return;
}
finish(entry.get(), false);
addAndFinish(entry.get());
},
(dialog, which) -> super.onBackPressed()
);
@ -361,7 +367,7 @@ public class EditEntryActivity extends AegisActivity {
break;
case R.id.action_delete:
Dialogs.showDeleteEntryDialog(this, (dialog, which) -> {
finish(_origEntry, true);
deleteAndFinish(_origEntry);
});
break;
case R.id.action_default_icon:
@ -389,12 +395,30 @@ public class EditEntryActivity extends AegisActivity {
return true;
}
private void finish(VaultEntry entry, boolean delete) {
private void addAndFinish(VaultEntry entry) {
if (_isNew) {
_vault.addEntry(entry);
} else {
_vault.replaceEntry(entry);
}
saveAndFinish(entry, false);
}
private void deleteAndFinish(VaultEntry entry) {
_vault.removeEntry(entry);
saveAndFinish(entry, true);
}
private void saveAndFinish(VaultEntry entry, boolean delete) {
Intent intent = new Intent();
intent.putExtra("entry", entry);
intent.putExtra("entryUUID", entry.getUUID());
intent.putExtra("delete", delete);
setResult(RESULT_OK, intent);
finish();
if (saveVault()) {
setResult(RESULT_OK, intent);
finish();
}
}
@Override
@ -540,7 +564,7 @@ public class EditEntryActivity extends AegisActivity {
return false;
}
finish(entry, false);
addAndFinish(entry);
return true;
}

View file

@ -51,17 +51,17 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;
import java.util.UUID;
public class MainActivity extends AegisActivity implements EntryListView.Listener {
// activity request codes
private static final int CODE_SCAN = 0;
private static final int CODE_ADD_ENTRY = 1;
private static final int CODE_EDIT_ENTRY = 2;
private static final int CODE_ENTER_ENTRY = 3;
private static final int CODE_DO_INTRO = 4;
private static final int CODE_DECRYPT = 5;
private static final int CODE_PREFERENCES = 6;
private static final int CODE_SCAN_IMAGE = 7;
private static final int CODE_DO_INTRO = 3;
private static final int CODE_DECRYPT = 4;
private static final int CODE_PREFERENCES = 5;
private static final int CODE_SCAN_IMAGE = 6;
// permission request codes
private static final int CODE_PERM_CAMERA = 0;
@ -112,7 +112,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
_fabMenu = findViewById(R.id.fab);
findViewById(R.id.fab_enter).setOnClickListener(view -> {
_fabMenu.collapse();
startEditProfileActivity(CODE_ENTER_ENTRY, null, true);
startEditEntryActivity(CODE_ADD_ENTRY, null, true);
});
findViewById(R.id.fab_scan_image).setOnClickListener(view -> {
_fabMenu.collapse();
@ -179,9 +179,6 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
case CODE_EDIT_ENTRY:
onEditEntryResult(resultCode, data);
break;
case CODE_ENTER_ENTRY:
onEnterEntryResult(resultCode, data);
break;
case CODE_DO_INTRO:
onDoIntroResult(resultCode, data);
break;
@ -238,50 +235,42 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
}
}
private void startEditProfileActivity(int requestCode, VaultEntry entry, boolean isNew) {
private void startEditEntryActivity(int requestCode, VaultEntry entry, boolean isNew) {
Intent intent = new Intent(this, EditEntryActivity.class);
intent.putExtra("entry", entry != null ? entry : VaultEntry.getDefault());
intent.putExtra("isNew", isNew);
if (isNew) {
intent.putExtra("newEntry", entry != null ? entry : VaultEntry.getDefault());
} else {
intent.putExtra("entryUUID", entry.getUUID());
}
intent.putExtra("selectedGroup", _selectedGroup);
intent.putExtra("groups", new ArrayList<>(_vault.getGroups()));
startActivityForResult(intent, requestCode);
}
private void onScanResult(int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
VaultEntry entry = (VaultEntry) data.getSerializableExtra("entry");
startEditProfileActivity(CODE_ADD_ENTRY, entry, true);
startEditEntryActivity(CODE_ADD_ENTRY, entry, true);
}
}
private void onAddEntryResult(int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
VaultEntry entry = (VaultEntry) data.getSerializableExtra("entry");
addEntry(entry);
saveVault();
UUID entryUUID = (UUID) data.getSerializableExtra("entryUUID");
VaultEntry entry = _vault.getEntryByUUID(entryUUID);
_entryListView.addEntry(entry);
}
}
private void onEditEntryResult(int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
VaultEntry entry = (VaultEntry) data.getSerializableExtra("entry");
if (data.getBooleanExtra("delete", false)) {
deleteEntry(entry);
} else {
// this profile has been serialized/deserialized and is no longer the same instance it once was
// to deal with this, the replaceEntry functions are used
VaultEntry oldEntry = _vault.replaceEntry(entry);
_entryListView.replaceEntry(oldEntry, entry);
saveVault();
}
}
}
UUID entryUUID = (UUID) data.getSerializableExtra("entryUUID");
private void onEnterEntryResult(int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
VaultEntry entry = (VaultEntry) data.getSerializableExtra("entry");
addEntry(entry);
saveVault();
if (data.getBooleanExtra("delete", false)) {
_entryListView.removeEntry(entryUUID);
} else {
VaultEntry entry = _vault.getEntryByUUID(entryUUID);
_entryListView.replaceEntry(entryUUID, entry);
}
}
}
@ -309,7 +298,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
GoogleAuthInfo info = GoogleAuthInfo.parseUri(result.getText());
VaultEntry entry = new VaultEntry(info);
startEditProfileActivity(CODE_ADD_ENTRY, entry, true);
startEditEntryActivity(CODE_ADD_ENTRY, entry, true);
} catch (NotFoundException | IOException | ChecksumException | FormatException | GoogleAuthInfoException e) {
Toast.makeText(this, getString(R.string.unable_to_read_qrcode), Toast.LENGTH_SHORT).show();
e.printStackTrace();
@ -359,11 +348,6 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
_entryListView.setGroupFilter(group, true);
}
private void addEntry(VaultEntry entry) {
_vault.addEntry(entry);
_entryListView.addEntry(entry);
}
private void onDoIntroResult(int resultCode, Intent data) {
if (resultCode == IntroActivity.RESULT_EXCEPTION) {
// TODO: user feedback
@ -442,10 +426,9 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
if (info != null) {
VaultEntry entry = new VaultEntry(info);
startEditProfileActivity(CODE_ADD_ENTRY, entry, true);
startEditEntryActivity(CODE_ADD_ENTRY, entry, true);
}
}
}
@Override
@ -511,13 +494,6 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
saveVault();
}
private void deleteEntry(VaultEntry entry) {
VaultEntry oldEntry = _vault.removeEntry(entry);
saveVault();
_entryListView.removeEntry(oldEntry);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
_menu = menu;
@ -662,14 +638,6 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
startActivityForResult(intent, CODE_DECRYPT);
}
private void saveVault() {
try {
_vault.save();
} catch (VaultManagerException e) {
Toast.makeText(this, getString(R.string.saving_error), Toast.LENGTH_LONG).show();
}
}
private void updateLockIcon() {
// hide the lock icon if the vault is not unlocked
if (_menu != null && !_vault.isLocked()) {
@ -784,7 +752,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
return true;
case R.id.action_edit:
startEditProfileActivity(CODE_EDIT_ENTRY, _selectedEntries.get(0), false);
startEditEntryActivity(CODE_EDIT_ENTRY, _selectedEntries.get(0), false);
mode.finish();
return true;

View file

@ -10,12 +10,12 @@ import androidx.recyclerview.widget.RecyclerView;
import com.beemdevelopment.aegis.R;
import com.beemdevelopment.aegis.SortCategory;
import com.beemdevelopment.aegis.ViewMode;
import com.beemdevelopment.aegis.vault.VaultEntry;
import com.beemdevelopment.aegis.helpers.ItemTouchHelperAdapter;
import com.beemdevelopment.aegis.otp.HotpInfo;
import com.beemdevelopment.aegis.otp.OtpInfo;
import com.beemdevelopment.aegis.otp.OtpInfoException;
import com.beemdevelopment.aegis.otp.TotpInfo;
import com.beemdevelopment.aegis.vault.VaultEntry;
import java.util.ArrayList;
import java.util.Collections;
@ -23,6 +23,7 @@ import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements ItemTouchHelperAdapter {
private EntryListView _view;
@ -144,6 +145,11 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
checkPeriodUniformity();
}
public void removeEntry(UUID uuid) {
VaultEntry entry = getEntryByUUID(uuid);
removeEntry(entry);
}
public void clearEntries() {
_entries.clear();
_shownEntries.clear();
@ -151,7 +157,8 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
checkPeriodUniformity();
}
public void replaceEntry(VaultEntry oldEntry, VaultEntry newEntry) {
public void replaceEntry(UUID uuid, VaultEntry newEntry) {
VaultEntry oldEntry = getEntryByUUID(uuid);
_entries.set(_entries.indexOf(oldEntry), newEntry);
if (_shownEntries.contains(oldEntry)) {
@ -174,6 +181,16 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
checkPeriodUniformity();
}
private VaultEntry getEntryByUUID(UUID uuid) {
for (VaultEntry entry : _entries) {
if (entry.getUUID().equals(uuid)) {
return entry;
}
}
return null;
}
private boolean isEntryFiltered(VaultEntry entry) {
String group = entry.getGroup();
String issuer = entry.getIssuer().toLowerCase();

View file

@ -22,10 +22,10 @@ import androidx.recyclerview.widget.RecyclerView;
import com.beemdevelopment.aegis.R;
import com.beemdevelopment.aegis.SortCategory;
import com.beemdevelopment.aegis.ViewMode;
import com.beemdevelopment.aegis.vault.VaultEntry;
import com.beemdevelopment.aegis.helpers.SimpleItemTouchHelperCallback;
import com.beemdevelopment.aegis.helpers.UiRefresher;
import com.beemdevelopment.aegis.otp.TotpInfo;
import com.beemdevelopment.aegis.vault.VaultEntry;
import com.bumptech.glide.Glide;
import com.bumptech.glide.ListPreloader;
import com.bumptech.glide.RequestBuilder;
@ -35,6 +35,7 @@ import com.bumptech.glide.util.ViewPreloadSizeProvider;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
public class EntryListView extends Fragment implements EntryAdapter.Listener {
private EntryAdapter _adapter;
@ -262,12 +263,17 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
updateEmptyState();
}
public void removeEntry(UUID uuid) {
_adapter.removeEntry(uuid);
updateEmptyState();
}
public void clearEntries() {
_adapter.clearEntries();
}
public void replaceEntry(VaultEntry oldEntry, VaultEntry newEntry) {
_adapter.replaceEntry(oldEntry, newEntry);
public void replaceEntry(UUID uuid, VaultEntry newEntry) {
_adapter.replaceEntry(uuid, newEntry);
}
public void runEntriesAnimation() {

View file

@ -17,6 +17,7 @@ import java.io.OutputStream;
import java.text.Collator;
import java.util.Collection;
import java.util.TreeSet;
import java.util.UUID;
public class VaultManager {
public static final String FILENAME = "aegis.json";
@ -144,6 +145,11 @@ public class VaultManager {
_vault.getEntries().add(entry);
}
public VaultEntry getEntryByUUID(UUID uuid) {
assertState(false, true);
return _vault.getEntries().getByUUID(uuid);
}
public VaultEntry removeEntry(VaultEntry entry) {
assertState(false, true);
return _vault.getEntries().remove(entry);