How to Add Fingerprint Authentication in Android

82
views
add fingerprint authentication in android
(Last Updated On: February 11, 2018)

Recently with the release of Android 6.0 (M) last year, there has been a significant amount of changes to the APIs, one of them is Fingerprint Authentication. With the release of new APIs, authenticating users with help of fingerprint sensors on various devices is possible.
Following the tutorial, the example shows how to implement Fingerprint Authentication in your application.

To authenticate users using the fingerprint sensor, you need to get an instance of the newly implemented FingerprintManager class and call the authenticate() method. However, your app must be running on a compatible device which includes a fingerprint sensor. Moreover, you must implement the user interface for the fingerprint authentication flow on your app, and use the standard Android fingerprint icon in your UI. Note that If you are developing multiple apps that use fingerprint authentication, each app must authenticate the user’s fingerprint separately.

Advantages of Using Fingerprint Authentication

1. Doesn’t matter how sick you are or unable to recollect things, your fingerprint still stays faultless as your identity and can never be misplaced.
2. Fast, Convenient and Reliable to use.
3. Unique fingerprints assure that it’s unlocked just by you.
4. With the help of Fingerprint authentication, online transactions become more convenient, hence your just a tap away from getting verified.

Here is the final app we are about to build.

1. Creating New Project

1. Create a new project in Android Studio from File ⇒ New Project and set the minimum SDK version to Android 6.0 (API 23).

2. Since we are going to work with Fingerprint authentication, we need to add USE_FINGERPRINT permission to AndroidManifest.xml file

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.coderforevers.fingerprint">
 
   <uses-permission android:name="android.permission.USE_FINGERPRINT" />
 
   <application
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:supportsRtl="true"
      android:theme="@style/AppTheme">
       <activity android:name=".FingerprintActivity">
           <intent-filter>
               <action android:name="android.intent.action.MAIN" />
 
 
               <category android:name="android.intent.category.LAUNCHER" />
           </intent-filter>
       </activity>
   </application>
</manifest>

3. Open colors.xml file located under res ⇒ values and update the file.

colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
   <color name="colorPrimary">#263237</color>
   <color name="colorPrimaryDark">#1e282d</color>
   <color name="colorAccent">#1e282d</color>
   <color name="textPrimary">#f5f5f5</color>
   <color name="textPrimaryDark">#95aab4</color>
   <color name="errorText">#ff7878</color>
</resources>

4. Open strings.xml file located under res ⇒ values and update the file.

strings.xml
<resources>
   <string name="app_name">Fingerprint</string>
   <string name="title_activity_main">MainActivity</string>
   <string name="title_fingerprint">One-touch Sign In</string>
   <string name="desc_fingerprint">Please place your fingertip on the scanner to verify your identity</string>
   <string name="note">(Fingerprint sign in makes your app login much faster. Your device should have at least one fingerprint registered in device settings)</string>
   <string name="title_activity_home">Fingerprint</string>
   <string name="activity_home_desc">You have successfully logged in with fingerprint authentication</string>
   <string name="activity_home_note">Close and re-open the app to see the fingerprint auth screen again</string>
</resources>
5. Create the fingerprint icon with the help of “Android Image Assets”. To do so, Right click on the drawable folder and Create a New ⇒ Image Asset named ic_action_fingerprint
 

2. Creating Fingerprint Activity

6. Create a layout XML file named activity_fingerprint.xml and place the below code.

activity_fingerprint.xml
<?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:id="@+id/activity_fingerprint"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="@color/colorPrimary"
  tools:context="com.coderforevers.fingerprint.FingerprintActivity">
 
 
   <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:layout_width="70dp"
          android:layout_height="70dp"
          android:src="@drawable/ic_action_fingerprint"
          android:id="@+id/icon"
          android:paddingTop="2dp"
          android:layout_marginBottom="30dp"/>
 
 
       <TextView
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:textColor="@color/textPrimary"
          android:textSize="24sp"
          android:text="@string/title_fingerprint"
          android:layout_marginLeft="5dp"
          android:layout_marginRight="5dp"
          android:layout_marginTop="20dp"
          android:layout_marginBottom="10dp"/>
 
       <TextView
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:textColor="@color/textPrimary"
          android:textSize="16sp"
          android:textAlignment="center"
          android:gravity="center"
          android:id="@+id/desc"
          android:text="@string/desc_fingerprint"
          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="@color/textPrimaryDark"
      android:textSize="14sp"
      android:text="@string/note"
      android:layout_marginLeft="16dp"
      android:textAlignment="center"
      android:layout_marginRight="16dp"
      android:layout_marginBottom="26dp"
      android:layout_alignParentBottom="true"/>
 
</RelativeLayout>

7. Create an Android Activity class and name it FingeprintActivity.java. The following class includes various methods and functions like, onCreate() method that inflates activity_fingerprint.xml.

> generateKey() function which generates an encryption key which is then stored securely on the device.

> cipherInit() function that initializes the cypher 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.

Add the following final code of Fingerprint Activity to the FinagerprintActvity.java file.

FinagerprintActvity.java
package com.coderforevers.fingerprint;
 
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 FingerprintActivity extends AppCompatActivity {
 
 
   private KeyStore keyStore;
   // Variable used for storing the key in the Android Keystore container
   private static final String KEY_NAME = "coderForevers";
   private Cipher cipher;
   private TextView textView;
 
 
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_fingerprint);
 
 
       // Initializing both Android Keyguard Manager and Fingerprint Manager
       KeyguardManager keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
       FingerprintManager fingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);
 
 
       textView = (TextView) findViewById(R.id.errorText);
 
 
       // 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,
            * you can redirect the user to a default authentication activity from here.
            * Example:
            * Intent intent = new Intent(this, DefaultAuthenticationActivity.class);
            * startActivity(intent);
            */
           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);
                           FingerprintHandler helper = new FingerprintHandler(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);
       }
   }
}




3. Creating Home Activity

8. Create the Activity by right-clicking your Project, New ⇒ Activity ⇒ Basic Activity and update the following files as shown below.

activity_home.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:fitsSystemWindows="true"
  tools:context="com.coderforevers.fingerprint.HomeActivity">
 
 
   <android.support.design.widget.AppBarLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:theme="@style/AppTheme.AppBarOverlay">
 
 
       <android.support.v7.widget.Toolbar
          android:id="@+id/toolbar"
          android:layout_width="match_parent"
          android:layout_height="?attr/actionBarSize"
          android:background="?attr/colorPrimary"
          app:popupTheme="@style/AppTheme.PopupOverlay" />
 
 
   </android.support.design.widget.AppBarLayout>
 
   <include layout="@layout/content_home" />
 
</android.support.design.widget.CoordinatorLayout>
content_home.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/content_home"
  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"
  app:layout_behavior="@string/appbar_scrolling_view_behavior"
  tools:context="com.coderforevers.fingerprint.HomeActivity"
  tools:showIn="@layout/activity_home">
 
 
   <TextView
      android:layout_width="match_parent"
      android:text="@string/activity_home_desc"
      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="@string/activity_home_note"
      android:layout_alignParentBottom="true"
      android:textSize="14sp"
      android:textAlignment="center"
      android:textColor="@color/colorPrimary"
      android:layout_height="wrap_content"
      android:layout_marginBottom="24dp"/>
 
</RelativeLayout>
HomeActivity.class
package com.coderforevers.fingerprint;
 
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
 
public class HomeActivity extends AppCompatActivity {
 
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_home);
       Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
       setSupportActionBar(toolbar);
   }
}

4. Creating Fingerprint Authentication Handler Class

9. Create a class and name it FingerprintHandler.java. The Handler class extends FingerprintManager.AuthenticationCallback and includes some additional modules. Replace the following set of codes with any existing codes on FingerprintHandler.java file.

FingerprintHandler.java
package com.coderforevers.fingerprint;
 
 
import android.Manifest;
import android.app.Activity;
import android.content.Context;
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;
 
 
/**
* Created by whit3hawks on 11/16/16.
*/
public class FingerprintHandler extends FingerprintManager.AuthenticationCallback {
 
 
   private Context context;
 
 
   // Constructor
   public FingerprintHandler(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));
       }
   }
}

5. Testing the Project

Testing on a Physical Device

With the project now complete, debug the app on a physical Android device by placing your fingertip on the fingerprint scanner. If Fingerprint Authentication is succeeded, the user will be taken to the Home Activity as shown below.

Testing on an Emulator

You could also test the app on an emulator:

> Install Android SDK Tools Revision 24.3, if you have not done so.

> Enroll a new fingerprint in the emulator by going to Settings ⇒ Security ⇒ Fingerprint, then follow the enrollment instructions.

> Use an emulator to emulate fingerprint touch events with the following command. Use the same command to emulate fingerprint touch events on the lock screen or in your app.

adb -e emu finger touch <finger_id>

On Windows, you may have to run telnet 127.0.0.1 followed by finger touch.

Credits: androidhive