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;
|
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;
|
|
|
|
import android.net.Uri;
|
2016-08-15 21:29:41 +02:00
|
|
|
import android.os.Bundle;
|
2020-05-03 16:57:51 +02:00
|
|
|
import android.provider.Settings;
|
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;
|
|
|
|
import android.widget.LinearLayout;
|
2016-08-17 01:14:25 +02:00
|
|
|
import android.widget.Toast;
|
|
|
|
|
2020-07-01 15:35:54 +02:00
|
|
|
import androidx.annotation.NonNull;
|
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
|
|
|
|
2019-04-04 14:07:36 +02:00
|
|
|
import com.beemdevelopment.aegis.AegisApplication;
|
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;
|
2020-10-25 15:01:39 +01:00
|
|
|
import com.beemdevelopment.aegis.helpers.BitmapHelper;
|
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;
|
2021-01-19 20:26:45 +01:00
|
|
|
import com.beemdevelopment.aegis.helpers.QrCodeAnalyzer;
|
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;
|
2021-01-13 21:03:14 +01:00
|
|
|
import com.beemdevelopment.aegis.ui.fragments.BackupsPreferencesFragment;
|
|
|
|
import com.beemdevelopment.aegis.ui.fragments.PreferencesFragment;
|
2019-02-07 22:39:33 +01:00
|
|
|
import com.beemdevelopment.aegis.ui.views.EntryListView;
|
2019-12-25 19:21:34 +01:00
|
|
|
import com.beemdevelopment.aegis.vault.VaultEntry;
|
2020-05-02 18:51:12 +02:00
|
|
|
import com.beemdevelopment.aegis.vault.VaultFile;
|
2019-12-25 19:21:34 +01:00
|
|
|
import com.beemdevelopment.aegis.vault.VaultManager;
|
|
|
|
import com.beemdevelopment.aegis.vault.VaultManagerException;
|
2021-01-02 13:41:58 +01:00
|
|
|
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
|
|
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
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.NotFoundException;
|
|
|
|
import com.google.zxing.RGBLuminanceSource;
|
|
|
|
import com.google.zxing.Reader;
|
|
|
|
import com.google.zxing.Result;
|
|
|
|
import com.google.zxing.common.HybridBinarizer;
|
2020-10-25 14:47:59 +01:00
|
|
|
import com.google.zxing.qrcode.QRCodeReader;
|
2017-12-30 00:26:16 +01:00
|
|
|
|
2019-04-19 23:10:18 +02:00
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
2018-12-11 11:44:36 +01:00
|
|
|
import java.util.ArrayList;
|
2019-03-31 19:57:45 +02:00
|
|
|
import java.util.List;
|
2020-05-02 18:51:33 +02:00
|
|
|
import java.util.UUID;
|
2020-12-22 13:29:38 +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;
|
2016-08-24 23:48:25 +02:00
|
|
|
|
2017-12-13 19:00:58 +01:00
|
|
|
// permission request codes
|
2018-05-10 19:34:42 +02:00
|
|
|
private static final int CODE_PERM_CAMERA = 0;
|
2019-07-03 18:57:03 +02:00
|
|
|
private static final int CODE_PERM_READ_STORAGE = 1;
|
2017-12-13 19:00:58 +01:00
|
|
|
|
2017-12-23 22:33:32 +01:00
|
|
|
private AegisApplication _app;
|
2019-12-25 19:21:34 +01:00
|
|
|
private VaultManager _vault;
|
2018-06-09 20:23:39 +02:00
|
|
|
private boolean _loaded;
|
2020-12-22 13:29:38 +01:00
|
|
|
private List<String> _selectedGroups;
|
2019-05-30 02:07:30 +02:00
|
|
|
private boolean _searchSubmitted;
|
2016-09-30 01:08:03 +02:00
|
|
|
|
2020-07-01 15:35:54 +02:00
|
|
|
private boolean _isAuthenticating;
|
|
|
|
private boolean _isDoingIntro;
|
|
|
|
|
2020-01-04 20:38:40 +01:00
|
|
|
private List<VaultEntry> _selectedEntries;
|
2019-08-03 16:15:39 +02:00
|
|
|
private ActionMode _actionMode;
|
|
|
|
|
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;
|
2020-06-13 12:45:02 +02:00
|
|
|
private LinearLayout _btnBackupError;
|
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
|
|
|
|
2019-08-03 16:15:39 +02:00
|
|
|
private ActionMode.Callback _actionModeCallbacks = new ActionModeCallbacks();
|
|
|
|
|
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));
|
2019-09-05 00:24:33 +02:00
|
|
|
|
2017-12-23 22:33:32 +01:00
|
|
|
_app = (AegisApplication) getApplication();
|
2019-12-25 19:21:34 +01:00
|
|
|
_vault = _app.getVaultManager();
|
2018-06-09 20:23:39 +02:00
|
|
|
_loaded = false;
|
2016-09-29 12:31:55 +02:00
|
|
|
|
2020-07-01 15:35:54 +02:00
|
|
|
if (savedInstanceState != null) {
|
|
|
|
_isAuthenticating = savedInstanceState.getBoolean("isAuthenticating");
|
|
|
|
_isDoingIntro = savedInstanceState.getBoolean("isDoingIntro");
|
|
|
|
}
|
2017-12-03 16:47:27 +01:00
|
|
|
|
2018-06-06 16:15:31 +02:00
|
|
|
_entryListView = (EntryListView) getSupportFragmentManager().findFragmentById(R.id.key_profiles);
|
|
|
|
_entryListView.setListener(this);
|
2020-04-23 23:19:38 +02:00
|
|
|
_entryListView.setCodeGroupSize(getPreferences().getCodeGroupSize());
|
2018-09-19 00:10:03 +02:00
|
|
|
_entryListView.setShowAccountName(getPreferences().isAccountNameVisible());
|
2019-09-07 22:26:34 +02:00
|
|
|
_entryListView.setHighlightEntry(getPreferences().isEntryHighlightEnabled());
|
2019-03-25 21:32:29 +01:00
|
|
|
_entryListView.setTapToReveal(getPreferences().isTapToRevealEnabled());
|
2019-03-26 00:06:39 +01:00
|
|
|
_entryListView.setTapToRevealTime(getPreferences().getTapToRevealTime());
|
2019-05-15 21:29:45 +02:00
|
|
|
_entryListView.setSortCategory(getPreferences().getCurrentSortCategory(), false);
|
|
|
|
_entryListView.setViewMode(getPreferences().getCurrentViewMode());
|
2020-05-25 15:49:37 +02:00
|
|
|
_entryListView.setIsCopyOnTapEnabled(getPreferences().isCopyOnTapEnabled());
|
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();
|
|
|
|
startEditEntryActivity(CODE_ADD_ENTRY, null, true);
|
|
|
|
});
|
|
|
|
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
|
|
|
|
2020-06-13 12:45:02 +02:00
|
|
|
_btnBackupError = findViewById(R.id.btn_backup_error);
|
|
|
|
_btnBackupError.setOnClickListener(view -> {
|
2021-01-13 21:03:14 +01:00
|
|
|
startPreferencesActivity(BackupsPreferencesFragment.class, "pref_backups");
|
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
|
|
|
|
2020-07-01 15:35:54 +02:00
|
|
|
@Override
|
|
|
|
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
|
|
|
super.onSaveInstanceState(outState);
|
|
|
|
outState.putBoolean("isAuthenticating", _isAuthenticating);
|
|
|
|
outState.putBoolean("isDoingIntro", _isDoingIntro);
|
|
|
|
}
|
|
|
|
|
2019-06-22 12:12:26 +02:00
|
|
|
@Override
|
|
|
|
protected void onDestroy() {
|
|
|
|
_entryListView.setListener(null);
|
|
|
|
super.onDestroy();
|
|
|
|
}
|
|
|
|
|
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) {
|
2020-07-01 15:35:54 +02:00
|
|
|
_isAuthenticating = false;
|
|
|
|
_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:
|
2020-05-02 18:51:12 +02:00
|
|
|
onDoIntroResult();
|
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);
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (requestCode) {
|
|
|
|
case CODE_PERM_CAMERA:
|
2018-06-09 19:23:30 +02:00
|
|
|
startScanActivity();
|
2017-12-13 19:00:58 +01:00
|
|
|
break;
|
2019-07-03 18:57:03 +02:00
|
|
|
case CODE_PERM_READ_STORAGE:
|
|
|
|
startScanImageActivity();
|
|
|
|
break;
|
2017-12-13 19:00:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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)) {
|
|
|
|
boolean showAccountName = getPreferences().isAccountNameVisible();
|
|
|
|
int codeGroupSize = getPreferences().getCodeGroupSize();
|
|
|
|
boolean highlightEntry = getPreferences().isEntryHighlightEnabled();
|
|
|
|
boolean tapToReveal = getPreferences().isTapToRevealEnabled();
|
|
|
|
int tapToRevealTime = getPreferences().getTapToRevealTime();
|
|
|
|
ViewMode viewMode = getPreferences().getCurrentViewMode();
|
2020-05-25 15:49:37 +02:00
|
|
|
boolean copyOnTap = getPreferences().isCopyOnTapEnabled();
|
2020-05-24 20:24:04 +02:00
|
|
|
_entryListView.setShowAccountName(showAccountName);
|
|
|
|
_entryListView.setCodeGroupSize(codeGroupSize);
|
|
|
|
_entryListView.setHighlightEntry(highlightEntry);
|
|
|
|
_entryListView.setTapToReveal(tapToReveal);
|
|
|
|
_entryListView.setTapToRevealTime(tapToRevealTime);
|
|
|
|
_entryListView.setViewMode(viewMode);
|
2020-05-25 15:49:37 +02:00
|
|
|
_entryListView.setIsCopyOnTapEnabled(copyOnTap);
|
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
|
|
|
|
2020-05-02 18:51:33 +02:00
|
|
|
private void startEditEntryActivity(int requestCode, VaultEntry entry, boolean isNew) {
|
2018-06-06 16:15:31 +02:00
|
|
|
Intent intent = new Intent(this, EditEntryActivity.class);
|
2020-05-02 18:51:33 +02:00
|
|
|
if (isNew) {
|
|
|
|
intent.putExtra("newEntry", entry != null ? entry : VaultEntry.getDefault());
|
|
|
|
} else {
|
|
|
|
intent.putExtra("entryUUID", entry.getUUID());
|
|
|
|
}
|
2020-12-22 13:29:38 +01:00
|
|
|
intent.putExtra("selectedGroup", (ArrayList<String>) _selectedGroups);
|
2018-01-02 21:50:07 +01:00
|
|
|
startActivityForResult(intent, requestCode);
|
|
|
|
}
|
|
|
|
|
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");
|
|
|
|
if (entries.size() == 1) {
|
|
|
|
startEditEntryActivity(CODE_ADD_ENTRY, entries.get(0), true);
|
|
|
|
} else {
|
|
|
|
for (VaultEntry entry : entries) {
|
|
|
|
_vault.addEntry(entry);
|
2020-05-24 20:24:04 +02:00
|
|
|
if (_loaded) {
|
|
|
|
_entryListView.addEntry(entry);
|
|
|
|
}
|
2020-05-09 15:32:57 +02:00
|
|
|
}
|
|
|
|
|
2020-06-13 12:45:02 +02:00
|
|
|
saveVault(true);
|
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");
|
|
|
|
VaultEntry entry = _vault.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 {
|
|
|
|
VaultEntry entry = _vault.getEntryByUUID(entryUUID);
|
|
|
|
_entryListView.replaceEntry(entryUUID, entry);
|
|
|
|
}
|
2017-12-27 22:04:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-02 18:51:12 +02:00
|
|
|
private void onScanImageResult(Intent intent) {
|
|
|
|
Uri inputFile = (intent.getData());
|
|
|
|
Bitmap bitmap;
|
2019-04-19 23:10:18 +02:00
|
|
|
|
2020-05-02 18:51:12 +02:00
|
|
|
try {
|
|
|
|
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
|
2019-04-19 23:10:18 +02:00
|
|
|
|
2020-05-02 18:51:12 +02:00
|
|
|
try (InputStream inputStream = getContentResolver().openInputStream(inputFile)) {
|
|
|
|
bitmap = BitmapFactory.decodeStream(inputStream, null, bmOptions);
|
2021-01-19 20:26:45 +01:00
|
|
|
bitmap = BitmapHelper.resize(bitmap, QrCodeAnalyzer.RESOLUTION.getWidth(), QrCodeAnalyzer.RESOLUTION.getHeight());
|
2020-05-02 18:51:12 +02:00
|
|
|
}
|
2019-04-19 23:10:18 +02:00
|
|
|
|
2020-05-02 18:51:12 +02:00
|
|
|
int[] intArray = new int[bitmap.getWidth() * bitmap.getHeight()];
|
|
|
|
bitmap.getPixels(intArray, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
|
2019-04-19 23:10:18 +02:00
|
|
|
|
2020-05-02 18:51:12 +02:00
|
|
|
LuminanceSource source = new RGBLuminanceSource(bitmap.getWidth(), bitmap.getHeight(), intArray);
|
|
|
|
BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source));
|
2019-04-19 23:10:18 +02:00
|
|
|
|
2020-10-25 14:47:59 +01:00
|
|
|
Reader reader = new QRCodeReader();
|
2020-05-02 18:51:12 +02:00
|
|
|
Result result = reader.decode(binaryBitmap);
|
2019-04-19 23:10:18 +02:00
|
|
|
|
2020-05-02 18:51:12 +02:00
|
|
|
GoogleAuthInfo info = GoogleAuthInfo.parseUri(result.getText());
|
|
|
|
VaultEntry entry = new VaultEntry(info);
|
2019-04-19 23:10:18 +02:00
|
|
|
|
2020-05-02 18:51:12 +02:00
|
|
|
startEditEntryActivity(CODE_ADD_ENTRY, entry, true);
|
|
|
|
} catch (NotFoundException | IOException | ChecksumException | FormatException | GoogleAuthInfoException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
Dialogs.showErrorDialog(this, R.string.unable_to_read_qrcode, e);
|
2019-04-19 23:10:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-15 21:29:45 +02:00
|
|
|
private void updateSortCategoryMenu() {
|
|
|
|
SortCategory category = getPreferences().getCurrentSortCategory();
|
|
|
|
_menu.findItem(category.getMenuItem()).setChecked(true);
|
|
|
|
}
|
|
|
|
|
2020-12-22 13:29:38 +01:00
|
|
|
private void setGroupFilter(List<String> group) {
|
|
|
|
_selectedGroups = group;
|
2019-05-15 21:29:45 +02:00
|
|
|
_entryListView.setGroupFilter(group, true);
|
2019-03-31 22:34:25 +02:00
|
|
|
}
|
|
|
|
|
2020-05-02 18:51:12 +02:00
|
|
|
private void onDoIntroResult() {
|
|
|
|
_vault = _app.getVaultManager();
|
|
|
|
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;
|
|
|
|
if (!autoTime && getPreferences().isTimeSyncWarningEnabled()) {
|
|
|
|
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() {
|
|
|
|
_vault = _app.getVaultManager();
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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 });
|
|
|
|
startActivityForResult(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");
|
2020-05-02 18:51:12 +02:00
|
|
|
if (action == null || _app.isVaultLocked()) {
|
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
|
|
|
|
2019-08-02 22:36:12 +02:00
|
|
|
private void handleDeeplink() {
|
2020-05-02 18:51:12 +02:00
|
|
|
if (_app.isVaultLocked()) {
|
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();
|
2020-08-15 17:08:08 +02:00
|
|
|
Uri uri = intent.getData();
|
|
|
|
if (Intent.ACTION_VIEW.equals(intent.getAction()) && uri != null) {
|
|
|
|
intent.setData(null);
|
|
|
|
intent.setAction(null);
|
2019-08-02 22:36:12 +02:00
|
|
|
|
|
|
|
GoogleAuthInfo info = null;
|
|
|
|
try {
|
|
|
|
info = GoogleAuthInfo.parseUri(uri);
|
|
|
|
} catch (GoogleAuthInfoException e) {
|
|
|
|
e.printStackTrace();
|
2020-05-02 18:51:12 +02:00
|
|
|
Dialogs.showErrorDialog(this, R.string.unable_to_read_qrcode, e);
|
2019-08-02 22:36:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (info != null) {
|
2019-12-25 19:21:34 +01:00
|
|
|
VaultEntry entry = new VaultEntry(info);
|
2020-05-02 18:51:33 +02:00
|
|
|
startEditEntryActivity(CODE_ADD_ENTRY, entry, true);
|
2019-08-02 22:36:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-30 01:08:03 +02:00
|
|
|
@Override
|
|
|
|
protected void onResume() {
|
|
|
|
super.onResume();
|
2017-12-24 21:42:08 +01:00
|
|
|
|
2020-05-02 18:51:12 +02:00
|
|
|
if (_vault == null) {
|
2019-12-25 19:21:34 +01:00
|
|
|
// start the intro if the vault file doesn't exist
|
2020-07-01 15:35:54 +02:00
|
|
|
if (!_isDoingIntro && !VaultManager.fileExists(this)) {
|
2018-06-09 20:23:39 +02:00
|
|
|
if (getPreferences().isIntroDone()) {
|
2018-10-09 23:13:51 +02:00
|
|
|
Toast.makeText(this, getString(R.string.vault_not_found), Toast.LENGTH_SHORT).show();
|
2018-06-09 20:23:39 +02:00
|
|
|
}
|
|
|
|
Intent intro = new Intent(this, IntroActivity.class);
|
|
|
|
startActivityForResult(intro, CODE_DO_INTRO);
|
2020-07-01 15:35:54 +02:00
|
|
|
_isDoingIntro = true;
|
2018-06-09 20:23:39 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-05-02 18:51:12 +02:00
|
|
|
|
|
|
|
// read the vault from disk
|
|
|
|
// if this fails, show the error to the user and close the app
|
|
|
|
try {
|
|
|
|
VaultFile vaultFile = _app.loadVaultFile();
|
|
|
|
if (!vaultFile.isEncrypted()) {
|
|
|
|
_vault = _app.initVaultManager(vaultFile, null);
|
|
|
|
}
|
|
|
|
} catch (VaultManagerException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
Dialogs.showErrorDialog(this, R.string.vault_load_error, e, (dialog1, which) -> finish());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_app.isVaultLocked()) {
|
2020-07-05 19:49:51 +02:00
|
|
|
startAuthActivity(false);
|
2018-06-09 20:23:39 +02:00
|
|
|
} else if (_loaded) {
|
2018-12-11 11:44:36 +01:00
|
|
|
// update the list of groups in the filter menu
|
|
|
|
if (_menu != null) {
|
2020-12-22 13:29:38 +01:00
|
|
|
_entryListView.setGroups(_vault.getGroups());
|
2018-12-11 11:44:36 +01: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
|
|
|
}
|
|
|
|
|
2019-08-02 22:36:12 +02:00
|
|
|
handleDeeplink();
|
2018-06-09 20:23:39 +02:00
|
|
|
updateLockIcon();
|
2019-04-08 23:13:11 +02:00
|
|
|
doShortcutActions();
|
2020-06-13 12:45:02 +02:00
|
|
|
updateBackupErrorBar();
|
2016-09-30 01:08:03 +02:00
|
|
|
}
|
|
|
|
|
2019-04-07 18:18:50 +02:00
|
|
|
@Override
|
|
|
|
public void onBackPressed() {
|
2019-09-10 23:10:11 +02:00
|
|
|
if (!_searchView.isIconified() || _searchSubmitted) {
|
2019-05-30 02:07:30 +02:00
|
|
|
_searchSubmitted = false;
|
|
|
|
_entryListView.setSearchFilter(null);
|
|
|
|
|
|
|
|
collapseSearchView();
|
|
|
|
setTitle("Aegis");
|
2020-12-22 13:29:38 +01:00
|
|
|
setGroupFilter(_selectedGroups);
|
2019-05-30 02:07:30 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-08-12 21:33:25 +02:00
|
|
|
if (_app.isAutoLockEnabled(Preferences.AUTO_LOCK_ON_BACK_BUTTON)) {
|
|
|
|
_app.lock(false);
|
2019-06-22 12:12:26 +02:00
|
|
|
return;
|
2019-04-07 18:18:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
super.onBackPressed();
|
|
|
|
}
|
|
|
|
|
2020-01-04 20:38:40 +01:00
|
|
|
private void deleteEntries(List<VaultEntry> entries) {
|
|
|
|
for (VaultEntry entry: entries) {
|
|
|
|
VaultEntry oldEntry = _vault.removeEntry(entry);
|
|
|
|
_entryListView.removeEntry(oldEntry);
|
|
|
|
}
|
|
|
|
|
2020-06-13 12:45:02 +02:00
|
|
|
saveVault(true);
|
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);
|
2017-08-26 21:15:53 +02:00
|
|
|
updateLockIcon();
|
2018-12-12 16:20:35 +01:00
|
|
|
if (_loaded) {
|
2020-12-22 13:29:38 +01:00
|
|
|
_entryListView.setGroups(_vault.getGroups());
|
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();
|
2019-09-10 23:10:11 +02:00
|
|
|
_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;
|
|
|
|
}
|
2019-05-30 02:07:30 +02:00
|
|
|
|
2019-09-10 23:10:11 +02:00
|
|
|
@Override
|
|
|
|
public boolean onQueryTextChange(String s) {
|
|
|
|
if (!_searchSubmitted) {
|
|
|
|
_entryListView.setSearchFilter(s);
|
2019-05-30 02:07:30 +02:00
|
|
|
}
|
2019-09-10 23:10:11 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
_searchView.setOnSearchClickListener(v -> {
|
|
|
|
if (_searchSubmitted) {
|
|
|
|
_searchSubmitted = false;
|
|
|
|
_entryListView.setSearchFilter(null);
|
|
|
|
}
|
|
|
|
});
|
2019-05-30 02:07:30 +02:00
|
|
|
|
2016-08-16 14:14:17 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onOptionsItemSelected(MenuItem item) {
|
2017-08-14 00:04:06 +02:00
|
|
|
switch (item.getItemId()) {
|
2019-09-05 00:24:33 +02:00
|
|
|
case R.id.action_settings: {
|
2021-01-13 21:03:14 +01:00
|
|
|
startPreferencesActivity();
|
2017-08-14 00:04:06 +02:00
|
|
|
return true;
|
2019-09-05 00:24:33 +02:00
|
|
|
}
|
|
|
|
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:
|
2020-08-12 21:33:25 +02:00
|
|
|
_app.lock(true);
|
2017-08-14 00:04:06 +02:00
|
|
|
return true;
|
|
|
|
default:
|
2020-12-22 13:29:38 +01:00
|
|
|
/*if (item.getGroupId() == R.id.action_filter_group) {
|
2018-12-11 11:44:36 +01:00
|
|
|
item.setChecked(true);
|
|
|
|
|
|
|
|
String group = null;
|
|
|
|
if (item.getItemId() != R.id.menu_filter_all) {
|
|
|
|
group = item.getTitle().toString();
|
|
|
|
}
|
|
|
|
setGroupFilter(group);
|
2020-12-22 13:29:38 +01:00
|
|
|
}*/
|
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:
|
2019-05-15 21:29:45 +02:00
|
|
|
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:
|
2019-05-15 21:29:45 +02:00
|
|
|
sortCategory = SortCategory.ACCOUNT_REVERSED;
|
2019-03-31 19:57:45 +02:00
|
|
|
break;
|
2019-03-31 22:34:25 +02:00
|
|
|
case R.id.menu_sort_custom:
|
2019-03-31 19:57:45 +02:00
|
|
|
default:
|
2019-03-31 21:23:14 +02:00
|
|
|
sortCategory = SortCategory.CUSTOM;
|
2019-03-31 19:57:45 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-05-15 21:29:45 +02:00
|
|
|
_entryListView.setSortCategory(sortCategory, true);
|
2019-03-31 22:34:25 +02:00
|
|
|
getPreferences().setCurrentSortCategory(sortCategory);
|
2019-03-31 19:57:45 +02:00
|
|
|
}
|
2017-08-14 00:04:06 +02:00
|
|
|
return super.onOptionsItemSelected(item);
|
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) {
|
|
|
|
_entryListView.addEntries(_vault.getEntries());
|
|
|
|
_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) {
|
2020-07-01 15:35:54 +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
|
2020-05-02 18:51:12 +02:00
|
|
|
if (_menu != null && !_app.isVaultLocked()) {
|
2017-08-26 21:15:53 +02:00
|
|
|
MenuItem item = _menu.findItem(R.id.action_lock);
|
2019-12-25 19:21:34 +01:00
|
|
|
item.setVisible(_vault.isEncryptionEnabled());
|
2017-08-26 21:15:53 +02:00
|
|
|
}
|
|
|
|
}
|
2017-12-12 01:50:00 +01:00
|
|
|
|
2020-06-13 12:45:02 +02:00
|
|
|
private void updateBackupErrorBar() {
|
|
|
|
String error = null;
|
|
|
|
if (_app.getPreferences().isBackupsEnabled()) {
|
|
|
|
error = _app.getPreferences().getBackupsError();
|
|
|
|
}
|
|
|
|
|
|
|
|
_btnBackupError.setVisibility(error == null ? View.GONE : View.VISIBLE);
|
|
|
|
}
|
|
|
|
|
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 {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
_actionMode = this.startSupportActionMode(_actionModeCallbacks);
|
2017-12-12 01:50:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2019-12-25 19:21:34 +01:00
|
|
|
public void onEntryMove(VaultEntry entry1, VaultEntry entry2) {
|
|
|
|
_vault.swapEntries(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) {
|
2020-06-13 12:45:02 +02:00
|
|
|
saveVault(false);
|
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) {
|
2020-06-13 12:45:02 +02:00
|
|
|
saveVault(true);
|
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) {
|
2019-04-20 01:25:04 +02:00
|
|
|
_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); }
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
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 {
|
|
|
|
super.onLocked(userInitiated);
|
2019-05-26 21:45:36 +02:00
|
|
|
}
|
2019-05-12 17:12:09 +02:00
|
|
|
}
|
2019-08-03 16:15:39 +02:00
|
|
|
|
2019-12-26 22:17:32 +01:00
|
|
|
private void copyEntryCode(VaultEntry entry) {
|
2019-12-07 18:59:49 +01:00
|
|
|
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
|
|
|
|
ClipData clip = ClipData.newPlainText("text/plain", entry.getInfo().getOtp());
|
|
|
|
clipboard.setPrimaryClip(clip);
|
|
|
|
}
|
|
|
|
|
2019-08-03 16:15:39 +02:00
|
|
|
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()) {
|
2019-12-07 18:59:49 +01:00
|
|
|
case R.id.action_copy:
|
2020-01-04 20:38:40 +01:00
|
|
|
copyEntryCode(_selectedEntries.get(0));
|
2019-12-07 18:59:49 +01:00
|
|
|
mode.finish();
|
|
|
|
return true;
|
|
|
|
|
2019-08-03 16:15:39 +02:00
|
|
|
case R.id.action_edit:
|
2020-05-02 18:51:33 +02:00
|
|
|
startEditEntryActivity(CODE_EDIT_ENTRY, _selectedEntries.get(0), false);
|
2019-08-03 16:15:39 +02:00
|
|
|
mode.finish();
|
|
|
|
return true;
|
|
|
|
|
2020-05-22 02:52:12 +02:00
|
|
|
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;
|
|
|
|
|
2019-08-03 16:15:39 +02:00
|
|
|
case R.id.action_delete:
|
2021-01-24 14:20:29 +01:00
|
|
|
Dialogs.showDeleteEntriesDialog(MainActivity.this, _selectedEntries.stream().map(VaultEntry::getIssuer).collect(Collectors.toList()), (d, which) -> {
|
2020-01-04 20:38:40 +01:00
|
|
|
deleteEntries(_selectedEntries);
|
|
|
|
|
|
|
|
for (VaultEntry entry : _selectedEntries) {
|
|
|
|
if (entry.getGroup() != null) {
|
|
|
|
if (!_vault.getGroups().contains(entry.getGroup())) {
|
2020-12-22 13:29:38 +01:00
|
|
|
_entryListView.setGroups(_vault.getGroups());
|
2020-01-04 20:38:40 +01:00
|
|
|
}
|
2019-08-03 16:15:39 +02:00
|
|
|
}
|
|
|
|
}
|
2020-01-04 20:38:40 +01:00
|
|
|
|
2019-08-03 16:15:39 +02:00
|
|
|
mode.finish();
|
2021-01-24 14:20:29 +01:00
|
|
|
});
|
2019-08-03 16:15:39 +02:00
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroyActionMode(ActionMode mode) {
|
|
|
|
_entryListView.setActionModeState(false, null);
|
2020-01-04 20:38:40 +01:00
|
|
|
_selectedEntries.clear();
|
2019-08-03 16:15:39 +02:00
|
|
|
_actionMode = null;
|
|
|
|
}
|
|
|
|
}
|
2016-08-15 21:29:41 +02:00
|
|
|
}
|