Reputation: 21
In my mobile application, I have created a separate class file to implement the BiometricManager and BiometricPrompt to use the fingerprint authentication. I have to trigger the Biometric popup in three activities, so I created a common function in separate class file. But the BiometricPrompt object has three parameters such as activity, executor & authentication callback. If I pass the Login activity object (in below code) then it is throwing an error as "Your activity is not yet attached to the Application instance. You can't request ViewModel before onCreate call". Can somebody please help to fix this issue. Thanks in advance.
NewLoginActivity newLoginActivity = new NewLoginActivity();
BiometricManager biometricManager = BiometricManager.from(context);
switch (biometricManager.canAuthenticate(BIOMETRIC_STRONG | DEVICE_CREDENTIAL)) {
case BiometricManager.BIOMETRIC_SUCCESS:
Log.d("MY_APP_TAG", "App can authenticate using biometrics.");
break;
case BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE:
Log.e("MY_APP_TAG", "No biometric features available on this device.");
break;
case BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE:
Log.e("MY_APP_TAG", "Biometric features are currently unavailable.");
break;
case BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED:
// Prompts the user to create credentials that your app accepts.
final Intent enrollIntent = new Intent(Settings.ACTION_BIOMETRIC_ENROLL);
enrollIntent.putExtra(Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED,
BIOMETRIC_STRONG | DEVICE_CREDENTIAL);
startActivityForResult(enrollIntent, REQUEST_CODE);
break;
}
executor = ContextCompat.getMainExecutor(context);
biometricPrompt = new BiometricPrompt(newLoginActivity,
executor, new BiometricPrompt.AuthenticationCallback() {
@Override
public void onAuthenticationError(int errorCode,
@NonNull CharSequence errString) {
super.onAuthenticationError(errorCode, errString);
Toast.makeText(getApplicationContext(),
"Authentication error: " + errString, Toast.LENGTH_SHORT)
.show();
}
@Override
public void onAuthenticationSucceeded(
@NonNull BiometricPrompt.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
Toast.makeText(getApplicationContext(),
"Authentication succeeded!", Toast.LENGTH_SHORT).show();
authErrorStatus.setVisibility(View.GONE);
login();
}
@Override
public void onAuthenticationFailed() {
super.onAuthenticationFailed();
Toast.makeText(getApplicationContext(), "Authentication failed",
Toast.LENGTH_SHORT)
.show();
}
});
promptInfo = new BiometricPrompt.PromptInfo.Builder()
.setTitle("Biometric login for my app")
.setSubtitle("Log in using your biometric credential")
.setNegativeButtonText("Use account password")
.build();
Please check the below log error I got in logcat.
2021-05-11 12:21:21.245 6808-6808/com.purchasingpower.ppow E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.purchasingpower.ppow, PID: 6808
java.lang.IllegalStateException: Your activity is not yet attached to the Application instance. You can't request ViewModel before onCreate call.
at androidx.activity.ComponentActivity.getViewModelStore(ComponentActivity.java:263)
at androidx.lifecycle.ViewModelProvider.<init>(ViewModelProvider.java:99)
at androidx.biometric.BiometricPrompt.getViewModel(BiometricPrompt.java:1027)
at androidx.biometric.BiometricPrompt.<init>(BiometricPrompt.java:844)
at com.app.purchasingpower.utility.BiometricHandler.checkBiometricSensor(BiometricHandler.java:109)
at com.app.purchasingpower.activity.NewLoginActivity.checkFingerprintSensor(NewLoginActivity.java:861)
at com.app.purchasingpower.activity.NewLoginActivity.access$2900(NewLoginActivity.java:92)
at com.app.purchasingpower.activity.NewLoginActivity$6.onCallback(NewLoginActivity.java:802)
at com.app.purchasingpower.activity.NewLoginActivity$1.onCallback(NewLoginActivity.java:324)
at com.app.purchasingpower.volley.JsonObjectResponseController$1$1.onResponse(JsonObjectResponseController.java:131)
at com.app.purchasingpower.volley.JsonObjectResponseController$1$1.onResponse(JsonObjectResponseController.java:127)
at com.android.volley.toolbox.JsonRequest.deliverResponse(JsonRequest.java:83)
at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:106)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
2021-05-11 12:21:21.282 6808-6808/com.purchasingpower.ppow I/Process: Sending signal. PID: 6808 SIG: 9
Upvotes: -4
Views: 2529
Reputation: 20177
You're creating an instance of an Activity
yourself:
NewLoginActivity newLoginActivity = new NewLoginActivity();
You should never, ever create an Activity
instance in Android. The system will always create it for you.
The solution depends where this code is: if it's in a FragmentActivity
subclass, just pass this
. If it's in a Fragment
, pass getActivity()
. And if it's in another class, you'll need to pass the FragmentActivity
as a parameter over to that class so that you can pass it to BiometricPrompt
.
Upvotes: 2