Fixed
Status Update
Comments
ad...@google.com <ad...@google.com>
ad...@google.com <ad...@google.com> #2
Hi Ed, Thank you so much for these suggestions. I've been reviewing them and merging them in. Hopefully it should be live. I've included a thank you note too in the article.
xe...@gmail.com <xe...@gmail.com> #3
Great! Thanks a lot, I'll look for the live updates soon!
xe...@gmail.com <xe...@gmail.com> #4
manually closing the FingerprintHelperFragment works as a workaround
```
override fun onPause() {
// WORKAROUND forhttps://issuetracker.google.com/issues/123857949
activity?.let { activity ->
activity.supportFragmentManager.findFragmentByTag("FingerprintHelperFragment")?.let {
activity.supportFragmentManager.beginTransaction().remove(it).commitAllowingStateLoss()
}
super.onPause()
}
}
```
```
override fun onPause() {
// WORKAROUND for
activity?.let { activity ->
activity.supportFragmentManager.findFragmentByTag("FingerprintHelperFragment")?.let {
activity.supportFragmentManager.beginTransaction().remove(it).commitAllowingStateLoss()
}
super.onPause()
}
}
```
ad...@google.com <ad...@google.com> #5
kc...@google.com <kc...@google.com> #6
There's might be something slightly different in the way lifecycle is being managed between O and lower, and P+
Looking at how mAuthenticationCallback is being passed around here should give us some ideas
https://cs.corp.google.com/aosp-androidx/biometric/src/main/java/androidx/biometric/BiometricPrompt.java?q=biometricprompt.java&dr
Josh can you take a look when convenient? I think the callback isn't getting to the FingerprintHelperFragment for some reason. We can also chat offline when you get to this.
Looking at how mAuthenticationCallback is being passed around here should give us some ideas
Josh can you take a look when convenient? I think the callback isn't getting to the FingerprintHelperFragment for some reason. We can also chat offline when you get to this.
ch...@gmail.com <ch...@gmail.com> #7
This bug is actually a duplicate of https://issuetracker.google.com/issues/121117380 . This issue happens because the new AuthenticationCallback is not being supplied to the biometric prompt fragments if they already exist in the FragmentManager.
Until this is fixed, users of this library MUST manually check for and remove any biometric prompt fragments from the FragmentManager before attempting to call BiometricPrompt#authenticate().
Until this is fixed, users of this library MUST manually check for and remove any biometric prompt fragments from the FragmentManager before attempting to call BiometricPrompt#authenticate().
ma...@zentity.com <ma...@zentity.com> #8
#7
I think that:
1. BiometricPrompt#authenticateInternal should call mFingerprintHelperFragment.setCallback method even if mFingerprintHelperFragment was existed before.
2. FingerprintHelperFragment#cleanup has to set mClientAuthenticationCallback and mExecutor to null to prevent leaking.
I think that:
1. BiometricPrompt#authenticateInternal should call mFingerprintHelperFragment.setCallback method even if mFingerprintHelperFragment was existed before.
2. FingerprintHelperFragment#cleanup has to set mClientAuthenticationCallback and mExecutor to null to prevent leaking.
ma...@zentity.com <ma...@zentity.com> #9
My mistake in point one:
1. Biometric#mLifecycleObserver#onResume should call mFingerprintHelperFragment.setCallback(...) even if mFingerprintDialogFragment is null.
Here is my temporary fix. Just place it in androidx.biometric package and use it like BiometricPrompt:
package androidx.biometric
import android.annotation.SuppressLint
import androidx.fragment.app.FragmentActivity
import java.util.concurrent.Executor
/**
* Fix for isssuehttps://issuetracker.google.com/issues/123857949
*/
@SuppressLint("RestrictedApi")
class FixedBiometricPrompt(
private val fragmentActivity: FragmentActivity,
executor: Executor,
callback: BiometricPrompt.AuthenticationCallback
) {
private val delegate: BiometricPrompt
init {
// set executor and callback to helper fragment
(fragmentActivity.supportFragmentManager.findFragmentByTag("FingerprintHelperFragment") as? FingerprintHelperFragment)?.setCallback(
executor,
callback
)
delegate = BiometricPrompt(fragmentActivity, executor, callback)
}
fun authenticate(info: BiometricPrompt.PromptInfo, crypto: BiometricPrompt.CryptoObject) {
delegate.authenticate(info, crypto)
}
fun authenticate(info: BiometricPrompt.PromptInfo) {
delegate.authenticate(info)
}
fun cancelAuthentication() {
delegate.cancelAuthentication()
}
fun cleanup() {
// remove executor and callback from helper fragment to prevent memory leak
(fragmentActivity.supportFragmentManager.findFragmentByTag("FingerprintHelperFragment") as? FingerprintHelperFragment)?.setCallback(
null,
null
)
}
}
1. Biometric#mLifecycleObserver#onResume should call mFingerprintHelperFragment.setCallback(...) even if mFingerprintDialogFragment is null.
Here is my temporary fix. Just place it in androidx.biometric package and use it like BiometricPrompt:
package androidx.biometric
import android.annotation.SuppressLint
import androidx.fragment.app.FragmentActivity
import java.util.concurrent.Executor
/**
* Fix for isssue
*/
@SuppressLint("RestrictedApi")
class FixedBiometricPrompt(
private val fragmentActivity: FragmentActivity,
executor: Executor,
callback: BiometricPrompt.AuthenticationCallback
) {
private val delegate: BiometricPrompt
init {
// set executor and callback to helper fragment
(fragmentActivity.supportFragmentManager.findFragmentByTag("FingerprintHelperFragment") as? FingerprintHelperFragment)?.setCallback(
executor,
callback
)
delegate = BiometricPrompt(fragmentActivity, executor, callback)
}
fun authenticate(info: BiometricPrompt.PromptInfo, crypto: BiometricPrompt.CryptoObject) {
delegate.authenticate(info, crypto)
}
fun authenticate(info: BiometricPrompt.PromptInfo) {
delegate.authenticate(info)
}
fun cancelAuthentication() {
delegate.cancelAuthentication()
}
fun cleanup() {
// remove executor and callback from helper fragment to prevent memory leak
(fragmentActivity.supportFragmentManager.findFragmentByTag("FingerprintHelperFragment") as? FingerprintHelperFragment)?.setCallback(
null,
null
)
}
}
ma...@zentity.com <ma...@zentity.com> #10
...
Then call function cleanup() in onDestroyView...
override fun onDestroyView() {
super.onDestroyView()
biometricPrompt.cleanup()
}
Then call function cleanup() in onDestroyView...
override fun onDestroyView() {
super.onDestroyView()
biometricPrompt.cleanup()
}
sb...@doximity.com <sb...@doximity.com> #11
the proper fix (on google's side) is pretty simple
on line 498
if (mFingerprintHelperFragment == null) {
mFingerprintHelperFragment = FingerprintHelperFragment.newInstance();
mFingerprintHelperFragment.setCallback(mExecutor, mAuthenticationCallback); // <-- this line should be moved out side the if statement
}
on line 498
if (mFingerprintHelperFragment == null) {
mFingerprintHelperFragment = FingerprintHelperFragment.newInstance();
mFingerprintHelperFragment.setCallback(mExecutor, mAuthenticationCallback); // <-- this line should be moved out side the if statement
}
kc...@google.com <kc...@google.com> #12
Hmm we already fixed this. Just need to cut a new build for alpha04 now.
The bug was referenced in this CL but somehow buganizer didn't close it
https://android-review.googlesource.com/c/platform/frameworks/support/+/917882/
The bug was referenced in this CL but somehow buganizer didn't close it
Description
Version used: 1.0.0-alpha03
Devices/Android versions reproduced on: Emulator API 24
if used in more than one Fragment inside the same activity, BiometricPrompt only listens for callbacks in the first BiometricPrompt.AuthenticationCallback provided
no matter if you create a new instance of the prompt in another fragment
This only happens in API level below P
In P works fine,
I tested in 24 and P