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

916 lines
33 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;
import android.content.DialogInterface;
2016-08-15 22:31:28 +02:00
import android.content.Intent;
import android.graphics.Typeface;
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.provider.Settings;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.StyleSpan;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
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.Preferences;
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;
2021-01-27 13:54:11 +01:00
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
import com.beemdevelopment.aegis.ui.fragments.preferences.BackupsPreferencesFragment;
import com.beemdevelopment.aegis.ui.fragments.preferences.PreferencesFragment;
import com.beemdevelopment.aegis.ui.tasks.QrDecodeTask;
import com.beemdevelopment.aegis.ui.views.EntryListView;
import com.beemdevelopment.aegis.vault.VaultEntry;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;
import java.util.Collections;
2019-03-31 19:57:45 +02:00
import java.util.List;
import java.util.Map;
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_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;
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 boolean _loaded;
private boolean _isRecreated;
private boolean _isDPadPressed;
private String _submittedSearchSubtitle;
private String _searchQueryInputText;
private String _activeSearchFilter;
private List<VaultEntry> _selectedEntries;
private ActionMode _actionMode;
2017-08-26 21:15:53 +02:00
private Menu _menu;
private SearchView _searchView;
private EntryListView _entryListView;
private LinearLayout _btnErrorBar;
private TextView _textErrorBar;
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);
setContentView(R.layout.activity_main);
setSupportActionBar(findViewById(R.id.toolbar));
_loaded = false;
_isDPadPressed = false;
if (savedInstanceState != null) {
_isRecreated = true;
_searchQueryInputText = savedInstanceState.getString("searchQueryInputText");
_activeSearchFilter = savedInstanceState.getString("activeSearchFilter");
_submittedSearchSubtitle = savedInstanceState.getString("submittedSearchSubtitle");
}
2017-12-03 16:47:27 +01:00
_entryListView = (EntryListView) getSupportFragmentManager().findFragmentById(R.id.key_profiles);
_entryListView.setListener(this);
_entryListView.setCodeGroupSize(_prefs.getCodeGroupSize());
_entryListView.setShowAccountName(_prefs.isAccountNameVisible());
_entryListView.setHighlightEntry(_prefs.isEntryHighlightEnabled());
_entryListView.setPauseFocused(_prefs.isPauseFocusedEnabled());
_entryListView.setTapToReveal(_prefs.isTapToRevealEnabled());
_entryListView.setTapToRevealTime(_prefs.getTapToRevealTime());
_entryListView.setSortCategory(_prefs.getCurrentSortCategory(), false);
_entryListView.setViewMode(_prefs.getCurrentViewMode());
_entryListView.setIsCopyOnTapEnabled(_prefs.isCopyOnTapEnabled());
_entryListView.setPrefGroupFilter(_prefs.getGroupFilter());
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(v -> {
View view = getLayoutInflater().inflate(R.layout.dialog_add_entry, null);
BottomSheetDialog dialog = new BottomSheetDialog(this);
dialog.setContentView(view);
view.findViewById(R.id.fab_enter).setOnClickListener(v1 -> {
dialog.dismiss();
startEditEntryActivityForManual(CODE_ADD_ENTRY);
});
view.findViewById(R.id.fab_scan_image).setOnClickListener(v2 -> {
dialog.dismiss();
startScanImageActivity();
});
view.findViewById(R.id.fab_scan).setOnClickListener(v3 -> {
dialog.dismiss();
startScanActivity();
});
Dialogs.showSecureDialog(dialog);
});
_btnErrorBar = findViewById(R.id.btn_error_bar);
_textErrorBar = findViewById(R.id.text_error_bar);
_fabScrollHelper = new FabScrollHelper(fab);
_selectedEntries = new ArrayList<>();
2016-08-15 21:29:41 +02:00
}
@Override
protected void onDestroy() {
_entryListView.setListener(null);
super.onDestroy();
}
@Override
protected void onPause() {
Map<UUID, Integer> usageMap = _entryListView.getUsageCounts();
if (usageMap != null) {
_prefs.setUsageCount(usageMap);
}
super.onPause();
}
@Override
protected void onSaveInstanceState(Bundle instance) {
super.onSaveInstanceState(instance);
instance.putString("activeSearchFilter", _activeSearchFilter);
instance.putString("submittedSearchSubtitle", _submittedSearchSubtitle);
instance.putString("searchQueryInputText", _searchQueryInputText);
}
2017-12-24 21:42:08 +01:00
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != RESULT_OK) {
return;
}
switch (requestCode) {
case CODE_SCAN:
onScanResult(data);
break;
case CODE_ADD_ENTRY:
onAddEntryResult(data);
break;
case CODE_EDIT_ENTRY:
onEditEntryResult(data);
break;
case CODE_DO_INTRO:
onIntroResult();
break;
case CODE_DECRYPT:
onDecryptResult();
break;
case CODE_PREFERENCES:
onPreferencesResult(data);
break;
2019-04-19 23:10:18 +02:00
case CODE_SCAN_IMAGE:
onScanImageResult(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;
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
_isDPadPressed = isDPadKey(keyCode);
return super.onKeyDown(keyCode, event);
}
private static boolean isDPadKey(int keyCode) {
return keyCode == KeyEvent.KEYCODE_DPAD_DOWN || keyCode == KeyEvent.KEYCODE_DPAD_UP || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT || keyCode == KeyEvent.KEYCODE_DPAD_LEFT;
}
@Override
public void onEntryListTouch() {
_isDPadPressed = false;
}
private void onPreferencesResult(Intent data) {
// refresh the entire entry list if needed
if (_loaded) {
if (data.getBooleanExtra("needsRecreate", false)) {
recreate();
} else if (data.getBooleanExtra("needsRefresh", false)) {
boolean showAccountName = _prefs.isAccountNameVisible();
int codeGroupSize = _prefs.getCodeGroupSize();
boolean highlightEntry = _prefs.isEntryHighlightEnabled();
boolean pauseFocused = _prefs.isPauseFocusedEnabled();
boolean tapToReveal = _prefs.isTapToRevealEnabled();
int tapToRevealTime = _prefs.getTapToRevealTime();
ViewMode viewMode = _prefs.getCurrentViewMode();
boolean copyOnTap = _prefs.isCopyOnTapEnabled();
_entryListView.setShowAccountName(showAccountName);
_entryListView.setCodeGroupSize(codeGroupSize);
_entryListView.setHighlightEntry(highlightEntry);
_entryListView.setPauseFocused(pauseFocused);
_entryListView.setTapToReveal(tapToReveal);
_entryListView.setTapToRevealTime(tapToRevealTime);
_entryListView.setViewMode(viewMode);
_entryListView.setIsCopyOnTapEnabled(copyOnTap);
_entryListView.refresh(true);
}
}
}
private void startEditEntryActivityForNew(int requestCode, VaultEntry entry) {
Intent intent = new Intent(this, EditEntryActivity.class);
intent.putExtra("newEntry", entry);
intent.putExtra("isManual", false);
startActivityForResult(intent, requestCode);
}
private void startEditEntryActivityForManual(int requestCode) {
Intent intent = new Intent(this, EditEntryActivity.class);
intent.putExtra("newEntry", VaultEntry.getDefault());
intent.putExtra("isManual", true);
startActivityForResult(intent, requestCode);
}
private void startEditEntryActivity(int requestCode, VaultEntry entry) {
Intent intent = new Intent(this, EditEntryActivity.class);
intent.putExtra("entryUUID", entry.getUUID());
startActivityForResult(intent, requestCode);
}
private void onScanResult(Intent data) {
List<VaultEntry> entries = (ArrayList<VaultEntry>) data.getSerializableExtra("entries");
if (entries != null) {
importScannedEntries(entries);
}
}
private void onAddEntryResult(Intent data) {
if (_loaded) {
UUID entryUUID = (UUID) data.getSerializableExtra("entryUUID");
VaultEntry entry = _vaultManager.getVault().getEntryByUUID(entryUUID);
_entryListView.addEntry(entry, true);
}
}
private void onEditEntryResult(Intent data) {
if (_loaded) {
UUID entryUUID = (UUID) data.getSerializableExtra("entryUUID");
if (data.getBooleanExtra("delete", false)) {
_entryListView.removeEntry(entryUUID);
} else {
VaultEntry entry = _vaultManager.getVault().getEntryByUUID(entryUUID);
_entryListView.replaceEntry(entryUUID, entry);
}
}
}
private void onScanImageResult(Intent intent) {
if (intent.getData() != null) {
startDecodeQrCodeImages(Collections.singletonList(intent.getData()));
return;
}
if (intent.getClipData() != null) {
ClipData data = intent.getClipData();
List<Uri> uris = new ArrayList<>();
for (int i = 0; i < data.getItemCount(); i++) {
ClipData.Item item = data.getItemAt(i);
if (item.getUri() != null) {
uris.add(item.getUri());
}
}
if (uris.size() > 0) {
startDecodeQrCodeImages(uris);
}
}
}
private static CharSequence buildImportError(String fileName, Throwable e) {
SpannableStringBuilder builder = new SpannableStringBuilder(String.format("%s:\n%s", fileName, e));
builder.setSpan(new StyleSpan(Typeface.BOLD), 0, fileName.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return builder;
}
private void startDecodeQrCodeImages(List<Uri> uris) {
QrDecodeTask task = new QrDecodeTask(this, (results) -> {
List<CharSequence> errors = new ArrayList<>();
List<VaultEntry> entries = new ArrayList<>();
for (QrDecodeTask.Result res : results) {
if (res.getException() != null) {
errors.add(buildImportError(res.getFileName(), res.getException()));
continue;
}
try {
GoogleAuthInfo info = GoogleAuthInfo.parseUri(res.getResult().getText());
VaultEntry entry = new VaultEntry(info);
entries.add(entry);
} catch (GoogleAuthInfoException e) {
errors.add(buildImportError(res.getFileName(), e));
}
}
2019-04-19 23:10:18 +02:00
final DialogInterface.OnClickListener dialogDismissHandler = (dialog, which) -> importScannedEntries(entries);
if ((errors.size() > 0 && results.size() > 1) || errors.size() > 1) {
Dialogs.showMultiMessageDialog(this, R.string.import_error_title, getString(R.string.unable_to_read_qrcode_files, uris.size() - errors.size(), uris.size()), errors, dialogDismissHandler);
} else if (errors.size() > 0) {
Dialogs.showErrorDialog(this, getString(R.string.unable_to_read_qrcode_file, results.get(0).getFileName()), errors.get(0), dialogDismissHandler);
} else {
importScannedEntries(entries);
}
});
task.execute(getLifecycle(), uris);
}
private void importScannedEntries(List<VaultEntry> entries) {
if (entries.size() == 1) {
startEditEntryActivityForNew(CODE_ADD_ENTRY, entries.get(0));
} else if (entries.size() > 1) {
for (VaultEntry entry: entries) {
_vaultManager.getVault().addEntry(entry);
_entryListView.addEntry(entry);
}
if (saveAndBackupVault()) {
Toast.makeText(this, getResources().getQuantityString(R.plurals.added_new_entries, entries.size(), entries.size()), Toast.LENGTH_LONG).show();
}
}
2019-04-19 23:10:18 +02:00
}
private void updateSortCategoryMenu() {
SortCategory category = _prefs.getCurrentSortCategory();
_menu.findItem(category.getMenuItem()).setChecked(true);
}
private void onIntroResult() {
loadEntries();
checkTimeSyncSetting();
}
private void checkTimeSyncSetting() {
boolean autoTime = Settings.Global.getInt(getContentResolver(), Settings.Global.AUTO_TIME, 1) == 1;
if (!autoTime && _prefs.isTimeSyncWarningEnabled()) {
Dialogs.showTimeSyncWarningDialog(this, (dialog, which) -> {
Intent intent = new Intent(Settings.ACTION_DATE_SETTINGS);
startActivity(intent);
});
}
}
private void onDecryptResult() {
loadEntries();
checkTimeSyncSetting();
2017-12-03 16:47:27 +01:00
}
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() {
Intent galleryIntent = new Intent(Intent.ACTION_PICK);
galleryIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
galleryIntent.setDataAndType(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, "image/*");
Intent fileIntent = new Intent(Intent.ACTION_GET_CONTENT);
fileIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
fileIntent.setType("image/*");
Intent chooserIntent = Intent.createChooser(galleryIntent, getString(R.string.select_picture));
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { fileIntent });
_vaultManager.startActivityForResult(this, chooserIntent, CODE_SCAN_IMAGE);
}
private void startPreferencesActivity() {
startPreferencesActivity(null, null);
}
private void startPreferencesActivity(Class<? extends PreferencesFragment> fragmentType, String preference) {
Intent intent = new Intent(this, PreferencesActivity.class);
intent.putExtra("fragment", fragmentType);
intent.putExtra("pref", preference);
startActivityForResult(intent, CODE_PREFERENCES);
}
private void doShortcutActions() {
2017-12-03 16:47:27 +01:00
Intent intent = getIntent();
String action = intent.getStringExtra("action");
if (action == null || !_vaultManager.isVaultLoaded()) {
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 (!_vaultManager.isVaultLoaded()) {
return;
}
Intent intent = getIntent();
Uri uri = intent.getData();
if (Intent.ACTION_VIEW.equals(intent.getAction()) && uri != null) {
intent.setData(null);
intent.setAction(null);
GoogleAuthInfo info = null;
try {
info = GoogleAuthInfo.parseUri(uri);
} catch (GoogleAuthInfoException e) {
e.printStackTrace();
Dialogs.showErrorDialog(this, R.string.unable_to_process_deeplink, e);
}
if (info != null) {
VaultEntry entry = new VaultEntry(info);
startEditEntryActivityForNew(CODE_ADD_ENTRY, entry);
}
}
}
private void handleSharedImage() {
if (!_vaultManager.isVaultLoaded()) {
return;
}
Intent intent = getIntent();
String action = intent.getAction();
Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
if (Intent.ACTION_SEND.equals(action) && uri != null) {
intent.setAction(null);
intent.removeExtra(Intent.EXTRA_STREAM);
startDecodeQrCodeImages(Collections.singletonList(uri));
}
}
2016-09-30 01:08:03 +02:00
@Override
protected void onResume() {
super.onResume();
2017-12-24 21:42:08 +01:00
if (_vaultManager.isVaultInitNeeded()) {
if (_prefs.isIntroDone()) {
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;
}
if (!_vaultManager.isVaultLoaded() && !_vaultManager.isVaultFileLoaded()) {
Dialogs.showErrorDialog(this, R.string.vault_load_error, _vaultManager.getVaultFileError(), (dialog1, which) -> finish());
return;
}
if (!_vaultManager.isVaultLoaded()) {
startAuthActivity(false);
} else if (_loaded) {
// update the list of groups in the entry list view so that the chip gets updated
_entryListView.setGroups(_vaultManager.getVault().getGroups());
// update the usage counts in case they are edited outside of the EntryListView
_entryListView.setUsageCounts(_prefs.getUsageCounts());
// refresh all codes to prevent showing old ones
_entryListView.refresh(false);
} else {
loadEntries();
checkTimeSyncSetting();
}
handleDeeplink();
handleSharedImage();
updateLockIcon();
doShortcutActions();
updateErrorBar();
2016-09-30 01:08:03 +02:00
}
@Override
public void onBackPressed() {
if (!_searchView.isIconified() || _submittedSearchSubtitle != null) {
_submittedSearchSubtitle = null;
_entryListView.setSearchFilter(null);
_activeSearchFilter = null;
collapseSearchView();
setTitle(R.string.app_name);
getSupportActionBar().setSubtitle(null);
return;
}
if (_vaultManager.isAutoLockEnabled(Preferences.AUTO_LOCK_ON_BACK_BUTTON)) {
_vaultManager.lock(false);
return;
}
super.onBackPressed();
}
private void deleteEntries(List<VaultEntry> entries) {
for (VaultEntry entry: entries) {
VaultEntry oldEntry = _vaultManager.getVault().removeEntry(entry);
_entryListView.removeEntry(oldEntry);
}
saveAndBackupVault();
}
@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) {
_entryListView.setGroups(_vaultManager.getVault().getGroups());
updateSortCategoryMenu();
}
MenuItem searchViewMenuItem = menu.findItem(R.id.mi_search);
_searchView = (SearchView) searchViewMenuItem.getActionView();
_searchView.setMaxWidth(Integer.MAX_VALUE);
_searchView.setQueryHint(getString(R.string.search));
if (_prefs.getFocusSearchEnabled() && !_isRecreated) {
_searchView.setIconified(false);
_searchView.setFocusable(true);
_searchView.requestFocus();
_searchView.requestFocusFromTouch();
}
_searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
setTitle(getString(R.string.search));
getSupportActionBar().setSubtitle(s);
_searchQueryInputText = null;
_submittedSearchSubtitle = s;
collapseSearchView();
return false;
}
@Override
public boolean onQueryTextChange(String s) {
if (_submittedSearchSubtitle == null) {
_entryListView.setSearchFilter(s);
_activeSearchFilter = s;
_searchQueryInputText = s;
}
return false;
}
});
_searchView.setOnSearchClickListener(v -> {
if (_submittedSearchSubtitle != null) {
_entryListView.setSearchFilter(null);
_activeSearchFilter = null;
_submittedSearchSubtitle = null;
}
});
if (_submittedSearchSubtitle != null) {
getSupportActionBar().setSubtitle(_submittedSearchSubtitle);
}
if (_activeSearchFilter != null) {
_entryListView.setSearchFilter(_activeSearchFilter);
}
if (_searchQueryInputText != null) {
_searchView.setQuery(_searchQueryInputText, false);
_searchView.setIconified(false);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
2017-08-14 00:04:06 +02:00
switch (item.getItemId()) {
case R.id.action_settings: {
startPreferencesActivity();
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:
_vaultManager.lock(true);
2017-08-14 00:04:06 +02:00
return true;
default:
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_usage_count:
sortCategory = SortCategory.USAGE_COUNT;
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);
_prefs.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 void loadEntries() {
if (!_loaded) {
_entryListView.setUsageCounts(_prefs.getUsageCounts());
_entryListView.addEntries(_vaultManager.getVault().getEntries());
_entryListView.runEntriesAnimation();
_loaded = true;
}
}
private void startAuthActivity(boolean inhibitBioPrompt) {
Intent intent = new Intent(this, AuthActivity.class);
intent.putExtra("inhibitBioPrompt", inhibitBioPrompt);
startActivityForResult(intent, CODE_DECRYPT);
2017-12-24 21:42:08 +01:00
}
2017-08-26 21:15:53 +02:00
private void updateLockIcon() {
// hide the lock icon if the vault is not unlocked
if (_menu != null && _vaultManager.isVaultLoaded()) {
2017-08-26 21:15:53 +02:00
MenuItem item = _menu.findItem(R.id.action_lock);
item.setVisible(_vaultManager.getVault().isEncryptionEnabled());
2017-08-26 21:15:53 +02:00
}
}
private void updateErrorBar() {
String backupError = null;
if (_prefs.isBackupsEnabled()) {
backupError = _prefs.getBackupsError();
}
if (backupError != null) {
_textErrorBar.setText(R.string.backup_error_bar_message);
_btnErrorBar.setOnClickListener(view -> {
startPreferencesActivity(BackupsPreferencesFragment.class, "pref_backups");
});
_btnErrorBar.setVisibility(View.VISIBLE);
} else if (_prefs.isBackupsReminderNeeded()) {
_textErrorBar.setText(R.string.backup_reminder_bar_message);
_btnErrorBar.setOnClickListener(view -> {
startPreferencesActivity();
});
_btnErrorBar.setVisibility(View.VISIBLE);
} else {
_btnErrorBar.setVisibility(View.GONE);
}
}
@Override
public void onEntryClick(VaultEntry entry) {
if (_actionMode != null) {
if (_selectedEntries.isEmpty()) {
_actionMode.finish();
} else {
setIsMultipleSelected(_selectedEntries.size() > 1);
}
return;
}
}
@Override
public void onSelect(VaultEntry entry) {
_selectedEntries.add(entry);
}
@Override
public void onDeselect(VaultEntry entry) {
_selectedEntries.remove(entry);
}
private void setIsMultipleSelected(boolean multipleSelected) {
_entryListView.setIsLongPressDragEnabled(!multipleSelected);
_actionMode.getMenu().findItem(R.id.action_edit).setVisible(!multipleSelected);
_actionMode.getMenu().findItem(R.id.action_copy).setVisible(!multipleSelected);
}
@Override
public void onLongEntryClick(VaultEntry entry) {
if (!_selectedEntries.isEmpty()) {
return;
}
_selectedEntries.add(entry);
_entryListView.setActionModeState(true, entry);
_actionMode = startSupportActionMode(_actionModeCallbacks);
}
@Override
public void onEntryMove(VaultEntry entry1, VaultEntry entry2) {
_vaultManager.getVault().swapEntries(entry1, entry2);
}
@Override
public void onEntryDrop(VaultEntry entry) {
saveVault();
}
2018-06-06 17:23:40 +02:00
@Override
public void onEntryChange(VaultEntry entry) {
saveAndBackupVault();
2018-06-06 17:23:40 +02:00
}
public void onEntryCopy(VaultEntry entry) {
copyEntryCode(entry);
}
@Override
public void onScroll(int dx, int dy) {
if (!_isDPadPressed) {
_fabScrollHelper.onScroll(dx, dy);
}
}
2020-08-13 13:06:20 +02:00
@Override
public void onListChange() { _fabScrollHelper.setVisible(true); }
@Override
public void onSaveGroupFilter(List<String> groupFilter) {
_prefs.setGroupFilter(groupFilter);
}
@Override
public void onLocked(boolean userInitiated) {
if (_actionMode != null) {
_actionMode.finish();
}
if (_searchView != null && !_searchView.isIconified()) {
collapseSearchView();
}
_entryListView.clearEntries();
_loaded = false;
if (userInitiated) {
startAuthActivity(true);
} else {
super.onLocked(false);
}
}
2019-12-26 22:17:32 +01:00
private void copyEntryCode(VaultEntry entry) {
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("text/plain", entry.getInfo().getOtp());
clipboard.setPrimaryClip(clip);
}
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) {
if(_selectedEntries.size() == 0) {
mode.finish();
return true;
}
switch (item.getItemId()) {
case R.id.action_copy:
copyEntryCode(_selectedEntries.get(0));
mode.finish();
return true;
case R.id.action_edit:
startEditEntryActivity(CODE_EDIT_ENTRY, _selectedEntries.get(0));
mode.finish();
return true;
case R.id.action_share_qr:
Intent intent = new Intent(getBaseContext(), TransferEntriesActivity.class);
ArrayList<GoogleAuthInfo> authInfos = new ArrayList<>();
for (VaultEntry entry : _selectedEntries) {
GoogleAuthInfo authInfo = new GoogleAuthInfo(entry.getInfo(), entry.getName(), entry.getIssuer());
authInfos.add(authInfo);
}
intent.putExtra("authInfos", authInfos);
startActivity(intent);
mode.finish();
return true;
case R.id.action_delete:
Dialogs.showDeleteEntriesDialog(MainActivity.this, _selectedEntries, (d, which) -> {
deleteEntries(_selectedEntries);
for (VaultEntry entry : _selectedEntries) {
if (entry.getGroup() != null) {
TreeSet<String> groups = _vaultManager.getVault().getGroups();
if (!groups.contains(entry.getGroup())) {
_entryListView.setGroups(groups);
break;
}
}
}
mode.finish();
});
return true;
default:
return false;
}
}
@Override
public void onDestroyActionMode(ActionMode mode) {
_entryListView.setActionModeState(false, null);
_selectedEntries.clear();
_actionMode = null;
}
}
2016-08-15 21:29:41 +02:00
}