Skip to content

Commit d0b8d62

Browse files
committed
fix: avoid crash when biometrics fail due to a system error
1 parent 2b349dc commit d0b8d62

3 files changed

Lines changed: 38 additions & 14 deletions

File tree

owncloudApp/src/main/java/com/owncloud/android/presentation/security/biometric/BiometricActivity.kt

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
*
44
* @author David González Verdugo
55
* @author Juan Carlos Garrote Gascón
6+
* @author Jorge Aguado Recio
67
*
7-
* Copyright (C) 2023 ownCloud GmbH.
8+
* Copyright (C) 2025 ownCloud GmbH.
89
*
910
* This program is free software: you can redistribute it and/or modify
1011
* it under the terms of the GNU General Public License version 2,
@@ -82,7 +83,7 @@ class BiometricActivity : AppCompatActivity() {
8283
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
8384
super.onAuthenticationError(errorCode, errString)
8485
Timber.e("onAuthenticationError ($errorCode): $errString")
85-
authError()
86+
authError(errorCode == 13) // ErrorCode 13: Canceled
8687
}
8788

8889
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
@@ -110,14 +111,19 @@ class BiometricActivity : AppCompatActivity() {
110111
})
111112

112113
// Displays the "log in" prompt.
113-
biometricPrompt.authenticate(promptInfo, cryptoObject)
114+
try {
115+
biometricPrompt.authenticate(promptInfo, cryptoObject)
116+
} catch (e: Exception) {
117+
Timber.e(e, "cryptoObject property has not been initialized correctly")
118+
authError()
119+
}
114120
}
115121

116-
private fun authError() {
122+
private fun authError(biometricCanceledManually: Boolean = false) {
117123
if (PassCodeManager.isPassCodeEnabled()) {
118-
PassCodeManager.onBiometricCancelled(this)
124+
PassCodeManager.onBiometricCancelled(this, biometricCanceledManually)
119125
} else if (PatternManager.isPatternEnabled()) {
120-
PatternManager.onBiometricCancelled(this)
126+
PatternManager.onBiometricCancelled(this, biometricCanceledManually)
121127
}
122128

123129
finish()

owncloudApp/src/main/java/com/owncloud/android/presentation/security/passcode/PassCodeManager.kt

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
* ownCloud Android client application
33
*
44
* @author Juan Carlos Garrote Gascón
5+
* @author Jorge Aguado Recio
56
*
6-
* Copyright (C) 2023 ownCloud GmbH.
7+
* Copyright (C) 2025 ownCloud GmbH.
78
*
89
* This program is free software: you can redistribute it and/or modify
910
* it under the terms of the GNU General Public License version 2,
@@ -40,6 +41,8 @@ object PassCodeManager {
4041
private val visibleActivities: MutableSet<Class<*>> = mutableSetOf()
4142
private val preferencesProvider = OCSharedPreferencesProvider(appContext)
4243

44+
private const val BIOMETRIC_HAS_FAILED = "BIOMETRIC_HAS_FAILED"
45+
4346
fun onActivityStarted(activity: Activity) {
4447
if (!exemptOfPasscodeActivities.contains(activity.javaClass) && passCodeShouldBeRequested()) {
4548

@@ -86,15 +89,21 @@ object PassCodeManager {
8689
fun isPassCodeEnabled(): Boolean =
8790
preferencesProvider.getBoolean(PassCodeActivity.PREFERENCE_SET_PASSCODE, false)
8891

89-
private fun askUserForPasscode(activity: Activity) {
92+
private fun askUserForPasscode(activity: Activity, biometricHasFailed: Boolean = false) {
9093
val i = Intent(appContext, PassCodeActivity::class.java).apply {
9194
action = PassCodeActivity.ACTION_CHECK
9295
flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or Intent.FLAG_ACTIVITY_SINGLE_TOP
96+
putExtra(BIOMETRIC_HAS_FAILED, biometricHasFailed)
9397
}
9498
activity.startActivity(i)
9599
}
96100

97-
fun onBiometricCancelled(activity: Activity) {
98-
askUserForPasscode(activity)
101+
fun onBiometricCancelled(activity: Activity, biometricCanceledManually: Boolean = false) {
102+
if (biometricCanceledManually) {
103+
askUserForPasscode(activity)
104+
} else {
105+
// Biometric unlock has failed
106+
askUserForPasscode(activity, true)
107+
}
99108
}
100109
}

owncloudApp/src/main/java/com/owncloud/android/presentation/security/pattern/PatternManager.kt

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
* ownCloud Android client application
33
*
44
* @author Juan Carlos Garrote Gascón
5+
* @author Jorge Aguado Recio
56
*
6-
* Copyright (C) 2023 ownCloud GmbH.
7+
* Copyright (C) 2025 ownCloud GmbH.
78
*
89
* This program is free software: you can redistribute it and/or modify
910
* it under the terms of the GNU General Public License version 2,
@@ -40,6 +41,8 @@ object PatternManager {
4041
private val visibleActivities: MutableSet<Class<*>> = mutableSetOf()
4142
private val preferencesProvider = OCSharedPreferencesProvider(appContext)
4243

44+
private const val BIOMETRIC_HAS_FAILED = "BIOMETRIC_HAS_FAILED"
45+
4346
fun onActivityStarted(activity: Activity) {
4447
if (!exemptOfPatternActivities.contains(activity.javaClass) && patternShouldBeRequested()) {
4548

@@ -79,15 +82,21 @@ object PatternManager {
7982
fun isPatternEnabled(): Boolean =
8083
preferencesProvider.getBoolean(PatternActivity.PREFERENCE_SET_PATTERN, false)
8184

82-
private fun askUserForPattern(activity: Activity) {
85+
private fun askUserForPattern(activity: Activity, biometricHasFailed: Boolean = false) {
8386
val i = Intent(appContext, PatternActivity::class.java).apply {
8487
action = PatternActivity.ACTION_CHECK
8588
flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or Intent.FLAG_ACTIVITY_SINGLE_TOP
89+
putExtra(BIOMETRIC_HAS_FAILED, biometricHasFailed)
8690
}
8791
activity.startActivity(i)
8892
}
8993

90-
fun onBiometricCancelled(activity: Activity) {
91-
askUserForPattern(activity)
94+
fun onBiometricCancelled(activity: Activity, biometricCanceledManually: Boolean = false) {
95+
if (biometricCanceledManually) {
96+
askUserForPattern(activity)
97+
} else {
98+
// Biometric unlock has failed
99+
askUserForPattern(activity, true)
100+
}
92101
}
93102
}

0 commit comments

Comments
 (0)