mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Add device credential unlock
This commit is contained in:
@@ -200,11 +200,11 @@ open class PasswordActivity : SpecialModeActivity() {
|
|||||||
onActionFinish = { actionTask, result ->
|
onActionFinish = { actionTask, result ->
|
||||||
when (actionTask) {
|
when (actionTask) {
|
||||||
ACTION_DATABASE_LOAD_TASK -> {
|
ACTION_DATABASE_LOAD_TASK -> {
|
||||||
// Recheck biometric if error
|
// Recheck advanced unlock if error
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
if (PreferencesUtil.isBiometricUnlockEnable(this@PasswordActivity)) {
|
if (PreferencesUtil.isAdvancedUnlockEnable(this@PasswordActivity)) {
|
||||||
// Stay with the same mode and init it
|
// Stay with the same mode and init it
|
||||||
advancedUnlockedManager?.initBiometricMode()
|
advancedUnlockedManager?.initAdvancedUnlockMode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,7 +370,7 @@ open class PasswordActivity : SpecialModeActivity() {
|
|||||||
} else {
|
} else {
|
||||||
// Init Biometric elements
|
// Init Biometric elements
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
if (PreferencesUtil.isBiometricUnlockEnable(this)) {
|
if (PreferencesUtil.isAdvancedUnlockEnable(this)) {
|
||||||
if (advancedUnlockedManager == null
|
if (advancedUnlockedManager == null
|
||||||
&& databaseFileUri != null) {
|
&& databaseFileUri != null) {
|
||||||
advancedUnlockedManager = AdvancedUnlockedManager(this,
|
advancedUnlockedManager = AdvancedUnlockedManager(this,
|
||||||
@@ -658,7 +658,7 @@ open class PasswordActivity : SpecialModeActivity() {
|
|||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||||
&& !readOnlyEducationPerformed) {
|
&& !readOnlyEducationPerformed) {
|
||||||
val biometricCanAuthenticate = BiometricUnlockDatabaseHelper.canAuthenticate(this)
|
val biometricCanAuthenticate = BiometricUnlockDatabaseHelper.canAuthenticate(this)
|
||||||
PreferencesUtil.isBiometricUnlockEnable(applicationContext)
|
PreferencesUtil.isAdvancedUnlockEnable(applicationContext)
|
||||||
&& (biometricCanAuthenticate == BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED || biometricCanAuthenticate == BiometricManager.BIOMETRIC_SUCCESS)
|
&& (biometricCanAuthenticate == BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED || biometricCanAuthenticate == BiometricManager.BIOMETRIC_SUCCESS)
|
||||||
&& advancedUnlockInfoView != null && advancedUnlockInfoView?.visibility == View.VISIBLE
|
&& advancedUnlockInfoView != null && advancedUnlockInfoView?.visibility == View.VISIBLE
|
||||||
&& advancedUnlockInfoView?.unlockIconImageView != null
|
&& advancedUnlockInfoView?.unlockIconImageView != null
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ class AdvancedUnlockedManager(var context: FragmentActivity,
|
|||||||
val biometricCanAuthenticate = BiometricUnlockDatabaseHelper.canAuthenticate(context)
|
val biometricCanAuthenticate = BiometricUnlockDatabaseHelper.canAuthenticate(context)
|
||||||
allowOpenBiometricPrompt = true
|
allowOpenBiometricPrompt = true
|
||||||
|
|
||||||
if (!PreferencesUtil.isBiometricUnlockEnable(context)
|
if (!PreferencesUtil.isAdvancedUnlockEnable(context)
|
||||||
|| biometricCanAuthenticate == BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE
|
|| biometricCanAuthenticate == BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE
|
||||||
|| biometricCanAuthenticate == BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE) {
|
|| biometricCanAuthenticate == BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE) {
|
||||||
toggleMode(Mode.BIOMETRIC_UNAVAILABLE)
|
toggleMode(Mode.BIOMETRIC_UNAVAILABLE)
|
||||||
@@ -136,7 +136,7 @@ class AdvancedUnlockedManager(var context: FragmentActivity,
|
|||||||
private fun toggleMode(newBiometricMode: Mode) {
|
private fun toggleMode(newBiometricMode: Mode) {
|
||||||
if (newBiometricMode != biometricMode) {
|
if (newBiometricMode != biometricMode) {
|
||||||
biometricMode = newBiometricMode
|
biometricMode = newBiometricMode
|
||||||
initBiometricMode()
|
initAdvancedUnlockMode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,7 +292,7 @@ class AdvancedUnlockedManager(var context: FragmentActivity,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun initBiometricMode() {
|
fun initAdvancedUnlockMode() {
|
||||||
mAllowAdvancedUnlockMenu = false
|
mAllowAdvancedUnlockMenu = false
|
||||||
when (biometricMode) {
|
when (biometricMode) {
|
||||||
Mode.BIOMETRIC_UNAVAILABLE -> initNotAvailable()
|
Mode.BIOMETRIC_UNAVAILABLE -> initNotAvailable()
|
||||||
|
|||||||
@@ -29,11 +29,11 @@ import android.util.Base64
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.biometric.BiometricManager
|
import androidx.biometric.BiometricManager
|
||||||
import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG
|
import androidx.biometric.BiometricManager.Authenticators.*
|
||||||
import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK
|
|
||||||
import androidx.biometric.BiometricPrompt
|
import androidx.biometric.BiometricPrompt
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
import java.security.KeyStore
|
import java.security.KeyStore
|
||||||
import java.security.UnrecoverableKeyException
|
import java.security.UnrecoverableKeyException
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
@@ -58,31 +58,7 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
var authenticationCallback: BiometricPrompt.AuthenticationCallback? = null
|
var authenticationCallback: BiometricPrompt.AuthenticationCallback? = null
|
||||||
var biometricUnlockCallback: BiometricUnlockCallback? = null
|
var biometricUnlockCallback: BiometricUnlockCallback? = null
|
||||||
|
|
||||||
private val promptInfoStoreCredential = BiometricPrompt.PromptInfo.Builder().apply {
|
private val deviceCredentialUnlockEnable = PreferencesUtil.isDeviceCredentialUnlockEnable(context)
|
||||||
setTitle(context.getString(R.string.biometric_prompt_store_credential_title))
|
|
||||||
setDescription(context.getString(R.string.biometric_prompt_store_credential_message))
|
|
||||||
setConfirmationRequired(true)
|
|
||||||
// TODO device credential #102 #152
|
|
||||||
/*
|
|
||||||
if (keyguardManager?.isDeviceSecure == true)
|
|
||||||
setDeviceCredentialAllowed(true)
|
|
||||||
else
|
|
||||||
*/
|
|
||||||
setNegativeButtonText(context.getString(android.R.string.cancel))
|
|
||||||
}.build()
|
|
||||||
|
|
||||||
private val promptInfoExtractCredential = BiometricPrompt.PromptInfo.Builder().apply {
|
|
||||||
setTitle(context.getString(R.string.biometric_prompt_extract_credential_title))
|
|
||||||
//setDescription(context.getString(R.string.biometric_prompt_extract_credential_message))
|
|
||||||
setConfirmationRequired(false)
|
|
||||||
// TODO device credential #102 #152
|
|
||||||
/*
|
|
||||||
if (keyguardManager?.isDeviceSecure == true)
|
|
||||||
setDeviceCredentialAllowed(true)
|
|
||||||
else
|
|
||||||
*/
|
|
||||||
setNegativeButtonText(context.getString(android.R.string.cancel))
|
|
||||||
}.build()
|
|
||||||
|
|
||||||
val isKeyManagerInitialized: Boolean
|
val isKeyManagerInitialized: Boolean
|
||||||
get() {
|
get() {
|
||||||
@@ -139,6 +115,12 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
// Require the user to authenticate with a fingerprint to authorize every use
|
// Require the user to authenticate with a fingerprint to authorize every use
|
||||||
// of the key
|
// of the key
|
||||||
.setUserAuthenticationRequired(true)
|
.setUserAuthenticationRequired(true)
|
||||||
|
.apply {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
|
||||||
|
&& deviceCredentialUnlockEnable) {
|
||||||
|
setUserAuthenticationParameters(0, KeyProperties.AUTH_DEVICE_CREDENTIAL)
|
||||||
|
}
|
||||||
|
}
|
||||||
.build())
|
.build())
|
||||||
keyGenerator?.generateKey()
|
keyGenerator?.generateKey()
|
||||||
}
|
}
|
||||||
@@ -164,13 +146,27 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
// TODO if (keyguardManager?.isDeviceSecure == true) {
|
||||||
getSecretKey()?.let { secretKey ->
|
getSecretKey()?.let { secretKey ->
|
||||||
cipher?.init(Cipher.ENCRYPT_MODE, secretKey)
|
cipher?.init(Cipher.ENCRYPT_MODE, secretKey)
|
||||||
|
|
||||||
initBiometricPrompt()
|
initBiometricPrompt()
|
||||||
actionIfCypherInit.invoke(biometricPrompt, cryptoObject, promptInfoStoreCredential)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
val promptInfoStoreCredential = BiometricPrompt.PromptInfo.Builder().apply {
|
||||||
|
setTitle(context.getString(R.string.biometric_prompt_store_credential_title))
|
||||||
|
setDescription(context.getString(R.string.biometric_prompt_store_credential_message))
|
||||||
|
setConfirmationRequired(true)
|
||||||
|
if (deviceCredentialUnlockEnable) {
|
||||||
|
setAllowedAuthenticators(DEVICE_CREDENTIAL)
|
||||||
|
} else {
|
||||||
|
setNegativeButtonText(context.getString(android.R.string.cancel))
|
||||||
|
}
|
||||||
|
}.build()
|
||||||
|
|
||||||
|
actionIfCypherInit.invoke(biometricPrompt,
|
||||||
|
cryptoObject,
|
||||||
|
promptInfoStoreCredential)
|
||||||
|
}
|
||||||
} catch (unrecoverableKeyException: UnrecoverableKeyException) {
|
} catch (unrecoverableKeyException: UnrecoverableKeyException) {
|
||||||
Log.e(TAG, "Unable to initialize encrypt data", unrecoverableKeyException)
|
Log.e(TAG, "Unable to initialize encrypt data", unrecoverableKeyException)
|
||||||
biometricUnlockCallback?.onInvalidKeyException(unrecoverableKeyException)
|
biometricUnlockCallback?.onInvalidKeyException(unrecoverableKeyException)
|
||||||
@@ -211,6 +207,7 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
// TODO if (keyguardManager?.isDeviceSecure == true) {
|
||||||
// important to restore spec here that was used for decryption
|
// important to restore spec here that was used for decryption
|
||||||
val iv = Base64.decode(ivSpecValue, Base64.NO_WRAP)
|
val iv = Base64.decode(ivSpecValue, Base64.NO_WRAP)
|
||||||
val spec = IvParameterSpec(iv)
|
val spec = IvParameterSpec(iv)
|
||||||
@@ -219,9 +216,22 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
cipher?.init(Cipher.DECRYPT_MODE, secretKey, spec)
|
cipher?.init(Cipher.DECRYPT_MODE, secretKey, spec)
|
||||||
|
|
||||||
initBiometricPrompt()
|
initBiometricPrompt()
|
||||||
actionIfCypherInit.invoke(biometricPrompt, cryptoObject, promptInfoExtractCredential)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
val promptInfoExtractCredential = BiometricPrompt.PromptInfo.Builder().apply {
|
||||||
|
setTitle(context.getString(R.string.biometric_prompt_extract_credential_title))
|
||||||
|
//setDescription(context.getString(R.string.biometric_prompt_extract_credential_message))
|
||||||
|
setConfirmationRequired(false)
|
||||||
|
if (deviceCredentialUnlockEnable) {
|
||||||
|
setAllowedAuthenticators(DEVICE_CREDENTIAL)
|
||||||
|
} else {
|
||||||
|
setNegativeButtonText(context.getString(android.R.string.cancel))
|
||||||
|
}
|
||||||
|
}.build()
|
||||||
|
|
||||||
|
actionIfCypherInit.invoke(biometricPrompt,
|
||||||
|
cryptoObject,
|
||||||
|
promptInfoExtractCredential)
|
||||||
|
}
|
||||||
} catch (unrecoverableKeyException: UnrecoverableKeyException) {
|
} catch (unrecoverableKeyException: UnrecoverableKeyException) {
|
||||||
Log.e(TAG, "Unable to initialize decrypt data", unrecoverableKeyException)
|
Log.e(TAG, "Unable to initialize decrypt data", unrecoverableKeyException)
|
||||||
deleteEntryKey()
|
deleteEntryKey()
|
||||||
@@ -299,11 +309,19 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
|
|
||||||
fun canAuthenticate(context: Context): Int {
|
fun canAuthenticate(context: Context): Int {
|
||||||
return try {
|
return try {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
BiometricManager.from(context).canAuthenticate(BIOMETRIC_STRONG or DEVICE_CREDENTIAL)
|
||||||
|
} else {
|
||||||
BiometricManager.from(context).canAuthenticate(BIOMETRIC_STRONG)
|
BiometricManager.from(context).canAuthenticate(BIOMETRIC_STRONG)
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Unable to authenticate with strong biometric.", e)
|
Log.e(TAG, "Unable to authenticate with strong biometric.", e)
|
||||||
try {
|
try {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
BiometricManager.from(context).canAuthenticate(BIOMETRIC_WEAK or DEVICE_CREDENTIAL)
|
||||||
|
} else {
|
||||||
BiometricManager.from(context).canAuthenticate(BIOMETRIC_WEAK)
|
BiometricManager.from(context).canAuthenticate(BIOMETRIC_WEAK)
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Unable to authenticate with weak biometric.", e)
|
Log.e(TAG, "Unable to authenticate with weak biometric.", e)
|
||||||
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE
|
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE
|
||||||
|
|||||||
@@ -225,6 +225,10 @@ object PreferencesUtil {
|
|||||||
context.resources.getBoolean(R.bool.enable_auto_save_database_default))
|
context.resources.getBoolean(R.bool.enable_auto_save_database_default))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isAdvancedUnlockEnable(context: Context): Boolean {
|
||||||
|
return isBiometricUnlockEnable(context) || isDeviceCredentialUnlockEnable(context)
|
||||||
|
}
|
||||||
|
|
||||||
fun isBiometricUnlockEnable(context: Context): Boolean {
|
fun isBiometricUnlockEnable(context: Context): Boolean {
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
return prefs.getBoolean(context.getString(R.string.biometric_unlock_enable_key),
|
return prefs.getBoolean(context.getString(R.string.biometric_unlock_enable_key),
|
||||||
@@ -237,6 +241,12 @@ object PreferencesUtil {
|
|||||||
context.resources.getBoolean(R.bool.biometric_auto_open_prompt_default))
|
context.resources.getBoolean(R.bool.biometric_auto_open_prompt_default))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isDeviceCredentialUnlockEnable(context: Context): Boolean {
|
||||||
|
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
return prefs.getBoolean(context.getString(R.string.device_credential_unlock_enable_key),
|
||||||
|
context.resources.getBoolean(R.bool.device_credential_unlock_enable_default))
|
||||||
|
}
|
||||||
|
|
||||||
fun getListSort(context: Context): SortNodeEnum {
|
fun getListSort(context: Context): SortNodeEnum {
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
prefs.getString(context.getString(R.string.sort_node_key),
|
prefs.getString(context.getString(R.string.sort_node_key),
|
||||||
|
|||||||
@@ -416,7 +416,7 @@
|
|||||||
<string name="contains_duplicate_uuid_procedure">Résoudre le problème en générant de nouveaux UUID pour les doublons et continuer \?</string>
|
<string name="contains_duplicate_uuid_procedure">Résoudre le problème en générant de nouveaux UUID pour les doublons et continuer \?</string>
|
||||||
<string name="database_opened">Base de données ouverte</string>
|
<string name="database_opened">Base de données ouverte</string>
|
||||||
<string name="clipboard_explanation_summary">Copier les champs d’une entrée à l’aide du presse-papier de votre appareil</string>
|
<string name="clipboard_explanation_summary">Copier les champs d’une entrée à l’aide du presse-papier de votre appareil</string>
|
||||||
<string name="advanced_unlock_explanation_summary">Utilise le déverrouillage avancé pour ouvrir plus facilement une base de données</string>
|
<string name="advanced_unlock_explanation_summary">Utiliser le déverrouillage avancé pour ouvrir plus facilement une base de données</string>
|
||||||
<string name="database_data_compression_title">Compression de données</string>
|
<string name="database_data_compression_title">Compression de données</string>
|
||||||
<string name="database_data_compression_summary">La compression des données réduit la taille de la base de données</string>
|
<string name="database_data_compression_summary">La compression des données réduit la taille de la base de données</string>
|
||||||
<string name="max_history_items_title">Nombre maximum</string>
|
<string name="max_history_items_title">Nombre maximum</string>
|
||||||
|
|||||||
@@ -97,6 +97,8 @@
|
|||||||
<string name="biometric_auto_open_prompt_key" translatable="false">biometric_auto_open_prompt_key</string>
|
<string name="biometric_auto_open_prompt_key" translatable="false">biometric_auto_open_prompt_key</string>
|
||||||
<bool name="biometric_auto_open_prompt_default" translatable="false">false</bool>
|
<bool name="biometric_auto_open_prompt_default" translatable="false">false</bool>
|
||||||
<string name="biometric_delete_all_key_key" translatable="false">biometric_delete_all_key_key</string>
|
<string name="biometric_delete_all_key_key" translatable="false">biometric_delete_all_key_key</string>
|
||||||
|
<string name="device_credential_unlock_enable_key" translatable="false">device_credential_unlock_enable_key</string>
|
||||||
|
<bool name="device_credential_unlock_enable_default" translatable="false">false</bool>
|
||||||
|
|
||||||
<!-- Form Filling Settings -->
|
<!-- Form Filling Settings -->
|
||||||
<string name="settings_form_filling_key" translatable="false">settings_form_filling_key</string>
|
<string name="settings_form_filling_key" translatable="false">settings_form_filling_key</string>
|
||||||
|
|||||||
@@ -293,6 +293,7 @@
|
|||||||
<string name="database_history">History</string>
|
<string name="database_history">History</string>
|
||||||
<string name="menu_appearance_settings">Appearance</string>
|
<string name="menu_appearance_settings">Appearance</string>
|
||||||
<string name="biometric">Biometric</string>
|
<string name="biometric">Biometric</string>
|
||||||
|
<string name="device_credential">Device credential</string>
|
||||||
<string name="general">General</string>
|
<string name="general">General</string>
|
||||||
<string name="autofill">Autofill</string>
|
<string name="autofill">Autofill</string>
|
||||||
<string name="autofill_service_name">KeePassDX form autofilling</string>
|
<string name="autofill_service_name">KeePassDX form autofilling</string>
|
||||||
@@ -321,11 +322,13 @@
|
|||||||
<string name="advanced_unlock_explanation_summary">Use advanced unlocking to open a database more easily</string>
|
<string name="advanced_unlock_explanation_summary">Use advanced unlocking to open a database more easily</string>
|
||||||
<string name="biometric_unlock_enable_title">Biometric unlocking</string>
|
<string name="biometric_unlock_enable_title">Biometric unlocking</string>
|
||||||
<string name="biometric_unlock_enable_summary">Lets you scan your biometric to open the database</string>
|
<string name="biometric_unlock_enable_summary">Lets you scan your biometric to open the database</string>
|
||||||
|
<string name="device_credential_unlock_enable_title">Device credential unlocking</string>
|
||||||
|
<string name="device_credential_unlock_enable_summary">Lets you use your device credential to open the database</string>
|
||||||
<string name="biometric_auto_open_prompt_title">Auto-open biometric prompt</string>
|
<string name="biometric_auto_open_prompt_title">Auto-open biometric prompt</string>
|
||||||
<string name="biometric_auto_open_prompt_summary">Automatically ask for biometric if the database is set up to use it</string>
|
<string name="biometric_auto_open_prompt_summary">Automatically ask for biometric if the database is set up to use it</string>
|
||||||
<string name="biometric_delete_all_key_title">Delete encryption keys</string>
|
<string name="biometric_delete_all_key_title">Delete encryption keys</string>
|
||||||
<string name="biometric_delete_all_key_summary">Delete all encryption keys related to biometric recognition</string>
|
<string name="biometric_delete_all_key_summary">Delete all encryption keys related to advanced unlock recognition</string>
|
||||||
<string name="biometric_delete_all_key_warning">Delete all encryption keys related to biometric recognition?</string>
|
<string name="biometric_delete_all_key_warning">Delete all encryption keys related to advanced unlock recognition?</string>
|
||||||
<string name="unavailable_feature_text">Could not start this feature.</string>
|
<string name="unavailable_feature_text">Could not start this feature.</string>
|
||||||
<string name="unavailable_feature_version">The device is running Android %1$s, but needs %2$s or later.</string>
|
<string name="unavailable_feature_version">The device is running Android %1$s, but needs %2$s or later.</string>
|
||||||
<string name="unavailable_feature_hardware">Could not find the corresponding hardware.</string>
|
<string name="unavailable_feature_hardware">Could not find the corresponding hardware.</string>
|
||||||
|
|||||||
@@ -18,12 +18,12 @@
|
|||||||
along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||||
-->
|
-->
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<PreferenceCategory
|
|
||||||
android:title="@string/biometric">
|
|
||||||
<Preference
|
<Preference
|
||||||
android:key="@string/advanced_unlock_explanation_key"
|
android:key="@string/advanced_unlock_explanation_key"
|
||||||
android:icon="@drawable/prefs_info_24dp"
|
android:icon="@drawable/prefs_info_24dp"
|
||||||
android:summary="@string/advanced_unlock_explanation_summary"/>
|
android:summary="@string/advanced_unlock_explanation_summary"/>
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="@string/biometric">
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:key="@string/biometric_unlock_enable_key"
|
android:key="@string/biometric_unlock_enable_key"
|
||||||
android:title="@string/biometric_unlock_enable_title"
|
android:title="@string/biometric_unlock_enable_title"
|
||||||
@@ -35,10 +35,20 @@
|
|||||||
android:summary="@string/biometric_auto_open_prompt_summary"
|
android:summary="@string/biometric_auto_open_prompt_summary"
|
||||||
android:dependency="@string/biometric_unlock_enable_key"
|
android:dependency="@string/biometric_unlock_enable_key"
|
||||||
android:defaultValue="@bool/biometric_auto_open_prompt_default"/>
|
android:defaultValue="@bool/biometric_auto_open_prompt_default"/>
|
||||||
|
</PreferenceCategory>
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="@string/device_credential">
|
||||||
|
<SwitchPreference
|
||||||
|
android:key="@string/device_credential_unlock_enable_key"
|
||||||
|
android:title="@string/device_credential_unlock_enable_title"
|
||||||
|
android:summary="@string/device_credential_unlock_enable_summary"
|
||||||
|
android:defaultValue="@bool/device_credential_unlock_enable_default"/>
|
||||||
|
</PreferenceCategory>
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="@string/general">
|
||||||
<Preference
|
<Preference
|
||||||
android:key="@string/biometric_delete_all_key_key"
|
android:key="@string/biometric_delete_all_key_key"
|
||||||
android:title="@string/biometric_delete_all_key_title"
|
android:title="@string/biometric_delete_all_key_title"
|
||||||
android:summary="@string/biometric_delete_all_key_summary" />
|
android:summary="@string/biometric_delete_all_key_summary" />
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
Reference in New Issue
Block a user