2 * Copyright (C) 2015 The Android Open Source Project
3 * Modifications copyright (C) 2016 Niklas Merz
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License
18 package de.niklasmerz.cordova.fingerprint;
20 import android.app.DialogFragment;
21 import android.app.KeyguardManager;
22 import android.content.Context;
23 import android.content.DialogInterface;
24 import android.content.Intent;
25 import android.content.SharedPreferences;
26 import android.hardware.fingerprint.FingerprintManager;
27 import android.os.Bundle;
28 import android.util.Log;
29 import android.view.LayoutInflater;
30 import android.view.View;
31 import android.view.ViewGroup;
32 import android.view.inputmethod.InputMethodManager;
33 import android.widget.Button;
34 import android.widget.ImageView;
35 import android.widget.TextView;
36 import android.widget.Toast;
39 * A dialog which uses fingerprint APIs to authenticate the user, and falls back to password
40 * authentication if fingerprint is not available.
42 public class FingerprintAuthenticationDialogFragment extends DialogFragment
43 implements FingerprintUiHelper.Callback {
45 private static final String TAG = "FingerprintAuthDialog";
46 private static final int REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 1;
48 private Button mCancelButton;
49 private Button mSecondDialogButton;
50 private View mFingerprintContent;
52 private Stage mStage = Stage.FINGERPRINT;
54 private KeyguardManager mKeyguardManager;
55 private FingerprintManager.CryptoObject mCryptoObject;
56 private FingerprintUiHelper mFingerprintUiHelper;
57 FingerprintUiHelper.FingerprintUiHelperBuilder mFingerprintUiHelperBuilder;
59 boolean disableBackup;
61 public FingerprintAuthenticationDialogFragment() {
65 public void onCreate(Bundle savedInstanceState) {
66 super.onCreate(savedInstanceState);
68 // Do not create a new Fragment when the Activity is re-created such as orientation changes.
69 setRetainInstance(true);
70 setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Material_Light_Dialog);
72 mKeyguardManager = (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
73 mFingerprintUiHelperBuilder = new FingerprintUiHelper.FingerprintUiHelperBuilder(
74 getContext(), getContext().getSystemService(FingerprintManager.class));
79 public View onCreateView(LayoutInflater inflater, ViewGroup container,
80 Bundle savedInstanceState) {
81 Bundle args = getArguments();
82 disableBackup = args.getBoolean("disableBackup");
83 Log.d(TAG, "disableBackup: " + disableBackup);
85 int fingerprint_auth_dialog_title_id = getResources()
86 .getIdentifier("fingerprint_auth_dialog_title", "string",
87 Fingerprint.packageName);
88 getDialog().setTitle(getString(fingerprint_auth_dialog_title_id));
89 int fingerprint_dialog_container_id = getResources()
90 .getIdentifier("fingerprint_dialog_container", "layout",
91 Fingerprint.packageName);
92 View v = inflater.inflate(fingerprint_dialog_container_id, container, false);
93 int cancel_button_id = getResources()
94 .getIdentifier("cancel_button", "id", Fingerprint.packageName);
95 mCancelButton = (Button) v.findViewById(cancel_button_id);
96 mCancelButton.setOnClickListener(new View.OnClickListener() {
98 public void onClick(View view) {
99 Fingerprint.onCancelled();
100 dismissAllowingStateLoss();
104 int second_dialog_button_id = getResources()
105 .getIdentifier("second_dialog_button", "id", Fingerprint.packageName);
106 mSecondDialogButton = (Button) v.findViewById(second_dialog_button_id);
108 mSecondDialogButton.setVisibility(View.GONE);
110 mSecondDialogButton.setOnClickListener(new View.OnClickListener() {
112 public void onClick(View view) {
116 int fingerprint_container_id = getResources()
117 .getIdentifier("fingerprint_container", "id", Fingerprint.packageName);
118 mFingerprintContent = v.findViewById(fingerprint_container_id);
120 int new_fingerprint_enrolled_description_id = getResources()
121 .getIdentifier("new_fingerprint_enrolled_description", "id",
122 Fingerprint.packageName);
124 int fingerprint_icon_id = getResources()
125 .getIdentifier("fingerprint_icon", "id", Fingerprint.packageName);
126 int fingerprint_status_id = getResources()
127 .getIdentifier("fingerprint_status", "id", Fingerprint.packageName);
128 mFingerprintUiHelper = mFingerprintUiHelperBuilder.build(
129 (ImageView) v.findViewById(fingerprint_icon_id),
130 (TextView) v.findViewById(fingerprint_status_id), this);
133 // If fingerprint authentication is not available, switch immediately to the backup
134 // (password) screen.
135 if (!mFingerprintUiHelper.isFingerprintAuthAvailable()) {
143 public void onResume() {
145 if (mStage == Stage.FINGERPRINT) {
146 mFingerprintUiHelper.startListening(mCryptoObject);
150 public void setStage(Stage stage) {
155 public void onPause() {
157 mFingerprintUiHelper.stopListening();
161 * Sets the crypto object to be passed in when authenticating with fingerprint.
163 public void setCryptoObject(FingerprintManager.CryptoObject cryptoObject) {
164 mCryptoObject = cryptoObject;
168 * Switches to backup (password) screen. This either can happen when fingerprint is not
169 * available or the user chooses to use the password authentication method by pressing the
170 * button. This can also happen when the user had too many fingerprint attempts.
172 private void goToBackup() {
175 Fingerprint.onCancelled();
176 dismissAllowingStateLoss();
179 mStage = Stage.BACKUP;
184 private void updateStage() {
185 int cancel_id = getResources()
186 .getIdentifier("fingerprint_cancel", "string", Fingerprint.packageName);
189 mCancelButton.setText(cancel_id);
190 int use_backup_id = getResources()
191 .getIdentifier("fingerprint_use_backup", "string", Fingerprint.packageName);
192 mSecondDialogButton.setText(use_backup_id);
193 mFingerprintContent.setVisibility(View.VISIBLE);
195 case NEW_FINGERPRINT_ENROLLED:
196 // Intentional fall through
198 if (mStage == Stage.NEW_FINGERPRINT_ENROLLED) {
201 if (!mKeyguardManager.isKeyguardSecure()) {
202 // Show a message that the user hasn't set up a lock screen.
203 int secure_lock_screen_required_id = getResources()
204 .getIdentifier("secure_lock_screen_required", "string",
205 Fingerprint.packageName);
206 Toast.makeText(getContext(),
207 getString(secure_lock_screen_required_id),
208 Toast.LENGTH_LONG).show();
211 showAuthenticationScreen();
216 private void showAuthenticationScreen() {
217 // Create the Confirm Credentials screen. You can customize the title and description. Or
218 // we will provide a generic one for you if you leave it null
219 Intent intent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, null);
220 if (intent != null) {
221 startActivityForResult(intent, REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS);
226 public void onActivityResult(int requestCode, int resultCode, Intent data) {
227 if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS) {
228 // Challenge completed, proceed with using cipher
229 if (resultCode == getActivity().RESULT_OK) {
230 Fingerprint.onAuthenticated(false /* used backup */);
232 // The user canceled or didn’t complete the lock screen
233 // operation. Go to error/cancellation flow.
234 Fingerprint.onCancelled();
236 dismissAllowingStateLoss();
241 public void onAuthenticated() {
242 // Callback from FingerprintUiHelper. Let the activity know that authentication was
244 Fingerprint.onAuthenticated(true /* withFingerprint */);
245 dismissAllowingStateLoss();
249 public void onError() {
250 if(this.getActivity() != null)
255 public void onCancel(DialogInterface dialog) {
256 super.onCancel(dialog);
257 Fingerprint.onCancelled();
261 * Enumeration to indicate which authentication method the user is trying to authenticate with.
265 NEW_FINGERPRINT_ENROLLED,