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>

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