In this tutorial, we will learn how to implement Fingerprint or Biometric Authentication in Android Application.

To authenticate the user using fingerprint sensor, we must need to get an instance of the newly implemented FingerprintManager class and call the authenticate() method. Most of the device not supported in fingerprint sensor and it is working on above API 23.





Create a new project

We are going to create a new android project. Go to File ⇒ New ⇒ New Projects in Android studio and set the minimum SDK version to API 23: Android 6.0(Marshmallow).
Android Marshmallow create project

Add Permission

To authenticate user, we need to add USE_FINGERPRINT permission in AndroidManifest.xml file.

<uses-permission android:name="android.permission.USE_FINGERPRINT" />

Adding Layout

Adding below code in activity_main.xml file. click here to Download Fingerprint icon image.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="in.studytutorial
           .androidfingerprintauthentication.MainActivity">


    <LinearLayout
        android:layout_width="match_parent"
        android:id="@+id/headerLayout"
        android:orientation="vertical"
        android:gravity="center"
        android:layout_marginTop="100dp"
        android:layout_height="wrap_content">


        <ImageView
            android:id="@+id/icon"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:src="@drawable/ic_fp"
            android:paddingTop="2dp"
            android:layout_marginBottom="30dp"/>



        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColor="#000"
            android:textSize="16sp"
            android:textAlignment="center"
            android:gravity="center"
            android:id="@+id/desc"
            android:text="Please place your fingertip 
                  on the scanner to verify your identity"
            android:layout_margin="16dp"
            android:paddingEnd="30dp"
            android:paddingStart="30dp"/>


        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColor="@color/errorText"
            android:textSize="14sp"
            android:textAlignment="center"
            android:id="@+id/errorText"
            android:paddingEnd="30dp"
            android:paddingStart="30dp"
            android:layout_marginTop="30dp"
            android:gravity="center"/>

    </LinearLayout>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#000"
        android:textSize="14sp"
        android:text="(Your device should have at 
         least one fingerprint registered in device settings)"
        android:layout_marginLeft="16dp"
        android:textAlignment="center"
        android:layout_marginRight="16dp"
        android:layout_marginBottom="26dp"
        android:layout_alignParentBottom="true"/>
</RelativeLayout>

Android Fingerprint scanner layout

Create Another Activity

After successfully authentication, we will start another activity. Hence we need to create a new Activity named as HomeActivity. Add below code in acitivity_home.xml file

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="in.studytutorial
           .androidfingerprintauthentication.HomeActivity">

    <TextView
        android:layout_width="match_parent"
        android:text="Welcome To Home Activity"
        android:layout_centerVertical="true"
        android:textSize="24sp"
        android:textAlignment="center"
        android:textColor="@color/colorPrimary"
        android:layout_height="wrap_content" />


    <TextView
        android:layout_width="match_parent"
        android:text="You have successfully authenticate 
          with fingerprint"
        android:layout_alignParentBottom="true"
        android:textSize="14sp"
        android:textAlignment="center"
        android:textColor="@color/colorPrimary"
        android:layout_height="wrap_content"
        android:layout_marginBottom="24dp"/>

</RelativeLayout>

Android Home Activity


Creating Fingerprint Authentication Handler Class

We will create a new java class names as FingerprintAuthenticationHandler. It will use to handle authentication response. This class extends FingerprintManager.AuthenticationCallback and include some addition function. Use the below code


import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.CancellationSignal;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.widget.TextView;


public class FingerprintAuthenticationHandler extends 
                      FingerprintManager.AuthenticationCallback {


    private Context context;

    // Constructor
    public FingerprintAuthenticationHandler(Context mContext) {
        context = mContext;
    }


    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
    public void onAuthenticationError(int errMsgId, CharSequence errString) {
        this.update("Fingerprint Authentication error\n" + errString, false);
    }


    @Override
    public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
        this.update("Fingerprint Authentication help\n" + helpString, false);
    }


    @Override
    public void onAuthenticationFailed() {
        this.update("Fingerprint Authentication failed.", false);
    }


    @Override
    public void onAuthenticationSucceeded(
             FingerprintManager.AuthenticationResult result) {
        this.update("Fingerprint Authentication succeeded.", true);
    }


    public void update(String e, Boolean success){
        TextView textView = (TextView) ((Activity)context)
           .findViewById(R.id.errorText);
        textView.setText(e);
        if(success){
            textView.setTextColor(ContextCompat.getColor(context,
               R.color.colorPrimaryDark));
            Intent i = new Intent(context, HomeActivity.class);
            context.startActivity(i);
        }
    }
}

MainAcivity Class

We have already create MainActivity.class. In this class, we will implemented some method which used to check hardware capability, generate encrypt key, create the encrypted FingerprintManager and authentication process.

We will be Initialize both Android Keyguard Manager and Fingerprint Manager. Keyguard Manager is used to check lock screen security enabled in the setting. Fingerprint Manager is used to check hardware capability. Also create some below method:

  • generateKey() function which generates an encryption key which is then stored securely on the device.
  • cipherInit() function that initializes the cipher that will be used to create the encrypted FingerprintManager.
  • CryptoObject instance and various other checks before initiating the authentication process which is implemented inside onCreate() method.

import android.Manifest;
import android.annotation.TargetApi;
import android.app.KeyguardManager;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;


public class MainActivity extends AppCompatActivity {

    private KeyStore keyStore;
    // Variable used for storing the key in the Android Keystore container
    private static final String KEY_NAME = "studytutorial";
    private Cipher cipher;
    private TextView textView;
    public KeyguardManager keyguardManager;
    public FingerprintManager fingerprintManager;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Initializing both Android Keyguard Manager and Fingerprint Manager
        keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
        fingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);


        textView = (TextView) findViewById(R.id.errorText);

        checkFingerPrintScanner();

    }

    protected void checkFingerPrintScanner(){
        // Check whether the device has a Fingerprint sensor.
        if(!fingerprintManager.isHardwareDetected()){
            /**
             * An error message will be displayed if the device does not contain the fingerprint hardware.
             * However if you plan to implement a default authentication method,
             */
            textView.setText("Your Device does not have a Fingerprint Sensor");
        }else {
            // Checks whether fingerprint permission is set on manifest
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
                textView.setText("Fingerprint authentication permission not enabled");
            }else{
                // Check whether at least one fingerprint is registered
                if (!fingerprintManager.hasEnrolledFingerprints()) {
                    textView.setText("Register at least one fingerprint in Settings");
                }else{
                    // Checks whether lock screen security is enabled or not
                    if (!keyguardManager.isKeyguardSecure()) {
                        textView.setText("Lock screen security not enabled in Settings");
                    }else{
                        generateKey();


                        if (cipherInit()) {
                            FingerprintManager.CryptoObject cryptoObject = new FingerprintManager.CryptoObject(cipher);
                            FingerprintAuthenticationHandler helper = new FingerprintAuthenticationHandler(this);
                            helper.startAuth(fingerprintManager, cryptoObject);

                        }
                    }
                }
            }
        }
    }


    @TargetApi(Build.VERSION_CODES.M)
    protected void generateKey() {
        try {
            keyStore = KeyStore.getInstance("AndroidKeyStore");
        } catch (Exception e) {
            e.printStackTrace();
        }


        KeyGenerator keyGenerator;
        try {
            keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
        } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
            throw new RuntimeException("Failed to get KeyGenerator instance", e);
        }


        try {
            keyStore.load(null);
            keyGenerator.init(new
                    KeyGenParameterSpec.Builder(KEY_NAME,
                    KeyProperties.PURPOSE_ENCRYPT |
                            KeyProperties.PURPOSE_DECRYPT)
                    .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
                    .setUserAuthenticationRequired(true)
                    .setEncryptionPaddings(
                            KeyProperties.ENCRYPTION_PADDING_PKCS7)
                    .build());
            keyGenerator.generateKey();
        } catch (NoSuchAlgorithmException |
                InvalidAlgorithmParameterException
                | CertificateException | IOException e) {
            throw new RuntimeException(e);
        }
    }


    @TargetApi(Build.VERSION_CODES.M)
    public boolean cipherInit() {
        try {
            cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new RuntimeException("Failed to get Cipher", e);
        }


        try {
            keyStore.load(null);
            SecretKey key = (SecretKey) keyStore.getKey(KEY_NAME,
                    null);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            return true;
        } catch (KeyPermanentlyInvalidatedException e) {
            return false;
        } catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException | NoSuchAlgorithmException | InvalidKeyException e) {
            throw new RuntimeException("Failed to init Cipher", e);
        }
    }
}