blob: 516de709c34f68e752e5e6f5c3006d821f23b96d [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
Kevin Chynf8688a02019-08-27 17:04:05 -070014 * limitations under the License.
Kevin Chynaae4a152018-01-18 11:48:09 -080015 */
16
Kevin Chyne9275662018-07-23 16:42:06 -070017package com.android.systemui.biometrics;
Kevin Chynaae4a152018-01-18 11:48:09 -080018
Ilya Matyukhin0f9da352019-10-03 14:10:01 -070019import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
20import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
21
Kevin Chyn050315f2019-08-08 14:22:54 -070022import android.app.ActivityManager;
23import android.app.ActivityTaskManager;
24import android.app.IActivityTaskManager;
25import android.app.TaskStackListener;
Kevin Chyn42653e82018-01-19 14:15:46 -080026import android.content.Context;
Kevin Chynaae4a152018-01-18 11:48:09 -080027import android.content.pm.PackageManager;
Gus Prevasa7df7b22018-10-30 10:29:34 -040028import android.content.res.Configuration;
Kevin Chyn86f1b8e2019-09-24 19:00:49 -070029import android.hardware.biometrics.Authenticator;
Kevin Chyn8429da22019-09-24 12:42:35 -070030import android.hardware.biometrics.BiometricConstants;
Vishwath Mohanecf00ce2018-04-05 10:28:24 -070031import android.hardware.biometrics.BiometricPrompt;
Kevin Chyn23289ef2018-11-28 16:32:36 -080032import android.hardware.biometrics.IBiometricServiceReceiverInternal;
Ilya Matyukhin0f9da352019-10-03 14:10:01 -070033import android.hardware.face.FaceManager;
34import android.hardware.fingerprint.FingerprintManager;
Kevin Chynaae4a152018-01-18 11:48:09 -080035import android.os.Bundle;
Kevin Chyn050315f2019-08-08 14:22:54 -070036import android.os.Handler;
37import android.os.Looper;
Kevin Chyn42653e82018-01-19 14:15:46 -080038import android.os.RemoteException;
Kevin Chynaae4a152018-01-18 11:48:09 -080039import android.util.Log;
Kevin Chyn42653e82018-01-19 14:15:46 -080040import android.view.WindowManager;
Kevin Chynaae4a152018-01-18 11:48:09 -080041
Ilya Matyukhin0f9da352019-10-03 14:10:01 -070042import com.android.internal.R;
Kevin Chyn050315f2019-08-08 14:22:54 -070043import com.android.internal.annotations.VisibleForTesting;
Kevin Chyn42653e82018-01-19 14:15:46 -080044import com.android.internal.os.SomeArgs;
Kevin Chynaae4a152018-01-18 11:48:09 -080045import com.android.systemui.SystemUI;
46import com.android.systemui.statusbar.CommandQueue;
47
Kevin Chyn050315f2019-08-08 14:22:54 -070048import java.util.List;
49
Dave Mankoffbcaca8a2019-10-31 18:04:08 -040050import javax.inject.Inject;
51import javax.inject.Singleton;
52
Kevin Chyne9275662018-07-23 16:42:06 -070053/**
Kevin Chync53d9812019-07-30 18:10:30 -070054 * Receives messages sent from {@link com.android.server.biometrics.BiometricService} and shows the
55 * appropriate biometric UI (e.g. BiometricDialogView).
Kevin Chyne9275662018-07-23 16:42:06 -070056 */
Dave Mankoffbcaca8a2019-10-31 18:04:08 -040057@Singleton
Kevin Chynf8688a02019-08-27 17:04:05 -070058public class AuthController extends SystemUI implements CommandQueue.Callbacks,
59 AuthDialogCallback {
Kevin Chynfc468262019-08-20 17:17:11 -070060
Kevin Chynf8688a02019-08-27 17:04:05 -070061 private static final String TAG = "BiometricPrompt/AuthController";
Kevin Chyn42653e82018-01-19 14:15:46 -080062 private static final boolean DEBUG = true;
63
Dave Mankoffbcaca8a2019-10-31 18:04:08 -040064 private final CommandQueue mCommandQueue;
Kevin Chyn050315f2019-08-08 14:22:54 -070065 private final Injector mInjector;
66
Kevin Chync53d9812019-07-30 18:10:30 -070067 // TODO: These should just be saved from onSaveState
Gus Prevasa7df7b22018-10-30 10:29:34 -040068 private SomeArgs mCurrentDialogArgs;
Kevin Chyn050315f2019-08-08 14:22:54 -070069 @VisibleForTesting
Kevin Chynf8688a02019-08-27 17:04:05 -070070 AuthDialog mCurrentDialog;
Kevin Chync53d9812019-07-30 18:10:30 -070071
Kevin Chyn050315f2019-08-08 14:22:54 -070072 private Handler mHandler = new Handler(Looper.getMainLooper());
Kevin Chyn42653e82018-01-19 14:15:46 -080073 private WindowManager mWindowManager;
Kevin Chyn050315f2019-08-08 14:22:54 -070074 @VisibleForTesting
75 IActivityTaskManager mActivityTaskManager;
76 @VisibleForTesting
77 BiometricTaskStackListener mTaskStackListener;
78 @VisibleForTesting
79 IBiometricServiceReceiverInternal mReceiver;
80
81 public class BiometricTaskStackListener extends TaskStackListener {
82 @Override
83 public void onTaskStackChanged() {
84 mHandler.post(mTaskStackChangedRunnable);
85 }
86 }
87
88 private final Runnable mTaskStackChangedRunnable = () -> {
89 if (mCurrentDialog != null) {
90 try {
91 final String clientPackage = mCurrentDialog.getOpPackageName();
92 Log.w(TAG, "Task stack changed, current client: " + clientPackage);
93 final List<ActivityManager.RunningTaskInfo> runningTasks =
94 mActivityTaskManager.getTasks(1);
95 if (!runningTasks.isEmpty()) {
96 final String topPackage = runningTasks.get(0).topActivity.getPackageName();
97 if (!topPackage.contentEquals(clientPackage)) {
98 Log.w(TAG, "Evicting client due to: " + topPackage);
99 mCurrentDialog.dismissWithoutCallback(true /* animate */);
100 mCurrentDialog = null;
Curtis Belmonteffa9d872019-10-24 12:55:01 -0700101 if (mReceiver != null) {
102 mReceiver.onDialogDismissed(
103 BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
104 mReceiver = null;
105 }
Kevin Chyn050315f2019-08-08 14:22:54 -0700106 }
107 }
108 } catch (RemoteException e) {
109 Log.e(TAG, "Remote exception", e);
110 }
111 }
112 };
Kevin Chyn42653e82018-01-19 14:15:46 -0800113
Kevin Chync53d9812019-07-30 18:10:30 -0700114 @Override
115 public void onTryAgainPressed() {
Curtis Belmonteffa9d872019-10-24 12:55:01 -0700116 if (mReceiver == null) {
117 Log.e(TAG, "onTryAgainPressed: Receiver is null");
118 return;
119 }
Kevin Chync53d9812019-07-30 18:10:30 -0700120 try {
121 mReceiver.onTryAgainPressed();
122 } catch (RemoteException e) {
123 Log.e(TAG, "RemoteException when handling try again", e);
Kevin Chyn5906c172018-07-23 15:43:02 -0700124 }
125 }
126
Kevin Chync53d9812019-07-30 18:10:30 -0700127 @Override
Kevin Chynff168dc2019-09-16 16:04:38 -0700128 public void onDeviceCredentialPressed() {
Curtis Belmonteffa9d872019-10-24 12:55:01 -0700129 if (mReceiver == null) {
130 Log.e(TAG, "onDeviceCredentialPressed: Receiver is null");
131 return;
132 }
Kevin Chynff168dc2019-09-16 16:04:38 -0700133 try {
134 mReceiver.onDeviceCredentialPressed();
135 } catch (RemoteException e) {
136 Log.e(TAG, "RemoteException when handling credential button", e);
137 }
138 }
139
140 @Override
Kevin Chyn050315f2019-08-08 14:22:54 -0700141 public void onDismissed(@DismissedReason int reason) {
Kevin Chync53d9812019-07-30 18:10:30 -0700142 switch (reason) {
Kevin Chynf8688a02019-08-27 17:04:05 -0700143 case AuthDialogCallback.DISMISSED_USER_CANCELED:
Kevin Chync53d9812019-07-30 18:10:30 -0700144 sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
145 break;
146
Kevin Chynf8688a02019-08-27 17:04:05 -0700147 case AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE:
Kevin Chync53d9812019-07-30 18:10:30 -0700148 sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_NEGATIVE);
149 break;
150
Kevin Chynf8688a02019-08-27 17:04:05 -0700151 case AuthDialogCallback.DISMISSED_BUTTON_POSITIVE:
Kevin Chynff168dc2019-09-16 16:04:38 -0700152 sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED);
Kevin Chync53d9812019-07-30 18:10:30 -0700153 break;
154
Kevin Chynff168dc2019-09-16 16:04:38 -0700155 case AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED:
156 sendResultAndCleanUp(
157 BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED);
Kevin Chync53d9812019-07-30 18:10:30 -0700158 break;
159
Kevin Chynf8688a02019-08-27 17:04:05 -0700160 case AuthDialogCallback.DISMISSED_ERROR:
Kevin Chync53d9812019-07-30 18:10:30 -0700161 sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_ERROR);
Kevin Chync53d9812019-07-30 18:10:30 -0700162 break;
Kevin Chyn050315f2019-08-08 14:22:54 -0700163
Kevin Chynf8688a02019-08-27 17:04:05 -0700164 case AuthDialogCallback.DISMISSED_BY_SYSTEM_SERVER:
Kevin Chyn050315f2019-08-08 14:22:54 -0700165 sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED);
166 break;
167
Kevin Chynff168dc2019-09-16 16:04:38 -0700168 case AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED:
169 sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED);
170 break;
171
Kevin Chync53d9812019-07-30 18:10:30 -0700172 default:
173 Log.e(TAG, "Unhandled reason: " + reason);
174 break;
Kevin Chync94b7db2019-05-15 17:28:16 -0700175 }
Kevin Chync53d9812019-07-30 18:10:30 -0700176 }
177
Kevin Chyn050315f2019-08-08 14:22:54 -0700178 private void sendResultAndCleanUp(@DismissedReason int reason) {
Kevin Chync53d9812019-07-30 18:10:30 -0700179 if (mReceiver == null) {
Curtis Belmonteffa9d872019-10-24 12:55:01 -0700180 Log.e(TAG, "sendResultAndCleanUp: Receiver is null");
Kevin Chync53d9812019-07-30 18:10:30 -0700181 return;
182 }
183 try {
Kevin Chyn050315f2019-08-08 14:22:54 -0700184 mReceiver.onDialogDismissed(reason);
Kevin Chync53d9812019-07-30 18:10:30 -0700185 } catch (RemoteException e) {
186 Log.w(TAG, "Remote exception", e);
187 }
Kevin Chyn050315f2019-08-08 14:22:54 -0700188 onDialogDismissed(reason);
189 }
190
191 public static class Injector {
192 IActivityTaskManager getActivityTaskManager() {
193 return ActivityTaskManager.getService();
194 }
195 }
196
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400197 @Inject
198 public AuthController(Context context, CommandQueue commandQueue) {
199 this(context, commandQueue, new Injector());
Kevin Chyn050315f2019-08-08 14:22:54 -0700200 }
201
202 @VisibleForTesting
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400203 AuthController(Context context, CommandQueue commandQueue, Injector injector) {
Dave Mankoffa5d8a392019-10-10 12:21:09 -0400204 super(context);
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400205 mCommandQueue = commandQueue;
Kevin Chyn050315f2019-08-08 14:22:54 -0700206 mInjector = injector;
Kevin Chync53d9812019-07-30 18:10:30 -0700207 }
Kevin Chync94b7db2019-05-15 17:28:16 -0700208
Kevin Chynaae4a152018-01-18 11:48:09 -0800209 @Override
210 public void start() {
Kevin Chyne1912712019-01-04 14:22:34 -0800211 final PackageManager pm = mContext.getPackageManager();
212 if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
213 || pm.hasSystemFeature(PackageManager.FEATURE_FACE)
214 || pm.hasSystemFeature(PackageManager.FEATURE_IRIS)) {
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400215 mCommandQueue.addCallback(this);
Gus Prevasa7df7b22018-10-30 10:29:34 -0400216 mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
Kevin Chyn050315f2019-08-08 14:22:54 -0700217 mActivityTaskManager = mInjector.getActivityTaskManager();
218
219 try {
220 mTaskStackListener = new BiometricTaskStackListener();
221 mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
222 } catch (RemoteException e) {
223 Log.w(TAG, "Unable to register task stack listener", e);
224 }
Gus Prevasa7df7b22018-10-30 10:29:34 -0400225 }
226 }
227
Kevin Chynaae4a152018-01-18 11:48:09 -0800228 @Override
Kevin Chyn86f1b8e2019-09-24 19:00:49 -0700229 public void showAuthenticationDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
230 int biometricModality, boolean requireConfirmation, int userId, String opPackageName) {
231 final int authenticators = Utils.getAuthenticators(bundle);
232
Kevin Chyn158fefb2019-01-03 18:59:05 -0800233 if (DEBUG) {
Kevin Chyn86f1b8e2019-09-24 19:00:49 -0700234 Log.d(TAG, "showAuthenticationDialog, authenticators: " + authenticators
235 + ", biometricModality: " + biometricModality
Kevin Chyn158fefb2019-01-03 18:59:05 -0800236 + ", requireConfirmation: " + requireConfirmation);
237 }
Kevin Chyn42653e82018-01-19 14:15:46 -0800238 SomeArgs args = SomeArgs.obtain();
239 args.arg1 = bundle;
240 args.arg2 = receiver;
Kevin Chyn86f1b8e2019-09-24 19:00:49 -0700241 args.argi1 = biometricModality;
Kevin Chyn6cf54e82018-09-18 19:13:27 -0700242 args.arg3 = requireConfirmation;
Kevin Chyn1b9f8df2018-11-12 19:04:55 -0800243 args.argi2 = userId;
Kevin Chyn050315f2019-08-08 14:22:54 -0700244 args.arg4 = opPackageName;
Kevin Chync53d9812019-07-30 18:10:30 -0700245
246 boolean skipAnimation = false;
247 if (mCurrentDialog != null) {
248 Log.w(TAG, "mCurrentDialog: " + mCurrentDialog);
249 skipAnimation = true;
250 }
Kevin Chyn86f1b8e2019-09-24 19:00:49 -0700251
252 showDialog(args, skipAnimation, null /* savedState */);
Kevin Chynaae4a152018-01-18 11:48:09 -0800253 }
254
255 @Override
Ilya Matyukhin0f9da352019-10-03 14:10:01 -0700256 public void onBiometricAuthenticated() {
257 mCurrentDialog.onAuthenticationSucceeded();
Kevin Chyn42653e82018-01-19 14:15:46 -0800258 }
259
Kevin Chync53d9812019-07-30 18:10:30 -0700260 @Override
261 public void onBiometricHelp(String message) {
262 if (DEBUG) Log.d(TAG, "onBiometricHelp: " + message);
263
264 mCurrentDialog.onHelp(message);
Kevin Chyn42653e82018-01-19 14:15:46 -0800265 }
266
Ilya Matyukhin0f9da352019-10-03 14:10:01 -0700267 private String getErrorString(int modality, int error, int vendorCode) {
268 switch (modality) {
269 case TYPE_FACE:
270 return FaceManager.getErrorString(mContext, error, vendorCode);
Kevin Chyn8429da22019-09-24 12:42:35 -0700271
Ilya Matyukhin0f9da352019-10-03 14:10:01 -0700272 case TYPE_FINGERPRINT:
273 return FingerprintManager.getErrorString(mContext, error, vendorCode);
274
275 default:
276 return "";
277 }
278 }
279
280 @Override
281 public void onBiometricError(int modality, int error, int vendorCode) {
282 if (DEBUG) {
283 Log.d(TAG, String.format("onBiometricError(%d, %d, %d)", modality, error, vendorCode));
284 }
285
286 final boolean isLockout = (error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT)
287 || (error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT);
288
289 // TODO(b/141025588): Create separate methods for handling hard and soft errors.
290 final boolean isSoftError = (error == BiometricConstants.BIOMETRIC_PAUSED_REJECTED
291 || error == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT);
292
Kevin Chyn8429da22019-09-24 12:42:35 -0700293 if (mCurrentDialog.isAllowDeviceCredentials() && isLockout) {
Ilya Matyukhin0f9da352019-10-03 14:10:01 -0700294 if (DEBUG) Log.d(TAG, "onBiometricError, lockout");
Kevin Chyn8429da22019-09-24 12:42:35 -0700295 mCurrentDialog.animateToCredentialUI();
Ilya Matyukhin0f9da352019-10-03 14:10:01 -0700296 } else if (isSoftError) {
297 final String errorMessage = (error == BiometricConstants.BIOMETRIC_PAUSED_REJECTED)
298 ? mContext.getString(R.string.biometric_not_recognized)
299 : getErrorString(modality, error, vendorCode);
300 if (DEBUG) Log.d(TAG, "onBiometricError, soft error: " + errorMessage);
301 mCurrentDialog.onAuthenticationFailed(errorMessage);
Kevin Chyn8429da22019-09-24 12:42:35 -0700302 } else {
Ilya Matyukhin0f9da352019-10-03 14:10:01 -0700303 final String errorMessage = getErrorString(modality, error, vendorCode);
304 if (DEBUG) Log.d(TAG, "onBiometricError, hard error: " + errorMessage);
305 mCurrentDialog.onError(errorMessage);
Kevin Chyn8429da22019-09-24 12:42:35 -0700306 }
Kevin Chyn42653e82018-01-19 14:15:46 -0800307 }
308
Kevin Chync53d9812019-07-30 18:10:30 -0700309 @Override
Kevin Chyn86f1b8e2019-09-24 19:00:49 -0700310 public void hideAuthenticationDialog() {
311 if (DEBUG) Log.d(TAG, "hideAuthenticationDialog");
Kevin Chync53d9812019-07-30 18:10:30 -0700312
Kevin Chyn050315f2019-08-08 14:22:54 -0700313 mCurrentDialog.dismissFromSystemServer();
Kevin Chync53d9812019-07-30 18:10:30 -0700314 }
315
Kevin Chyn86f1b8e2019-09-24 19:00:49 -0700316 private void showDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) {
Kevin Chync53d9812019-07-30 18:10:30 -0700317 mCurrentDialogArgs = args;
318 final int type = args.argi1;
Kevin Chyn050315f2019-08-08 14:22:54 -0700319 final Bundle biometricPromptBundle = (Bundle) args.arg1;
320 final boolean requireConfirmation = (boolean) args.arg3;
321 final int userId = args.argi2;
322 final String opPackageName = (String) args.arg4;
Kevin Chync53d9812019-07-30 18:10:30 -0700323
324 // Create a new dialog but do not replace the current one yet.
Kevin Chynf8688a02019-08-27 17:04:05 -0700325 final AuthDialog newDialog = buildDialog(
Kevin Chyn050315f2019-08-08 14:22:54 -0700326 biometricPromptBundle,
327 requireConfirmation,
328 userId,
329 type,
Kevin Chynfc468262019-08-20 17:17:11 -0700330 opPackageName,
Kevin Chyn86f1b8e2019-09-24 19:00:49 -0700331 skipAnimation);
Kevin Chync53d9812019-07-30 18:10:30 -0700332
333 if (newDialog == null) {
334 Log.e(TAG, "Unsupported type: " + type);
Kevin Chyn42653e82018-01-19 14:15:46 -0800335 return;
336 }
Kevin Chync53d9812019-07-30 18:10:30 -0700337
338 if (DEBUG) {
Kevin Chyn86f1b8e2019-09-24 19:00:49 -0700339 Log.d(TAG, "showDialog: " + args
Kevin Chync53d9812019-07-30 18:10:30 -0700340 + " savedState: " + savedState
341 + " mCurrentDialog: " + mCurrentDialog
342 + " newDialog: " + newDialog
Kevin Chyn86f1b8e2019-09-24 19:00:49 -0700343 + " type: " + type);
Kevin Chync53d9812019-07-30 18:10:30 -0700344 }
345
Kevin Chyn9cf89912019-08-30 13:33:58 -0700346 if (mCurrentDialog != null) {
Kevin Chync53d9812019-07-30 18:10:30 -0700347 // If somehow we're asked to show a dialog, the old one doesn't need to be animated
348 // away. This can happen if the app cancels and re-starts auth during configuration
349 // change. This is ugly because we also have to do things on onConfigurationChanged
350 // here.
351 mCurrentDialog.dismissWithoutCallback(false /* animate */);
352 }
353
354 mReceiver = (IBiometricServiceReceiverInternal) args.arg2;
355 mCurrentDialog = newDialog;
Kevin Chyn9cf89912019-08-30 13:33:58 -0700356 mCurrentDialog.show(mWindowManager, savedState);
Kevin Chync53d9812019-07-30 18:10:30 -0700357 }
358
Kevin Chyn050315f2019-08-08 14:22:54 -0700359 private void onDialogDismissed(@DismissedReason int reason) {
360 if (DEBUG) Log.d(TAG, "onDialogDismissed: " + reason);
Kevin Chync53d9812019-07-30 18:10:30 -0700361 if (mCurrentDialog == null) {
362 Log.w(TAG, "Dialog already dismissed");
Kevin Chyn42653e82018-01-19 14:15:46 -0800363 }
364 mReceiver = null;
Kevin Chync53d9812019-07-30 18:10:30 -0700365 mCurrentDialog = null;
Kevin Chyn23289ef2018-11-28 16:32:36 -0800366 }
367
Gus Prevasa7df7b22018-10-30 10:29:34 -0400368 @Override
369 protected void onConfigurationChanged(Configuration newConfig) {
Kevin Chyn02129b12018-11-01 16:47:12 -0700370 super.onConfigurationChanged(newConfig);
Kevin Chyne1912712019-01-04 14:22:34 -0800371
372 // Save the state of the current dialog (buttons showing, etc)
Kevin Chyne1912712019-01-04 14:22:34 -0800373 if (mCurrentDialog != null) {
Kevin Chync53d9812019-07-30 18:10:30 -0700374 final Bundle savedState = new Bundle();
Kevin Chyne1912712019-01-04 14:22:34 -0800375 mCurrentDialog.onSaveState(savedState);
Kevin Chync53d9812019-07-30 18:10:30 -0700376 mCurrentDialog.dismissWithoutCallback(false /* animate */);
377 mCurrentDialog = null;
Kevin Chyne1912712019-01-04 14:22:34 -0800378
Kevin Chyn27da7182019-09-11 12:17:55 -0700379 // Only show the dialog if necessary. If it was animating out, the dialog is supposed
380 // to send its pending callback immediately.
381 if (savedState.getInt(AuthDialog.KEY_CONTAINER_STATE)
382 != AuthContainerView.STATE_ANIMATING_OUT) {
Kevin Chyn8cbb4882019-09-19 16:49:02 -0700383 final boolean credentialShowing =
384 savedState.getBoolean(AuthDialog.KEY_CREDENTIAL_SHOWING);
Kevin Chyn86f1b8e2019-09-24 19:00:49 -0700385 if (credentialShowing) {
386 // TODO: Clean this up
387 Bundle bundle = (Bundle) mCurrentDialogArgs.arg1;
388 bundle.putInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED,
389 Authenticator.TYPE_CREDENTIAL);
390 }
Kevin Chyn8cbb4882019-09-19 16:49:02 -0700391
Kevin Chyn86f1b8e2019-09-24 19:00:49 -0700392 showDialog(mCurrentDialogArgs, true /* skipAnimation */, savedState);
Kevin Chyn27da7182019-09-11 12:17:55 -0700393 }
Gus Prevasa7df7b22018-10-30 10:29:34 -0400394 }
Kevin Chync53d9812019-07-30 18:10:30 -0700395 }
Kevin Chyne1912712019-01-04 14:22:34 -0800396
Kevin Chynf8688a02019-08-27 17:04:05 -0700397 protected AuthDialog buildDialog(Bundle biometricPromptBundle, boolean requireConfirmation,
Kevin Chyn86f1b8e2019-09-24 19:00:49 -0700398 int userId, int type, String opPackageName, boolean skipIntro) {
Kevin Chynd837ced2019-09-11 16:09:43 -0700399 return new AuthContainerView.Builder(mContext)
400 .setCallback(this)
401 .setBiometricPromptBundle(biometricPromptBundle)
402 .setRequireConfirmation(requireConfirmation)
403 .setUserId(userId)
404 .setOpPackageName(opPackageName)
405 .setSkipIntro(skipIntro)
406 .build(type);
Gus Prevasa7df7b22018-10-30 10:29:34 -0400407 }
Kevin Chynaae4a152018-01-18 11:48:09 -0800408}