Fingerprint Operation Cancelled while using in app authentication

Varun Joshi picture Varun Joshi · Jul 17, 2017 · Viewed 8k times · Source

I'm using FingerprintManager in my app to authenticate the user everytime he returns to the app after screen was unlocked. The first time it works fine, the next time it shows fingerprint operation cancelled.

Here's my code:

public class FingerprintHandler extends FingerprintManager.AuthenticationCallback
{
    private AlertDialog.Builder dialogBuilder;
    private AlertDialog b;

    private TextView text_state;
    private ImageView image_state;
    View view;
    private Context context;

    public FingerprintHandler(Context mContext, View mView) {
        context = mContext;
        this.view = mView;
        dialogBuilder = new AlertDialog.Builder(context);
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        final View dialogView = inflater.inflate(R.layout.custom_fingerprint_auth_dialog, null);
        text_state = (TextView) dialogView.findViewById(R.id.text_state);
        image_state = (ImageView) dialogView.findViewById(R.id.image_state);
       // view = inflater.inflate(R.layout.activity_passcode, null);
        dialogBuilder.setView(dialogView);
        dialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                dialog.dismiss();
            }
        });
        dialogBuilder.setPositiveButton("Use Password", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

                PasscodeActivity.enterPassword(view, context);
            }
        });
        b = dialogBuilder.create();
        b.show();
        b.setCancelable(false);
        b.setCanceledOnTouchOutside(false);
    }

    //Implement the startAuth method, which is responsible for starting the fingerprint authentication process//

    public void startAuth(FingerprintManager manager, FingerprintManager.CryptoObject cryptoObject) {

        CancellationSignal cancellationSignal = new CancellationSignal();
        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        manager.authenticate(cryptoObject, cancellationSignal, 0, this, null);
    }

    @Override
    //onAuthenticationError is called when a fatal error has occurred. It provides the error code and error message as its parameters//

    public void onAuthenticationError(int errMsgId, CharSequence errString) {

        //I’m going to display the results of fingerprint authentication as a series of toasts.
        //Here, I’m creating the message that’ll be displayed if an error occurs//

        if (errMsgId != FINGERPRINT_ERROR_CANCELED) {
            text_state.setText(errString);
            Log.e("ERROR", "" + errString);
            image_state.setImageResource(R.drawable.ic_fingerprint_failure);
            text_state.setTextColor(context.getResources().getColor(R.color.notVerified));
            //Toast.makeText(context, "Authentication error\n" + errString, Toast.LENGTH_LONG).show();
        }
    }

    @Override

    //onAuthenticationFailed is called when the fingerprint doesn’t match with any of the fingerprints registered on the device//

    public void onAuthenticationFailed() {
        text_state.setText(context.getString(R.string.fingerFailure));
        image_state.setImageResource(R.drawable.ic_fingerprint_failure);
        text_state.setTextColor(context.getResources().getColor(R.color.notVerified));
        //Toast.makeText(context, "Authentication failed", Toast.LENGTH_LONG).show();
    }

    @Override

    //onAuthenticationHelp is called when a non-fatal error has occurred. This method provides additional information about the error,
    //so to provide the user with as much feedback as possible I’m incorporating this information into my toast//
    public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
        text_state.setText(helpString);
        Log.e("HELP",""+helpString);
        image_state.setImageResource(R.drawable.ic_fingerprint_failure);
        text_state.setTextColor(context.getResources().getColor(R.color.notVerified));
        //Toast.makeText(context, "Authentication help\n" + helpString, Toast.LENGTH_LONG).show();
    }

    @Override

    //onAuthenticationSucceeded is called when a fingerprint has been successfully matched to one of the fingerprints stored on the user’s device//
    public void onAuthenticationSucceeded(
            FingerprintManager.AuthenticationResult result) {

        text_state.setText(context.getString(R.string.fingerSuccess));
        image_state.setImageResource(R.drawable.ic_fingerprint_success);
        text_state.setTextColor(context.getResources().getColor(R.color.colorPrimaryDark));
        Activity activity = (Activity) context;
        activity.finish();
        b.dismiss();

        //Toast.makeText(context, "Success!", Toast.LENGTH_LONG).show();
    }
}

Answer

MrODG picture MrODG · Sep 18, 2017

Fingerprint operation cancelled is usually triggered when the sensor is occupied by a previous operation. Everytime you leave the app or when you have finished authentication call the cancellationSignal.cancel(); This will make sure that the sensor has finished the job and it can be released. In your case I would add that line in your LockScreens onPause and also Important: and that line in each of your FingerPrintHandler Callback just to make sure e.g

    @Override
//onAuthenticationFailed is called when the fingerprint doesn’t match with any of the fingerprints registered on the device//
public void onAuthenticationFailed() {
    text_state.setText(context.getString(R.string.fingerFailure));
    image_state.setImageResource(R.drawable.ic_fingerprint_failure);
    cancellationSignal.cancel();
    text_state.setTextColor(context.getResources().getColor(R.color.notVerified));
    //Toast.makeText(context, "Authentication failed", Toast.LENGTH_LONG).show();
}