From 97ab31301e99f9ae7a2ca371b0e92c9cac9e7103 Mon Sep 17 00:00:00 2001 From: Shihaam Abdul Rahman Date: Fri, 15 May 2026 03:36:20 +0500 Subject: [PATCH] add lock timer poup to dismiss lock --- .../sh/sar/basedbank/ui/home/HomeActivity.kt | 52 ++++++++++++++++++- .../sar/basedbank/ui/home/SettingsFragment.kt | 7 ++- .../ui/onboarding/SecuritySetupFragment.kt | 5 ++ app/src/main/res/values/strings.xml | 4 ++ 4 files changed, 65 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/sh/sar/basedbank/ui/home/HomeActivity.kt b/app/src/main/java/sh/sar/basedbank/ui/home/HomeActivity.kt index 04631c9..9ca43e7 100644 --- a/app/src/main/java/sh/sar/basedbank/ui/home/HomeActivity.kt +++ b/app/src/main/java/sh/sar/basedbank/ui/home/HomeActivity.kt @@ -2,12 +2,15 @@ package sh.sar.basedbank.ui.home import android.content.Intent import android.os.Bundle +import android.os.CountDownTimer import android.os.Handler import android.os.Looper import android.view.Menu import android.view.MenuItem import android.view.View import android.widget.Toast +import androidx.appcompat.app.AlertDialog +import com.google.android.material.dialog.MaterialAlertDialogBuilder import androidx.activity.viewModels import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.AppCompatActivity @@ -45,7 +48,14 @@ class HomeActivity : AppCompatActivity() { private val viewModel: HomeViewModel by viewModels() private val autolockHandler = Handler(Looper.getMainLooper()) + private var warningDialog: AlertDialog? = null + private var countdownTimer: CountDownTimer? = null + + private val warningRunnable = Runnable { showAutolockWarning() } + private val autolockRunnable = Runnable { + countdownTimer?.cancel(); countdownTimer = null + warningDialog?.dismiss(); warningDialog = null val securitySet = getSharedPreferences("prefs", MODE_PRIVATE) .getString("security_method", null) != null if (securitySet) { @@ -153,6 +163,9 @@ class HomeActivity : AppCompatActivity() { override fun onPause() { super.onPause() autolockHandler.removeCallbacks(autolockRunnable) + autolockHandler.removeCallbacks(warningRunnable) + countdownTimer?.cancel(); countdownTimer = null + warningDialog?.dismiss(); warningDialog = null } override fun onUserInteraction() { @@ -160,11 +173,46 @@ class HomeActivity : AppCompatActivity() { resetAutolockTimer() } - private fun resetAutolockTimer() { + fun resetAutolockTimer() { autolockHandler.removeCallbacks(autolockRunnable) + autolockHandler.removeCallbacks(warningRunnable) + countdownTimer?.cancel(); countdownTimer = null + warningDialog?.dismiss(); warningDialog = null val timeout = getSharedPreferences("prefs", MODE_PRIVATE) .getLong("autolock_timeout", 60_000L) - if (timeout > 0) autolockHandler.postDelayed(autolockRunnable, timeout) + if (timeout <= 0) return + if (timeout > 10_000L) autolockHandler.postDelayed(warningRunnable, timeout - 10_000L) + autolockHandler.postDelayed(autolockRunnable, timeout) + } + + private fun showAutolockWarning() { + if (warningDialog?.isShowing == true) return + val dialog = MaterialAlertDialogBuilder(this) + .setTitle(R.string.autolock_warning_title) + .setMessage(getString(R.string.autolock_warning_message, 10)) + .setPositiveButton(R.string.autolock_stay) { _, _ -> + countdownTimer?.cancel(); countdownTimer = null + resetAutolockTimer() + } + .setNegativeButton(R.string.autolock_lock_now) { _, _ -> + countdownTimer?.cancel(); countdownTimer = null + autolockHandler.removeCallbacks(autolockRunnable) + autolockHandler.removeCallbacks(warningRunnable) + autolockRunnable.run() + } + .setCancelable(false) + .create() + warningDialog = dialog + dialog.show() + countdownTimer = object : CountDownTimer(10_000L, 1_000L) { + override fun onTick(millisUntilFinished: Long) { + val secs = ((millisUntilFinished + 999L) / 1000L).toInt() + dialog.setMessage(getString(R.string.autolock_warning_message, secs)) + } + override fun onFinish() { + dialog.setMessage(getString(R.string.autolock_warning_message, 0)) + } + }.start() } override fun onCreateOptionsMenu(menu: Menu): Boolean { diff --git a/app/src/main/java/sh/sar/basedbank/ui/home/SettingsFragment.kt b/app/src/main/java/sh/sar/basedbank/ui/home/SettingsFragment.kt index fdcc173..73dcae0 100644 --- a/app/src/main/java/sh/sar/basedbank/ui/home/SettingsFragment.kt +++ b/app/src/main/java/sh/sar/basedbank/ui/home/SettingsFragment.kt @@ -79,6 +79,7 @@ class SettingsFragment : Fragment() { else -> 60_000L } prefs.edit().putLong("autolock_timeout", timeout).apply() + (activity as? HomeActivity)?.resetAutolockTimer() } // Change lock @@ -93,7 +94,6 @@ class SettingsFragment : Fragment() { .canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK) == BiometricManager.BIOMETRIC_SUCCESS if (canUseBiometrics) { binding.rowBiometrics.visibility = View.VISIBLE - binding.switchBiometrics.isChecked = prefs.getBoolean("biometrics_enabled", false) binding.switchBiometrics.setOnCheckedChangeListener { _, isChecked -> prefs.edit().putBoolean("biometrics_enabled", isChecked).apply() } @@ -103,6 +103,11 @@ class SettingsFragment : Fragment() { override fun onResume() { super.onResume() requireActivity().title = getString(R.string.nav_settings) + // Re-read biometrics pref in case it was changed by SecuritySetupFragment + val prefs = requireContext().getSharedPreferences("prefs", Context.MODE_PRIVATE) + if (binding.rowBiometrics.visibility == View.VISIBLE) { + binding.switchBiometrics.isChecked = prefs.getBoolean("biometrics_enabled", false) + } } override fun onDestroyView() { diff --git a/app/src/main/java/sh/sar/basedbank/ui/onboarding/SecuritySetupFragment.kt b/app/src/main/java/sh/sar/basedbank/ui/onboarding/SecuritySetupFragment.kt index 1ccb49b..21406e8 100644 --- a/app/src/main/java/sh/sar/basedbank/ui/onboarding/SecuritySetupFragment.kt +++ b/app/src/main/java/sh/sar/basedbank/ui/onboarding/SecuritySetupFragment.kt @@ -186,6 +186,11 @@ class SecuritySetupFragment : Fragment() { } private fun goToBiometricOrFinish() { + // In change mode, biometrics is managed from Settings — skip this step + if (arguments?.getBoolean(ARG_CHANGE_MODE, false) == true) { + finishSetup() + return + } val canAuth = BiometricManager.from(requireContext()) .canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK) if (canAuth == BiometricManager.BIOMETRIC_SUCCESS) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index db38009..db2bc93 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -84,6 +84,10 @@ Lock app + Locking soon + Locking in %d seconds + Stay unlocked + Lock now Security