Add opt-in device credential app lock

This commit is contained in:
ajp_anton
2026-07-23 10:00:12 +00:00
parent 53cc4eb529
commit 6280c8ef80
4 changed files with 41 additions and 1 deletions
@@ -1,6 +1,9 @@
package se.ajpanton.notificationlog
import android.os.Bundle
import android.hardware.biometrics.BiometricPrompt
import android.hardware.biometrics.BiometricManager.Authenticators
import android.os.CancellationSignal
import android.content.res.Configuration
import android.view.Menu
import android.view.MenuItem
@@ -19,11 +22,13 @@ import androidx.fragment.app.commit
import com.google.android.material.navigation.NavigationView
import se.ajpanton.notificationlog.databinding.ActivityMainBinding
import se.ajpanton.notificationlog.settings.LoggingType
import se.ajpanton.notificationlog.settings.AppLockStore
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
private lateinit var binding: ActivityMainBinding
private lateinit var drawerToggle: ActionBarDrawerToggle
private var permanentSidebar = false
private var needsUnlock = true
private var currentItemId = R.id.nav_view_logs
private var drawerNavigationBasePaddingLeft: Int? = null
private var permanentNavigationBasePaddingLeft: Int? = null
@@ -77,6 +82,27 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
super.onSaveInstanceState(outState)
}
override fun onResume() {
super.onResume()
if (needsUnlock && AppLockStore(this).enabled) requestUnlock()
}
override fun onStop() {
super.onStop()
if (!isChangingConfigurations) needsUnlock = true
}
private fun requestUnlock() {
BiometricPrompt.Builder(this)
.setTitle("Unlock Notification Log")
.setAllowedAuthenticators(Authenticators.BIOMETRIC_STRONG or Authenticators.DEVICE_CREDENTIAL)
.build()
.authenticate(CancellationSignal(), mainExecutor, object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult?) { needsUnlock = false }
override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) { finishAndRemoveTask() }
})
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.nav_settings_header) {
return false
@@ -11,6 +11,7 @@ import se.ajpanton.notificationlog.settings.LogViewSettingsStore
import se.ajpanton.notificationlog.settings.TimestampZone
import se.ajpanton.notificationlog.settings.LoggingType
import se.ajpanton.notificationlog.settings.LoggingRuleStore
import se.ajpanton.notificationlog.settings.AppLockStore
import com.google.android.material.dialog.MaterialAlertDialogBuilder
class SettingsFragment : Fragment(R.layout.fragment_settings) {
@@ -46,6 +47,9 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
}
}
binding!!.copyEventSettings.setOnClickListener { chooseCopySource() }
val lockStore = AppLockStore(requireContext())
binding!!.appLock.isChecked = lockStore.enabled
binding!!.appLock.setOnCheckedChangeListener { _, enabled -> lockStore.enabled = enabled }
}
override fun onDestroyView() { binding = null; super.onDestroyView() }
@@ -0,0 +1,10 @@
package se.ajpanton.notificationlog.settings
import android.content.Context
class AppLockStore(context: Context) {
private val prefs = context.getSharedPreferences("app-lock", Context.MODE_PRIVATE)
var enabled: Boolean
get() = prefs.getBoolean("enabled", false)
set(value) = prefs.edit().putBoolean("enabled", value).apply()
}