From 2733834df005637722b26446f8dd3fe0ab2868b1 Mon Sep 17 00:00:00 2001 From: MrLetsplay Date: Mon, 18 Sep 2023 16:56:34 +0200 Subject: [PATCH] Unlock UI --- .idea/deploymentTargetDropDown.xml | 17 +++ app/src/main/AndroidManifest.xml | 9 +- .../cringe_authenticator/BaseActivity.java | 37 ++++++ .../cringe_authenticator/IntroActivity.java | 3 +- .../cringe_authenticator/MainActivity.java | 62 +-------- .../fragment/GroupFragment.java | 59 +++++---- .../fragment/SettingsFragment.java | 1 + .../otplist/OTPListAdapter.java | 2 + .../unlock/UnlockActivity.java | 123 ++++++++++++++++++ .../unlock/UnlockContract.java | 25 ++++ .../urihandler/URIHandlerActivity.java | 19 +-- .../cringe_authenticator/util/FabUtil.java | 16 +-- .../util/OTPDatabase.java | 16 ++- app/src/main/res/drawable/fingerprint.xml | 9 ++ app/src/main/res/layout/activity_main.xml | 2 +- app/src/main/res/layout/activity_unlock.xml | 65 +++++++++ app/src/main/res/layout/fragment_about.xml | 7 +- app/src/main/res/layout/fragment_group.xml | 7 + app/src/main/res/layout/fragment_home.xml | 2 +- 19 files changed, 371 insertions(+), 110 deletions(-) create mode 100644 .idea/deploymentTargetDropDown.xml create mode 100644 app/src/main/java/com/cringe_studios/cringe_authenticator/BaseActivity.java create mode 100644 app/src/main/java/com/cringe_studios/cringe_authenticator/unlock/UnlockActivity.java create mode 100644 app/src/main/java/com/cringe_studios/cringe_authenticator/unlock/UnlockContract.java create mode 100644 app/src/main/res/drawable/fingerprint.xml create mode 100644 app/src/main/res/layout/activity_unlock.xml diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml new file mode 100644 index 0000000..9c70fc5 --- /dev/null +++ b/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 82d44dd..f7ee53f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -36,8 +36,13 @@ android:theme="@style/Theme.CringeAuthenticator.None" android:configChanges="orientation|screenSize"> + + @@ -47,7 +52,7 @@ - + diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/BaseActivity.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/BaseActivity.java new file mode 100644 index 0000000..88c5b9f --- /dev/null +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/BaseActivity.java @@ -0,0 +1,37 @@ +package com.cringe_studios.cringe_authenticator; + +import android.os.Bundle; +import android.util.Log; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import com.cringe_studios.cringe_authenticator.unlock.UnlockContract; + +public class BaseActivity extends AppCompatActivity { + + private ActivityResultLauncher startUnlockActivity; + + private Runnable unlockSuccess, unlockFailure; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + registerCallbacks(); + } + + private void registerCallbacks() { + startUnlockActivity = registerForActivityResult(new UnlockContract(), success -> { + if(success && unlockSuccess != null) unlockSuccess.run(); + if(!success && unlockFailure != null) unlockFailure.run(); + }); + } + + public void promptUnlock(Runnable success, Runnable failure) { + unlockSuccess = success; + unlockFailure = failure; + startUnlockActivity.launch(null); + } + +} diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/IntroActivity.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/IntroActivity.java index d719313..52430b4 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/IntroActivity.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/IntroActivity.java @@ -10,6 +10,7 @@ import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import com.cringe_studios.cringe_authenticator.databinding.ActivityIntroBinding; +import com.cringe_studios.cringe_authenticator.unlock.UnlockActivity; import com.cringe_studios.cringe_authenticator.util.SettingsUtil; public class IntroActivity extends AppCompatActivity { @@ -50,7 +51,7 @@ public class IntroActivity extends AppCompatActivity { } public void openMainActivity() { - Intent m = new Intent(getApplicationContext(), MainActivity.class); + Intent m = new Intent(getApplicationContext(), UnlockActivity.class); m.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION); startActivity(m); finish(); diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/MainActivity.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/MainActivity.java index f1a393a..e6d736d 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/MainActivity.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/MainActivity.java @@ -1,12 +1,7 @@ package com.cringe_studios.cringe_authenticator; -import static androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG; -import static androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL; - import android.content.res.Configuration; import android.os.Bundle; -import android.security.keystore.KeyProtection; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -19,13 +14,8 @@ import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; -import androidx.biometric.BiometricManager; -import androidx.biometric.BiometricPrompt; -import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; -import com.cringe_studios.cringe_authenticator.crypto.Crypto; -import com.cringe_studios.cringe_authenticator.crypto.CryptoException; import com.cringe_studios.cringe_authenticator.databinding.ActivityMainBinding; import com.cringe_studios.cringe_authenticator.databinding.DialogInputCodeChoiceBinding; import com.cringe_studios.cringe_authenticator.fragment.AboutFragment; @@ -44,25 +34,9 @@ import com.cringe_studios.cringe_authenticator.util.StyledDialogBuilder; import com.cringe_studios.cringe_authenticator.util.ThemeUtil; import com.cringe_studios.cringe_authenticator_library.OTPType; -import org.bouncycastle.crypto.generators.Argon2BytesGenerator; -import org.bouncycastle.crypto.params.Argon2Parameters; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.cert.CertificateException; -import java.util.Arrays; import java.util.Locale; -import java.util.concurrent.Executor; -import javax.crypto.SecretKey; - -public class MainActivity extends AppCompatActivity { - - private static final long LOCK_TIMEOUT = 10000; +public class MainActivity extends BaseActivity { private ActivityMainBinding binding; @@ -95,37 +69,7 @@ public class MainActivity extends AppCompatActivity { setLocale(SettingsUtil.getLocale(this)); - OTPDatabase.promptLoadDatabase(this, () -> { - launchApp(); - }, () -> finishAffinity()); - - /*Executor executor = ContextCompat.getMainExecutor(this); - BiometricPrompt prompt = new BiometricPrompt(this, executor, new BiometricPrompt.AuthenticationCallback() { - @Override - public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) { - finishAffinity(); - } - - @Override - public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) { - launchApp(); - } - }); - - boolean supportsBiometricAuth = BiometricManager.from(this).canAuthenticate(BIOMETRIC_STRONG | DEVICE_CREDENTIAL) == BiometricManager.BIOMETRIC_SUCCESS; - boolean recentlyUnlocked = savedInstanceState != null && (System.currentTimeMillis() - savedInstanceState.getLong("pauseTime", 0L) < LOCK_TIMEOUT); - - if(!recentlyUnlocked && SettingsUtil.isBiometricLock(this) && supportsBiometricAuth) { - BiometricPrompt.PromptInfo info = new BiometricPrompt.PromptInfo.Builder() - .setTitle(getString(R.string.app_name)) - .setSubtitle(getString(R.string.biometric_lock_subtitle)) - .setAllowedAuthenticators(BIOMETRIC_STRONG | DEVICE_CREDENTIAL) - .build(); - - prompt.authenticate(info); - }else { - launchApp(); - }*/ + OTPDatabase.promptLoadDatabase(this, this::launchApp, this::finishAffinity); startQRCodeScan = registerForActivityResult(new QRScannerContract(), obj -> { if(obj == null) return; // Cancelled @@ -160,7 +104,7 @@ public class MainActivity extends AppCompatActivity { binding.fabMenu.setOnClickListener(view -> NavigationUtil.navigate(this, MenuFragment.class, null)); binding.fabScan.setOnClickListener(view -> scanCode()); - binding.fabScanImage.setOnClickListener(view -> scanCode()); + //binding.fabScanImage.setOnClickListener(view -> scanCode()); TODO: scan image binding.fabInput.setOnClickListener(view -> inputCode()); Fragment fragment = NavigationUtil.getCurrentFragment(this); diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/GroupFragment.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/GroupFragment.java index e5ec699..704f7f2 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/GroupFragment.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/GroupFragment.java @@ -93,11 +93,16 @@ public class GroupFragment extends NamedFragment { break; case 2: DialogUtil.showChooseGroupDialog(requireContext(), group -> { - OTPDatabase.promptLoadDatabase(requireContext(), () -> { - OTPDatabase.getLoadedDatabase().addOTP(group, data); - // TODO: save - otpListAdapter.remove(data); - }, () -> DialogUtil.showErrorDialog(requireContext(), "Failed to add OTP")); + OTPDatabase.promptLoadDatabase(requireActivity(), () -> { + try { + OTPDatabase.getLoadedDatabase().addOTP(group, data); + OTPDatabase.saveDatabase(requireContext(), SettingsUtil.getCryptoParameters(requireContext())); + otpListAdapter.remove(data); + saveOTPs(); + } catch (OTPDatabaseException | CryptoException e) { + DialogUtil.showErrorDialog(requireContext(), e.toString()); + } + }, null); saveOTPs(); }, null); break; @@ -119,33 +124,37 @@ public class GroupFragment extends NamedFragment { } private void saveOTPs() { - //SettingsUtil.updateOTPs(requireContext(), groupID, otpListAdapter.getItems()); - if(OTPDatabase.getLoadedDatabase() == null) { - // TODO: prompt user - return; - } - - OTPDatabase.getLoadedDatabase().updateOTPs(groupID, otpListAdapter.getItems()); - try { - OTPDatabase.saveDatabase(requireContext(), SettingsUtil.getCryptoParameters(requireContext())); - } catch (OTPDatabaseException | CryptoException e) { - DialogUtil.showErrorDialog(requireContext(), e.toString()); - } - - refreshCodes(); + OTPDatabase.promptLoadDatabase(requireActivity(), () -> { + try { + OTPDatabase.getLoadedDatabase().updateOTPs(groupID, otpListAdapter.getItems()); + OTPDatabase.saveDatabase(requireContext(), SettingsUtil.getCryptoParameters(requireContext())); + refreshCodes(); + } catch (OTPDatabaseException | CryptoException e) { + DialogUtil.showErrorDialog(requireContext(), e.toString()); + } + }, null); } private void loadOTPs() { - /*List data = SettingsUtil.getOTPs(requireContext(), groupID); TODO + OTPDatabase.promptLoadDatabase(requireActivity(), () -> { + List data = OTPDatabase.getLoadedDatabase().getOTPs(groupID); - for(OTPData otp : data) { - otpListAdapter.add(otp); - }*/ + for(OTPData otp : data) { + otpListAdapter.add(otp); + } + }, null); } public void addOTP(OTPData data) { - //SettingsUtil.addOTP(requireContext(), groupID, data); TODO - otpListAdapter.add(data); + OTPDatabase.promptLoadDatabase(requireActivity(), () -> { + try { + OTPDatabase.getLoadedDatabase().addOTP(groupID, data); + OTPDatabase.saveDatabase(requireContext(), SettingsUtil.getCryptoParameters(requireContext())); + otpListAdapter.add(data); + } catch (OTPDatabaseException | CryptoException e) { + DialogUtil.showErrorDialog(requireContext(), "Failed to save database: " + e); + } + }, null); } public void refreshCodes() { diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/SettingsFragment.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/SettingsFragment.java index 436b2ef..58b452b 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/SettingsFragment.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/SettingsFragment.java @@ -71,6 +71,7 @@ public class SettingsFragment extends NamedFragment { } }); + binding.settingsEnableEncryption.setChecked(SettingsUtil.isDatabaseEncrypted(requireContext())); binding.settingsEnableEncryption.setOnCheckedChangeListener((view, checked) -> { if(!OTPDatabase.isDatabaseLoaded()) { // TODO: prompt user diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/otplist/OTPListAdapter.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/otplist/OTPListAdapter.java index 7978a27..cd6f801 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/otplist/OTPListAdapter.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/otplist/OTPListAdapter.java @@ -3,6 +3,7 @@ package com.cringe_studios.cringe_authenticator.otplist; import android.content.Context; import android.os.Handler; import android.os.Looper; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -58,6 +59,7 @@ public class OTPListAdapter extends RecyclerView.Adapter { holder.getBinding().progress.setVisibility(data.getType() == OTPType.TOTP ? View.VISIBLE : View.INVISIBLE); holder.getBinding().getRoot().setOnClickListener(view -> { + Log.i("CLICKED", "CLICKED: " + view.isClickable()); if(data.getType() != OTPType.HOTP) return; // Click delay for HOTP diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/unlock/UnlockActivity.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/unlock/UnlockActivity.java new file mode 100644 index 0000000..4359af8 --- /dev/null +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/unlock/UnlockActivity.java @@ -0,0 +1,123 @@ +package com.cringe_studios.cringe_authenticator.unlock; + +import static androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG; +import static androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL; + +import android.content.Intent; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.biometric.BiometricManager; +import androidx.biometric.BiometricPrompt; +import androidx.core.content.ContextCompat; + +import com.cringe_studios.cringe_authenticator.MainActivity; +import com.cringe_studios.cringe_authenticator.R; +import com.cringe_studios.cringe_authenticator.crypto.Crypto; +import com.cringe_studios.cringe_authenticator.crypto.CryptoException; +import com.cringe_studios.cringe_authenticator.databinding.ActivityUnlockBinding; +import com.cringe_studios.cringe_authenticator.util.DialogUtil; +import com.cringe_studios.cringe_authenticator.util.OTPDatabase; +import com.cringe_studios.cringe_authenticator.util.OTPDatabaseException; +import com.cringe_studios.cringe_authenticator.util.SettingsUtil; +import com.cringe_studios.cringe_authenticator.util.ThemeUtil; + +import java.util.concurrent.Executor; + +import javax.crypto.SecretKey; + +public class UnlockActivity extends AppCompatActivity { + + private static final long LOCK_TIMEOUT = 10000; + + private ActivityUnlockBinding binding; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ThemeUtil.loadTheme(this); + + if(!SettingsUtil.isDatabaseEncrypted(this)) { + launchApp(); + return; + } + + binding = ActivityUnlockBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + + if(SettingsUtil.isBiometricLock(this)) { + Executor executor = ContextCompat.getMainExecutor(this); + BiometricPrompt prompt = new BiometricPrompt(this, executor, new BiometricPrompt.AuthenticationCallback() { + @Override + public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) { + //finishAffinity(); + } + + @Override + public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) { + launchApp(); + } + }); + + boolean supportsBiometricAuth = BiometricManager.from(this).canAuthenticate(BIOMETRIC_STRONG | DEVICE_CREDENTIAL) == BiometricManager.BIOMETRIC_SUCCESS; + boolean recentlyUnlocked = savedInstanceState != null && (System.currentTimeMillis() - savedInstanceState.getLong("pauseTime", 0L) < LOCK_TIMEOUT); + + if(!recentlyUnlocked && SettingsUtil.isBiometricLock(this) && supportsBiometricAuth) { + BiometricPrompt.PromptInfo info = new BiometricPrompt.PromptInfo.Builder() + .setTitle(getString(R.string.app_name)) + .setSubtitle(getString(R.string.biometric_lock_subtitle)) + .setAllowedAuthenticators(BIOMETRIC_STRONG | DEVICE_CREDENTIAL) + .build(); + + //prompt.authenticate(info); + + binding.unlockBiometrics.setOnClickListener(view -> { + //prompt.authenticate(info); + }); + }else { + launchApp(); + } + } + + binding.unlockButton.setOnClickListener(view -> { + if(binding.unlockPassword.getText().length() == 0) { + DialogUtil.showErrorDialog(this, "You need to enter a password"); + return; + } + + String password = binding.unlockPassword.getText().toString(); + + try { + SecretKey key = Crypto.generateKey(SettingsUtil.getCryptoParameters(this), password); + OTPDatabase.loadDatabase(this, key); + launchApp(); + }catch(CryptoException e) { + DialogUtil.showErrorDialog(this, "Failed to load database: Invalid password or database corrupted", this::failure); + } catch (OTPDatabaseException e) { + DialogUtil.showErrorDialog(this, "Failed to load database: " + e, this::failure); + } + }); + } + + private void launchApp() { + if(getIntent() != null && getIntent().hasExtra("contract")) { + setResult(RESULT_OK); + finish(); + return; + } + + Intent m = new Intent(getApplicationContext(), MainActivity.class); + m.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION); + startActivity(m); + finish(); + } + + private void failure() { + setResult(RESULT_CANCELED); + finish(); + } + +} diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/unlock/UnlockContract.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/unlock/UnlockContract.java new file mode 100644 index 0000000..8485fb8 --- /dev/null +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/unlock/UnlockContract.java @@ -0,0 +1,25 @@ +package com.cringe_studios.cringe_authenticator.unlock; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; + +import androidx.activity.result.contract.ActivityResultContract; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.cringe_studios.cringe_authenticator.scanner.QRScannerActivity; +import com.cringe_studios.cringe_authenticator.scanner.ScannerResult; + +public class UnlockContract extends ActivityResultContract { + @NonNull + @Override + public Intent createIntent(@NonNull Context context, Void unused) { + return new Intent(context, UnlockActivity.class).putExtra("contract", true); + } + + @Override + public Boolean parseResult(int i, @Nullable Intent intent) { + return i == Activity.RESULT_OK; + } +} diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/urihandler/URIHandlerActivity.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/urihandler/URIHandlerActivity.java index d1c1f4f..4bc8191 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/urihandler/URIHandlerActivity.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/urihandler/URIHandlerActivity.java @@ -3,15 +3,18 @@ package com.cringe_studios.cringe_authenticator.urihandler; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.util.Log; import android.widget.Toast; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; +import com.cringe_studios.cringe_authenticator.BaseActivity; import com.cringe_studios.cringe_authenticator.R; import com.cringe_studios.cringe_authenticator.crypto.CryptoException; import com.cringe_studios.cringe_authenticator.model.OTPData; +import com.cringe_studios.cringe_authenticator.unlock.UnlockContract; import com.cringe_studios.cringe_authenticator.util.DialogUtil; import com.cringe_studios.cringe_authenticator.util.OTPDatabase; import com.cringe_studios.cringe_authenticator.util.OTPDatabaseException; @@ -20,7 +23,7 @@ import com.cringe_studios.cringe_authenticator.util.SettingsUtil; import com.cringe_studios.cringe_authenticator.util.StyledDialogBuilder; import com.cringe_studios.cringe_authenticator.util.ThemeUtil; -public class URIHandlerActivity extends AppCompatActivity { +public class URIHandlerActivity extends BaseActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -63,19 +66,19 @@ public class URIHandlerActivity extends AppCompatActivity { } private void importCodes(OTPData... data) { - DialogUtil.showChooseGroupDialog(this, group -> { - for(OTPData d : data) { - OTPDatabase.promptLoadDatabase(this, () -> { + OTPDatabase.promptLoadDatabase(this, () -> { + DialogUtil.showChooseGroupDialog(this, group -> { + for(OTPData d : data) { OTPDatabase.getLoadedDatabase().addOTP(group, d); try { OTPDatabase.saveDatabase(this, SettingsUtil.getCryptoParameters(this)); } catch (OTPDatabaseException | CryptoException e) { DialogUtil.showErrorDialog(this, e.toString()); } - }, () -> finishAffinity()); - } - Toast.makeText(this, R.string.uri_handler_code_added, Toast.LENGTH_SHORT).show(); - }, this::finishAndRemoveTask); + } + Toast.makeText(this, R.string.uri_handler_code_added, Toast.LENGTH_SHORT).show(); + }, this::finishAndRemoveTask); + }, null); } } diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/util/FabUtil.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/util/FabUtil.java index 0862e57..e3c5342 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/util/FabUtil.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/util/FabUtil.java @@ -9,18 +9,18 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton; public class FabUtil { public static void showFabs(Activity activity) { - FloatingActionButton fabScan = activity.findViewById(R.id.fab_scan); - if(fabScan != null) { - fabScan.setVisibility(View.VISIBLE); - fabScan.setClickable(true); - fabScan.animate().translationX(-activity.getResources().getDimension(R.dimen.fab1_offset)); - } - FloatingActionButton fabScanImage = activity.findViewById(R.id.fab_scan_image); if(fabScanImage != null) { fabScanImage.setVisibility(View.VISIBLE); fabScanImage.setClickable(true); - fabScanImage.animate().translationX(-activity.getResources().getDimension(R.dimen.fab2_offset)); + fabScanImage.animate().translationX(-activity.getResources().getDimension(R.dimen.fab1_offset)); + } + + FloatingActionButton fabScan = activity.findViewById(R.id.fab_scan); + if(fabScan != null) { + fabScan.setVisibility(View.VISIBLE); + fabScan.setClickable(true); + fabScan.animate().translationX(-activity.getResources().getDimension(R.dimen.fab2_offset)); } FloatingActionButton fabInput = activity.findViewById(R.id.fab_input); diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/util/OTPDatabase.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/util/OTPDatabase.java index 52be296..a6cbc6e 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/util/OTPDatabase.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/util/OTPDatabase.java @@ -1,13 +1,18 @@ package com.cringe_studios.cringe_authenticator.util; +import android.app.Activity; import android.content.Context; +import android.util.Log; +import androidx.appcompat.app.AppCompatActivity; import androidx.core.util.Consumer; +import com.cringe_studios.cringe_authenticator.BaseActivity; import com.cringe_studios.cringe_authenticator.crypto.Crypto; import com.cringe_studios.cringe_authenticator.crypto.CryptoException; import com.cringe_studios.cringe_authenticator.crypto.CryptoParameters; import com.cringe_studios.cringe_authenticator.model.OTPData; +import com.cringe_studios.cringe_authenticator.unlock.UnlockContract; import com.google.gson.JsonObject; import com.google.gson.JsonSyntaxException; @@ -60,12 +65,16 @@ public class OTPDatabase { otps.remove(groupId); } - public static void promptLoadDatabase(Context ctx, Runnable success, Runnable failure) { + public static void promptLoadDatabase(Activity ctx, Runnable success, Runnable failure) { if(isDatabaseLoaded()) { success.run(); return; } + if(!(ctx instanceof BaseActivity)) { + throw new RuntimeException("NOT BASEACTIVITY"); + } + if(!SettingsUtil.isDatabaseEncrypted(ctx)) { try { loadDatabase(ctx, null); @@ -76,7 +85,7 @@ public class OTPDatabase { return; } - DialogUtil.showInputPasswordDialog(ctx, password -> { + /*DialogUtil.showInputPasswordDialog(ctx, password -> { try { SecretKey key = Crypto.generateKey(SettingsUtil.getCryptoParameters(ctx), password); loadDatabase(ctx, key); @@ -86,7 +95,8 @@ public class OTPDatabase { } catch (OTPDatabaseException e) { DialogUtil.showErrorDialog(ctx, "Failed to load database: " + e, failure); } - }, failure); + }, failure);*/ + ((BaseActivity) ctx).promptUnlock(success, failure); } public static OTPDatabase loadDatabase(Context context, SecretKey key) throws OTPDatabaseException, CryptoException { diff --git a/app/src/main/res/drawable/fingerprint.xml b/app/src/main/res/drawable/fingerprint.xml new file mode 100644 index 0000000..a6b290b --- /dev/null +++ b/app/src/main/res/drawable/fingerprint.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 822f3b4..c00956a 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -54,7 +54,7 @@ android:layout_marginBottom="16dp" android:backgroundTint="?attr/colorTheme1" android:visibility="gone" - app:srcCompat="@drawable/baseline_qr_code_scanner_24" + app:srcCompat="@drawable/baseline_settings_24" app:tint="@color/white" /> + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml index d230d9c..92d1be6 100644 --- a/app/src/main/res/layout/fragment_about.xml +++ b/app/src/main/res/layout/fragment_about.xml @@ -3,6 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + xmlns:app="http://schemas.android.com/apk/res-auto" tools:context=".fragment.HomeFragment"> + android:src="@drawable/ic_hamburger" + app:tint="?android:attr/textColorPrimary" /> + android:src="@drawable/ic_hamburger" + app:tint="?android:attr/textColorPrimary" /> + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 0b6c590..db74851 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -12,7 +12,7 @@ android:padding="16dp">