mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Better biometric view message implementation
This commit is contained in:
@@ -29,7 +29,6 @@ import androidx.appcompat.app.AlertDialog
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.biometric.FingerPrintAnimatedVector
|
import com.kunzisoft.keepass.biometric.FingerPrintAnimatedVector
|
||||||
import com.kunzisoft.keepass.settings.SettingsActivity
|
|
||||||
import com.kunzisoft.keepass.settings.SettingsAdvancedUnlockActivity
|
import com.kunzisoft.keepass.settings.SettingsAdvancedUnlockActivity
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||||
@@ -53,7 +52,7 @@ class FingerPrintExplanationDialog : DialogFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fingerPrintAnimatedVector = FingerPrintAnimatedVector(activity,
|
fingerPrintAnimatedVector = FingerPrintAnimatedVector(activity,
|
||||||
rootView.findViewById(R.id.fingerprint_image))
|
rootView.findViewById(R.id.biometric_image))
|
||||||
|
|
||||||
builder.setView(rootView)
|
builder.setView(rootView)
|
||||||
.setPositiveButton(android.R.string.ok) { _, _ -> }
|
.setPositiveButton(android.R.string.ok) { _, _ -> }
|
||||||
|
|||||||
@@ -114,13 +114,13 @@ class AdvancedUnlockedViewManager(var context: FragmentActivity,
|
|||||||
override fun onAuthenticationError(
|
override fun onAuthenticationError(
|
||||||
errorCode: Int,
|
errorCode: Int,
|
||||||
errString: CharSequence) {
|
errString: CharSequence) {
|
||||||
Log.e(TAG, "Fingerprint authentication error. Code : $errorCode Error : $errString")
|
Log.e(TAG, "Biometric authentication error. Code : $errorCode Error : $errString")
|
||||||
setAdvancedUnlockedView(errString.toString())
|
setAdvancedUnlockedMessageView(errString.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAuthenticationFailed() {
|
override fun onAuthenticationFailed() {
|
||||||
Log.e(TAG, "Fingerprint authentication failed, fingerprint not recognized")
|
Log.e(TAG, "Biometric authentication failed, biometric not recognized")
|
||||||
setAdvancedUnlockedView(R.string.fingerprint_not_recognized)
|
setAdvancedUnlockedMessageView(R.string.fingerprint_not_recognized)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
||||||
@@ -155,21 +155,21 @@ class AdvancedUnlockedViewManager(var context: FragmentActivity,
|
|||||||
|
|
||||||
private fun initNotConfigured() {
|
private fun initNotConfigured() {
|
||||||
showFingerPrintViews(true)
|
showFingerPrintViews(true)
|
||||||
setAdvancedUnlockedView(R.string.configure_biometric)
|
setAdvancedUnlockedTitleView(R.string.configure_biometric)
|
||||||
|
|
||||||
advancedUnlockInfoView?.setIconViewClickListener(null)
|
advancedUnlockInfoView?.setIconViewClickListener(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initWaitData() {
|
private fun initWaitData() {
|
||||||
showFingerPrintViews(true)
|
showFingerPrintViews(true)
|
||||||
setAdvancedUnlockedView(R.string.no_credentials_stored)
|
setAdvancedUnlockedTitleView(R.string.no_credentials_stored)
|
||||||
|
|
||||||
advancedUnlockInfoView?.setIconViewClickListener(null)
|
advancedUnlockInfoView?.setIconViewClickListener(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initEncryptData() {
|
private fun initEncryptData() {
|
||||||
showFingerPrintViews(true)
|
showFingerPrintViews(true)
|
||||||
setAdvancedUnlockedView(R.string.open_biometric_prompt_store_credential)
|
setAdvancedUnlockedTitleView(R.string.open_biometric_prompt_store_credential)
|
||||||
|
|
||||||
biometricHelper?.initEncryptData { biometricPrompt, cryptoObject, promptInfo ->
|
biometricHelper?.initEncryptData { biometricPrompt, cryptoObject, promptInfo ->
|
||||||
|
|
||||||
@@ -185,7 +185,7 @@ class AdvancedUnlockedViewManager(var context: FragmentActivity,
|
|||||||
|
|
||||||
private fun initDecryptData() {
|
private fun initDecryptData() {
|
||||||
showFingerPrintViews(true)
|
showFingerPrintViews(true)
|
||||||
setAdvancedUnlockedView(R.string.open_biometric_prompt_unlock_database)
|
setAdvancedUnlockedTitleView(R.string.open_biometric_prompt_unlock_database)
|
||||||
|
|
||||||
if (biometricHelper != null) {
|
if (biometricHelper != null) {
|
||||||
prefsNoBackup.getString(preferenceKeyIvSpec, null)?.let {
|
prefsNoBackup.getString(preferenceKeyIvSpec, null)?.let {
|
||||||
@@ -244,22 +244,6 @@ class AdvancedUnlockedViewManager(var context: FragmentActivity,
|
|||||||
menuInflater.inflate(R.menu.advanced_unlock, menu)
|
menuInflater.inflate(R.menu.advanced_unlock, menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showFingerPrintViews(show: Boolean) {
|
|
||||||
context.runOnUiThread { advancedUnlockInfoView?.hide = !show }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setAdvancedUnlockedView(textId: Int) {
|
|
||||||
context.runOnUiThread {
|
|
||||||
advancedUnlockInfoView?.setText(textId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setAdvancedUnlockedView(text: CharSequence) {
|
|
||||||
context.runOnUiThread {
|
|
||||||
advancedUnlockInfoView?.text = text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun removePrefsNoBackupKey() {
|
private fun removePrefsNoBackupKey() {
|
||||||
prefsNoBackup.edit()
|
prefsNoBackup.edit()
|
||||||
?.remove(preferenceKeyValue)
|
?.remove(preferenceKeyValue)
|
||||||
@@ -267,6 +251,13 @@ class AdvancedUnlockedViewManager(var context: FragmentActivity,
|
|||||||
?.apply()
|
?.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun deleteEntryKey() {
|
||||||
|
biometricHelper?.deleteEntryKey()
|
||||||
|
removePrefsNoBackupKey()
|
||||||
|
biometricMode = Mode.NOT_CONFIGURED
|
||||||
|
checkBiometricAvailability()
|
||||||
|
}
|
||||||
|
|
||||||
override fun handleEncryptedResult(
|
override fun handleEncryptedResult(
|
||||||
value: String,
|
value: String,
|
||||||
ivSpec: String) {
|
ivSpec: String) {
|
||||||
@@ -275,7 +266,7 @@ class AdvancedUnlockedViewManager(var context: FragmentActivity,
|
|||||||
?.putString(preferenceKeyIvSpec, ivSpec)
|
?.putString(preferenceKeyIvSpec, ivSpec)
|
||||||
?.apply()
|
?.apply()
|
||||||
loadDatabase.invoke(null)
|
loadDatabase.invoke(null)
|
||||||
setAdvancedUnlockedView(R.string.encrypted_value_stored)
|
setAdvancedUnlockedMessageView(R.string.encrypted_value_stored)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleDecryptedResult(value: String) {
|
override fun handleDecryptedResult(value: String) {
|
||||||
@@ -284,22 +275,36 @@ class AdvancedUnlockedViewManager(var context: FragmentActivity,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onInvalidKeyException(e: Exception) {
|
override fun onInvalidKeyException(e: Exception) {
|
||||||
setAdvancedUnlockedView(R.string.biometric_invalid_key)
|
setAdvancedUnlockedMessageView(R.string.biometric_invalid_key)
|
||||||
deleteEntryKey()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBiometricException(e: Exception) {
|
override fun onBiometricException(e: Exception) {
|
||||||
// Don't show error here;
|
// Don't show error here;
|
||||||
// showError(getString(R.string.fingerprint_error, e.getMessage()));
|
// showError(getString(R.string.fingerprint_error, e.getMessage()));
|
||||||
// Can be uninit in Activity and init in fragment
|
// Can be uninit in Activity and init in fragment
|
||||||
setAdvancedUnlockedView(e.localizedMessage)
|
setAdvancedUnlockedMessageView(e.localizedMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteEntryKey() {
|
private fun showFingerPrintViews(show: Boolean) {
|
||||||
biometricHelper?.deleteEntryKey()
|
context.runOnUiThread { advancedUnlockInfoView?.hide = !show }
|
||||||
removePrefsNoBackupKey()
|
}
|
||||||
biometricMode = Mode.NOT_CONFIGURED
|
|
||||||
checkBiometricAvailability()
|
private fun setAdvancedUnlockedTitleView(textId: Int) {
|
||||||
|
context.runOnUiThread {
|
||||||
|
advancedUnlockInfoView?.setTitle(textId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setAdvancedUnlockedMessageView(textId: Int) {
|
||||||
|
context.runOnUiThread {
|
||||||
|
advancedUnlockInfoView?.setMessage(textId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setAdvancedUnlockedMessageView(text: CharSequence) {
|
||||||
|
context.runOnUiThread {
|
||||||
|
advancedUnlockInfoView?.message = text
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Mode {
|
enum class Mode {
|
||||||
|
|||||||
@@ -62,12 +62,14 @@ class BiometricHelper(private val context: FragmentActivity, private val biometr
|
|||||||
|
|
||||||
private val promptInfoStoreCredential = BiometricPrompt.PromptInfo.Builder()
|
private val promptInfoStoreCredential = BiometricPrompt.PromptInfo.Builder()
|
||||||
.setTitle(context.getString(R.string.biometric_prompt_store_credential_title))
|
.setTitle(context.getString(R.string.biometric_prompt_store_credential_title))
|
||||||
//.setDeviceCredentialAllowed(true)
|
.setDescription(context.getString(R.string.biometric_prompt_store_credential_message))
|
||||||
|
//.setDeviceCredentialAllowed(true) TODO device credential
|
||||||
.setNegativeButtonText(context.getString(android.R.string.cancel))
|
.setNegativeButtonText(context.getString(android.R.string.cancel))
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
private val promptInfoExtractCredential = BiometricPrompt.PromptInfo.Builder()
|
private val promptInfoExtractCredential = BiometricPrompt.PromptInfo.Builder()
|
||||||
.setTitle(context.getString(R.string.biometric_prompt_extract_credential_title))
|
.setTitle(context.getString(R.string.biometric_prompt_extract_credential_title))
|
||||||
|
.setDescription(context.getString(R.string.biometric_prompt_extract_credential_message))
|
||||||
//.setDeviceCredentialAllowed(true)
|
//.setDeviceCredentialAllowed(true)
|
||||||
.setNegativeButtonText(context.getString(android.R.string.cancel))
|
.setNegativeButtonText(context.getString(android.R.string.cancel))
|
||||||
.build()
|
.build()
|
||||||
@@ -294,8 +296,8 @@ class BiometricHelper(private val context: FragmentActivity, private val biometr
|
|||||||
/**
|
/**
|
||||||
* Remove entry key in keystore
|
* Remove entry key in keystore
|
||||||
*/
|
*/
|
||||||
fun deleteEntryKeyInKeystoreForFingerprints(context: FragmentActivity,
|
fun deleteEntryKeyInKeystoreForBiometric(context: FragmentActivity,
|
||||||
biometricUnlockCallback: BiometricUnlockErrorCallback) {
|
biometricUnlockCallback: BiometricUnlockErrorCallback) {
|
||||||
val fingerPrintHelper = BiometricHelper(context, object : BiometricUnlockCallback {
|
val fingerPrintHelper = BiometricHelper(context, object : BiometricUnlockCallback {
|
||||||
|
|
||||||
override fun handleEncryptedResult(value: String, ivSpec: String) {}
|
override fun handleEncryptedResult(value: String, ivSpec: String) {}
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ class NestedSettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferen
|
|||||||
.setPositiveButton(resources.getString(android.R.string.yes)
|
.setPositiveButton(resources.getString(android.R.string.yes)
|
||||||
) { _, _ ->
|
) { _, _ ->
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
BiometricHelper.deleteEntryKeyInKeystoreForFingerprints(
|
BiometricHelper.deleteEntryKeyInKeystoreForBiometric(
|
||||||
activity,
|
activity,
|
||||||
object : BiometricHelper.BiometricUnlockErrorCallback {
|
object : BiometricHelper.BiometricUnlockErrorCallback {
|
||||||
override fun onInvalidKeyException(e: Exception) {}
|
override fun onInvalidKeyException(e: Exception) {}
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ class AdvancedUnlockInfoView @JvmOverloads constructor(context: Context,
|
|||||||
|
|
||||||
private val unlockContainerView: View
|
private val unlockContainerView: View
|
||||||
private var unlockAnimatedVector: FingerPrintAnimatedVector? = null
|
private var unlockAnimatedVector: FingerPrintAnimatedVector? = null
|
||||||
private var unlockTextView: TextView? = null
|
private var unlockTitleTextView: TextView? = null
|
||||||
|
private var unlockMessageTextView: TextView? = null
|
||||||
var unlockIconImageView: ImageView? = null
|
var unlockIconImageView: ImageView? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -30,8 +31,9 @@ class AdvancedUnlockInfoView @JvmOverloads constructor(context: Context,
|
|||||||
unlockContainerView = findViewById(R.id.fingerprint_container)
|
unlockContainerView = findViewById(R.id.fingerprint_container)
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
unlockTextView = findViewById(R.id.fingerprint_label)
|
unlockTitleTextView = findViewById(R.id.biometric_title)
|
||||||
unlockIconImageView = findViewById(R.id.fingerprint_image)
|
unlockMessageTextView = findViewById(R.id.biometric_message)
|
||||||
|
unlockIconImageView = findViewById(R.id.biometric_image)
|
||||||
// Init the fingerprint animation
|
// Init the fingerprint animation
|
||||||
unlockAnimatedVector = FingerPrintAnimatedVector(context, unlockIconImageView!!)
|
unlockAnimatedVector = FingerPrintAnimatedVector(context, unlockIconImageView!!)
|
||||||
}
|
}
|
||||||
@@ -58,16 +60,28 @@ class AdvancedUnlockInfoView @JvmOverloads constructor(context: Context,
|
|||||||
unlockIconImageView?.setOnClickListener(listener)
|
unlockIconImageView?.setOnClickListener(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
var text: CharSequence
|
var title: CharSequence
|
||||||
get() {
|
get() {
|
||||||
return unlockTextView?.text?.toString() ?: ""
|
return unlockTitleTextView?.text?.toString() ?: ""
|
||||||
}
|
}
|
||||||
set(value) {
|
set(value) {
|
||||||
unlockTextView?.text = value
|
unlockTitleTextView?.text = value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setText(@StringRes textId: Int) {
|
fun setTitle(@StringRes textId: Int) {
|
||||||
text = context.getString(textId)
|
title = context.getString(textId)
|
||||||
|
}
|
||||||
|
|
||||||
|
var message: CharSequence
|
||||||
|
get() {
|
||||||
|
return unlockMessageTextView?.text?.toString() ?: ""
|
||||||
|
}
|
||||||
|
set(value) {
|
||||||
|
unlockMessageTextView?.text = value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setMessage(@StringRes textId: Int) {
|
||||||
|
message = context.getString(textId)
|
||||||
}
|
}
|
||||||
|
|
||||||
var hide: Boolean
|
var hide: Boolean
|
||||||
|
|||||||
@@ -98,7 +98,7 @@
|
|||||||
android:text="@string/fingerprint_open_biometric_prompt"/>
|
android:text="@string/fingerprint_open_biometric_prompt"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/fingerprint_image"
|
android:id="@+id/biometric_image"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
|
|||||||
@@ -1,37 +1,55 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/fingerprint_container"
|
android:id="@+id/fingerprint_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content">
|
||||||
tools:visibility="gone">
|
|
||||||
<View
|
<View
|
||||||
|
android:id="@+id/biometric_delimiter"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
android:background="?attr/colorPrimaryDark"/>
|
android:background="?attr/colorPrimaryDark"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/fingerprint_label"
|
android:layout_width="0dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_marginStart="24dp"
|
android:layout_marginStart="24dp"
|
||||||
android:layout_marginEnd="18dp"
|
android:layout_marginEnd="18dp"
|
||||||
android:layout_toStartOf="@+id/fingerprint_image"
|
android:orientation="vertical"
|
||||||
style="@style/KeepassDXStyle.TextAppearance.Default.TextOnPrimary"
|
android:gravity="center_vertical"
|
||||||
android:gravity="center_vertical|start" />
|
app:layout_constraintTop_toTopOf="@+id/biometric_delimiter"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/biometric_image" >
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/biometric_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:text="@string/biometric_prompt_store_credential_title"
|
||||||
|
style="@style/KeepassDXStyle.TextAppearance.Default.TextOnPrimary"
|
||||||
|
android:gravity="center_vertical|end" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/biometric_message"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:text="Sample error"
|
||||||
|
style="@style/KeepassDXStyle.TextAppearance.Secondary.TextOnPrimary"
|
||||||
|
android:gravity="center_vertical|end" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/fingerprint_image"
|
android:id="@+id/biometric_image"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
android:layout_marginTop="@dimen/default_margin"
|
android:layout_margin="@dimen/default_margin"
|
||||||
android:layout_marginBottom="@dimen/default_margin"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
android:layout_marginStart="4dp"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
android:layout_marginEnd="@dimen/default_margin"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:elevation="8dp"
|
android:elevation="8dp"
|
||||||
android:src="@drawable/fingerprint"
|
android:src="@drawable/fingerprint"
|
||||||
android:background="@drawable/background_image"
|
android:background="@drawable/background_image"
|
||||||
android:backgroundTint="?attr/colorAccent" />
|
android:backgroundTint="?attr/colorAccent" />
|
||||||
</RelativeLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|||||||
@@ -229,8 +229,10 @@
|
|||||||
<string name="configure_biometric">Biometric prompt is supported but not set up.</string>
|
<string name="configure_biometric">Biometric prompt is supported but not set up.</string>
|
||||||
<string name="open_biometric_prompt_unlock_database">Open the biometric prompt to unlock the database</string>
|
<string name="open_biometric_prompt_unlock_database">Open the biometric prompt to unlock the database</string>
|
||||||
<string name="open_biometric_prompt_store_credential">Open the biometric prompt to store credentials</string>
|
<string name="open_biometric_prompt_store_credential">Open the biometric prompt to store credentials</string>
|
||||||
<string name="biometric_prompt_store_credential_title">Store database credentials with biometric data</string>
|
<string name="biometric_prompt_store_credential_title">Save biometric recognition</string>
|
||||||
<string name="biometric_prompt_extract_credential_title">Extract database credential with biometric data</string>
|
<string name="biometric_prompt_store_credential_message">Store database credentials with biometric data</string>
|
||||||
|
<string name="biometric_prompt_extract_credential_title">Open database with biometric recognition</string>
|
||||||
|
<string name="biometric_prompt_extract_credential_message">Extract database credential with biometric data</string>
|
||||||
<string name="encrypted_value_stored">Encrypted password stored</string>
|
<string name="encrypted_value_stored">Encrypted password stored</string>
|
||||||
<string name="biometric_invalid_key">Could not read biometric key. Restore your credential.</string>
|
<string name="biometric_invalid_key">Could not read biometric key. Restore your credential.</string>
|
||||||
<string name="fingerprint_not_recognized">Could not recognize fingerprint</string>
|
<string name="fingerprint_not_recognized">Could not recognize fingerprint</string>
|
||||||
|
|||||||
@@ -226,6 +226,7 @@
|
|||||||
<item name="android:textColor">?attr/textColorInverse</item>
|
<item name="android:textColor">?attr/textColorInverse</item>
|
||||||
</style>
|
</style>
|
||||||
<style name="KeepassDXStyle.TextAppearance.Secondary.TextOnPrimary" parent="KeepassDXStyle.TextAppearance.Default.TextOnPrimary">
|
<style name="KeepassDXStyle.TextAppearance.Secondary.TextOnPrimary" parent="KeepassDXStyle.TextAppearance.Default.TextOnPrimary">
|
||||||
|
<item name="android:textColor">?android:attr/textColorHintInverse</item>
|
||||||
<item name="android:textSize">14sp</item>
|
<item name="android:textSize">14sp</item>
|
||||||
<item name="android:textStyle">italic</item>
|
<item name="android:textStyle">italic</item>
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user