blob: 5d8c5b985e2bc2a83c54af39b24d005dee73c3c8 [file] [log] [blame]
Kevin Chynaae4a152018-01-18 11:48:09 -08001/*
2 * Copyright (C) 2018 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
17package com.android.systemui.fingerprint;
18
Kevin Chyn42653e82018-01-19 14:15:46 -080019import android.content.Context;
Kevin Chynaae4a152018-01-18 11:48:09 -080020import android.content.pm.PackageManager;
Vishwath Mohanecf00ce2018-04-05 10:28:24 -070021import android.hardware.biometrics.BiometricPrompt;
22import android.hardware.biometrics.IBiometricPromptReceiver;
Kevin Chynaae4a152018-01-18 11:48:09 -080023import android.os.Bundle;
Kevin Chyn42653e82018-01-19 14:15:46 -080024import android.os.Handler;
25import android.os.Message;
26import android.os.RemoteException;
Kevin Chynaae4a152018-01-18 11:48:09 -080027import android.util.Log;
Kevin Chyn42653e82018-01-19 14:15:46 -080028import android.view.WindowManager;
Kevin Chynaae4a152018-01-18 11:48:09 -080029
Kevin Chyn42653e82018-01-19 14:15:46 -080030import com.android.internal.os.SomeArgs;
Kevin Chynaae4a152018-01-18 11:48:09 -080031import com.android.systemui.SystemUI;
32import com.android.systemui.statusbar.CommandQueue;
33
34public class FingerprintDialogImpl extends SystemUI implements CommandQueue.Callbacks {
35 private static final String TAG = "FingerprintDialogImpl";
Kevin Chyn42653e82018-01-19 14:15:46 -080036 private static final boolean DEBUG = true;
37
Kevin Chyn5906c172018-07-23 15:43:02 -070038 private static final int MSG_SHOW_DIALOG = 1;
39 private static final int MSG_FINGERPRINT_AUTHENTICATED = 2;
40 private static final int MSG_FINGERPRINT_HELP = 3;
41 private static final int MSG_FINGERPRINT_ERROR = 4;
42 private static final int MSG_FINGERPRINT_DIALOG = 5;
43 private static final int MSG_BUTTON_NEGATIVE = 6;
44 private static final int MSG_USER_CANCELED = 7;
45 private static final int MSG_BUTTON_POSITIVE = 8;
Kevin Chyn42653e82018-01-19 14:15:46 -080046
47 private FingerprintDialogView mDialogView;
48 private WindowManager mWindowManager;
Vishwath Mohanecf00ce2018-04-05 10:28:24 -070049 private IBiometricPromptReceiver mReceiver;
Kevin Chyn42653e82018-01-19 14:15:46 -080050 private boolean mDialogShowing;
Kevin Chyn5906c172018-07-23 15:43:02 -070051 private Callback mCallback = new Callback();
Kevin Chyn42653e82018-01-19 14:15:46 -080052
53 private Handler mHandler = new Handler() {
54 @Override
55 public void handleMessage(Message msg) {
56 switch(msg.what) {
57 case MSG_SHOW_DIALOG:
58 handleShowDialog((SomeArgs) msg.obj);
59 break;
60 case MSG_FINGERPRINT_AUTHENTICATED:
61 handleFingerprintAuthenticated();
62 break;
63 case MSG_FINGERPRINT_HELP:
64 handleFingerprintHelp((String) msg.obj);
65 break;
66 case MSG_FINGERPRINT_ERROR:
67 handleFingerprintError((String) msg.obj);
68 break;
69 case MSG_HIDE_DIALOG:
70 handleHideDialog((Boolean) msg.obj);
71 break;
72 case MSG_BUTTON_NEGATIVE:
73 handleButtonNegative();
74 break;
75 case MSG_USER_CANCELED:
76 handleUserCanceled();
77 break;
78 case MSG_BUTTON_POSITIVE:
79 handleButtonPositive();
80 break;
Kevin Chyn42653e82018-01-19 14:15:46 -080081 }
82 }
83 };
Kevin Chynaae4a152018-01-18 11:48:09 -080084
Kevin Chyn5906c172018-07-23 15:43:02 -070085 private class Callback implements DialogViewCallback {
86 @Override
87 public void onUserCanceled() {
88 mHandler.obtainMessage(FingerprintDialogImpl.MSG_USER_CANCELED).sendToTarget();
89 }
90
91 @Override
92 public void onErrorShown() {
93 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_HIDE_DIALOG,
94 false /* userCanceled */), BiometricPrompt.HIDE_DIALOG_DELAY);
95 }
96
97 @Override
98 public void onNegativePressed() {
99 mHandler.obtainMessage(FingerprintDialogImpl.MSG_BUTTON_NEGATIVE).sendToTarget();
100 }
101
102 @Override
103 public void onPositivePressed() {
104 mHandler.obtainMessage(FingerprintDialogImpl.MSG_BUTTON_POSITIVE).sendToTarget();
105 }
106 }
107
Kevin Chynaae4a152018-01-18 11:48:09 -0800108 @Override
109 public void start() {
110 if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
111 return;
112 }
113 getComponent(CommandQueue.class).addCallbacks(this);
Kevin Chyne8f3e1b2018-01-23 17:33:58 -0800114 mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
Kevin Chyn5906c172018-07-23 15:43:02 -0700115 mDialogView = new FingerprintDialogView(mContext, mCallback);
Kevin Chynaae4a152018-01-18 11:48:09 -0800116 }
117
118 @Override
Vishwath Mohanecf00ce2018-04-05 10:28:24 -0700119 public void showFingerprintDialog(Bundle bundle, IBiometricPromptReceiver receiver) {
Kevin Chyn42653e82018-01-19 14:15:46 -0800120 if (DEBUG) Log.d(TAG, "showFingerprintDialog");
121 // Remove these messages as they are part of the previous client
122 mHandler.removeMessages(MSG_FINGERPRINT_ERROR);
123 mHandler.removeMessages(MSG_FINGERPRINT_HELP);
124 mHandler.removeMessages(MSG_FINGERPRINT_AUTHENTICATED);
125 SomeArgs args = SomeArgs.obtain();
126 args.arg1 = bundle;
127 args.arg2 = receiver;
128 mHandler.obtainMessage(MSG_SHOW_DIALOG, args).sendToTarget();
Kevin Chynaae4a152018-01-18 11:48:09 -0800129 }
130
131 @Override
132 public void onFingerprintAuthenticated() {
133 if (DEBUG) Log.d(TAG, "onFingerprintAuthenticated");
Kevin Chyn42653e82018-01-19 14:15:46 -0800134 mHandler.obtainMessage(MSG_FINGERPRINT_AUTHENTICATED).sendToTarget();
Kevin Chynaae4a152018-01-18 11:48:09 -0800135 }
136
137 @Override
138 public void onFingerprintHelp(String message) {
139 if (DEBUG) Log.d(TAG, "onFingerprintHelp: " + message);
Kevin Chyn42653e82018-01-19 14:15:46 -0800140 mHandler.obtainMessage(MSG_FINGERPRINT_HELP, message).sendToTarget();
Kevin Chynaae4a152018-01-18 11:48:09 -0800141 }
142
143 @Override
144 public void onFingerprintError(String error) {
145 if (DEBUG) Log.d(TAG, "onFingerprintError: " + error);
Kevin Chyn42653e82018-01-19 14:15:46 -0800146 mHandler.obtainMessage(MSG_FINGERPRINT_ERROR, error).sendToTarget();
Kevin Chynaae4a152018-01-18 11:48:09 -0800147 }
148
149 @Override
150 public void hideFingerprintDialog() {
151 if (DEBUG) Log.d(TAG, "hideFingerprintDialog");
Kevin Chyn42653e82018-01-19 14:15:46 -0800152 mHandler.obtainMessage(MSG_HIDE_DIALOG, false /* userCanceled */).sendToTarget();
153 }
154
155 private void handleShowDialog(SomeArgs args) {
Kevin Chyn87df0682018-04-10 19:29:23 -0700156 if (DEBUG) Log.d(TAG, "handleShowDialog, isAnimatingAway: "
157 + mDialogView.isAnimatingAway());
158 if (mDialogView.isAnimatingAway()) {
159 mDialogView.forceRemove();
160 } else if (mDialogShowing) {
Kevin Chyn42653e82018-01-19 14:15:46 -0800161 Log.w(TAG, "Dialog already showing");
162 return;
163 }
Vishwath Mohanecf00ce2018-04-05 10:28:24 -0700164 mReceiver = (IBiometricPromptReceiver) args.arg2;
Kevin Chyn42653e82018-01-19 14:15:46 -0800165 mDialogView.setBundle((Bundle)args.arg1);
166 mWindowManager.addView(mDialogView, mDialogView.getLayoutParams());
167 mDialogShowing = true;
168 }
169
170 private void handleFingerprintAuthenticated() {
171 if (DEBUG) Log.d(TAG, "handleFingerprintAuthenticated");
Kevin Chyn932e1df2018-03-26 11:53:47 -0700172 mDialogView.announceForAccessibility(
173 mContext.getResources().getText(
174 com.android.internal.R.string.fingerprint_authenticated));
Kevin Chyn42653e82018-01-19 14:15:46 -0800175 handleHideDialog(false /* userCanceled */);
176 }
177
178 private void handleFingerprintHelp(String message) {
179 if (DEBUG) Log.d(TAG, "handleFingerprintHelp: " + message);
180 mDialogView.showHelpMessage(message);
181 }
182
183 private void handleFingerprintError(String error) {
184 if (DEBUG) Log.d(TAG, "handleFingerprintError: " + error);
185 if (!mDialogShowing) {
186 if (DEBUG) Log.d(TAG, "Dialog already dismissed");
187 return;
188 }
189 mDialogView.showErrorMessage(error);
190 }
191
192 private void handleHideDialog(boolean userCanceled) {
Kevin Chyn87df0682018-04-10 19:29:23 -0700193 if (DEBUG) Log.d(TAG, "handleHideDialog, userCanceled: " + userCanceled);
Kevin Chyn42653e82018-01-19 14:15:46 -0800194 if (!mDialogShowing) {
195 // This can happen if there's a race and we get called from both
196 // onAuthenticated and onError, etc.
197 Log.w(TAG, "Dialog already dismissed, userCanceled: " + userCanceled);
198 return;
199 }
200 if (userCanceled) {
201 try {
Vishwath Mohanecf00ce2018-04-05 10:28:24 -0700202 mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
Kevin Chyn42653e82018-01-19 14:15:46 -0800203 } catch (RemoteException e) {
204 Log.e(TAG, "RemoteException when hiding dialog", e);
205 }
206 }
207 mReceiver = null;
Kevin Chyn42653e82018-01-19 14:15:46 -0800208 mDialogShowing = false;
Kevin Chyn27e1f262018-03-08 16:38:32 -0800209 mDialogView.startDismiss();
Kevin Chyn42653e82018-01-19 14:15:46 -0800210 }
211
212 private void handleButtonNegative() {
213 if (mReceiver == null) {
214 Log.e(TAG, "Receiver is null");
215 return;
216 }
217 try {
Vishwath Mohanecf00ce2018-04-05 10:28:24 -0700218 mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_NEGATIVE);
Kevin Chyn42653e82018-01-19 14:15:46 -0800219 } catch (RemoteException e) {
220 Log.e(TAG, "Remote exception when handling negative button", e);
221 }
222 handleHideDialog(false /* userCanceled */);
223 }
224
225 private void handleButtonPositive() {
226 if (mReceiver == null) {
227 Log.e(TAG, "Receiver is null");
228 return;
229 }
230 try {
Vishwath Mohanecf00ce2018-04-05 10:28:24 -0700231 mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_POSITIVE);
Kevin Chyn42653e82018-01-19 14:15:46 -0800232 } catch (RemoteException e) {
233 Log.e(TAG, "Remote exception when handling positive button", e);
234 }
235 handleHideDialog(false /* userCanceled */);
236 }
237
Kevin Chyn42653e82018-01-19 14:15:46 -0800238 private void handleUserCanceled() {
239 handleHideDialog(true /* userCanceled */);
Kevin Chynaae4a152018-01-18 11:48:09 -0800240 }
241}