Skip to content

Most visited

Recently visited

navigation
FingerprintDialog / src / com.example.android.fingerprintdialog /

FingerprintAuthenticationDialogFragment.java

1
/*
2
 * Copyright (C) 2015 The Android Open Source Project
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License
15
 */
16
 
17
package com.example.android.fingerprintdialog;
18
 
19
import android.app.DialogFragment;
20
import android.content.Context;
21
import android.content.SharedPreferences;
22
import android.hardware.fingerprint.FingerprintManager;
23
import android.os.Bundle;
24
import android.preference.PreferenceManager;
25
import android.view.KeyEvent;
26
import android.view.LayoutInflater;
27
import android.view.View;
28
import android.view.ViewGroup;
29
import android.view.inputmethod.EditorInfo;
30
import android.view.inputmethod.InputMethodManager;
31
import android.widget.Button;
32
import android.widget.CheckBox;
33
import android.widget.EditText;
34
import android.widget.ImageView;
35
import android.widget.TextView;
36
 
37
/**
38
 * A dialog which uses fingerprint APIs to authenticate the user, and falls back to password
39
 * authentication if fingerprint is not available.
40
 */
41
public class FingerprintAuthenticationDialogFragment extends DialogFragment
42
        implements TextView.OnEditorActionListener, FingerprintUiHelper.Callback {
43
 
44
    private Button mCancelButton;
45
    private Button mSecondDialogButton;
46
    private View mFingerprintContent;
47
    private View mBackupContent;
48
    private EditText mPassword;
49
    private CheckBox mUseFingerprintFutureCheckBox;
50
    private TextView mPasswordDescriptionTextView;
51
    private TextView mNewFingerprintEnrolledTextView;
52
 
53
    private Stage mStage = Stage.FINGERPRINT;
54
 
55
    private FingerprintManager.CryptoObject mCryptoObject;
56
    private FingerprintUiHelper mFingerprintUiHelper;
57
    private MainActivity mActivity;
58
 
59
    private InputMethodManager mInputMethodManager;
60
    private SharedPreferences mSharedPreferences;
61
 
62
    @Override
63
    public void onCreate(Bundle savedInstanceState) {
64
        super.onCreate(savedInstanceState);
65
 
66
        // Do not create a new Fragment when the Activity is re-created such as orientation changes.
67
        setRetainInstance(true);
68
        setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Material_Light_Dialog);
69
    }
70
 
71
    @Override
72
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
73
            Bundle savedInstanceState) {
74
        getDialog().setTitle(getString(R.string.sign_in));
75
        View v = inflater.inflate(R.layout.fingerprint_dialog_container, container, false);
76
        mCancelButton = (Button) v.findViewById(R.id.cancel_button);
77
        mCancelButton.setOnClickListener(new View.OnClickListener() {
78
            @Override
79
            public void onClick(View view) {
80
                dismiss();
81
            }
82
        });
83
 
84
        mSecondDialogButton = (Button) v.findViewById(R.id.second_dialog_button);
85
        mSecondDialogButton.setOnClickListener(new View.OnClickListener() {
86
            @Override
87
            public void onClick(View view) {
88
                if (mStage == Stage.FINGERPRINT) {
89
                    goToBackup();
90
                } else {
91
                    verifyPassword();
92
                }
93
            }
94
        });
95
        mFingerprintContent = v.findViewById(R.id.fingerprint_container);
96
        mBackupContent = v.findViewById(R.id.backup_container);
97
        mPassword = (EditText) v.findViewById(R.id.password);
98
        mPassword.setOnEditorActionListener(this);
99
        mPasswordDescriptionTextView = (TextView) v.findViewById(R.id.password_description);
100
        mUseFingerprintFutureCheckBox = (CheckBox)
101
                v.findViewById(R.id.use_fingerprint_in_future_check);
102
        mNewFingerprintEnrolledTextView = (TextView)
103
                v.findViewById(R.id.new_fingerprint_enrolled_description);
104
        mFingerprintUiHelper = new FingerprintUiHelper(
105
                mActivity.getSystemService(FingerprintManager.class),
106
                (ImageView) v.findViewById(R.id.fingerprint_icon),
107
                (TextView) v.findViewById(R.id.fingerprint_status), this);
108
        updateStage();
109
 
110
        // If fingerprint authentication is not available, switch immediately to the backup
111
        // (password) screen.
112
        if (!mFingerprintUiHelper.isFingerprintAuthAvailable()) {
113
            goToBackup();
114
        }
115
        return v;
116
    }
117
 
118
    @Override
119
    public void onResume() {
120
        super.onResume();
121
        if (mStage == Stage.FINGERPRINT) {
122
            mFingerprintUiHelper.startListening(mCryptoObject);
123
        }
124
    }
125
 
126
    public void setStage(Stage stage) {
127
        mStage = stage;
128
    }
129
 
130
    @Override
131
    public void onPause() {
132
        super.onPause();
133
        mFingerprintUiHelper.stopListening();
134
    }
135
 
136
    @Override
137
    public void onAttach(Context context) {
138
        super.onAttach(context);
139
        mActivity = (MainActivity) getActivity();
140
        mInputMethodManager = context.getSystemService(InputMethodManager.class);
141
        mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
142
    }
143
 
144
    /**
145
     * Sets the crypto object to be passed in when authenticating with fingerprint.
146
     */
147
    public void setCryptoObject(FingerprintManager.CryptoObject cryptoObject) {
148
        mCryptoObject = cryptoObject;
149
    }
150
 
151
    /**
152
     * Switches to backup (password) screen. This either can happen when fingerprint is not
153
     * available or the user chooses to use the password authentication method by pressing the
154
     * button. This can also happen when the user had too many fingerprint attempts.
155
     */
156
    private void goToBackup() {
157
        mStage = Stage.PASSWORD;
158
        updateStage();
159
        mPassword.requestFocus();
160
 
161
        // Show the keyboard.
162
        mPassword.postDelayed(mShowKeyboardRunnable, 500);
163
 
164
        // Fingerprint is not used anymore. Stop listening for it.
165
        mFingerprintUiHelper.stopListening();
166
    }
167
 
168
    /**
169
     * Checks whether the current entered password is correct, and dismisses the the dialog and
170
     * let's the activity know about the result.
171
     */
172
    private void verifyPassword() {
173
        if (!checkPassword(mPassword.getText().toString())) {
174
            return;
175
        }
176
        if (mStage == Stage.NEW_FINGERPRINT_ENROLLED) {
177
            SharedPreferences.Editor editor = mSharedPreferences.edit();
178
            editor.putBoolean(getString(R.string.use_fingerprint_to_authenticate_key),
179
                    mUseFingerprintFutureCheckBox.isChecked());
180
            editor.apply();
181
 
182
            if (mUseFingerprintFutureCheckBox.isChecked()) {
183
                // Re-create the key so that fingerprints including new ones are validated.
184
                mActivity.createKey(MainActivity.DEFAULT_KEY_NAME, true);
185
                mStage = Stage.FINGERPRINT;
186
            }
187
        }
188
        mPassword.setText("");
189
        mActivity.onPurchased(false /* without Fingerprint */, null);
190
        dismiss();
191
    }
192
 
193
    /**
194
     * @return true if {@code password} is correct, false otherwise
195
     */
196
    private boolean checkPassword(String password) {
197
        // Assume the password is always correct.
198
        // In the real world situation, the password needs to be verified in the server side.
199
        return password.length() > 0;
200
    }
201
 
202
    private final Runnable mShowKeyboardRunnable = new Runnable() {
203
        @Override
204
        public void run() {
205
            mInputMethodManager.showSoftInput(mPassword, 0);
206
        }
207
    };
208
 
209
    private void updateStage() {
210
        switch (mStage) {
211
            case FINGERPRINT:
212
                mCancelButton.setText(R.string.cancel);
213
                mSecondDialogButton.setText(R.string.use_password);
214
                mFingerprintContent.setVisibility(View.VISIBLE);
215
                mBackupContent.setVisibility(View.GONE);
216
                break;
217
            case NEW_FINGERPRINT_ENROLLED:
218
                // Intentional fall through
219
            case PASSWORD:
220
                mCancelButton.setText(R.string.cancel);
221
                mSecondDialogButton.setText(R.string.ok);
222
                mFingerprintContent.setVisibility(View.GONE);
223
                mBackupContent.setVisibility(View.VISIBLE);
224
                if (mStage == Stage.NEW_FINGERPRINT_ENROLLED) {
225
                    mPasswordDescriptionTextView.setVisibility(View.GONE);
226
                    mNewFingerprintEnrolledTextView.setVisibility(View.VISIBLE);
227
                    mUseFingerprintFutureCheckBox.setVisibility(View.VISIBLE);
228
                }
229
                break;
230
        }
231
    }
232
 
233
    @Override
234
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
235
        if (actionId == EditorInfo.IME_ACTION_GO) {
236
            verifyPassword();
237
            return true;
238
        }
239
        return false;
240
    }
241
 
242
    @Override
243
    public void onAuthenticated() {
244
        // Callback from FingerprintUiHelper. Let the activity know that authentication was
245
        // successful.
246
        mActivity.onPurchased(true /* withFingerprint */, mCryptoObject);
247
        dismiss();
248
    }
249
 
250
    @Override
251
    public void onError() {
252
        goToBackup();
253
    }
254
 
255
    /**
256
     * Enumeration to indicate which authentication method the user is trying to authenticate with.
257
     */
258
    public enum Stage {
259
        FINGERPRINT,
260
        NEW_FINGERPRINT_ENROLLED,
261
        PASSWORD
262
    }
263
}
This site uses cookies to store your preferences for site-specific language and display options.