Aegis/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java

790 lines
27 KiB
Java
Raw Normal View History

package com.beemdevelopment.aegis.ui;
2016-08-15 21:29:41 +02:00
import android.Manifest;
2016-08-21 22:32:07 +02:00
import android.content.ClipData;
import android.content.ClipboardManager;
2016-08-21 22:24:04 +02:00
import android.content.Context;
2016-08-15 22:31:28 +02:00
import android.content.Intent;
2019-04-19 23:10:18 +02:00
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
2018-01-01 21:11:40 +01:00
import android.graphics.Rect;
2019-04-19 23:10:18 +02:00
import android.net.Uri;
2016-08-15 21:29:41 +02:00
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
2018-01-01 21:11:40 +01:00
import android.view.MotionEvent;
import android.view.SubMenu;
2016-08-17 01:14:25 +02:00
import android.widget.Toast;
import androidx.appcompat.view.ActionMode;
import androidx.appcompat.widget.SearchView;
import com.beemdevelopment.aegis.AegisApplication;
import com.beemdevelopment.aegis.CancelAction;
import com.beemdevelopment.aegis.R;
import com.beemdevelopment.aegis.SortCategory;
import com.beemdevelopment.aegis.ViewMode;
import com.beemdevelopment.aegis.helpers.FabScrollHelper;
import com.beemdevelopment.aegis.helpers.PermissionHelper;
2019-04-19 23:10:18 +02:00
import com.beemdevelopment.aegis.otp.GoogleAuthInfo;
import com.beemdevelopment.aegis.otp.GoogleAuthInfoException;
import com.beemdevelopment.aegis.ui.views.EntryListView;
import com.beemdevelopment.aegis.vault.VaultEntry;
import com.beemdevelopment.aegis.vault.VaultFileCredentials;
import com.beemdevelopment.aegis.vault.VaultManager;
import com.beemdevelopment.aegis.vault.VaultManagerException;
import com.getbase.floatingactionbutton.FloatingActionsMenu;
2019-04-19 23:10:18 +02:00
import com.google.zxing.BinaryBitmap;
import com.google.zxing.ChecksumException;
import com.google.zxing.FormatException;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.NotFoundException;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.Reader;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
2019-04-19 23:10:18 +02:00
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
2019-03-31 19:57:45 +02:00
import java.util.List;
import java.util.TreeSet;
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;
2019-04-19 23:10:18 +02:00
private static final int CODE_SCAN_IMAGE = 7;
2016-08-24 23:48:25 +02:00
// permission request codes
private static final int CODE_PERM_CAMERA = 0;
private static final int CODE_PERM_READ_STORAGE = 1;
private AegisApplication _app;
private VaultManager _vault;
private boolean _loaded;
private String _selectedGroup;
private boolean _searchSubmitted;
2016-09-30 01:08:03 +02:00
private VaultEntry _selectedEntry;
private ActionMode _actionMode;
2017-08-26 21:15:53 +02:00
private Menu _menu;
private SearchView _searchView;
2018-01-01 21:11:40 +01:00
private FloatingActionsMenu _fabMenu;
private EntryListView _entryListView;
private FabScrollHelper _fabScrollHelper;
private ActionMode.Callback _actionModeCallbacks = new ActionModeCallbacks();
2016-08-15 21:29:41 +02:00
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
_app = (AegisApplication) getApplication();
_vault = _app.getVaultManager();
_loaded = false;
// set up the main view
2016-08-15 21:29:41 +02:00
setContentView(R.layout.activity_main);
2017-12-03 16:47:27 +01:00
// set up the entry view
_entryListView = (EntryListView) getSupportFragmentManager().findFragmentById(R.id.key_profiles);
_entryListView.setListener(this);
2018-09-19 00:10:03 +02:00
_entryListView.setShowAccountName(getPreferences().isAccountNameVisible());
2019-09-11 20:51:02 +02:00
_entryListView.setSearchAccountName(getPreferences().isSearchAccountNameEnabled());
_entryListView.setHighlightEntry(getPreferences().isEntryHighlightEnabled());
_entryListView.setTapToReveal(getPreferences().isTapToRevealEnabled());
_entryListView.setTapToRevealTime(getPreferences().getTapToRevealTime());
_entryListView.setSortCategory(getPreferences().getCurrentSortCategory(), false);
_entryListView.setViewMode(getPreferences().getCurrentViewMode());
// set up the floating action button
2018-01-01 21:11:40 +01:00
_fabMenu = findViewById(R.id.fab);
findViewById(R.id.fab_enter).setOnClickListener(view -> {
2018-01-01 21:11:40 +01:00
_fabMenu.collapse();
startEditProfileActivity(CODE_ENTER_ENTRY, null, true);
});
2019-04-19 23:10:18 +02:00
findViewById(R.id.fab_scan_image).setOnClickListener(view -> {
_fabMenu.collapse();
startScanImageActivity();
2019-04-19 23:10:18 +02:00
});
findViewById(R.id.fab_scan).setOnClickListener(view -> {
2018-01-01 21:11:40 +01:00
_fabMenu.collapse();
startScanActivity();
});
_fabScrollHelper = new FabScrollHelper(_fabMenu);
2016-08-15 21:29:41 +02:00
}
@Override
protected void onDestroy() {
_entryListView.setListener(null);
super.onDestroy();
}
2018-01-01 21:11:40 +01:00
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
// collapse the fab menu on touch
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (_fabMenu.isExpanded()) {
Rect rect = new Rect();
_fabMenu.getGlobalVisibleRect(rect);
if (!rect.contains((int) event.getRawX(), (int) event.getRawY())) {
_fabMenu.collapse();
}
}
}
return super.dispatchTouchEvent(event);
}
2017-12-25 20:01:58 +01:00
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
doShortcutActions();
2017-12-25 20:01:58 +01:00
}
2017-12-24 21:42:08 +01:00
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
2017-12-25 20:01:58 +01:00
if (data == null) {
return;
}
// don't process any activity results if the vault is locked
if (requestCode != CODE_DECRYPT && requestCode != CODE_DO_INTRO && _vault.isLocked()) {
return;
}
switch (requestCode) {
case CODE_SCAN:
onScanResult(resultCode, data);
break;
case CODE_ADD_ENTRY:
onAddEntryResult(resultCode, data);
break;
case CODE_EDIT_ENTRY:
onEditEntryResult(resultCode, data);
break;
case CODE_ENTER_ENTRY:
onEnterEntryResult(resultCode, data);
break;
case CODE_DO_INTRO:
onDoIntroResult(resultCode, data);
break;
case CODE_DECRYPT:
onDecryptResult(resultCode, data);
break;
case CODE_PREFERENCES:
onPreferencesResult(resultCode, data);
break;
2019-04-19 23:10:18 +02:00
case CODE_SCAN_IMAGE:
onScanImageResult(resultCode, data);
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (!PermissionHelper.checkResults(grantResults)) {
2018-10-09 23:13:51 +02:00
Toast.makeText(this, getString(R.string.permission_denied), Toast.LENGTH_SHORT).show();
return;
}
switch (requestCode) {
case CODE_PERM_CAMERA:
startScanActivity();
break;
case CODE_PERM_READ_STORAGE:
startScanImageActivity();
break;
}
}
private void onPreferencesResult(int resultCode, Intent data) {
// refresh the entire entry list if needed
if (data.getBooleanExtra("needsRecreate", false)) {
recreate();
} else if (data.getBooleanExtra("needsRefresh", false)) {
2018-09-19 00:10:03 +02:00
boolean showAccountName = getPreferences().isAccountNameVisible();
2019-09-11 20:51:02 +02:00
boolean searchAccountName = getPreferences().isSearchAccountNameEnabled();
boolean highlightEntry = getPreferences().isEntryHighlightEnabled();
boolean tapToReveal = getPreferences().isTapToRevealEnabled();
int tapToRevealTime = getPreferences().getTapToRevealTime();
ViewMode viewMode = getPreferences().getCurrentViewMode();
2018-09-19 00:10:03 +02:00
_entryListView.setShowAccountName(showAccountName);
2019-09-11 20:51:02 +02:00
_entryListView.setSearchAccountName(searchAccountName);
_entryListView.setHighlightEntry(highlightEntry);
_entryListView.setTapToReveal(tapToReveal);
_entryListView.setTapToRevealTime(tapToRevealTime);
_entryListView.setViewMode(viewMode);
2018-06-09 21:40:18 +02:00
_entryListView.refresh(true);
}
}
private void startEditProfileActivity(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);
intent.putExtra("selectedGroup", _selectedGroup);
intent.putExtra("groups", new ArrayList<>(_vault.getGroups()));
startActivityForResult(intent, requestCode);
}
private void onScanResult(int resultCode, Intent data) {
2017-12-03 16:47:27 +01:00
if (resultCode == RESULT_OK) {
VaultEntry entry = (VaultEntry) data.getSerializableExtra("entry");
startEditProfileActivity(CODE_ADD_ENTRY, entry, true);
}
}
private void onAddEntryResult(int resultCode, Intent data) {
2017-12-03 16:47:27 +01:00
if (resultCode == RESULT_OK) {
VaultEntry entry = (VaultEntry) data.getSerializableExtra("entry");
addEntry(entry);
saveVault();
}
}
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();
}
}
}
private void onEnterEntryResult(int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
VaultEntry entry = (VaultEntry) data.getSerializableExtra("entry");
addEntry(entry);
saveVault();
}
}
2019-04-19 23:10:18 +02:00
private void onScanImageResult(int resultCode, Intent intent) {
if (resultCode == RESULT_OK) {
Uri inputFile = (intent.getData());
Bitmap bitmap;
try {
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
try (InputStream inputStream = getContentResolver().openInputStream(inputFile)) {
bitmap = BitmapFactory.decodeStream(inputStream, null, bmOptions);
}
int[] intArray = new int[bitmap.getWidth() * bitmap.getHeight()];
bitmap.getPixels(intArray, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
LuminanceSource source = new RGBLuminanceSource(bitmap.getWidth(), bitmap.getHeight(), intArray);
BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source));
Reader reader = new MultiFormatReader();
Result result = reader.decode(binaryBitmap);
GoogleAuthInfo info = GoogleAuthInfo.parseUri(result.getText());
VaultEntry entry = new VaultEntry(info);
2019-04-19 23:10:18 +02:00
startEditProfileActivity(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();
}
}
}
private void updateGroupFilterMenu() {
SubMenu menu = _menu.findItem(R.id.action_filter).getSubMenu();
for (int i = menu.size() - 1; i >= 0; i--) {
MenuItem item = menu.getItem(i);
if (item.getItemId() == R.id.menu_filter_all) {
continue;
}
menu.removeItem(item.getItemId());
}
// if the group no longer exists, switch back to 'All'
TreeSet<String> groups = _vault.getGroups();
if (_selectedGroup != null && !groups.contains(_selectedGroup)) {
menu.findItem(R.id.menu_filter_all).setChecked(true);
setGroupFilter(null);
}
for (String group : groups) {
MenuItem item = menu.add(R.id.action_filter_group, Menu.NONE, Menu.NONE, group);
if (group.equals(_selectedGroup)) {
item.setChecked(true);
}
}
2019-09-16 23:02:48 +02:00
if (groups.size() > 0) {
menu.add(R.id.action_filter_group, Menu.NONE, 10, R.string.filter_ungrouped);
}
menu.setGroupCheckable(R.id.action_filter_group, true, true);
}
private void updateSortCategoryMenu() {
SortCategory category = getPreferences().getCurrentSortCategory();
_menu.findItem(category.getMenuItem()).setChecked(true);
}
private void setGroupFilter(String group) {
2018-12-17 23:09:07 +01:00
getSupportActionBar().setSubtitle(group);
_selectedGroup = group;
_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
Exception e = (Exception) data.getSerializableExtra("exception");
throw new RuntimeException(e);
}
VaultFileCredentials creds = (VaultFileCredentials) data.getSerializableExtra("creds");
unlockVault(creds);
}
private void onDecryptResult(int resultCode, Intent intent) {
VaultFileCredentials creds = (VaultFileCredentials) intent.getSerializableExtra("creds");
boolean unlocked = unlockVault(creds);
// save the vault in case a slot was repaired
if (unlocked && intent.getBooleanExtra("repairedSlot", false)) {
_vault.setCredentials(creds);
saveVault();
}
2017-12-03 16:47:27 +01:00
doShortcutActions();
}
private void startScanActivity() {
if (!PermissionHelper.request(this, CODE_PERM_CAMERA, Manifest.permission.CAMERA)) {
return;
}
Intent scannerActivity = new Intent(getApplicationContext(), ScannerActivity.class);
startActivityForResult(scannerActivity, CODE_SCAN);
}
private void startScanImageActivity() {
if (!PermissionHelper.request(this, CODE_PERM_READ_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)) {
return;
}
Intent galleryIntent = new Intent(Intent.ACTION_PICK);
galleryIntent.setDataAndType(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, "image/*");
Intent chooserIntent = Intent.createChooser(galleryIntent, getString(R.string.select_picture));
startActivityForResult(Intent.createChooser(chooserIntent, getString(R.string.select_picture)), CODE_SCAN_IMAGE);
}
private void doShortcutActions() {
2017-12-03 16:47:27 +01:00
Intent intent = getIntent();
String action = intent.getStringExtra("action");
if (action == null || _vault.isLocked()) {
return;
2017-12-03 16:47:27 +01:00
}
switch (action) {
case "scan":
startScanActivity();
2017-12-03 16:47:27 +01:00
break;
}
2017-12-25 20:01:58 +01:00
intent.removeExtra("action");
}
private void handleDeeplink() {
if (_vault.isLocked()) {
return;
}
Intent intent = getIntent();
if (Intent.ACTION_VIEW.equals(intent.getAction())) {
Uri uri = intent.getData();
getIntent().setData(null);
getIntent().setAction(null);
GoogleAuthInfo info = null;
try {
info = GoogleAuthInfo.parseUri(uri);
} catch (GoogleAuthInfoException e) {
Toast.makeText(this, getString(R.string.unable_to_read_qrcode), Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
if (info != null) {
VaultEntry entry = new VaultEntry(info);
startEditProfileActivity(CODE_ADD_ENTRY, entry, true);
}
}
}
2016-09-30 01:08:03 +02:00
@Override
protected void onResume() {
super.onResume();
2017-12-24 21:42:08 +01:00
if (_vault.isLocked()) {
// start the intro if the vault file doesn't exist
if (!_vault.isLoaded() && !_vault.fileExists()) {
// the vault doesn't exist, start the intro
if (getPreferences().isIntroDone()) {
2018-10-09 23:13:51 +02:00
Toast.makeText(this, getString(R.string.vault_not_found), Toast.LENGTH_SHORT).show();
}
Intent intro = new Intent(this, IntroActivity.class);
startActivityForResult(intro, CODE_DO_INTRO);
return;
} else {
unlockVault(null);
}
} else if (_loaded) {
// update the list of groups in the filter menu
if (_menu != null) {
updateGroupFilterMenu();
}
// refresh all codes to prevent showing old ones
_entryListView.refresh(false);
} else {
loadEntries();
}
handleDeeplink();
updateLockIcon();
doShortcutActions();
2016-09-30 01:08:03 +02:00
}
@Override
public void onBackPressed() {
if (!_searchView.isIconified() || _searchSubmitted) {
_searchSubmitted = false;
_entryListView.setSearchFilter(null);
collapseSearchView();
setTitle("Aegis");
setGroupFilter(_selectedGroup);
return;
}
if (_app.isAutoLockEnabled()) {
_app.lock();
return;
}
super.onBackPressed();
}
private void deleteEntry(VaultEntry entry) {
VaultEntry oldEntry = _vault.removeEntry(entry);
saveVault();
_entryListView.removeEntry(oldEntry);
2016-11-01 22:16:54 +01:00
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
2017-08-26 21:15:53 +02:00
_menu = menu;
getMenuInflater().inflate(R.menu.menu_main, menu);
2017-08-26 21:15:53 +02:00
updateLockIcon();
if (_loaded) {
updateGroupFilterMenu();
updateSortCategoryMenu();
}
MenuItem searchViewMenuItem = menu.findItem(R.id.mi_search);
_searchView = (SearchView) searchViewMenuItem.getActionView();
_searchView.setFocusable(false);
_searchView.setQueryHint(getString(R.string.search));
_searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
setTitle(getString(R.string.search));
getSupportActionBar().setSubtitle(s);
_searchSubmitted = true;
collapseSearchView();
return false;
}
@Override
public boolean onQueryTextChange(String s) {
if (!_searchSubmitted) {
_entryListView.setSearchFilter(s);
}
return false;
}
});
_searchView.setOnSearchClickListener(v -> {
if (_searchSubmitted) {
_searchSubmitted = false;
_entryListView.setSearchFilter(null);
}
});
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
2017-08-14 00:04:06 +02:00
switch (item.getItemId()) {
case R.id.action_settings: {
Intent intent = new Intent(this, PreferencesActivity.class);
startActivityForResult(intent, CODE_PREFERENCES);
2017-08-14 00:04:06 +02:00
return true;
}
case R.id.action_about: {
Intent intent = new Intent(this, AboutActivity.class);
startActivity(intent);
return true;
}
2017-08-14 00:04:06 +02:00
case R.id.action_lock:
_app.lock();
2017-08-14 00:04:06 +02:00
return true;
default:
if (item.getGroupId() == R.id.action_filter_group) {
item.setChecked(true);
String group = null;
if (item.getItemId() != R.id.menu_filter_all) {
group = item.getTitle().toString();
}
setGroupFilter(group);
}
2019-03-31 19:57:45 +02:00
if (item.getGroupId() == R.id.action_sort_category) {
item.setChecked(true);
SortCategory sortCategory;
switch (item.getItemId()) {
case R.id.menu_sort_alphabetically:
sortCategory = SortCategory.ISSUER;
break;
case R.id.menu_sort_alphabetically_reverse:
sortCategory = SortCategory.ISSUER_REVERSED;
2019-03-31 19:57:45 +02:00
break;
case R.id.menu_sort_alphabetically_name:
sortCategory = SortCategory.ACCOUNT;
break;
case R.id.menu_sort_alphabetically_name_reverse:
sortCategory = SortCategory.ACCOUNT_REVERSED;
2019-03-31 19:57:45 +02:00
break;
case R.id.menu_sort_custom:
2019-03-31 19:57:45 +02:00
default:
sortCategory = SortCategory.CUSTOM;
2019-03-31 19:57:45 +02:00
break;
}
_entryListView.setSortCategory(sortCategory, true);
getPreferences().setCurrentSortCategory(sortCategory);
2019-03-31 19:57:45 +02:00
}
2017-08-14 00:04:06 +02:00
return super.onOptionsItemSelected(item);
}
}
2016-09-30 01:08:03 +02:00
private void collapseSearchView() {
_searchView.setQuery(null, false);
_searchView.setIconified(true);
}
private boolean unlockVault(VaultFileCredentials creds) {
try {
if (!_vault.isLoaded()) {
_vault.load();
}
if (_vault.isLocked()) {
if (creds == null) {
startAuthActivity();
return false;
} else {
_vault.unlock(creds);
}
}
} catch (VaultManagerException e) {
2018-10-09 23:13:51 +02:00
Toast.makeText(this, getString(R.string.decryption_error), Toast.LENGTH_LONG).show();
startAuthActivity();
return false;
}
loadEntries();
return true;
}
private void loadEntries() {
// load all entries
List<VaultEntry> entries = new ArrayList<VaultEntry>(_vault.getEntries());
2019-03-31 19:57:45 +02:00
_entryListView.addEntries(entries);
_entryListView.runEntriesAnimation();
_loaded = true;
}
2017-12-24 21:42:08 +01:00
private void startAuthActivity() {
Intent intent = new Intent(this, AuthActivity.class);
intent.putExtra("slots", _vault.getFileHeader().getSlots());
intent.putExtra("requiresUnlock", false);
2019-09-06 21:41:55 +02:00
intent.putExtra("cancelAction", CancelAction.KILL);
2017-12-24 21:42:08 +01:00
startActivityForResult(intent, CODE_DECRYPT);
}
private void saveVault() {
try {
_vault.save();
} catch (VaultManagerException e) {
2018-10-09 23:13:51 +02:00
Toast.makeText(this, getString(R.string.saving_error), Toast.LENGTH_LONG).show();
}
}
2017-08-26 21:15:53 +02:00
private void updateLockIcon() {
// hide the lock icon if the vault is not unlocked
if (_menu != null && !_vault.isLocked()) {
2017-08-26 21:15:53 +02:00
MenuItem item = _menu.findItem(R.id.action_lock);
item.setVisible(_vault.isEncryptionEnabled());
2017-08-26 21:15:53 +02:00
}
}
@Override
public void onEntryClick(VaultEntry entry) {
if (_selectedEntry != null) {
if (_selectedEntry == entry) {
_actionMode.finish();
}
return;
}
copyEntryCode(entry);
}
@Override
public void onLongEntryClick(VaultEntry entry) {
if (_selectedEntry != null) {
return;
}
_selectedEntry = entry;
_entryListView.setActionModeState(true, entry);
_actionMode = this.startSupportActionMode(_actionModeCallbacks);
}
@Override
public void onEntryMove(VaultEntry entry1, VaultEntry entry2) {
_vault.swapEntries(entry1, entry2);
}
@Override
public void onEntryDrop(VaultEntry entry) {
saveVault();
}
2018-06-06 17:23:40 +02:00
@Override
public void onEntryChange(VaultEntry entry) {
saveVault();
2018-06-06 17:23:40 +02:00
}
@Override
public void onScroll(int dx, int dy) {
_fabScrollHelper.onScroll(dx, dy);
}
@Override
public void onLocked() {
if (_actionMode != null) {
_actionMode.finish();
}
_entryListView.clearEntries();
_loaded = false;
if (isOpen()) {
startAuthActivity();
}
super.onLocked();
}
private void copyEntryCode(DatabaseEntry entry) {
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("text/plain", entry.getInfo().getOtp());
clipboard.setPrimaryClip(clip);
Toast.makeText(this, getString(R.string.code_copied), Toast.LENGTH_SHORT).show();
}
private class ActionModeCallbacks implements ActionMode.Callback {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.menu_action_mode, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.action_copy:
copyEntryCode(_selectedEntry);
mode.finish();
return true;
case R.id.action_edit:
startEditProfileActivity(CODE_EDIT_ENTRY, _selectedEntry, false);
mode.finish();
return true;
case R.id.action_delete:
Dialogs.showDeleteEntryDialog(MainActivity.this, (d, which) -> {
deleteEntry(_selectedEntry);
if (_selectedEntry.getGroup() != null) {
if (!_vault.getGroups().contains(_selectedEntry.getGroup())) {
updateGroupFilterMenu();
}
}
mode.finish();
});
return true;
default:
return false;
}
}
@Override
public void onDestroyActionMode(ActionMode mode) {
_entryListView.setActionModeState(false, null);
_selectedEntry = null;
_actionMode = null;
}
}
2016-08-15 21:29:41 +02:00
}