BiometricPrompt builder system UI type - android

I am working on authenticating my my via BiometricPrompt
The UI shown by system varies
on Motorola (stock Android) I get BottomSheet
on OnePlus I get Full screen activity
How can I know what type of UI would be shown Or how can I control the ui
My problem
Facing a big issue in Activity transition
In BottomSheet UI I can see the my app screen UI elements which I don't want
I can't guess how GooglePay(Tez) is doing
MyCode
val executor = ContextCompat.getMainExecutor(activity)
val biometricPrompt = BiometricPrompt(activity, executor,
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
super.onAuthenticationError(errorCode, errString)
if (errorCode == BiometricConstants.ERROR_USER_CANCELED) {
listener.onAuthCancelled()
} else {
listener.onAuthFailed()
}
}
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
super.onAuthenticationSucceeded(result)
listener.onAuthSucceeded()
}
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
listener.onAuthFailed()
}
})
val promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Title")
.setSubtitle("Sub title ")
.setConfirmationRequired(false)
.setDeviceCredentialAllowed(true)
.build()
biometricPrompt.authenticate(promptInfo)

Related

Face Id authentication for Android

User wants to login only with FaceId,But when I code like
executor = ContextCompat.getMainExecutor(requireContext())
biometricPrompt = BiometricPrompt(this, executor,
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationError(
errorCode: Int,
errString: CharSequence
) {
super.onAuthenticationError(errorCode, errString)
}
override fun onAuthenticationSucceeded(
result: BiometricPrompt.AuthenticationResult
) {
super.onAuthenticationSucceeded(result)
moveToLogin()
}
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
}
})
promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Biometric login of ${getString(R.string.app_name)}")
.setSubtitle("Log in using your biometric credential")
.setNegativeButtonText("Use account password")
.setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_WEAK)
.build()
biometricPrompt.authenticate(promptInfo)
This shows both Fingerprint and FaceId, But i need to show only faceID Eventhough both authentication is enabled in system level.

move from callback to suspend function

I have this function :
fun createBiometricPrompt(
activity: AppCompatActivity,
processSuccess: (BiometricPrompt.AuthenticationResult) -> Unit,
callback: BiometricCallback
): BiometricPrompt {
var nbFailure = 0
val executor = ContextCompat.getMainExecutor(activity)
val callback = object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationError(errCode: Int, errString: CharSequence) {
super.onAuthenticationError(errCode, errString)
Log.d(TAG, "errCode is $errCode and errString is: $errString")
}
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
Log.d(TAG, "User biometric rejected.")
nbFailure++;
if(nbFailure == MAX_BIOMETRICS_FAILURE){
nbFailure = 0
callback.onFailure()
}
}
which is using a callback callback: BiometricCallback, it's only for now using it for notifying that a failure happened by sending callback.onFailure()
Callback is called in the calling Fragment by doing this:
Fragment.kt
biometricPrompt =
BiometricPromptUtils.createBiometricPrompt(requireActivity() as AppCompatActivity, ::encryptAndStoreServerToken, object: BiometricCallback {
override fun onFailure() {
biometricPrompt.cancelAuthentication()
viewModel.loginError.set("Error Biometrics")
}
})
The onFailure is used then to cancel the process and display an error.
The Callback interface is defined as :
interface BiometricCallback {
fun onFailure()
}
I have been asked to use a suspend function instead of a callback but I have no clue how to do it properly. Should I use LiveData ? If any idea, please help
Thanks
you can use suspendCancellableCoroutine or suspendCoroutine to convert any callback based Api in direct style to make it more kotlin friendly plus it provides more encapsulation you will be just returned with the result all complexity is handled inside the function only
suspend fun authenticate():BiomatricPrompt.AuthenticationResult? {
return suspendCancelableCoroutine { continuation ->
biometricPrompt = BiometricPrompt(this, executor,
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationError(errorCode: Int,
errString: CharSequence) {
super.onAuthenticationError(errorCode, errString)
continuation.resume(null,null)
}
override fun onAuthenticationSucceeded(
result: BiometricPrompt.AuthenticationResult) {
super.onAuthenticationSucceeded(result)
continuation.resume(result,null)
}
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
continuation.resume(null,null)
}
})
promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Biometric login for my app")
.setSubtitle("Log in using your biometric credential")
.setNegativeButtonText("Use account password")
.build()
biometricPrompt.authenticate(promptInfo)
}
}
usage
val authenticationResult = authenticate()
if(authenticationResult == null){
//authentication failed
}else{
//authenticated successfully
}
you can use custom object as result type to handle more use cases
more information

FaceUnlock is not working in my app android kotlin

I have tried to setup fingerprint, pattern/password/pin, faceUnlock for my app. But Biometric doesn't works it always showing fingerprint with use pattern dialog. Is Still Biometrics not support FaceUnlock? If Not supported Biometric dependency means which library I should use in my app which contains fingerprint, pattern/password/pin and faceUnlock.
class LoginActivity : AppCompatActivity(){
private lateinit var biometricPrompt: BiometricPrompt
private lateinit var executor: Executor
private lateinit var callBack: BiometricPrompt.AuthenticationCallback
lateinit var prompt: BiometricPrompt.PromptInfo
private var keyguardManager: KeyguardManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityLoginBinding>(this, R.layout.activity_login)
executor = ContextCompat.getMainExecutor(this)
biometricPrompt = BiometricPrompt(this, executor, object: BiometricPrompt.AuthenticationCallback(){
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
tvAuthStatus.text = "Authentication Failed"
}
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
super.onAuthenticationSucceeded(result)
startActivity(Intent(this#LoginActivity, MainActivity::class.java))
finish()
tvAuthStatus.text = "Authentication Success"
}
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
super.onAuthenticationError(errorCode, errString)
tvAuthStatus.text = "Error" + errString
}
})
prompt = BiometricPrompt.PromptInfo.Builder()
.setTitle("RoomDB FingerPrint Login")
.setNegativeButtonText("Login using fingerprint or face")
.setNegativeButtonText("Cancel")
.build()
btnAuth.setOnClickListener {
biometricPrompt.authenticate(prompt)
}
}
}
Maybe, in your case, the reason is your test device is released with the face authentication feature before the same API for face authentication appears in the official Android SDK. It makes third-party applications in your test device cannot use face authentication. Check this library, it said about this thing in README.md "I have a device that can be unlocked using Fingerprint/Face/Iris and(or) I can use this biometric type in pre-installed apps. But it doesn't work on 3rd party apps. Can you help?"
https://github.com/sergeykomlach/AdvancedBiometricPromptCompat#i-have-a-device-that-can-be-unlocked-using-fingerprintfaceiris-andor-i-can-use-this-biometric-type-in-pre-installed-apps-but-it-doesnt-work-on-3rd-party-apps-can--you-help
Hope it can help.

Biometric not detected in Samsung galaxy M01 device with Android Q?

Following is my code to detect biometric functionality
class MainActivity : AppCompatActivity() {
private var executor: Executor? = null
private var biometricPrompt: BiometricPrompt? = null
private var promptInfo: BiometricPrompt.PromptInfo? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val bioMetricManager = BiometricManager.from(this)
when (bioMetricManager.canAuthenticate()) {
BiometricManager.BIOMETRIC_SUCCESS -> {
executor = ContextCompat.getMainExecutor(this)
promptInfo = BiometricPrompt.PromptInfo.Builder().setTitle("Biometric login for leaao")
.setSubtitle("Log in using biometric credentials").setDeviceCredentialAllowed(true).build()
biometricPrompt = BiometricPrompt(this,
executor!!, object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
super.onAuthenticationError(errorCode, errString)
Log.i("here4","Authentication error: $errString")
}
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
super.onAuthenticationSucceeded(result)
Log.i("here5","Success")
}
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
Log.i("here6","Authentication failed: ")
}
})
biometricPrompt?.authenticate(promptInfo!!)
}
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> {
Log.i("here","No biometric features available on this device.")
}
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> {
Log.i("here2","Biometric features are currently unavailable.")
}
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> {
Log.i("here3","The user hasn't associated any biometric credentials with their account.")
}
}
}
}
I have added <uses-permission android:name="android.permission.USE_BIOMETRIC" /> to Manifest file and added implementation 'androidx.biometric:biometric:1.0.1' to gradle
Still my code fails to detect biometric prompt. I have enabled face recognition on my mobile but it does not work when i open my app. It goes to BIOMETRIC_ERROR_HW_UNAVAILABLE case in my code.
By default, the BiometricManager seeks BIOMETRIC_STRONG sensors on the device, unless you specify them in .setAllowedAutnenticators(). However, you should know that as of now, there are no devices with STRONG face/iris sensors. That means that only the fingerprint sensor is "seen" as STRONG and all of the face and iris sensors (with some exceptions, where they are not seen as a sensor at all) are "seen" as BIOMETRIC_WEAK. With "seen" I mean they were set as such by the manufacturer. So having said that, something like this should be able to fix your issue:
BiometricPrompt.PromptInfo.Builder()
.setTitle(...)
.setDescription(...)
.setAllowedAuthenticators(
BiometricManager.Authenticators.BIOMETRIC_STRONG or
BiometricManager.Authenticators.BIOMETRIC_WEAK
)
and when checking for available authentication:
when (BiometricManager.from(requireContext()).canAuthenticate(
BiometricManager.Authenticators.BIOMETRIC_STRONG
or BiometricManager.Authenticators.BIOMETRIC_WEAK
)) { ... }

Android BiometricPrompt DeviceCredentialHandler: onCreate: Executor and/or callback was null

It looks like BiometricPrompt 1.0.0 has a bug where it stays in invisible state throwing that exception
ill suggest a workaround in the answer
EDIT(thanks to #Isai Damier):
Way to reproduce:
open the BiometricPrompt
press back button - close the prompt
press back again and exit the app
return to the app - try to open the prompt again
this fix was introduces when biometric prompt version was 1.0.0. this issue dosent reproduces in 1.0.1
//-------------------------------------------------------------------------
i came up with a work around - call 'cancelAuthentication' on the prompt upon user cancelation.
full code is as follows (used in a react native app - thats why the promise are for):
private const val E_BIOMETRIC_ERR = "E_FINGER_PRINT_ERR"
private const val OPENED = "success"
private var bp: BiometricPrompt? = null
private var mAuthenticationPromise: Promise? = null
fun authenticate(activity: AppCompatActivity, title: String,
subTitle: String, description: String, authenticationPromise: Promise) {
mAuthenticationPromise = authenticationPromise
val executor = Executors.newSingleThreadExecutor()
bp?.cancelAuthentication()
bp = getBiometricPrompt(activity, executor)
val promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle(title)
.setSubtitle(subTitle)
.setDescription(description)
.setDeviceCredentialAllowed(true)
.build()
bp!!.authenticate(promptInfo)
}
private fun getBiometricPrompt(activity: AppCompatActivity, executor: Executor): BiometricPrompt {
return BiometricPrompt(activity, executor, object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
super.onAuthenticationSucceeded(result)
mAuthenticationPromise?.resolve(OPENED)
}
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
super.onAuthenticationError(errorCode, errString)
bp!!.cancelAuthentication()
}
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
bp!!.cancelAuthentication()
}
})
}
I hope it helps anyone - cheers

Categories

Resources