diff --git a/app/src/main/java/me/impy/aegis/ui/PreferencesActivity.java b/app/src/main/java/me/impy/aegis/ui/PreferencesActivity.java index 7b2d9cf5..b11638b1 100644 --- a/app/src/main/java/me/impy/aegis/ui/PreferencesActivity.java +++ b/app/src/main/java/me/impy/aegis/ui/PreferencesActivity.java @@ -2,12 +2,7 @@ package me.impy.aegis.ui; import android.os.Bundle; -import javax.crypto.Cipher; - -import me.impy.aegis.db.slots.Slot; -import me.impy.aegis.ui.dialogs.PasswordDialogFragment; - -public class PreferencesActivity extends AegisActivity implements PasswordDialogFragment.Listener { +public class PreferencesActivity extends AegisActivity { private PreferencesFragment _fragment; @Override @@ -41,14 +36,4 @@ public class PreferencesActivity extends AegisActivity implements PasswordDialog outState.putParcelable("result", _fragment.getResult()); super.onSaveInstanceState(outState); } - - @Override - public void onSlotResult(Slot slot, Cipher cipher) { - _fragment.onSlotResult(slot, cipher); - } - - @Override - public void onException(Exception e) { - _fragment.onException(e); - } } diff --git a/app/src/main/java/me/impy/aegis/ui/PreferencesFragment.java b/app/src/main/java/me/impy/aegis/ui/PreferencesFragment.java index 664fd631..cfefe5d6 100644 --- a/app/src/main/java/me/impy/aegis/ui/PreferencesFragment.java +++ b/app/src/main/java/me/impy/aegis/ui/PreferencesFragment.java @@ -29,20 +29,23 @@ import me.impy.aegis.BuildConfig; import me.impy.aegis.R; import me.impy.aegis.db.DatabaseEntry; import me.impy.aegis.db.DatabaseFileCredentials; -import me.impy.aegis.db.DatabaseFileException; import me.impy.aegis.db.DatabaseManager; import me.impy.aegis.db.DatabaseManagerException; +import me.impy.aegis.db.slots.FingerprintSlot; +import me.impy.aegis.db.slots.PasswordSlot; import me.impy.aegis.db.slots.Slot; import me.impy.aegis.db.slots.SlotException; +import me.impy.aegis.db.slots.SlotList; +import me.impy.aegis.helpers.FingerprintHelper; import me.impy.aegis.helpers.PermissionHelper; import me.impy.aegis.importers.AegisImporter; import me.impy.aegis.importers.DatabaseImporter; import me.impy.aegis.importers.DatabaseImporterException; -import me.impy.aegis.ui.dialogs.PasswordDialogFragment; +import me.impy.aegis.ui.dialogs.Dialogs; import me.impy.aegis.ui.preferences.SwitchPreference; import me.impy.aegis.util.ByteInputStream; -public class PreferencesFragment extends PreferenceFragmentCompat implements PasswordDialogFragment.Listener { +public class PreferencesFragment extends PreferenceFragmentCompat { // activity request codes private static final int CODE_IMPORT = 0; private static final int CODE_IMPORT_DECRYPT = 1; @@ -61,6 +64,8 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas private Class _importerType; private SwitchPreference _encryptionPreference; + private SwitchPreference _fingerprintPreference; + private Preference _setPasswordPreference; private Preference _slotsPreference; @Override @@ -140,9 +145,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas @Override public boolean onPreferenceChange(Preference preference, Object newValue) { if (!_db.isEncryptionEnabled()) { - PasswordDialogFragment dialog = new PasswordDialogFragment(); - // TODO: find a less ugly way to obtain the fragment manager - dialog.show(getActivity().getSupportFragmentManager(), null); + Dialogs.showSetPasswordDialog(getActivity(), new EnableEncryptionListener()); } else { new AlertDialog.Builder(getActivity()) .setTitle(getString(R.string.disable_encryption)) @@ -154,7 +157,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas } catch (DatabaseManagerException e) { Toast.makeText(getActivity(), getString(R.string.encrypting_error), Toast.LENGTH_SHORT).show(); } - updateEncryptionPreference(); + updateEncryptionPreferences(); } }) .setNegativeButton(android.R.string.no, null) @@ -164,20 +167,37 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas } }); - Preference setPasswordPreference = findPreference("pref_password"); - setPasswordPreference.setOnPreferenceClickListener(preference -> { - PasswordDialogFragment dialog = new PasswordDialogFragment(); - // TODO: find a less ugly way to obtain the fragment manager - dialog.show(getActivity().getSupportFragmentManager(), null); + _fingerprintPreference = (SwitchPreference) findPreference("pref_fingerprint"); + _fingerprintPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + DatabaseFileCredentials creds = _db.getCredentials(); + SlotList slots = creds.getSlots(); + + if (!slots.has(FingerprintSlot.class)) { + Dialogs.showFingerprintDialog(getActivity(), new RegisterFingerprintListener()); + } else { + // remove the fingerprint slot + FingerprintSlot slot = slots.find(FingerprintSlot.class); + slots.remove(slot); + _db.setCredentials(creds); + + saveDatabase(); + updateEncryptionPreferences(); + } + + return false; + } + }); + + _setPasswordPreference = findPreference("pref_password"); + _setPasswordPreference.setOnPreferenceClickListener(preference -> { + Dialogs.showSetPasswordDialog(getActivity(), new SetPasswordListener()); return false; }); + _slotsPreference = findPreference("pref_slots"); - if (BuildConfig.DEBUG) { - _slotsPreference.setVisible(true); - } else { - _slotsPreference.setVisible(false); - } _slotsPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { @@ -187,7 +207,8 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas return true; } }); - updateEncryptionPreference(); + + updateEncryptionPreferences(); } @Override @@ -383,6 +404,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas DatabaseFileCredentials creds = (DatabaseFileCredentials) data.getSerializableExtra("creds"); _db.setCredentials(creds); saveDatabase(); + updateEncryptionPreferences(); } private boolean saveDatabase() { @@ -396,31 +418,108 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas return true; } - @Override - public void onSlotResult(Slot slot, Cipher cipher) { - DatabaseFileCredentials creds = new DatabaseFileCredentials(); - - try { - slot.setKey(creds.getKey(), cipher); - creds.getSlots().add(slot); - _db.enableEncryption(creds); - } catch (DatabaseManagerException | SlotException e) { - onException(e); - return; - } - - updateEncryptionPreference(); - } - - @Override - public void onException(Exception e) { - updateEncryptionPreference(); - Toast.makeText(getActivity(), getString(R.string.encryption_set_password_error) + e.getMessage(), Toast.LENGTH_SHORT).show(); - } - - private void updateEncryptionPreference() { + private void updateEncryptionPreferences() { boolean encrypted = _db.isEncryptionEnabled(); _encryptionPreference.setChecked(encrypted, true); + _setPasswordPreference.setVisible(encrypted); + _fingerprintPreference.setVisible(encrypted); _slotsPreference.setEnabled(encrypted); + + if (encrypted) { + SlotList slots = _db.getCredentials().getSlots(); + boolean multiPassword = slots.findAll(PasswordSlot.class).size() > 1; + boolean multiFinger = slots.findAll(FingerprintSlot.class).size() > 1; + boolean showSlots = BuildConfig.DEBUG || multiPassword || multiFinger; + _setPasswordPreference.setEnabled(!multiPassword); + _fingerprintPreference.setEnabled(FingerprintHelper.getManager(getContext()) != null && !multiFinger); + _fingerprintPreference.setChecked(slots.has(FingerprintSlot.class), true); + _slotsPreference.setVisible(showSlots); + } else { + _setPasswordPreference.setEnabled(false); + _fingerprintPreference.setEnabled(false); + _fingerprintPreference.setChecked(false, true); + _slotsPreference.setVisible(false); + } + } + + private class SetPasswordListener implements Dialogs.SlotListener { + @Override + public void onSlotResult(Slot slot, Cipher cipher) { + DatabaseFileCredentials creds = new DatabaseFileCredentials(); + + try { + slot.setKey(creds.getKey(), cipher); + creds.getSlots().add(slot); + _db.enableEncryption(creds); + } catch (DatabaseManagerException | SlotException e) { + onException(e); + return; + } + + updateEncryptionPreferences(); + } + + @Override + public void onException(Exception e) { + updateEncryptionPreferences(); + Toast.makeText(getActivity(), getString(R.string.encryption_set_password_error) + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + + private class RegisterFingerprintListener implements Dialogs.SlotListener { + @Override + public void onSlotResult(Slot slot, Cipher cipher) { + DatabaseFileCredentials creds = _db.getCredentials(); + SlotList slots = creds.getSlots(); + + try { + slot.setKey(creds.getKey(), cipher); + } catch (SlotException e) { + onException(e); + return; + } + + slots.add(slot); + _db.setCredentials(creds); + + saveDatabase(); + updateEncryptionPreferences(); + } + + @Override + public void onException(Exception e) { + Toast.makeText(getActivity(), getString(R.string.encryption_enable_fingerprint_error) + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + + private class EnableEncryptionListener implements Dialogs.SlotListener { + @Override + public void onSlotResult(Slot slot, Cipher cipher) { + DatabaseFileCredentials creds = _db.getCredentials(); + SlotList slots = creds.getSlots(); + + try { + // encrypt the master key for this slot + slot.setKey(creds.getKey(), cipher); + + // remove the old master password slot + PasswordSlot oldSlot = creds.getSlots().find(PasswordSlot.class); + slots.remove(oldSlot); + + // add the new master password slot + slots.add(slot); + } catch (SlotException e) { + onException(e); + return; + } + + _db.setCredentials(creds); + saveDatabase(); + } + + @Override + public void onException(Exception e) { + Toast.makeText(getActivity(), getString(R.string.encryption_set_password_error) + e.getMessage(), Toast.LENGTH_SHORT).show(); + } } } diff --git a/app/src/main/java/me/impy/aegis/ui/SlotManagerActivity.java b/app/src/main/java/me/impy/aegis/ui/SlotManagerActivity.java index b6ba141a..a77b7242 100644 --- a/app/src/main/java/me/impy/aegis/ui/SlotManagerActivity.java +++ b/app/src/main/java/me/impy/aegis/ui/SlotManagerActivity.java @@ -24,11 +24,9 @@ import me.impy.aegis.db.slots.SlotList; import me.impy.aegis.db.slots.SlotException; import me.impy.aegis.helpers.FingerprintHelper; import me.impy.aegis.ui.dialogs.Dialogs; -import me.impy.aegis.ui.dialogs.FingerprintDialogFragment; import me.impy.aegis.ui.views.SlotAdapter; -import me.impy.aegis.ui.dialogs.SlotDialogFragment; -public class SlotManagerActivity extends AegisActivity implements SlotAdapter.Listener, SlotDialogFragment.Listener { +public class SlotManagerActivity extends AegisActivity implements SlotAdapter.Listener, Dialogs.SlotListener { private DatabaseFileCredentials _creds; private SlotAdapter _adapter; @@ -45,8 +43,11 @@ public class SlotManagerActivity extends AegisActivity implements SlotAdapter.Li bar.setDisplayHomeAsUpEnabled(true); findViewById(R.id.button_add_fingerprint).setOnClickListener(view -> { - FingerprintDialogFragment dialog = new FingerprintDialogFragment(); - dialog.show(getSupportFragmentManager(), null); + Dialogs.showFingerprintDialog(this ,this); + }); + + findViewById(R.id.button_add_password).setOnClickListener(view -> { + Dialogs.showSetPasswordDialog(this, this); }); // set up the recycler view diff --git a/app/src/main/java/me/impy/aegis/ui/dialogs/Dialogs.java b/app/src/main/java/me/impy/aegis/ui/dialogs/Dialogs.java index d1459c8d..117fac27 100644 --- a/app/src/main/java/me/impy/aegis/ui/dialogs/Dialogs.java +++ b/app/src/main/java/me/impy/aegis/ui/dialogs/Dialogs.java @@ -2,17 +2,40 @@ package me.impy.aegis.ui.dialogs; import android.app.Activity; import android.content.DialogInterface; +import android.hardware.fingerprint.FingerprintManager; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; + +import com.mattprecious.swirl.SwirlView; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; + import androidx.appcompat.app.AlertDialog; import me.impy.aegis.R; +import me.impy.aegis.crypto.KeyStoreHandle; +import me.impy.aegis.crypto.KeyStoreHandleException; +import me.impy.aegis.db.slots.FingerprintSlot; +import me.impy.aegis.db.slots.PasswordSlot; +import me.impy.aegis.db.slots.Slot; +import me.impy.aegis.db.slots.SlotException; +import me.impy.aegis.helpers.EditTextHelper; +import me.impy.aegis.helpers.FingerprintHelper; +import me.impy.aegis.helpers.FingerprintUiHelper; +import me.impy.aegis.ui.tasks.DerivationTask; public class Dialogs { private Dialogs() { } - public static AlertDialog showDeleteEntryDialog(Activity activity, DialogInterface.OnClickListener onDelete) { - return new AlertDialog.Builder(activity) + public static void showDeleteEntryDialog(Activity activity, DialogInterface.OnClickListener onDelete) { + new AlertDialog.Builder(activity) .setTitle(activity.getString(R.string.delete_entry)) .setMessage(activity.getString(R.string.delete_entry_description)) .setPositiveButton(android.R.string.yes, onDelete) @@ -20,12 +43,115 @@ public class Dialogs { .show(); } - public static AlertDialog showDiscardDialog(Activity activity, DialogInterface.OnClickListener onSave, DialogInterface.OnClickListener onDiscard) { - return new AlertDialog.Builder(activity) + public static void showDiscardDialog(Activity activity, DialogInterface.OnClickListener onSave, DialogInterface.OnClickListener onDiscard) { + new AlertDialog.Builder(activity) .setTitle(activity.getString(R.string.discard_changes)) .setMessage(activity.getString(R.string.discard_changes_description)) .setPositiveButton(R.string.save, onSave) .setNegativeButton(R.string.discard, onDiscard) .show(); } + + public static void showSetPasswordDialog(Activity activity, Dialogs.SlotListener listener) { + View view = activity.getLayoutInflater().inflate(R.layout.dialog_password, null); + EditText textPassword = view.findViewById(R.id.text_password); + EditText textPasswordConfirm = view.findViewById(R.id.text_password_confirm); + + AlertDialog alert = new AlertDialog.Builder(activity) + .setTitle(R.string.set_password) + .setView(view) + .setPositiveButton(android.R.string.ok, null) + .setNegativeButton(android.R.string.cancel, null) + .create(); + + final Button[] buttonOK = new Button[1]; + alert.setOnShowListener(dialog -> { + buttonOK[0] = alert.getButton(AlertDialog.BUTTON_POSITIVE); + buttonOK[0].setEnabled(false); + + // replace the default listener + buttonOK[0].setOnClickListener(v -> { + if (!EditTextHelper.areEditTextsEqual(textPassword, textPasswordConfirm)) { + return; + } + + char[] password = EditTextHelper.getEditTextChars(textPassword); + PasswordSlot slot = new PasswordSlot(); + DerivationTask task = new DerivationTask(activity, key -> { + Cipher cipher; + try { + cipher = Slot.createEncryptCipher(key); + } catch (SlotException e) { + listener.onException(e); + dialog.cancel(); + return; + } + listener.onSlotResult(slot, cipher); + dialog.dismiss(); + }); + task.execute(new DerivationTask.Params(slot, password)); + }); + }); + + TextWatcher watcher = new TextWatcher() { + public void onTextChanged(CharSequence c, int start, int before, int count) { + boolean equal = EditTextHelper.areEditTextsEqual(textPassword, textPasswordConfirm); + buttonOK[0].setEnabled(equal); + } + public void beforeTextChanged(CharSequence c, int start, int count, int after) { } + public void afterTextChanged(Editable c) { } + }; + textPassword.addTextChangedListener(watcher); + textPasswordConfirm.addTextChangedListener(watcher); + + alert.show(); + } + + public static void showFingerprintDialog(Activity activity, Dialogs.SlotListener listener) { + View view = activity.getLayoutInflater().inflate(R.layout.dialog_fingerprint, null); + TextView textFingerprint = view.findViewById(R.id.text_fingerprint); + SwirlView imgFingerprint = view.findViewById(R.id.img_fingerprint); + + Cipher cipher; + FingerprintSlot slot; + final FingerprintUiHelper[] helper = new FingerprintUiHelper[1]; + FingerprintManager manager = FingerprintHelper.getManager(activity); + + try { + slot = new FingerprintSlot(); + SecretKey key = new KeyStoreHandle().generateKey(slot.getUUID().toString()); + cipher = Slot.createEncryptCipher(key); + } catch (KeyStoreHandleException | SlotException e) { + throw new RuntimeException(e); + } + + AlertDialog dialog = new AlertDialog.Builder(activity) + .setTitle(R.string.register_fingerprint) + .setView(view) + .setNegativeButton(android.R.string.cancel, null) + .setOnDismissListener(d -> { + helper[0].stopListening(); + }) + .show(); + + helper[0] = new FingerprintUiHelper(manager, imgFingerprint, textFingerprint, new FingerprintUiHelper.Callback() { + @Override + public void onAuthenticated() { + listener.onSlotResult(slot, cipher); + dialog.dismiss(); + } + + @Override + public void onError() { + + } + }); + + helper[0].startListening(new FingerprintManager.CryptoObject(cipher)); + } + + public interface SlotListener { + void onSlotResult(Slot slot, Cipher cipher); + void onException(Exception e); + } } diff --git a/app/src/main/java/me/impy/aegis/ui/dialogs/FingerprintDialogFragment.java b/app/src/main/java/me/impy/aegis/ui/dialogs/FingerprintDialogFragment.java deleted file mode 100644 index ff5b8a7b..00000000 --- a/app/src/main/java/me/impy/aegis/ui/dialogs/FingerprintDialogFragment.java +++ /dev/null @@ -1,82 +0,0 @@ -package me.impy.aegis.ui.dialogs; - -import android.app.Dialog; -import android.hardware.fingerprint.FingerprintManager; -import android.os.Bundle; -import androidx.appcompat.app.AlertDialog; -import androidx.annotation.NonNull; -import android.view.View; -import android.widget.TextView; - -import com.mattprecious.swirl.SwirlView; - -import javax.crypto.Cipher; -import javax.crypto.SecretKey; - -import me.impy.aegis.R; -import me.impy.aegis.crypto.KeyStoreHandle; -import me.impy.aegis.crypto.KeyStoreHandleException; -import me.impy.aegis.db.slots.FingerprintSlot; -import me.impy.aegis.db.slots.Slot; -import me.impy.aegis.db.slots.SlotException; -import me.impy.aegis.helpers.FingerprintHelper; -import me.impy.aegis.helpers.FingerprintUiHelper; - -public class FingerprintDialogFragment extends SlotDialogFragment implements FingerprintUiHelper.Callback { - private Cipher _cipher; - private FingerprintUiHelper _helper; - private FingerprintSlot _slot; - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_fingerprint, null); - TextView textFingerprint = view.findViewById(R.id.text_fingerprint); - SwirlView imgFingerprint = view.findViewById(R.id.img_fingerprint); - - FingerprintManager manager = FingerprintHelper.getManager(getContext()); - try { - _slot = new FingerprintSlot(); - SecretKey key = new KeyStoreHandle().generateKey(_slot.getUUID().toString()); - _cipher = Slot.createEncryptCipher(key); - _helper = new FingerprintUiHelper(manager, imgFingerprint, textFingerprint, this); - } catch (KeyStoreHandleException | SlotException e) { - throw new RuntimeException(e); - } - - return new AlertDialog.Builder(getActivity()) - .setTitle(R.string.register_fingerprint) - .setView(view) - .setNegativeButton(android.R.string.cancel, null) - .create(); - } - - @Override - public void onResume() { - super.onResume(); - - if (_helper != null) { - _helper.startListening(new FingerprintManager.CryptoObject(_cipher)); - } - } - - @Override - public void onPause() { - super.onPause(); - - if (_helper != null) { - _helper.stopListening(); - } - } - - @Override - public void onAuthenticated() { - getListener().onSlotResult(_slot, _cipher); - dismiss(); - } - - @Override - public void onError() { - - } -} diff --git a/app/src/main/java/me/impy/aegis/ui/dialogs/PasswordDialogFragment.java b/app/src/main/java/me/impy/aegis/ui/dialogs/PasswordDialogFragment.java deleted file mode 100644 index d2d72462..00000000 --- a/app/src/main/java/me/impy/aegis/ui/dialogs/PasswordDialogFragment.java +++ /dev/null @@ -1,80 +0,0 @@ -package me.impy.aegis.ui.dialogs; - -import android.app.Dialog; -import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; -import android.text.Editable; -import android.text.TextWatcher; -import android.view.View; -import android.widget.Button; -import android.widget.EditText; - -import javax.crypto.Cipher; - -import me.impy.aegis.R; -import me.impy.aegis.db.slots.PasswordSlot; -import me.impy.aegis.db.slots.Slot; -import me.impy.aegis.db.slots.SlotException; -import me.impy.aegis.helpers.EditTextHelper; -import me.impy.aegis.ui.tasks.DerivationTask; - -public class PasswordDialogFragment extends SlotDialogFragment { - private Button _buttonOK; - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_password, null); - EditText textPassword = view.findViewById(R.id.text_password); - EditText textPasswordConfirm = view.findViewById(R.id.text_password_confirm); - - AlertDialog alert = new AlertDialog.Builder(getActivity()) - .setTitle(R.string.set_password) - .setView(view) - .setPositiveButton(android.R.string.ok, null) - .setNegativeButton(android.R.string.cancel, null) - .create(); - - alert.setOnShowListener(dialog -> { - _buttonOK = alert.getButton(AlertDialog.BUTTON_POSITIVE); - _buttonOK.setEnabled(false); - - // replace the default listener - _buttonOK.setOnClickListener(v -> { - if (!EditTextHelper.areEditTextsEqual(textPassword, textPasswordConfirm)) { - return; - } - - char[] password = EditTextHelper.getEditTextChars(textPassword); - PasswordSlot slot = new PasswordSlot(); - DerivationTask task = new DerivationTask(getActivity(), key -> { - Cipher cipher; - try { - cipher = Slot.createEncryptCipher(key); - } catch (SlotException e) { - getListener().onException(e); - dialog.cancel(); - return; - } - getListener().onSlotResult(slot, cipher); - dialog.dismiss(); - }); - task.execute(new DerivationTask.Params(slot, password)); - }); - }); - - TextWatcher watcher = new TextWatcher() { - public void onTextChanged(CharSequence c, int start, int before, int count) { - boolean equal = EditTextHelper.areEditTextsEqual(textPassword, textPasswordConfirm); - _buttonOK.setEnabled(equal); - } - public void beforeTextChanged(CharSequence c, int start, int count, int after) { } - public void afterTextChanged(Editable c) { } - }; - textPassword.addTextChangedListener(watcher); - textPasswordConfirm.addTextChangedListener(watcher); - - return alert; - } -} diff --git a/app/src/main/java/me/impy/aegis/ui/dialogs/SlotDialogFragment.java b/app/src/main/java/me/impy/aegis/ui/dialogs/SlotDialogFragment.java deleted file mode 100644 index f7b41251..00000000 --- a/app/src/main/java/me/impy/aegis/ui/dialogs/SlotDialogFragment.java +++ /dev/null @@ -1,32 +0,0 @@ -package me.impy.aegis.ui.dialogs; - -import android.content.Context; -import androidx.fragment.app.DialogFragment; - -import javax.crypto.Cipher; - -import me.impy.aegis.db.slots.Slot; - -public class SlotDialogFragment extends DialogFragment { - private Listener _listener; - - protected Listener getListener() { - return _listener; - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - - try { - _listener = (Listener) context; - } catch (ClassCastException e) { - throw new ClassCastException(context.toString() + " must implement SlotDialogFragment.Listener"); - } - } - - public interface Listener { - void onSlotResult(Slot slot, Cipher cipher); - void onException(Exception e); - } -} diff --git a/app/src/main/res/layout/activity_slots.xml b/app/src/main/res/layout/activity_slots.xml index 9d8d18d2..0b5c136b 100644 --- a/app/src/main/res/layout/activity_slots.xml +++ b/app/src/main/res/layout/activity_slots.xml @@ -25,6 +25,34 @@ android:layout_height="wrap_content" android:scrollbars="vertical"/> + + + + + + + Block screenshots and other attempts to capture the screen within the app Encryption Encrypt the database and unlock it with a password or fingerprint + Fingerprint + Allow fingerprints registered on this device to unlock the vault Change password Set a new password which you will need to unlock your vault @@ -81,6 +83,7 @@ Scan QR code Enter manually Add fingerprint + Add password The vault is only as secure as your weakest secret. When a new fingerprint is added to your device, you will to reactivate fingerprint authentication within Aegis. Copy Edit @@ -122,7 +125,8 @@ An error occurred while trying to export the database The database has been exported to: This action will export the database out of Aegis\' private storage. - An error occurred while trying to set the password: + An error occurred while trying to set the password: + An error occurred while trying to enable fingerprint unlock: No cameras available An error occurred while trying to read the QR code Raw diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index e9d626fb..cd846caf 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -53,6 +53,13 @@ android:dependency="pref_encryption" app:iconSpaceReserved="false"/> + +