In android API level 23 i.e. Android Marshmallow, Google introduced Fingerprint authentication. It not only enables the user to unlock the device using figerprint but also have developer’s APIs using which the developers can add the functionality to their own applications and its pretty simple as well.
For Fingerprint login you have to check the hardware support on the device, whether the lock is enable and lastly that there should be at-least one fingerprint stored on the device then you can pop user to authenticate the fingerprint. Ans I can tell you its quiet simple just follow me and you will be able to do this in your application as well.
Firstly you need a login activity like I have
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
public class LoginActivity extends Activity { public Editor editor; Object response = null; ProgressBar spinner; SharedPreferences app_shared; ProgressDialog progressDialog; AlertDialog forgotPasswordDialog; LinearLayout container; boolean fingerprint_enabled, fingerprintsupported = false; boolean Authenticated = false; private ProgressDialog progress; private String email, password; int NORMAL_REQUEST= -1; int CHANGE_REQUEST= 1; DialogInterface onCancelDialog = new DialogInterface() { @Override public void cancel() { Login(); } @Override public void dismiss() { Login(); } }; @Override public void onBackPressed() { super.onBackPressed(); startActivity(new Intent(this, HomeActivity.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)); this.finish(); } @Override protected void onResume() { super.onResume(); invalidateOptionsMenu(); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); return true; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.USE_FINGERPRINT}, -1); } else { fingerprintsupported = gotPermission(); } } app_shared = getSharedPreferences("shared", MODE_PRIVATE); fingerprint_enabled = app_shared.getBoolean("FingetprintEnabled", false); container = (LinearLayout) findViewById(R.id.container); spinner = (ProgressBar) findViewById(R.id.loginprogress); spinner.setVisibility(View.GONE); if (fingerprintsupported && fingerprint_enabled) { findViewById(R.id.login_through_fp).setVisibility(View.VISIBLE); FingerprintDemoFragment fragment = FingerprintDemoFragment.newInstance(1, NORMAL_REQUEST); fragment.show(getSupportFragmentManager(), "tag"); } } public void onClickFingerPrintButton(View v){ FingerprintDemoFragment fragment = FingerprintDemoFragment.newInstance(1, NORMAL_REQUEST); fragment.show(getSupportFragmentManager(), "tag"); } public void loginPost(View v) { progress = ProgressDialog.show(LoginActivity.this, getResources().getString(R.string.please_wait), getResources().getString(R.string.processing_request_response), true); progress.setCanceledOnTouchOutside(false); if (fingerprintsupported) { if (fingerprint_enabled) { if(!app_shared.getString("TouchEmail","").equals(email) || !app_shared.getString("TouchPassword","").equals(password)) { AlertDialog fingerprintDialog = new AlertDialog.Builder(this) .setMessage("Do you want to replace previous credentials with these ones, for Fingerprint authentication?").setCancelable(false) .setPositiveButton(android.R.string.ok, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); app_shared.edit().remove("TouchEmail").remove("TouchPassword").apply(); FingerprintDemoFragment fragment = FingerprintDemoFragment.newInstance(0, CHANGE_REQUEST); fragment.show(getSupportFragmentManager(), "tag"); fragment.onCancel(onCancelDialog); } }).setNegativeButton(android.R.string.cancel, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); Login(); } }).create(); fingerprintDialog.show(); }else { Login(); } } else { FingerprintDemoFragment fragment = FingerprintDemoFragment.newInstance(0, NORMAL_REQUEST); fragment.show(getSupportFragmentManager(), "tag"); fragment.onCancel(onCancelDialog); } } else { Login(); } } } public void FingerPrintResult(boolean response, int requestCode) { Authenticated = response; if (Authenticated) { if(requestCode == NORMAL_REQUEST) { if (!app_shared.contains("TouchEmail")) { app_shared.edit().putString("TouchEmail", userNameField.getText().toString().trim()) .putString("TouchPassword", passwordField.getText().toString().trim()).apply(); } else { email = app_shared.getString("TouchEmail", ""); password = app_shared.getString("TouchPassword", ""); } }else{ app_shared.edit().putString("TouchEmail", userNameField.getText().toString().trim()) .putString("TouchPassword", passwordField.getText().toString().trim()).apply(); } progress = ProgressDialog.show(LoginActivity.this, getResources().getString(R.string.please_wait), getResources().getString(R.string.processing_request_response), true); progress.setCanceledOnTouchOutside(false); Login(); }else{ progress.dismiss(); } } @RequiresApi(23) public boolean gotPermission(){ try { FingerprintManager fingerprintManager = (FingerprintManager) getSystemService(Context.FINGERPRINT_SERVICE); return (fingerprintManager.isHardwareDetected() && fingerprintManager.hasEnrolledFingerprints()); }catch (SecurityException e){ e.printStackTrace(); } } @TargetApi(23) @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case -1: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { fingerprintsupported = gotPermission(); } break; default: break; } } public void Login() { // login function } } |
The XML for the LoginActivity is as below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 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"> <ScrollView android:layout_width="match_parent" android:layout_height="wrap_content" android:scrollbars="none"> <LinearLayout android:id="@+id/container" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/loginFormHeading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/loginFormHeading" android:textAppearance="?android:attr/textAppearanceLarge"/> <TextView android:id="@+id/loginFormSubHeading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:text="@string/loginFormSubHeading"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="5dp" android:background="@color/white" android:orientation="vertical" android:padding="5dp"> <TextView android:id="@+id/email_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/email" android:textAppearance="?android:attr/textAppearanceMedium"/> <EditText android:id="@+id/username" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" android:hint="@string/loginFormEmailTitle" android:inputType="textEmailAddress" android:padding="8dp"/> <TextView android:id="@+id/password_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="@string/password" android:textAppearance="?android:attr/textAppearanceMedium"/> <EditText android:id="@+id/password" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" android:hint="@string/password_" android:inputType="textPassword" android:padding="8dp"/> </LinearLayout> <Button android:id="@+id/login" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/secondary_color" android:onClick="loginPost" android:text="@string/loginFormSignInButton" android:textColor="@color/white" android:textSize="@dimen/Button_textSize"/> </LinearLayout> </ScrollView> <ImageView android:id="@+id/login_through_fp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" android:layout_alignParentBottom="true" android:onClick="onClickFingerPrintButton" android:layout_centerHorizontal="true" android:src="@drawable/ic_fp_40px"/> <ProgressBar android:id="@+id/loginprogress" style="\?android:attr/progressBarStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerInParent="true" android:translationZ="2dp"/> </RelativeLayout> |
The xml for the DailogFragment signin_using_fingerprint.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_gravity="center_horizontal" android:gravity="center_horizontal" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:text="Login" android:layout_marginBottom="20dp" android:padding="20dp" android:gravity="center" android:textSize="@dimen/heading_size_medium" android:background="@color/secondary_color" android:textColor="@color/white" android:layout_height="wrap_content"/> <TextView android:layout_width="wrap_content" android:layout_marginTop="20dp" android:textColor="@color/black" android:textSize="@dimen/text_size_medium" android:text="Start Using Your FingerPrint" android:layout_height="wrap_content"/> <ImageView android:layout_width="wrap_content" android:layout_marginTop="20dp" app:srcCompat="@drawable/finger_print" android:layout_height="wrap_content"/> <TextView android:layout_width="wrap_content" android:layout_marginTop="20dp" android:textSize="@dimen/Button_textSize" android:text="Authenticate with your Fingerprint" android:layout_marginBottom="20dp" android:layout_height="wrap_content"/> </LinearLayout> |
add_fingerprint_login.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_gravity="center_horizontal" android:gravity="center_horizontal" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:text="ADD FINGERPRINT" android:layout_marginBottom="20dp" android:padding="20dp" android:gravity="center" android:textSize="@dimen/heading_size_medium" android:background="@color/secondary_color" android:textColor="@color/white" android:layout_height="wrap_content"/> <TextView android:layout_width="wrap_content" android:layout_marginTop="20dp" android:textColor="@color/black" android:textSize="@dimen/text_size_medium" android:text="Start Using Your FingerPrint" android:layout_height="wrap_content"/> <ImageView android:layout_width="wrap_content" android:layout_marginTop="20dp" app:srcCompat="@drawable/finger_print" android:layout_height="wrap_content"/> <TextView android:layout_width="wrap_content" android:layout_marginTop="20dp" android:layout_marginBottom="20dp" android:textSize="@dimen/Button_textSize" android:text="Touch the sensor" android:layout_height="wrap_content"/> </LinearLayout> |
Finally the FragmentDialog
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
public class FingerprintDemoFragment extends BottomSheetDialogFragment implements FingerprintHandler.Callback { private static final String KEY_NAME = "fuhdschbaksu"; FingerprintManager fingerprintManager; KeyguardManager keyguardManager; private KeyStore keyStore; KeyGenerator keyGenerator; private Cipher cipher; FingerprintManager.CryptoObject cryptoObject; static int requestCode; public FingerprintDemoFragment() { } public static FingerprintDemoFragment newInstance(int tag, int req) { FingerprintDemoFragment frag = new FingerprintDemoFragment(); requestCode = req; Bundle argsBundle = new Bundle(); argsBundle.putInt("tag", tag); frag.setArguments(argsBundle); return frag; } @Override public void setupDialog(Dialog dialog, int style) { super.setupDialog(dialog, style); View contentView; if(getArguments()!=null && getArguments().getInt("tag")==1) { contentView = View.inflate(getContext(), R.layout.signin_using_fingerprint, null); }else contentView = View.inflate(getContext(), R.layout.add_fingerprint_login, null); dialog.setContentView(contentView); CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) ((View) contentView.getParent()).getLayoutParams(); CoordinatorLayout.Behavior behavior = layoutParams.getBehavior(); if (behavior != null && behavior instanceof BottomSheetBehavior) { ((BottomSheetBehavior) behavior).setBottomSheetCallback(mBottomSheetBehaviorCallback); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { Context mcontext = getActivity(); //initializing keyguard and fingerprint manager keyguardManager = (KeyguardManager) mcontext.getSystemService(KEYGUARD_SERVICE); fingerprintManager = (FingerprintManager) mcontext.getSystemService(FINGERPRINT_SERVICE); //check whether keyguard is enabled or not if (!keyguardManager.isKeyguardSecure()) { Toast.makeText(mcontext, "Lock screen security not enabled in Settings", Toast.LENGTH_LONG).show(); return; } //check whether fingerprint lock is enabled or not if (ActivityCompat.checkSelfPermission(mcontext, android.Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) { return; } //check whether fingerprint is registered or not if (!fingerprintManager.hasEnrolledFingerprints()) { // This happens when no fingerprints are registered. Toast.makeText(mcontext, "Register at least one fingerprint in Settings", Toast.LENGTH_LONG).show(); return; } generateKey(); if (cipherInit()) { cryptoObject = new FingerprintManager.CryptoObject(cipher); FingerprintHandler handler = new FingerprintHandler(mcontext, this); handler.startAuth(fingerprintManager, cryptoObject); } } } private BottomSheetBehavior.BottomSheetCallback mBottomSheetBehaviorCallback = new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { if (newState == BottomSheetBehavior.STATE_HIDDEN) { dismiss(); } } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { } }; @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); } protected void generateKey() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { //keystore instance needed for getting key access try { keyStore = KeyStore.getInstance("AndroidKeyStore"); } catch (Exception e) { e.printStackTrace(); } // key generater for generating new key try { keyGenerator = KeyGenerator.getInstance( KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); } catch (NoSuchAlgorithmException | NoSuchProviderException e) { throw new RuntimeException( "Failed to get KeyGenerator instance", e); } // generating key 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(23) public boolean cipherInit() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 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); } } return false; } @Override public void onAuthenticated() { ((LoginActivity) getActivity()).FingerPrintResult(true, requestCode); dismiss(); } @Override public void onError() { Toast.makeText(getActivity(),"Authentication Failed",Toast.LENGTH_LONG).show(); ((LoginActivity) getActivity()).FingerPrintResult(false, requestCode); dismiss(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
class FingerprintHandler extends FingerprintManager.AuthenticationCallback { CancellationSignal Signal; private Context appContext; private Callback mCallback; public FingerprintHandler(Context context, Callback callback) { appContext = context; mCallback = callback; } public void startAuth(FingerprintManager manager, FingerprintManager.CryptoObject cryptoObject) { Signal = new CancellationSignal(); if (ActivityCompat.checkSelfPermission(appContext, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) { return; } manager.authenticate(cryptoObject, Signal, 0, this, null); } @Override public void onAuthenticationError(int errMsgId, CharSequence errString) { } @Override public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { } @Override public void onAuthenticationFailed() { mCallback.onError(); } @Override public void onAuthenticationSucceeded( FingerprintManager.AuthenticationResult result) { SharedPreferences app_shared = appContext.getSharedPreferences("App_Data", Context.MODE_PRIVATE); if (!app_shared.getBoolean("FingetprintEnabled", false)) app_shared.edit().putBoolean("FingetprintEnabled", true).apply(); mCallback.onAuthenticated(); } interface Callback { void onAuthenticated(); void onError(); } } |
And here you go. Now your app supports fingerprint like other apps.
Source: http://www.techotopia.com/index.php/An_Android_Fingerprint_Authentication_Tutorial