2019-02-07 22:39:33 +01:00
|
|
|
package com.beemdevelopment.aegis.ui;
|
2016-08-15 21:29:41 +02:00
|
|
|
|
2017-12-13 19:00:58 +01:00
|
|
|
import android.Manifest;
|
2022-09-14 18:33:28 +02:00
|
|
|
import android.annotation.SuppressLint;
|
2016-08-21 22:32:07 +02:00
|
|
|
import android.content.ClipData;
|
2022-09-14 18:33:28 +02:00
|
|
|
import android.content.ClipDescription;
|
2016-08-21 22:32:07 +02:00
|
|
|
import android.content.ClipboardManager;
|
2016-08-21 22:24:04 +02:00
|
|
|
import android.content.Context;
|
2022-08-07 20:18:21 +02:00
|
|
|
import android.content.DialogInterface;
|
2016-08-15 22:31:28 +02:00
|
|
|
import android.content.Intent;
|
2022-08-07 20:18:21 +02:00
|
|
|
import android.graphics.Typeface;
|
2019-04-19 23:10:18 +02:00
|
|
|
import android.net.Uri;
|
2022-09-14 18:33:28 +02:00
|
|
|
import android.os.Build;
|
2016-08-15 21:29:41 +02:00
|
|
|
import android.os.Bundle;
|
2022-09-14 18:33:28 +02:00
|
|
|
import android.os.PersistableBundle;
|
2020-05-03 16:57:51 +02:00
|
|
|
import android.provider.Settings;
|
2022-08-07 20:18:21 +02:00
|
|
|
import android.text.Spannable;
|
|
|
|
import android.text.SpannableStringBuilder;
|
|
|
|
import android.text.style.StyleSpan;
|
2022-04-10 16:36:30 +02:00
|
|
|
import android.view.KeyEvent;
|
2022-08-07 19:55:36 +01:00
|
|
|
import android.view.LayoutInflater;
|
2016-08-16 14:14:17 +02:00
|
|
|
import android.view.Menu;
|
2019-08-03 16:15:39 +02:00
|
|
|
import android.view.MenuInflater;
|
2016-08-16 14:14:17 +02:00
|
|
|
import android.view.MenuItem;
|
2020-06-13 12:45:02 +02:00
|
|
|
import android.view.View;
|
2022-08-07 19:55:36 +01:00
|
|
|
import android.widget.Button;
|
|
|
|
import android.widget.CheckBox;
|
2020-06-13 12:45:02 +02:00
|
|
|
import android.widget.LinearLayout;
|
2022-04-10 16:47:44 +02:00
|
|
|
import android.widget.TextView;
|
2016-08-17 01:14:25 +02:00
|
|
|
import android.widget.Toast;
|
|
|
|
|
2022-10-10 22:32:30 +02:00
|
|
|
import androidx.activity.OnBackPressedCallback;
|
2022-10-09 14:35:51 +02:00
|
|
|
import androidx.annotation.NonNull;
|
2022-08-07 19:55:36 +01:00
|
|
|
import androidx.appcompat.app.AlertDialog;
|
2019-08-03 16:15:39 +02:00
|
|
|
import androidx.appcompat.view.ActionMode;
|
2019-09-10 23:10:11 +02:00
|
|
|
import androidx.appcompat.widget.SearchView;
|
2019-08-03 16:15:39 +02:00
|
|
|
|
2023-08-16 01:05:26 +02:00
|
|
|
import com.beemdevelopment.aegis.CopyBehavior;
|
2023-08-16 14:17:57 +02:00
|
|
|
import com.beemdevelopment.aegis.AccountNamePosition;
|
2020-08-12 21:33:25 +02:00
|
|
|
import com.beemdevelopment.aegis.Preferences;
|
2019-04-04 14:07:36 +02:00
|
|
|
import com.beemdevelopment.aegis.R;
|
|
|
|
import com.beemdevelopment.aegis.SortCategory;
|
|
|
|
import com.beemdevelopment.aegis.ViewMode;
|
2019-04-20 01:25:04 +02:00
|
|
|
import com.beemdevelopment.aegis.helpers.FabScrollHelper;
|
2019-02-07 22:39:33 +01:00
|
|
|
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;
|
2022-09-17 17:30:14 +02:00
|
|
|
import com.beemdevelopment.aegis.otp.OtpInfoException;
|
2021-01-27 13:54:11 +01:00
|
|
|
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
2022-02-06 19:00:01 +01:00
|
|
|
import com.beemdevelopment.aegis.ui.fragments.preferences.BackupsPreferencesFragment;
|
|
|
|
import com.beemdevelopment.aegis.ui.fragments.preferences.PreferencesFragment;
|
2022-08-07 17:05:08 +02:00
|
|
|
import com.beemdevelopment.aegis.ui.tasks.QrDecodeTask;
|
2019-02-07 22:39:33 +01:00
|
|
|
import com.beemdevelopment.aegis.ui.views.EntryListView;
|
2022-12-04 15:44:45 +01:00
|
|
|
import com.beemdevelopment.aegis.util.TimeUtils;
|
2019-12-25 19:21:34 +01:00
|
|
|
import com.beemdevelopment.aegis.vault.VaultEntry;
|
2021-01-02 13:41:58 +01:00
|
|
|
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
|
|
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
2022-10-10 22:32:30 +02:00
|
|
|
import com.google.common.base.Strings;
|
2022-08-07 17:05:08 +02:00
|
|
|
|
2018-12-11 11:44:36 +01:00
|
|
|
import java.util.ArrayList;
|
2022-08-07 20:18:21 +02:00
|
|
|
import java.util.Collections;
|
2022-12-04 15:44:45 +01:00
|
|
|
import java.util.Date;
|
2019-03-31 19:57:45 +02:00
|
|
|
import java.util.List;
|
2021-06-02 18:02:38 +02:00
|
|
|
import java.util.Map;
|
2022-08-11 15:23:11 +01:00
|
|
|
import java.util.Objects;
|
2023-04-30 15:31:38 +01:00
|
|
|
import java.util.Set;
|
2020-05-02 18:51:33 +02:00
|
|
|
import java.util.UUID;
|
2022-12-03 19:31:25 +01:00
|
|
|
import java.util.stream.Collectors;
|
2016-08-16 20:04:38 +02:00
|
|
|
|
2018-06-06 16:15:31 +02:00
|
|
|
public class MainActivity extends AegisActivity implements EntryListView.Listener {
|
2017-12-13 19:00:58 +01:00
|
|
|
// activity request codes
|
2018-06-06 16:15:31 +02:00
|
|
|
private static final int CODE_SCAN = 0;
|
|
|
|
private static final int CODE_ADD_ENTRY = 1;
|
|
|
|
private static final int CODE_EDIT_ENTRY = 2;
|
2020-05-02 18:51:33 +02:00
|
|
|
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;
|
2023-08-31 21:56:05 +02:00
|
|
|
private static final int CODE_ASSIGN_ICONS = 7;
|
|
|
|
|
2016-08-24 23:48:25 +02:00
|
|
|
|
2022-10-12 17:39:40 +02:00
|
|
|
// Permission request codes
|
2018-05-10 19:34:42 +02:00
|
|
|
private static final int CODE_PERM_CAMERA = 0;
|
2017-12-13 19:00:58 +01:00
|
|
|
|
2018-06-09 20:23:39 +02:00
|
|
|
private boolean _loaded;
|
2021-11-04 15:41:17 +05:30
|
|
|
private boolean _isRecreated;
|
2022-04-10 16:36:30 +02:00
|
|
|
private boolean _isDPadPressed;
|
2022-10-09 14:35:51 +02:00
|
|
|
private boolean _isDoingIntro;
|
|
|
|
private boolean _isAuthenticating;
|
2020-07-01 15:35:54 +02:00
|
|
|
|
2022-10-10 22:32:30 +02:00
|
|
|
private String _submittedSearchQuery;
|
|
|
|
private String _pendingSearchQuery;
|
2022-05-07 16:15:30 +02:00
|
|
|
|
2020-01-04 20:38:40 +01:00
|
|
|
private List<VaultEntry> _selectedEntries;
|
2019-08-03 16:15:39 +02:00
|
|
|
|
2017-08-26 21:15:53 +02:00
|
|
|
private Menu _menu;
|
2019-05-30 02:07:30 +02:00
|
|
|
private SearchView _searchView;
|
2018-06-09 20:23:39 +02:00
|
|
|
private EntryListView _entryListView;
|
2022-04-10 16:47:44 +02:00
|
|
|
private LinearLayout _btnErrorBar;
|
|
|
|
private TextView _textErrorBar;
|
2016-08-16 14:14:17 +02:00
|
|
|
|
2019-04-20 01:25:04 +02:00
|
|
|
private FabScrollHelper _fabScrollHelper;
|
2019-04-04 14:07:36 +02:00
|
|
|
|
2022-10-10 22:32:30 +02:00
|
|
|
private ActionMode _actionMode;
|
2019-08-03 16:15:39 +02:00
|
|
|
private ActionMode.Callback _actionModeCallbacks = new ActionModeCallbacks();
|
|
|
|
|
2022-10-10 22:32:30 +02:00
|
|
|
private LockBackPressHandler _lockBackPressHandler;
|
|
|
|
private SearchViewBackPressHandler _searchViewBackPressHandler;
|
|
|
|
private ActionModeBackPressHandler _actionModeBackPressHandler;
|
|
|
|
|
2016-08-15 21:29:41 +02:00
|
|
|
@Override
|
|
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
|
|
super.onCreate(savedInstanceState);
|
2020-07-01 15:35:54 +02:00
|
|
|
setContentView(R.layout.activity_main);
|
2021-01-17 13:12:43 +01:00
|
|
|
setSupportActionBar(findViewById(R.id.toolbar));
|
2018-06-09 20:23:39 +02:00
|
|
|
_loaded = false;
|
2022-04-10 16:36:30 +02:00
|
|
|
_isDPadPressed = false;
|
2022-10-09 14:35:51 +02:00
|
|
|
_isDoingIntro = false;
|
|
|
|
_isAuthenticating = false;
|
2020-07-01 15:35:54 +02:00
|
|
|
if (savedInstanceState != null) {
|
2021-11-04 15:41:17 +05:30
|
|
|
_isRecreated = true;
|
2022-10-10 22:32:30 +02:00
|
|
|
_pendingSearchQuery = savedInstanceState.getString("pendingSearchQuery");
|
|
|
|
_submittedSearchQuery = savedInstanceState.getString("submittedSearchQuery");
|
2022-10-09 14:35:51 +02:00
|
|
|
_isDoingIntro = savedInstanceState.getBoolean("isDoingIntro");
|
|
|
|
_isAuthenticating = savedInstanceState.getBoolean("isAuthenticating");
|
2020-07-01 15:35:54 +02:00
|
|
|
}
|
2017-12-03 16:47:27 +01:00
|
|
|
|
2022-10-10 22:32:30 +02:00
|
|
|
_lockBackPressHandler = new LockBackPressHandler();
|
|
|
|
getOnBackPressedDispatcher().addCallback(this, _lockBackPressHandler);
|
|
|
|
_searchViewBackPressHandler = new SearchViewBackPressHandler();
|
|
|
|
getOnBackPressedDispatcher().addCallback(this, _searchViewBackPressHandler);
|
|
|
|
_actionModeBackPressHandler = new ActionModeBackPressHandler();
|
|
|
|
getOnBackPressedDispatcher().addCallback(this, _actionModeBackPressHandler);
|
|
|
|
|
2018-06-06 16:15:31 +02:00
|
|
|
_entryListView = (EntryListView) getSupportFragmentManager().findFragmentById(R.id.key_profiles);
|
|
|
|
_entryListView.setListener(this);
|
2022-02-06 19:00:01 +01:00
|
|
|
_entryListView.setCodeGroupSize(_prefs.getCodeGroupSize());
|
2023-08-16 14:17:57 +02:00
|
|
|
_entryListView.setAccountNamePosition(_prefs.getAccountNamePosition());
|
2022-11-01 19:22:23 +00:00
|
|
|
_entryListView.setShowIcon(_prefs.isIconVisible());
|
2023-08-21 00:24:10 +02:00
|
|
|
_entryListView.setOnlyShowNecessaryAccountNames(_prefs.onlyShowNecessaryAccountNames());
|
2022-02-06 19:00:01 +01:00
|
|
|
_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());
|
2023-08-16 01:05:26 +02:00
|
|
|
_entryListView.setCopyBehavior(_prefs.getCopyBehavior());
|
2022-02-06 19:00:01 +01:00
|
|
|
_entryListView.setPrefGroupFilter(_prefs.getGroupFilter());
|
2017-12-25 15:36:29 +01:00
|
|
|
|
2021-01-02 13:41:58 +01:00
|
|
|
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();
|
2021-01-27 20:06:34 +01:00
|
|
|
startEditEntryActivityForManual(CODE_ADD_ENTRY);
|
2021-01-02 13:41:58 +01:00
|
|
|
});
|
|
|
|
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);
|
|
|
|
});
|
2019-04-20 01:25:04 +02:00
|
|
|
|
2022-04-10 16:47:44 +02:00
|
|
|
_btnErrorBar = findViewById(R.id.btn_error_bar);
|
|
|
|
_textErrorBar = findViewById(R.id.text_error_bar);
|
2020-06-13 12:45:02 +02:00
|
|
|
|
2021-01-02 13:41:58 +01:00
|
|
|
_fabScrollHelper = new FabScrollHelper(fab);
|
2020-01-04 20:38:40 +01:00
|
|
|
_selectedEntries = new ArrayList<>();
|
2016-08-15 21:29:41 +02:00
|
|
|
}
|
2016-08-16 00:08:01 +02:00
|
|
|
|
2019-06-22 12:12:26 +02:00
|
|
|
@Override
|
|
|
|
protected void onDestroy() {
|
|
|
|
_entryListView.setListener(null);
|
|
|
|
super.onDestroy();
|
|
|
|
}
|
|
|
|
|
2021-06-02 18:02:38 +02:00
|
|
|
@Override
|
|
|
|
protected void onPause() {
|
|
|
|
Map<UUID, Integer> usageMap = _entryListView.getUsageCounts();
|
|
|
|
if (usageMap != null) {
|
2022-02-06 19:00:01 +01:00
|
|
|
_prefs.setUsageCount(usageMap);
|
2021-06-02 18:02:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
super.onPause();
|
|
|
|
}
|
|
|
|
|
2022-05-07 16:15:30 +02:00
|
|
|
@Override
|
2022-10-09 14:35:51 +02:00
|
|
|
protected void onSaveInstanceState(@NonNull Bundle instance) {
|
2022-05-07 16:15:30 +02:00
|
|
|
super.onSaveInstanceState(instance);
|
2022-10-10 22:32:30 +02:00
|
|
|
instance.putString("pendingSearchQuery", _pendingSearchQuery);
|
|
|
|
instance.putString("submittedSearchQuery", _submittedSearchQuery);
|
2022-10-09 14:35:51 +02:00
|
|
|
instance.putBoolean("isDoingIntro", _isDoingIntro);
|
|
|
|
instance.putBoolean("isAuthenticating", _isAuthenticating);
|
2022-05-07 16:15:30 +02:00
|
|
|
}
|
|
|
|
|
2017-12-24 21:42:08 +01:00
|
|
|
@Override
|
2016-08-16 00:08:01 +02:00
|
|
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
2022-10-09 14:35:51 +02:00
|
|
|
if (requestCode == CODE_DECRYPT) {
|
|
|
|
_isAuthenticating = false;
|
|
|
|
}
|
|
|
|
if (requestCode == CODE_DO_INTRO) {
|
|
|
|
_isDoingIntro = false;
|
|
|
|
}
|
2020-05-02 18:51:12 +02:00
|
|
|
if (resultCode != RESULT_OK) {
|
2019-05-12 17:12:09 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-08-06 16:03:36 +02:00
|
|
|
switch (requestCode) {
|
2018-06-06 16:15:31 +02:00
|
|
|
case CODE_SCAN:
|
2020-05-02 18:51:12 +02:00
|
|
|
onScanResult(data);
|
2017-08-06 16:03:36 +02:00
|
|
|
break;
|
2018-06-06 16:15:31 +02:00
|
|
|
case CODE_ADD_ENTRY:
|
2020-05-02 18:51:12 +02:00
|
|
|
onAddEntryResult(data);
|
2017-08-06 16:03:36 +02:00
|
|
|
break;
|
2018-06-06 16:15:31 +02:00
|
|
|
case CODE_EDIT_ENTRY:
|
2020-05-02 18:51:12 +02:00
|
|
|
onEditEntryResult(data);
|
2017-12-27 22:04:22 +01:00
|
|
|
break;
|
2017-08-06 16:03:36 +02:00
|
|
|
case CODE_DO_INTRO:
|
2022-02-06 19:00:01 +01:00
|
|
|
onIntroResult();
|
2017-08-06 16:03:36 +02:00
|
|
|
break;
|
2017-08-06 18:15:47 +02:00
|
|
|
case CODE_DECRYPT:
|
2020-05-02 18:51:12 +02:00
|
|
|
onDecryptResult();
|
2017-08-06 18:15:47 +02:00
|
|
|
break;
|
2017-12-10 19:19:48 +01:00
|
|
|
case CODE_PREFERENCES:
|
2020-05-02 18:51:12 +02:00
|
|
|
onPreferencesResult(data);
|
2017-12-10 19:19:48 +01:00
|
|
|
break;
|
2019-04-19 23:10:18 +02:00
|
|
|
case CODE_SCAN_IMAGE:
|
2020-05-02 18:51:12 +02:00
|
|
|
onScanImageResult(data);
|
2023-08-31 21:56:05 +02:00
|
|
|
break;
|
|
|
|
case CODE_ASSIGN_ICONS:
|
|
|
|
onAssignEntriesResult(data);
|
|
|
|
break;
|
2017-12-10 19:19:48 +01:00
|
|
|
}
|
2019-09-14 15:20:02 +02:00
|
|
|
|
|
|
|
super.onActivityResult(requestCode, resultCode, data);
|
2017-12-10 19:19:48 +01:00
|
|
|
}
|
|
|
|
|
2017-12-13 19:00:58 +01:00
|
|
|
@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();
|
2017-12-13 19:00:58 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-10-12 17:39:40 +02:00
|
|
|
if (requestCode == CODE_PERM_CAMERA) {
|
|
|
|
startScanActivity();
|
2017-12-13 19:00:58 +01:00
|
|
|
}
|
2021-07-22 22:25:40 +02:00
|
|
|
|
|
|
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
2017-12-13 19:00:58 +01:00
|
|
|
}
|
|
|
|
|
2022-04-10 16:36:30 +02:00
|
|
|
@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;
|
|
|
|
}
|
|
|
|
|
2020-05-02 18:51:12 +02:00
|
|
|
private void onPreferencesResult(Intent data) {
|
2018-06-06 16:15:31 +02:00
|
|
|
// refresh the entire entry list if needed
|
2020-05-24 20:24:04 +02:00
|
|
|
if (_loaded) {
|
|
|
|
if (data.getBooleanExtra("needsRecreate", false)) {
|
|
|
|
recreate();
|
|
|
|
} else if (data.getBooleanExtra("needsRefresh", false)) {
|
2023-08-16 14:17:57 +02:00
|
|
|
AccountNamePosition accountNamePosition = _prefs.getAccountNamePosition();
|
2022-11-01 19:22:23 +00:00
|
|
|
boolean showIcons = _prefs.isIconVisible();
|
2023-08-21 00:24:10 +02:00
|
|
|
boolean onlyShowNecessaryAccountNames = _prefs.onlyShowNecessaryAccountNames();
|
2022-08-31 05:47:10 +01:00
|
|
|
Preferences.CodeGrouping codeGroupSize = _prefs.getCodeGroupSize();
|
2022-02-06 19:00:01 +01:00
|
|
|
boolean highlightEntry = _prefs.isEntryHighlightEnabled();
|
|
|
|
boolean pauseFocused = _prefs.isPauseFocusedEnabled();
|
|
|
|
boolean tapToReveal = _prefs.isTapToRevealEnabled();
|
|
|
|
int tapToRevealTime = _prefs.getTapToRevealTime();
|
|
|
|
ViewMode viewMode = _prefs.getCurrentViewMode();
|
2023-08-16 01:05:26 +02:00
|
|
|
CopyBehavior copyBehavior = _prefs.getCopyBehavior();
|
2023-08-16 14:17:57 +02:00
|
|
|
_entryListView.setAccountNamePosition(accountNamePosition);
|
2023-08-21 00:24:10 +02:00
|
|
|
_entryListView.setOnlyShowNecessaryAccountNames(onlyShowNecessaryAccountNames);
|
2022-11-01 19:22:23 +00:00
|
|
|
_entryListView.setShowIcon(showIcons);
|
2020-05-24 20:24:04 +02:00
|
|
|
_entryListView.setCodeGroupSize(codeGroupSize);
|
|
|
|
_entryListView.setHighlightEntry(highlightEntry);
|
2021-07-28 11:45:32 +02:00
|
|
|
_entryListView.setPauseFocused(pauseFocused);
|
2020-05-24 20:24:04 +02:00
|
|
|
_entryListView.setTapToReveal(tapToReveal);
|
|
|
|
_entryListView.setTapToRevealTime(tapToRevealTime);
|
|
|
|
_entryListView.setViewMode(viewMode);
|
2023-08-16 01:05:26 +02:00
|
|
|
_entryListView.setCopyBehavior(copyBehavior);
|
2020-05-24 20:24:04 +02:00
|
|
|
_entryListView.refresh(true);
|
|
|
|
}
|
2017-12-10 19:19:48 +01:00
|
|
|
}
|
2017-08-06 16:03:36 +02:00
|
|
|
}
|
2016-08-16 00:08:01 +02:00
|
|
|
|
2021-01-27 20:06:34 +01:00
|
|
|
private void startEditEntryActivityForNew(int requestCode, VaultEntry entry) {
|
2018-06-06 16:15:31 +02:00
|
|
|
Intent intent = new Intent(this, EditEntryActivity.class);
|
2021-01-27 20:06:34 +01:00
|
|
|
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());
|
2018-01-02 21:50:07 +01:00
|
|
|
startActivityForResult(intent, requestCode);
|
|
|
|
}
|
|
|
|
|
2023-08-31 21:56:05 +02:00
|
|
|
private void startAssignIconsActivity(int requestCode, List<VaultEntry> entries) {
|
|
|
|
ArrayList<UUID> assignIconEntriesIds = new ArrayList<>();
|
|
|
|
Intent assignIconIntent = new Intent(getBaseContext(), AssignIconsActivity.class);
|
|
|
|
for (VaultEntry entry : entries) {
|
|
|
|
assignIconEntriesIds.add(entry.getUUID());
|
|
|
|
}
|
|
|
|
|
|
|
|
assignIconIntent.putExtra("entries", assignIconEntriesIds);
|
|
|
|
startActivityForResult(assignIconIntent, requestCode);
|
|
|
|
}
|
|
|
|
|
2022-10-09 14:35:51 +02:00
|
|
|
private void startIntroActivity() {
|
|
|
|
if (!_isDoingIntro) {
|
|
|
|
Intent intro = new Intent(this, IntroActivity.class);
|
|
|
|
startActivityForResult(intro, CODE_DO_INTRO);
|
|
|
|
_isDoingIntro = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-02 18:51:12 +02:00
|
|
|
private void onScanResult(Intent data) {
|
2020-05-09 15:32:57 +02:00
|
|
|
List<VaultEntry> entries = (ArrayList<VaultEntry>) data.getSerializableExtra("entries");
|
2022-08-07 20:18:21 +02:00
|
|
|
if (entries != null) {
|
|
|
|
importScannedEntries(entries);
|
2020-05-09 15:32:57 +02:00
|
|
|
}
|
2017-08-06 16:03:36 +02:00
|
|
|
}
|
|
|
|
|
2020-05-02 18:51:12 +02:00
|
|
|
private void onAddEntryResult(Intent data) {
|
2020-05-24 20:24:04 +02:00
|
|
|
if (_loaded) {
|
|
|
|
UUID entryUUID = (UUID) data.getSerializableExtra("entryUUID");
|
2022-02-06 19:00:01 +01:00
|
|
|
VaultEntry entry = _vaultManager.getVault().getEntryByUUID(entryUUID);
|
2020-10-28 15:00:56 +01:00
|
|
|
_entryListView.addEntry(entry, true);
|
2020-05-24 20:24:04 +02:00
|
|
|
}
|
2017-08-26 15:47:57 +02:00
|
|
|
}
|
|
|
|
|
2020-05-02 18:51:12 +02:00
|
|
|
private void onEditEntryResult(Intent data) {
|
2020-05-24 20:24:04 +02:00
|
|
|
if (_loaded) {
|
|
|
|
UUID entryUUID = (UUID) data.getSerializableExtra("entryUUID");
|
2020-05-02 18:51:33 +02:00
|
|
|
|
2020-05-24 20:24:04 +02:00
|
|
|
if (data.getBooleanExtra("delete", false)) {
|
|
|
|
_entryListView.removeEntry(entryUUID);
|
|
|
|
} else {
|
2022-02-06 19:00:01 +01:00
|
|
|
VaultEntry entry = _vaultManager.getVault().getEntryByUUID(entryUUID);
|
2020-05-24 20:24:04 +02:00
|
|
|
_entryListView.replaceEntry(entryUUID, entry);
|
|
|
|
}
|
2017-12-27 22:04:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-31 21:56:05 +02:00
|
|
|
private void onAssignEntriesResult(Intent data) {
|
|
|
|
if (_loaded) {
|
|
|
|
ArrayList<UUID> entryUUIDs = (ArrayList<UUID>) data.getSerializableExtra("entryUUIDs");
|
|
|
|
|
|
|
|
for (UUID entryUUID: entryUUIDs) {
|
|
|
|
VaultEntry entry = _vaultManager.getVault().getEntryByUUID(entryUUID);
|
|
|
|
_entryListView.replaceEntry(entryUUID, entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-02 18:51:12 +02:00
|
|
|
private void onScanImageResult(Intent intent) {
|
2022-08-07 20:18:21 +02:00
|
|
|
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;
|
2021-02-14 15:56:12 +01:00
|
|
|
}
|
|
|
|
|
2022-08-07 20:18:21 +02:00
|
|
|
private void startDecodeQrCodeImages(List<Uri> uris) {
|
|
|
|
QrDecodeTask task = new QrDecodeTask(this, (results) -> {
|
|
|
|
List<CharSequence> errors = new ArrayList<>();
|
|
|
|
List<VaultEntry> entries = new ArrayList<>();
|
2022-08-11 15:23:11 +01:00
|
|
|
List<GoogleAuthInfo.Export> googleAuthExports = new ArrayList<>();
|
|
|
|
|
2022-08-07 20:18:21 +02:00
|
|
|
for (QrDecodeTask.Result res : results) {
|
|
|
|
if (res.getException() != null) {
|
|
|
|
errors.add(buildImportError(res.getFileName(), res.getException()));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2022-08-11 15:23:11 +01:00
|
|
|
Uri scanned = Uri.parse(res.getResult().getText());
|
|
|
|
if (Objects.equals(scanned.getScheme(), GoogleAuthInfo.SCHEME_EXPORT)) {
|
|
|
|
GoogleAuthInfo.Export export = GoogleAuthInfo.parseExportUri(scanned);
|
|
|
|
for (GoogleAuthInfo info: export.getEntries()) {
|
|
|
|
VaultEntry entry = new VaultEntry(info);
|
|
|
|
entries.add(entry);
|
|
|
|
}
|
|
|
|
googleAuthExports.add(export);
|
|
|
|
} else {
|
|
|
|
GoogleAuthInfo info = GoogleAuthInfo.parseUri(res.getResult().getText());
|
|
|
|
VaultEntry entry = new VaultEntry(info);
|
|
|
|
entries.add(entry);
|
|
|
|
}
|
2022-08-22 19:14:51 +02:00
|
|
|
} catch (GoogleAuthInfoException e) {
|
2022-08-07 20:18:21 +02:00
|
|
|
errors.add(buildImportError(res.getFileName(), e));
|
|
|
|
}
|
2020-05-02 18:51:12 +02:00
|
|
|
}
|
2019-04-19 23:10:18 +02:00
|
|
|
|
2022-08-07 20:18:21 +02:00
|
|
|
final DialogInterface.OnClickListener dialogDismissHandler = (dialog, which) -> importScannedEntries(entries);
|
2022-08-11 15:23:11 +01:00
|
|
|
if (!googleAuthExports.isEmpty()) {
|
2022-08-22 19:14:51 +02:00
|
|
|
boolean isSingleBatch = GoogleAuthInfo.Export.isSingleBatch(googleAuthExports);
|
|
|
|
if (!isSingleBatch && errors.size() > 0) {
|
|
|
|
errors.add(getString(R.string.unrelated_google_auth_batches_error));
|
|
|
|
Dialogs.showMultiMessageDialog(this, R.string.import_error_title, getString(R.string.no_tokens_can_be_imported), errors, null);
|
|
|
|
return;
|
|
|
|
} else if (!isSingleBatch) {
|
|
|
|
Dialogs.showErrorDialog(this, R.string.import_google_auth_failure, getString(R.string.unrelated_google_auth_batches_error));
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
List<Integer> missingIndices = GoogleAuthInfo.Export.getMissingIndices(googleAuthExports);
|
|
|
|
if (missingIndices.size() != 0) {
|
|
|
|
Dialogs.showPartialGoogleAuthImportWarningDialog(this, missingIndices, entries.size(), errors, dialogDismissHandler);
|
2022-08-11 15:23:11 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-07 20:18:21 +02:00
|
|
|
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);
|
2022-08-07 17:05:08 +02:00
|
|
|
}
|
|
|
|
});
|
2022-08-07 20:18:21 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2019-05-15 21:29:45 +02:00
|
|
|
private void updateSortCategoryMenu() {
|
2022-02-06 19:00:01 +01:00
|
|
|
SortCategory category = _prefs.getCurrentSortCategory();
|
2019-05-15 21:29:45 +02:00
|
|
|
_menu.findItem(category.getMenuItem()).setChecked(true);
|
|
|
|
}
|
|
|
|
|
2022-02-06 19:00:01 +01:00
|
|
|
private void onIntroResult() {
|
2020-05-02 18:51:12 +02:00
|
|
|
loadEntries();
|
2020-05-03 16:57:51 +02:00
|
|
|
checkTimeSyncSetting();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void checkTimeSyncSetting() {
|
|
|
|
boolean autoTime = Settings.Global.getInt(getContentResolver(), Settings.Global.AUTO_TIME, 1) == 1;
|
2022-02-06 19:00:01 +01:00
|
|
|
if (!autoTime && _prefs.isTimeSyncWarningEnabled()) {
|
2020-05-03 16:57:51 +02:00
|
|
|
Dialogs.showTimeSyncWarningDialog(this, (dialog, which) -> {
|
|
|
|
Intent intent = new Intent(Settings.ACTION_DATE_SETTINGS);
|
|
|
|
startActivity(intent);
|
|
|
|
});
|
|
|
|
}
|
2017-08-06 18:15:47 +02:00
|
|
|
}
|
|
|
|
|
2020-05-02 18:51:12 +02:00
|
|
|
private void onDecryptResult() {
|
|
|
|
loadEntries();
|
2020-05-03 16:57:51 +02:00
|
|
|
checkTimeSyncSetting();
|
2017-12-03 16:47:27 +01:00
|
|
|
}
|
|
|
|
|
2017-12-25 19:02:46 +01:00
|
|
|
private void startScanActivity() {
|
2018-06-09 19:23:30 +02:00
|
|
|
if (!PermissionHelper.request(this, CODE_PERM_CAMERA, Manifest.permission.CAMERA)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-12-25 19:02:46 +01:00
|
|
|
Intent scannerActivity = new Intent(getApplicationContext(), ScannerActivity.class);
|
2018-06-06 16:15:31 +02:00
|
|
|
startActivityForResult(scannerActivity, CODE_SCAN);
|
2017-12-25 19:02:46 +01:00
|
|
|
}
|
|
|
|
|
2019-07-03 18:57:03 +02:00
|
|
|
private void startScanImageActivity() {
|
|
|
|
Intent galleryIntent = new Intent(Intent.ACTION_PICK);
|
2022-08-07 20:18:21 +02:00
|
|
|
galleryIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
2019-07-03 18:57:03 +02:00
|
|
|
galleryIntent.setDataAndType(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, "image/*");
|
|
|
|
|
2020-10-25 14:47:59 +01:00
|
|
|
Intent fileIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
2022-08-07 20:18:21 +02:00
|
|
|
fileIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
2020-10-25 14:47:59 +01:00
|
|
|
fileIntent.setType("image/*");
|
|
|
|
|
2019-07-03 18:57:03 +02:00
|
|
|
Intent chooserIntent = Intent.createChooser(galleryIntent, getString(R.string.select_picture));
|
2020-10-25 14:47:59 +01:00
|
|
|
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { fileIntent });
|
2022-02-06 19:00:01 +01:00
|
|
|
_vaultManager.startActivityForResult(this, chooserIntent, CODE_SCAN_IMAGE);
|
2019-07-03 18:57:03 +02:00
|
|
|
}
|
|
|
|
|
2021-01-13 21:03:14 +01:00
|
|
|
private void startPreferencesActivity() {
|
|
|
|
startPreferencesActivity(null, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void startPreferencesActivity(Class<? extends PreferencesFragment> fragmentType, String preference) {
|
2020-06-13 12:45:02 +02:00
|
|
|
Intent intent = new Intent(this, PreferencesActivity.class);
|
2021-01-13 21:03:14 +01:00
|
|
|
intent.putExtra("fragment", fragmentType);
|
2020-06-13 12:45:02 +02:00
|
|
|
intent.putExtra("pref", preference);
|
|
|
|
startActivityForResult(intent, CODE_PREFERENCES);
|
|
|
|
}
|
|
|
|
|
2019-04-08 23:13:11 +02:00
|
|
|
private void doShortcutActions() {
|
2017-12-03 16:47:27 +01:00
|
|
|
Intent intent = getIntent();
|
2017-12-25 19:02:46 +01:00
|
|
|
String action = intent.getStringExtra("action");
|
2022-02-06 19:00:01 +01:00
|
|
|
if (action == null || !_vaultManager.isVaultLoaded()) {
|
2019-04-08 23:13:11 +02:00
|
|
|
return;
|
2017-12-03 16:47:27 +01:00
|
|
|
}
|
|
|
|
|
2017-12-25 19:02:46 +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");
|
2016-08-16 00:08:01 +02:00
|
|
|
}
|
2016-08-16 14:14:17 +02:00
|
|
|
|
2022-08-10 17:47:17 +02:00
|
|
|
private void handleIncomingIntent() {
|
2022-02-06 19:00:01 +01:00
|
|
|
if (!_vaultManager.isVaultLoaded()) {
|
2019-08-02 22:36:12 +02:00
|
|
|
return;
|
|
|
|
}
|
2019-09-10 23:10:11 +02:00
|
|
|
|
2019-08-02 22:36:12 +02:00
|
|
|
Intent intent = getIntent();
|
2022-08-10 17:47:17 +02:00
|
|
|
if (intent.getAction() == null) {
|
2021-02-14 15:56:12 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-08-10 17:47:17 +02:00
|
|
|
Uri uri;
|
|
|
|
switch (intent.getAction()) {
|
|
|
|
case Intent.ACTION_VIEW:
|
|
|
|
uri = intent.getData();
|
|
|
|
if (uri != null) {
|
|
|
|
intent.setData(null);
|
|
|
|
intent.setAction(null);
|
|
|
|
|
|
|
|
GoogleAuthInfo info;
|
|
|
|
try {
|
|
|
|
info = GoogleAuthInfo.parseUri(uri);
|
|
|
|
} catch (GoogleAuthInfoException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
Dialogs.showErrorDialog(this, R.string.unable_to_process_deeplink, e);
|
|
|
|
break;
|
|
|
|
}
|
2021-02-14 15:56:12 +01:00
|
|
|
|
2022-08-10 17:47:17 +02:00
|
|
|
VaultEntry entry = new VaultEntry(info);
|
|
|
|
startEditEntryActivityForNew(CODE_ADD_ENTRY, entry);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Intent.ACTION_SEND:
|
2022-08-11 21:32:33 +01:00
|
|
|
if (intent.hasExtra(Intent.EXTRA_STREAM)) {
|
|
|
|
uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
|
2022-08-10 17:47:17 +02:00
|
|
|
intent.setAction(null);
|
|
|
|
intent.removeExtra(Intent.EXTRA_STREAM);
|
2022-12-03 19:31:25 +01:00
|
|
|
|
|
|
|
if (uri != null) {
|
|
|
|
startDecodeQrCodeImages(Collections.singletonList(uri));
|
|
|
|
}
|
2022-08-10 17:47:17 +02:00
|
|
|
}
|
2022-08-11 21:32:33 +01:00
|
|
|
if (intent.hasExtra(Intent.EXTRA_TEXT)) {
|
|
|
|
String stringExtra = intent.getStringExtra(Intent.EXTRA_TEXT);
|
|
|
|
intent.setAction(null);
|
|
|
|
intent.removeExtra(Intent.EXTRA_TEXT);
|
|
|
|
|
2022-12-03 19:31:25 +01:00
|
|
|
if (stringExtra != null) {
|
|
|
|
GoogleAuthInfo info;
|
|
|
|
try {
|
|
|
|
info = GoogleAuthInfo.parseUri(stringExtra);
|
|
|
|
} catch (GoogleAuthInfoException e) {
|
|
|
|
Dialogs.showErrorDialog(this, R.string.unable_to_process_shared_text, e);
|
|
|
|
break;
|
|
|
|
}
|
2022-08-11 21:32:33 +01:00
|
|
|
|
2022-12-03 19:31:25 +01:00
|
|
|
VaultEntry entry = new VaultEntry(info);
|
|
|
|
startEditEntryActivityForNew(CODE_ADD_ENTRY, entry);
|
|
|
|
}
|
2022-08-11 21:32:33 +01:00
|
|
|
}
|
2022-08-10 17:47:17 +02:00
|
|
|
break;
|
|
|
|
case Intent.ACTION_SEND_MULTIPLE:
|
2022-12-03 19:31:25 +01:00
|
|
|
if (intent.hasExtra(Intent.EXTRA_STREAM)) {
|
|
|
|
List<Uri> uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
|
2022-08-10 17:47:17 +02:00
|
|
|
intent.setAction(null);
|
|
|
|
intent.removeExtra(Intent.EXTRA_STREAM);
|
2022-12-03 19:31:25 +01:00
|
|
|
|
|
|
|
if (uris != null) {
|
|
|
|
uris = uris.stream()
|
|
|
|
.filter(Objects::nonNull)
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
|
|
|
startDecodeQrCodeImages(uris);
|
|
|
|
}
|
2022-08-10 17:47:17 +02:00
|
|
|
}
|
|
|
|
break;
|
2021-02-14 15:56:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-30 01:08:03 +02:00
|
|
|
@Override
|
|
|
|
protected void onResume() {
|
|
|
|
super.onResume();
|
2017-12-24 21:42:08 +01:00
|
|
|
|
2022-02-06 19:00:01 +01:00
|
|
|
if (_vaultManager.isVaultInitNeeded()) {
|
|
|
|
if (_prefs.isIntroDone()) {
|
|
|
|
Toast.makeText(this, getString(R.string.vault_not_found), Toast.LENGTH_SHORT).show();
|
2018-06-09 20:23:39 +02:00
|
|
|
}
|
2022-10-09 14:35:51 +02:00
|
|
|
startIntroActivity();
|
2022-02-06 19:00:01 +01:00
|
|
|
return;
|
|
|
|
}
|
2020-05-02 18:51:12 +02:00
|
|
|
|
2022-02-06 19:00:01 +01:00
|
|
|
if (!_vaultManager.isVaultLoaded() && !_vaultManager.isVaultFileLoaded()) {
|
|
|
|
Dialogs.showErrorDialog(this, R.string.vault_load_error, _vaultManager.getVaultFileError(), (dialog1, which) -> finish());
|
|
|
|
return;
|
2020-05-02 18:51:12 +02:00
|
|
|
}
|
|
|
|
|
2022-02-06 19:00:01 +01:00
|
|
|
if (!_vaultManager.isVaultLoaded()) {
|
2020-07-05 19:49:51 +02:00
|
|
|
startAuthActivity(false);
|
2018-06-09 20:23:39 +02:00
|
|
|
} else if (_loaded) {
|
2021-01-27 18:24:52 +01:00
|
|
|
// update the list of groups in the entry list view so that the chip gets updated
|
2023-04-30 15:31:38 +01:00
|
|
|
_entryListView.setGroups(_vaultManager.getVault().getUsedGroups());
|
2018-12-11 11:44:36 +01:00
|
|
|
|
2022-02-06 19:00:01 +01:00
|
|
|
// update the usage counts in case they are edited outside of the EntryListView
|
|
|
|
_entryListView.setUsageCounts(_prefs.getUsageCounts());
|
2021-06-02 18:02:38 +02:00
|
|
|
|
2018-06-09 20:23:39 +02:00
|
|
|
// refresh all codes to prevent showing old ones
|
2019-05-15 21:29:45 +02:00
|
|
|
_entryListView.refresh(false);
|
2018-06-09 20:23:39 +02:00
|
|
|
} else {
|
|
|
|
loadEntries();
|
2020-05-03 16:57:51 +02:00
|
|
|
checkTimeSyncSetting();
|
2018-06-09 20:23:39 +02:00
|
|
|
}
|
|
|
|
|
2022-10-10 22:32:30 +02:00
|
|
|
_lockBackPressHandler.setEnabled(
|
|
|
|
_vaultManager.isAutoLockEnabled(Preferences.AUTO_LOCK_ON_BACK_BUTTON)
|
|
|
|
);
|
|
|
|
|
2022-08-10 17:47:17 +02:00
|
|
|
handleIncomingIntent();
|
2018-06-09 20:23:39 +02:00
|
|
|
updateLockIcon();
|
2019-04-08 23:13:11 +02:00
|
|
|
doShortcutActions();
|
2022-04-10 16:47:44 +02:00
|
|
|
updateErrorBar();
|
2016-09-30 01:08:03 +02:00
|
|
|
}
|
|
|
|
|
2020-01-04 20:38:40 +01:00
|
|
|
private void deleteEntries(List<VaultEntry> entries) {
|
|
|
|
for (VaultEntry entry: entries) {
|
2022-02-06 19:00:01 +01:00
|
|
|
VaultEntry oldEntry = _vaultManager.getVault().removeEntry(entry);
|
2020-01-04 20:38:40 +01:00
|
|
|
_entryListView.removeEntry(oldEntry);
|
|
|
|
}
|
|
|
|
|
2022-02-06 19:00:01 +01:00
|
|
|
saveAndBackupVault();
|
2020-01-04 20:38:40 +01:00
|
|
|
}
|
|
|
|
|
2016-08-16 14:14:17 +02:00
|
|
|
@Override
|
|
|
|
public boolean onCreateOptionsMenu(Menu menu) {
|
2017-08-26 21:15:53 +02:00
|
|
|
_menu = menu;
|
2016-08-16 14:14:17 +02:00
|
|
|
getMenuInflater().inflate(R.menu.menu_main, menu);
|
2022-10-26 14:07:49 +02:00
|
|
|
|
2017-08-26 21:15:53 +02:00
|
|
|
updateLockIcon();
|
2018-12-12 16:20:35 +01:00
|
|
|
if (_loaded) {
|
2023-04-30 15:31:38 +01:00
|
|
|
_entryListView.setGroups(_vaultManager.getVault().getUsedGroups());
|
2019-05-15 21:29:45 +02:00
|
|
|
updateSortCategoryMenu();
|
2018-12-12 16:20:35 +01:00
|
|
|
}
|
2019-05-30 02:07:30 +02:00
|
|
|
|
|
|
|
MenuItem searchViewMenuItem = menu.findItem(R.id.mi_search);
|
|
|
|
|
|
|
|
_searchView = (SearchView) searchViewMenuItem.getActionView();
|
2022-08-01 16:00:40 +08:00
|
|
|
_searchView.setMaxWidth(Integer.MAX_VALUE);
|
2022-10-10 22:32:30 +02:00
|
|
|
_searchView.setOnQueryTextFocusChangeListener((v, hasFocus) -> {
|
|
|
|
boolean enabled = _submittedSearchQuery != null || hasFocus;
|
|
|
|
_searchViewBackPressHandler.setEnabled(enabled);
|
|
|
|
});
|
|
|
|
_searchView.setOnCloseListener(() -> {
|
|
|
|
boolean enabled = _submittedSearchQuery != null;
|
|
|
|
_searchViewBackPressHandler.setEnabled(enabled);
|
|
|
|
return false;
|
|
|
|
});
|
2021-11-04 15:41:17 +05:30
|
|
|
|
2019-09-10 23:10:11 +02:00
|
|
|
_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);
|
2022-10-10 22:32:30 +02:00
|
|
|
_entryListView.setSearchFilter(s);
|
|
|
|
_pendingSearchQuery = null;
|
|
|
|
_submittedSearchQuery = s;
|
2019-09-10 23:10:11 +02:00
|
|
|
collapseSearchView();
|
2022-10-10 22:32:30 +02:00
|
|
|
_searchViewBackPressHandler.setEnabled(true);
|
2019-09-10 23:10:11 +02:00
|
|
|
return false;
|
|
|
|
}
|
2019-05-30 02:07:30 +02:00
|
|
|
|
2019-09-10 23:10:11 +02:00
|
|
|
@Override
|
|
|
|
public boolean onQueryTextChange(String s) {
|
2022-10-10 22:32:30 +02:00
|
|
|
if (_submittedSearchQuery == null) {
|
2019-09-10 23:10:11 +02:00
|
|
|
_entryListView.setSearchFilter(s);
|
2019-05-30 02:07:30 +02:00
|
|
|
}
|
2022-10-10 22:32:30 +02:00
|
|
|
|
|
|
|
_pendingSearchQuery = Strings.isNullOrEmpty(s) && !_searchView.isIconified() ? null : s;
|
|
|
|
if (_pendingSearchQuery != null) {
|
|
|
|
_entryListView.setSearchFilter(_pendingSearchQuery);
|
|
|
|
}
|
|
|
|
|
2019-09-10 23:10:11 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
_searchView.setOnSearchClickListener(v -> {
|
2022-10-10 22:32:30 +02:00
|
|
|
String query = _submittedSearchQuery != null ? _submittedSearchQuery : _pendingSearchQuery;
|
|
|
|
_searchView.setQuery(query, false);
|
2019-09-10 23:10:11 +02:00
|
|
|
});
|
2022-05-22 12:02:23 +02:00
|
|
|
|
2022-10-10 22:32:30 +02:00
|
|
|
if (_pendingSearchQuery != null) {
|
|
|
|
_searchView.setIconified(false);
|
|
|
|
_searchView.setQuery(_pendingSearchQuery, false);
|
|
|
|
_searchViewBackPressHandler.setEnabled(true);
|
|
|
|
} else if (_submittedSearchQuery != null) {
|
|
|
|
setTitle(getString(R.string.search));
|
|
|
|
getSupportActionBar().setSubtitle(_submittedSearchQuery);
|
|
|
|
_entryListView.setSearchFilter(_submittedSearchQuery);
|
|
|
|
_searchViewBackPressHandler.setEnabled(true);
|
|
|
|
} else if (_prefs.getFocusSearchEnabled() && !_isRecreated) {
|
2022-05-07 16:15:30 +02:00
|
|
|
_searchView.setIconified(false);
|
2022-10-10 22:32:30 +02:00
|
|
|
_searchView.setFocusable(true);
|
|
|
|
_searchView.requestFocus();
|
|
|
|
_searchView.requestFocusFromTouch();
|
2022-05-07 16:15:30 +02:00
|
|
|
}
|
2022-05-22 12:02:23 +02:00
|
|
|
|
2016-08-16 14:14:17 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onOptionsItemSelected(MenuItem item) {
|
2023-09-19 23:24:19 +02:00
|
|
|
int itemId = item.getItemId();
|
|
|
|
if (itemId == R.id.action_settings) {
|
|
|
|
startPreferencesActivity();
|
|
|
|
} else if (itemId == R.id.action_about) {
|
|
|
|
Intent intent = new Intent(this, AboutActivity.class);
|
|
|
|
startActivity(intent);
|
|
|
|
} else if (itemId == R.id.action_lock) {
|
|
|
|
_vaultManager.lock(true);
|
|
|
|
} else {
|
|
|
|
if (item.getGroupId() == R.id.action_sort_category) {
|
|
|
|
item.setChecked(true);
|
|
|
|
|
|
|
|
SortCategory sortCategory;
|
|
|
|
int subItemId = item.getItemId();
|
|
|
|
if (subItemId == R.id.menu_sort_alphabetically) {
|
|
|
|
sortCategory = SortCategory.ISSUER;
|
|
|
|
} else if (subItemId == R.id.menu_sort_alphabetically_reverse) {
|
|
|
|
sortCategory = SortCategory.ISSUER_REVERSED;
|
|
|
|
} else if (subItemId == R.id.menu_sort_alphabetically_name) {
|
|
|
|
sortCategory = SortCategory.ACCOUNT;
|
|
|
|
} else if (subItemId == R.id.menu_sort_alphabetically_name_reverse) {
|
|
|
|
sortCategory = SortCategory.ACCOUNT_REVERSED;
|
|
|
|
} else if (subItemId == R.id.menu_sort_usage_count) {
|
|
|
|
sortCategory = SortCategory.USAGE_COUNT;
|
|
|
|
} else {
|
|
|
|
sortCategory = SortCategory.CUSTOM;
|
|
|
|
}
|
|
|
|
|
|
|
|
_entryListView.setSortCategory(sortCategory, true);
|
|
|
|
_prefs.setCurrentSortCategory(sortCategory);
|
2019-09-05 00:24:33 +02:00
|
|
|
}
|
2019-03-31 19:57:45 +02:00
|
|
|
|
2023-09-19 23:24:19 +02:00
|
|
|
return super.onOptionsItemSelected(item);
|
2016-08-16 14:14:17 +02:00
|
|
|
}
|
2023-09-19 23:24:19 +02:00
|
|
|
|
|
|
|
return true;
|
2016-08-16 14:14:17 +02:00
|
|
|
}
|
2016-09-30 01:08:03 +02:00
|
|
|
|
2019-05-30 02:07:30 +02:00
|
|
|
private void collapseSearchView() {
|
|
|
|
_searchView.setQuery(null, false);
|
|
|
|
_searchView.setIconified(true);
|
|
|
|
}
|
|
|
|
|
2018-06-09 20:23:39 +02:00
|
|
|
private void loadEntries() {
|
2020-05-24 20:24:04 +02:00
|
|
|
if (!_loaded) {
|
2022-02-06 19:00:01 +01:00
|
|
|
_entryListView.setUsageCounts(_prefs.getUsageCounts());
|
|
|
|
_entryListView.addEntries(_vaultManager.getVault().getEntries());
|
2020-05-24 20:24:04 +02:00
|
|
|
_entryListView.runEntriesAnimation();
|
|
|
|
_loaded = true;
|
|
|
|
}
|
2018-06-09 20:23:39 +02:00
|
|
|
}
|
|
|
|
|
2020-06-23 18:35:46 +02:00
|
|
|
private void startAuthActivity(boolean inhibitBioPrompt) {
|
2022-10-09 14:35:51 +02:00
|
|
|
if (!_isAuthenticating) {
|
|
|
|
Intent intent = new Intent(this, AuthActivity.class);
|
|
|
|
intent.putExtra("inhibitBioPrompt", inhibitBioPrompt);
|
|
|
|
startActivityForResult(intent, CODE_DECRYPT);
|
|
|
|
_isAuthenticating = true;
|
|
|
|
}
|
2017-12-24 21:42:08 +01:00
|
|
|
}
|
|
|
|
|
2017-08-26 21:15:53 +02:00
|
|
|
private void updateLockIcon() {
|
2019-12-25 19:21:34 +01:00
|
|
|
// hide the lock icon if the vault is not unlocked
|
2022-02-06 19:00:01 +01:00
|
|
|
if (_menu != null && _vaultManager.isVaultLoaded()) {
|
2017-08-26 21:15:53 +02:00
|
|
|
MenuItem item = _menu.findItem(R.id.action_lock);
|
2022-02-06 19:00:01 +01:00
|
|
|
item.setVisible(_vaultManager.getVault().isEncryptionEnabled());
|
2017-08-26 21:15:53 +02:00
|
|
|
}
|
|
|
|
}
|
2017-12-12 01:50:00 +01:00
|
|
|
|
2022-04-10 16:47:44 +02:00
|
|
|
private void updateErrorBar() {
|
2022-10-05 18:21:50 +02:00
|
|
|
Preferences.BackupResult backupRes = _prefs.getErroredBackupResult();
|
|
|
|
if (backupRes != null) {
|
2022-04-10 16:47:44 +02:00
|
|
|
_textErrorBar.setText(R.string.backup_error_bar_message);
|
|
|
|
_btnErrorBar.setOnClickListener(view -> {
|
2022-10-05 18:21:50 +02:00
|
|
|
Dialogs.showBackupErrorDialog(this, backupRes, (dialog, which) -> {
|
|
|
|
startPreferencesActivity(BackupsPreferencesFragment.class, "pref_backups");
|
|
|
|
});
|
2022-04-10 16:47:44 +02:00
|
|
|
});
|
|
|
|
_btnErrorBar.setVisibility(View.VISIBLE);
|
2023-02-05 18:31:31 +01:00
|
|
|
} else if (_prefs.isBackupsReminderNeeded() && _prefs.isBackupReminderEnabled()) {
|
2022-12-04 15:44:45 +01:00
|
|
|
Date date = _prefs.getLatestBackupOrExportTime();
|
|
|
|
if (date != null) {
|
|
|
|
_textErrorBar.setText(getString(R.string.backup_reminder_bar_message_with_latest, TimeUtils.getElapsedSince(this, date)));
|
|
|
|
} else {
|
|
|
|
_textErrorBar.setText(R.string.backup_reminder_bar_message);
|
|
|
|
}
|
2023-02-05 18:31:31 +01:00
|
|
|
_btnErrorBar.setOnClickListener(view -> {
|
|
|
|
Dialogs.showSecureDialog(new AlertDialog.Builder(this)
|
|
|
|
.setTitle(R.string.backup_reminder_bar_dialog_title)
|
|
|
|
.setMessage(R.string.backup_reminder_bar_dialog_summary)
|
|
|
|
.setPositiveButton(R.string.backup_reminder_bar_dialog_accept, (dialog, whichButton) -> {
|
|
|
|
startPreferencesActivity(BackupsPreferencesFragment.class, "pref_backups");
|
|
|
|
})
|
|
|
|
.setNegativeButton(android.R.string.cancel, null)
|
|
|
|
.create());
|
|
|
|
});
|
2022-04-10 16:47:44 +02:00
|
|
|
_btnErrorBar.setVisibility(View.VISIBLE);
|
2022-08-07 19:55:36 +01:00
|
|
|
} else if (_prefs.isPlaintextBackupWarningNeeded()) {
|
|
|
|
_textErrorBar.setText(R.string.backup_plaintext_export_warning);
|
2022-12-04 15:44:45 +01:00
|
|
|
_btnErrorBar.setOnClickListener(view -> showPlaintextExportWarningOptions());
|
2022-08-07 19:55:36 +01:00
|
|
|
_btnErrorBar.setVisibility(View.VISIBLE);
|
2022-04-10 16:47:44 +02:00
|
|
|
} else {
|
|
|
|
_btnErrorBar.setVisibility(View.GONE);
|
|
|
|
}
|
2020-06-13 12:45:02 +02:00
|
|
|
}
|
|
|
|
|
2022-08-07 19:55:36 +01:00
|
|
|
private void showPlaintextExportWarningOptions() {
|
2022-10-25 18:38:07 +02:00
|
|
|
View view = LayoutInflater.from(this).inflate(R.layout.dialog_plaintext_warning, null);
|
2022-08-07 19:55:36 +01:00
|
|
|
|
|
|
|
AlertDialog dialog = new AlertDialog.Builder(this)
|
|
|
|
.setTitle(R.string.backup_plaintext_export_warning)
|
|
|
|
.setView(view)
|
|
|
|
.setPositiveButton(android.R.string.ok, null)
|
|
|
|
.setNegativeButton(android.R.string.cancel, null)
|
|
|
|
.create();
|
|
|
|
|
2022-10-25 18:38:07 +02:00
|
|
|
CheckBox checkBox = view.findViewById(R.id.checkbox_plaintext_warning);
|
2022-08-07 19:55:36 +01:00
|
|
|
checkBox.setChecked(false);
|
|
|
|
|
|
|
|
dialog.setOnShowListener(d -> {
|
|
|
|
Button btnPos = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
|
|
|
|
|
|
|
|
btnPos.setOnClickListener(l -> {
|
|
|
|
dialog.dismiss();
|
|
|
|
|
2022-10-25 18:38:07 +02:00
|
|
|
_prefs.setIsPlaintextBackupWarningDisabled(checkBox.isChecked());
|
2022-08-07 19:55:36 +01:00
|
|
|
_prefs.setIsPlaintextBackupWarningNeeded(false);
|
|
|
|
|
|
|
|
updateErrorBar();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
Dialogs.showSecureDialog(dialog);
|
|
|
|
}
|
|
|
|
|
2017-12-12 01:50:00 +01:00
|
|
|
@Override
|
2019-12-25 19:21:34 +01:00
|
|
|
public void onEntryClick(VaultEntry entry) {
|
2020-01-04 20:38:40 +01:00
|
|
|
if (_actionMode != null) {
|
|
|
|
if (_selectedEntries.isEmpty()) {
|
2019-08-03 16:15:39 +02:00
|
|
|
_actionMode.finish();
|
2020-01-04 20:38:40 +01:00
|
|
|
} else {
|
2022-10-26 14:07:49 +02:00
|
|
|
setFavoriteMenuItemVisiblity();
|
2020-01-04 20:38:40 +01:00
|
|
|
setIsMultipleSelected(_selectedEntries.size() > 1);
|
2019-08-03 16:15:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-04 20:38:40 +01:00
|
|
|
@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);
|
|
|
|
}
|
|
|
|
|
2023-08-31 21:56:05 +02:00
|
|
|
private void setAssignIconsMenuItemVisibility() {
|
|
|
|
MenuItem assignIconsMenuItem = _actionMode.getMenu().findItem(R.id.action_assign_icons);
|
|
|
|
assignIconsMenuItem.setVisible(_iconPackManager.hasIconPack());
|
|
|
|
}
|
|
|
|
|
2022-10-26 14:07:49 +02:00
|
|
|
private void setFavoriteMenuItemVisiblity() {
|
|
|
|
MenuItem toggleFavoriteMenuItem = _actionMode.getMenu().findItem(R.id.action_toggle_favorite);
|
|
|
|
|
|
|
|
if (_selectedEntries.size() == 1){
|
2022-11-01 20:43:27 +01:00
|
|
|
if (_selectedEntries.get(0).isFavorite()) {
|
2022-10-26 14:07:49 +02:00
|
|
|
toggleFavoriteMenuItem.setIcon(R.drawable.ic_set_favorite);
|
|
|
|
toggleFavoriteMenuItem.setTitle(R.string.unfavorite);
|
|
|
|
} else {
|
|
|
|
toggleFavoriteMenuItem.setIcon(R.drawable.ic_unset_favorite);
|
|
|
|
toggleFavoriteMenuItem.setTitle(R.string.favorite);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
toggleFavoriteMenuItem.setIcon(R.drawable.ic_unset_favorite);
|
|
|
|
toggleFavoriteMenuItem.setTitle(String.format("%s / %s", getString(R.string.favorite), getString(R.string.unfavorite)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-03 16:15:39 +02:00
|
|
|
@Override
|
2019-12-25 19:21:34 +01:00
|
|
|
public void onLongEntryClick(VaultEntry entry) {
|
2020-01-04 20:38:40 +01:00
|
|
|
if (!_selectedEntries.isEmpty()) {
|
2019-08-03 16:15:39 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-04 20:38:40 +01:00
|
|
|
_selectedEntries.add(entry);
|
2019-08-03 16:15:39 +02:00
|
|
|
_entryListView.setActionModeState(true, entry);
|
2022-10-10 22:32:30 +02:00
|
|
|
startActionMode();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void startActionMode() {
|
2022-02-06 19:00:01 +01:00
|
|
|
_actionMode = startSupportActionMode(_actionModeCallbacks);
|
2022-10-10 22:32:30 +02:00
|
|
|
_actionModeBackPressHandler.setEnabled(true);
|
2022-10-26 14:07:49 +02:00
|
|
|
setFavoriteMenuItemVisiblity();
|
2023-08-31 21:56:05 +02:00
|
|
|
setAssignIconsMenuItemVisibility();
|
2017-12-12 01:50:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2019-12-25 19:21:34 +01:00
|
|
|
public void onEntryMove(VaultEntry entry1, VaultEntry entry2) {
|
2023-02-08 02:51:03 +01:00
|
|
|
_vaultManager.getVault().moveEntry(entry1, entry2);
|
2017-12-12 01:50:00 +01:00
|
|
|
}
|
2017-12-12 03:14:26 +01:00
|
|
|
|
|
|
|
@Override
|
2019-12-25 19:21:34 +01:00
|
|
|
public void onEntryDrop(VaultEntry entry) {
|
2022-02-06 19:00:01 +01:00
|
|
|
saveVault();
|
2017-12-12 03:14:26 +01:00
|
|
|
}
|
2018-06-06 17:23:40 +02:00
|
|
|
|
|
|
|
@Override
|
2019-12-25 19:21:34 +01:00
|
|
|
public void onEntryChange(VaultEntry entry) {
|
2022-02-06 19:00:01 +01:00
|
|
|
saveAndBackupVault();
|
2018-06-06 17:23:40 +02:00
|
|
|
}
|
2019-03-26 00:53:32 +01:00
|
|
|
|
2020-05-25 15:49:37 +02:00
|
|
|
public void onEntryCopy(VaultEntry entry) {
|
|
|
|
copyEntryCode(entry);
|
|
|
|
}
|
|
|
|
|
2019-03-26 00:53:32 +01:00
|
|
|
@Override
|
|
|
|
public void onScroll(int dx, int dy) {
|
2022-04-10 16:36:30 +02:00
|
|
|
if (!_isDPadPressed) {
|
|
|
|
_fabScrollHelper.onScroll(dx, dy);
|
|
|
|
}
|
2019-03-26 00:53:32 +01:00
|
|
|
}
|
2019-05-12 17:12:09 +02:00
|
|
|
|
2020-08-13 13:06:20 +02:00
|
|
|
@Override
|
|
|
|
public void onListChange() { _fabScrollHelper.setVisible(true); }
|
|
|
|
|
2021-05-16 13:04:58 +02:00
|
|
|
@Override
|
2023-04-30 15:31:38 +01:00
|
|
|
public void onSaveGroupFilter(Set<UUID> groupFilter) {
|
2022-02-06 19:00:01 +01:00
|
|
|
_prefs.setGroupFilter(groupFilter);
|
2021-05-16 13:04:58 +02:00
|
|
|
}
|
|
|
|
|
2019-05-12 17:12:09 +02:00
|
|
|
@Override
|
2020-08-12 21:33:25 +02:00
|
|
|
public void onLocked(boolean userInitiated) {
|
2019-08-03 16:15:39 +02:00
|
|
|
if (_actionMode != null) {
|
|
|
|
_actionMode.finish();
|
|
|
|
}
|
2021-06-26 14:30:25 +02:00
|
|
|
if (_searchView != null && !_searchView.isIconified()) {
|
2021-06-02 18:14:18 +02:00
|
|
|
collapseSearchView();
|
|
|
|
}
|
2019-08-03 16:15:39 +02:00
|
|
|
|
2019-05-12 17:12:09 +02:00
|
|
|
_entryListView.clearEntries();
|
|
|
|
_loaded = false;
|
2019-05-26 21:45:36 +02:00
|
|
|
|
2020-08-12 21:33:25 +02:00
|
|
|
if (userInitiated) {
|
2020-07-05 19:49:51 +02:00
|
|
|
startAuthActivity(true);
|
2020-08-12 21:33:25 +02:00
|
|
|
} else {
|
2021-11-04 15:41:17 +05:30
|
|
|
super.onLocked(false);
|
2019-05-26 21:45:36 +02:00
|
|
|
}
|
2019-05-12 17:12:09 +02:00
|
|
|
}
|
2019-08-03 16:15:39 +02:00
|
|
|
|
2022-09-14 18:33:28 +02:00
|
|
|
@SuppressLint("InlinedApi")
|
2019-12-26 22:17:32 +01:00
|
|
|
private void copyEntryCode(VaultEntry entry) {
|
2022-09-17 17:30:14 +02:00
|
|
|
String otp;
|
|
|
|
try {
|
|
|
|
otp = entry.getInfo().getOtp();
|
|
|
|
} catch (OtpInfoException e) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-12-07 18:59:49 +01:00
|
|
|
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
|
2022-09-17 17:30:14 +02:00
|
|
|
ClipData clip = ClipData.newPlainText("text/plain", otp);
|
2022-09-14 18:33:28 +02:00
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
|
|
PersistableBundle extras = new PersistableBundle();
|
|
|
|
extras.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true);
|
|
|
|
clip.getDescription().setExtras(extras);
|
|
|
|
}
|
2019-12-07 18:59:49 +01:00
|
|
|
clipboard.setPrimaryClip(clip);
|
2022-08-26 20:54:46 +02:00
|
|
|
if (_prefs.isMinimizeOnCopyEnabled()) {
|
|
|
|
moveTaskToBack(true);
|
|
|
|
}
|
2019-12-07 18:59:49 +01:00
|
|
|
}
|
|
|
|
|
2022-10-10 22:32:30 +02:00
|
|
|
private class SearchViewBackPressHandler extends OnBackPressedCallback {
|
|
|
|
public SearchViewBackPressHandler() {
|
|
|
|
super(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void handleOnBackPressed() {
|
|
|
|
if (!_searchView.isIconified() || _submittedSearchQuery != null) {
|
|
|
|
_submittedSearchQuery = null;
|
|
|
|
_pendingSearchQuery = null;
|
|
|
|
_entryListView.setSearchFilter(null);
|
|
|
|
|
|
|
|
collapseSearchView();
|
|
|
|
setTitle(R.string.app_name);
|
|
|
|
getSupportActionBar().setSubtitle(null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class LockBackPressHandler extends OnBackPressedCallback {
|
|
|
|
public LockBackPressHandler() {
|
|
|
|
super(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void handleOnBackPressed() {
|
|
|
|
if (_vaultManager.isAutoLockEnabled(Preferences.AUTO_LOCK_ON_BACK_BUTTON)) {
|
|
|
|
_vaultManager.lock(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class ActionModeBackPressHandler extends OnBackPressedCallback {
|
|
|
|
public ActionModeBackPressHandler() {
|
|
|
|
super(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void handleOnBackPressed() {
|
|
|
|
if (_actionMode != null) {
|
|
|
|
_actionMode.finish();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-03 16:15:39 +02:00
|
|
|
private class ActionModeCallbacks implements ActionMode.Callback {
|
2023-09-19 23:24:19 +02:00
|
|
|
@Override
|
|
|
|
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
|
|
|
MenuInflater inflater = getMenuInflater();
|
|
|
|
inflater.inflate(R.menu.menu_action_mode, menu);
|
|
|
|
return true;
|
|
|
|
}
|
2019-08-03 16:15:39 +02:00
|
|
|
|
2023-09-19 23:24:19 +02:00
|
|
|
@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;
|
2019-08-03 16:15:39 +02:00
|
|
|
}
|
|
|
|
|
2023-09-19 23:24:19 +02:00
|
|
|
int itemId = item.getItemId();
|
|
|
|
if (itemId == R.id.action_copy) {
|
|
|
|
copyEntryCode(_selectedEntries.get(0));
|
|
|
|
mode.finish();
|
|
|
|
} else if (itemId == R.id.action_edit) {
|
|
|
|
startEditEntryActivity(CODE_EDIT_ENTRY, _selectedEntries.get(0));
|
|
|
|
mode.finish();
|
|
|
|
} else if (itemId == R.id.action_toggle_favorite) {
|
|
|
|
for (VaultEntry entry : _selectedEntries) {
|
|
|
|
entry.setIsFavorite(!entry.isFavorite());
|
|
|
|
_entryListView.replaceEntry(entry.getUUID(), entry);
|
2022-06-04 13:31:22 +02:00
|
|
|
}
|
2023-09-19 23:24:19 +02:00
|
|
|
_entryListView.refresh(true);
|
2020-05-22 02:52:12 +02:00
|
|
|
|
2023-09-19 23:24:19 +02:00
|
|
|
saveAndBackupVault();
|
|
|
|
mode.finish();
|
|
|
|
} else if (itemId == 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);
|
|
|
|
}
|
2023-08-31 21:56:05 +02:00
|
|
|
|
2023-09-19 23:24:19 +02:00
|
|
|
intent.putExtra("authInfos", authInfos);
|
|
|
|
startActivity(intent);
|
2023-08-31 21:56:05 +02:00
|
|
|
|
2023-09-19 23:24:19 +02:00
|
|
|
mode.finish();
|
|
|
|
} else if (itemId == R.id.action_delete) {
|
|
|
|
Dialogs.showDeleteEntriesDialog(MainActivity.this, _selectedEntries, (d, which) -> {
|
|
|
|
deleteEntries(_selectedEntries);
|
|
|
|
_entryListView.setGroups(_vaultManager.getVault().getUsedGroups());
|
|
|
|
mode.finish();
|
|
|
|
});
|
|
|
|
} else if (itemId == R.id.action_assign_icons) {
|
|
|
|
startAssignIconsActivity(CODE_ASSIGN_ICONS, _selectedEntries);
|
|
|
|
mode.finish();
|
|
|
|
} else {
|
|
|
|
return false;
|
2019-08-03 16:15:39 +02:00
|
|
|
}
|
|
|
|
|
2023-09-19 23:24:19 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroyActionMode(ActionMode mode) {
|
|
|
|
_entryListView.setActionModeState(false, null);
|
|
|
|
_actionModeBackPressHandler.setEnabled(false);
|
|
|
|
_selectedEntries.clear();
|
|
|
|
_actionMode = null;
|
|
|
|
}
|
2019-08-03 16:15:39 +02:00
|
|
|
}
|
2016-08-15 21:29:41 +02:00
|
|
|
}
|