Android Articles » Implementing Fingerprint Sensor in APPs

Introduction

We know, using FingerPrint access for doors and vaults is a highly secure option, to protect our belongings. Now the same means of protection is available for our SmartPhones too! Nowadays, the SmartPhones comes with inbuilt FingerPrint detection sensors. With the sensors specifically designed to detect fingerprints, hand held devices has never been more secure. The fingerprints are more secure, as you know, we all have got a very unique FingerPrint!


Starting from Android 6.0 Marshmallow its SDK is equipped with APIs for the FingerPrint detection. As the FingerPrint sensor supported devices are getting popular day by day, we can go for implementing this security system for each and every apps.


Let us have a look at the sample project to study how to implement Fingerprint Sensor in our Apps.


The final output of the project will be as shown below.





Let us create a new Android Project (Empty Actiity).

The first thing we need to do is to provide the permission to use the fingerprint sensor in our devices( if present). So we need to add the uses-permission code in the AndroidManifest.xml.




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



Next in the build.gradle(Module:app) set the minSdkVersion as 23. (Works only on devices with Android 6.0 and above)


Next, we need to create a new activity FingerprintActivity for the corresponding Layout - activity_fingerprint.xml. Here is the Layout:



					  
   <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/colorPrimaryDark">
   
       <LinearLayout
           android:id="@+id/headerLayout"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:layout_above="@+id/txt_msg"
           android:layout_alignParentLeft="true"
           android:layout_alignParentStart="true"
           android:layout_centerHorizontal="true"
           android:layout_marginBottom="250dp"
           android:gravity="center"
           android:orientation="vertical">
   
           <ImageView
               android:id="@+id/fng_icon"
               android:layout_width="70dp"
               android:layout_height="70dp"
               android:layout_gravity="center"
               android:layout_marginBottom="30dp"
               android:paddingTop="2dp"
               android:src="@mipmap/ic_fingerprint_black" />
   
   
           <TextView
               android:id="@+id/txt_descr"
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:layout_margin="16dp"
               android:gravity="center"
               android:paddingEnd="30dp"
               android:paddingStart="30dp"
               android:textColor="#000000"
               android:text="@string/note_finger"
               android:textAlignment="center"
               android:textSize="16sp" />
   
           <TextView
               android:id="@+id/txt_error"
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:layout_marginTop="30dp"
               android:gravity="center"
               android:paddingEnd="30dp"
               android:paddingStart="30dp"
               android:textAlignment="center"
               android:textColor="@color/errorMsg"
               android:textSize="14sp" />
       </LinearLayout>
   
       <TextView
           android:id="@+id/txt_msg"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_alignParentBottom="true"
           android:layout_centerHorizontal="true"
           android:layout_marginBottom="26dp"
           android:layout_marginLeft="16dp"
           android:layout_marginRight="16dp"
           android:text="@string/note"
           android:textColor="#000000"
           android:textSize="14sp" />
   
   </RelativeLayout>				  
					  


Now, go to the FingerprintActivity class which extends AppCompatActivity. In this class, we will first initialize the Keyguard Manager and Fingerprint Manager. We will also check if the Fingerprint sensor in present in our device. Let's look at the complete code.



					  
   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 TextView txt;
       private KeyStore kStore;
       // Variable used for storing the key in the Android Keystore container
       private static final String KEY_NAME = "fingerPrint";
       private Cipher cipher;
   
   
       @Override
       protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           setContentView(R.layout.activity_fingerprint);
           txt = (TextView) findViewById(R.id.txt_error);
   
           // Initializing Android Keyguard Manager and Fingerprint Manager
           KeyguardManager keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
           FingerprintManager fingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);
   
   
           // 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.
   //             * You can redirect the user to a default authentication activity from here.
               txt.setText("Fingerprint Sensor not Detected");
           } else {
               // Checks whether fingerprint permission is set on manifest
               if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
                   txt.setText("Fingerprint authentication permission not enabled");
               } else {
                   // Check whether at least one fingerprint is registered
                   if (!fingerprintManager.hasEnrolledFingerprints()) {
                       txt.setText("Fingerprint must be Registered in Your Device");
                   } else {
                       // Checks whether lock screen security is enabled or not
                       if (!keyguardManager.isKeyguardSecure()) {
                           txt.setText("Lock screen security not enabled");
                       } else {
                           generateKey();
   
                           if (cipherInit()) {
                               FingerprintManager.CryptoObject crypto = new FingerprintManager.CryptoObject(cipher);
                               FingerprintHandler helper = new FingerprintHandler(this);
                               helper.startAuth(fingerprintManager, crypto);
                           }
                       }
                   }
               }
           }
       }
   
       @TargetApi(Build.VERSION_CODES.M)
       protected void generateKey() {
           try {
               kStore = 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 obtain KeyGenerator instance", e);
           }
   
           try {
               kStore.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 obtain Cipher", e);
           }
   
           try {
               kStore.load(null);
               SecretKey key = (SecretKey) kStore.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 initialize Cipher", e);
           }
       }
   }
					  
                     


Now we need to create a FingerprintHandler class which extends FingerprintManager.AuthenticationCallback.



					  
   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;
   import android.widget.Toast;
   
   
   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 errorMsg, CharSequence errString) {
           Toast.makeText(context, "Authentication error\n" + errString, Toast.LENGTH_LONG).show();
       }
   
       @Override
       public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
           Toast.makeText(context, "Authentication help\n" + helpString, Toast.LENGTH_LONG).show();
       }
   
       @Override
       public void onAuthenticationFailed() {
           Toast.makeText(context, "Authentication failed.", Toast.LENGTH_LONG).show();
   
       }
   
       @Override
       public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
           context.startActivity(new Intent(context, MainActivity.class));
          /* TextView textView = (TextView) ((Activity) context).findViewById(R.id.txt_descr);
           textView.setText("FingerPrint Verification Successful");*/
       }
   
       public void update(String e, Boolean success) {
           TextView textView = (TextView) ((Activity) context).findViewById(R.id.txt_error);
           textView.setText(e);
           if (success) {
               textView.setTextColor(ContextCompat.getColor(context, R.color.colorPrimaryDark));
           }
       }
   }
                    


With this , the Fingerprint Authentication is ready.


Now, open activity_main.xml and place a TextView and an ImageView.



					  
   <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
       xmlns:tools="http://schemas.android.com/tools"
       android:id="@+id/activity_main"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:background="@color/colorPrimaryDark"
       android:orientation="vertical"
       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="com.mobsoln.fingerprint.MainActivity">
   
       <TextView
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_centerHorizontal="true"
           android:text="This page is shown to confirm that \nyou have successfully unlocked \nthe app using your \nFingerPrint"
           android:textAlignment="center"
           android:textSize="20dp" />
   
       <ImageView
           android:id="@+id/imageView"
           android:layout_width="match_parent"
           android:layout_height="100dp"
           android:layout_alignParentLeft="true"
           android:layout_alignParentStart="true"
           android:layout_centerVertical="true"
           android:src="@mipmap/ic_fingerprint_black" />
   </RelativeLayout>					  
					


Now in the MainActivity class, set the layout as activity_main.xml



					  
   import android.support.v7.app.AppCompatActivity;
   import android.os.Bundle;
   
   
   public class MainActivity extends AppCompatActivity {
   
       @Override
       protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           setContentView(R.layout.activity_main);
       }
   }
					  
					


*Note- Make sure you have added the activities in the AndroidManifest.xml and the fingerprint icons are copied in the drawable folder.



					  
   <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="your_package_name">
   
       <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>
           <activity android:name=".MainActivity" />
       </application>
   
   </manifest>