raghavendra rao
raghavendra rao

Reputation: 21

How to pass an activity in BiometricPrompt object in android

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

Answers (1)

Ryan M
Ryan M

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

Related Questions