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