54fb28d428bf0274541cb2b7f9143853edcd5cd3
[dali_platform/mobile.git] /
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  * Modifications copyright (C) 2016 Niklas Merz
4  *
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
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
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
16  */
17
18 package de.niklasmerz.cordova.fingerprint;
19
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;
37
38 /**
39  * A dialog which uses fingerprint APIs to authenticate the user, and falls back to password
40  * authentication if fingerprint is not available.
41  */
42 public class FingerprintAuthenticationDialogFragment extends DialogFragment
43         implements FingerprintUiHelper.Callback {
44
45     private static final String TAG = "FingerprintAuthDialog";
46     private static final int REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 1;
47
48     private Button mCancelButton;
49     private Button mSecondDialogButton;
50     private View mFingerprintContent;
51
52     private Stage mStage = Stage.FINGERPRINT;
53
54     private KeyguardManager mKeyguardManager;
55     private FingerprintManager.CryptoObject mCryptoObject;
56     private FingerprintUiHelper mFingerprintUiHelper;
57     FingerprintUiHelper.FingerprintUiHelperBuilder mFingerprintUiHelperBuilder;
58
59     boolean disableBackup;
60
61     public FingerprintAuthenticationDialogFragment() {
62     }
63
64     @Override
65     public void onCreate(Bundle savedInstanceState) {
66         super.onCreate(savedInstanceState);
67
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);
71
72         mKeyguardManager = (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
73         mFingerprintUiHelperBuilder = new FingerprintUiHelper.FingerprintUiHelperBuilder(
74                 getContext(), getContext().getSystemService(FingerprintManager.class));
75
76     }
77
78     @Override
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);
84
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() {
97             @Override
98             public void onClick(View view) {
99                 Fingerprint.onCancelled();
100                 dismissAllowingStateLoss();
101             }
102         });
103
104         int second_dialog_button_id = getResources()
105                 .getIdentifier("second_dialog_button", "id", Fingerprint.packageName);
106         mSecondDialogButton = (Button) v.findViewById(second_dialog_button_id);
107         if (disableBackup) {
108             mSecondDialogButton.setVisibility(View.GONE);
109         }
110         mSecondDialogButton.setOnClickListener(new View.OnClickListener() {
111             @Override
112             public void onClick(View view) {
113                 goToBackup();
114             }
115         });
116         int fingerprint_container_id = getResources()
117                 .getIdentifier("fingerprint_container", "id", Fingerprint.packageName);
118         mFingerprintContent = v.findViewById(fingerprint_container_id);
119
120         int new_fingerprint_enrolled_description_id = getResources()
121                 .getIdentifier("new_fingerprint_enrolled_description", "id",
122                         Fingerprint.packageName);
123
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);
131         updateStage();
132
133         // If fingerprint authentication is not available, switch immediately to the backup
134         // (password) screen.
135         if (!mFingerprintUiHelper.isFingerprintAuthAvailable()) {
136             goToBackup();
137         }
138         return v;
139     }
140
141
142     @Override
143     public void onResume() {
144         super.onResume();
145         if (mStage == Stage.FINGERPRINT) {
146             mFingerprintUiHelper.startListening(mCryptoObject);
147         }
148     }
149
150     public void setStage(Stage stage) {
151         mStage = stage;
152     }
153
154     @Override
155     public void onPause() {
156         super.onPause();
157         mFingerprintUiHelper.stopListening();
158     }
159
160     /**
161      * Sets the crypto object to be passed in when authenticating with fingerprint.
162      */
163     public void setCryptoObject(FingerprintManager.CryptoObject cryptoObject) {
164         mCryptoObject = cryptoObject;
165     }
166
167     /**
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.
171      */
172     private void goToBackup() {
173         if(disableBackup)
174         {
175             Fingerprint.onCancelled(); 
176             dismissAllowingStateLoss();
177         }
178         else{
179             mStage = Stage.BACKUP;
180             updateStage();
181         }
182     }
183
184     private void updateStage() {
185         int cancel_id = getResources()
186                 .getIdentifier("fingerprint_cancel", "string", Fingerprint.packageName);
187         switch (mStage) {
188             case FINGERPRINT:
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);
194                 break;
195             case NEW_FINGERPRINT_ENROLLED:
196                 // Intentional fall through
197             case BACKUP:
198                 if (mStage == Stage.NEW_FINGERPRINT_ENROLLED) {
199
200                 }
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();
209                     return;
210                 }
211                 showAuthenticationScreen();
212                 break;
213         }
214     }
215
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);
222         }
223     }
224
225     @Override
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 */);
231             } else {
232                 // The user canceled or didn’t complete the lock screen
233                 // operation. Go to error/cancellation flow.
234                 Fingerprint.onCancelled();
235             }
236             dismissAllowingStateLoss();
237         }
238     }
239
240     @Override
241     public void onAuthenticated() {
242         // Callback from FingerprintUiHelper. Let the activity know that authentication was
243         // successful.
244         Fingerprint.onAuthenticated(true /* withFingerprint */);
245         dismissAllowingStateLoss();
246     }
247
248     @Override
249     public void onError() {
250         if(this.getActivity() != null)
251             goToBackup();
252     }
253
254     @Override
255     public void onCancel(DialogInterface dialog) {
256         super.onCancel(dialog);
257         Fingerprint.onCancelled();
258     }
259
260     /**
261      * Enumeration to indicate which authentication method the user is trying to authenticate with.
262      */
263     public enum Stage {
264         FINGERPRINT,
265         NEW_FINGERPRINT_ENROLLED,
266         BACKUP
267     }
268 }