1 /* 2 * Copyright 2021 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.android.settings.biometrics.fingerprint; 18 19 import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED; 20 import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_TIMEOUT; 21 import static com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling.KEY_STATE_CANCELED; 22 23 import android.app.Activity; 24 import android.app.Dialog; 25 import android.app.settings.SettingsEnums; 26 import android.content.DialogInterface; 27 import android.content.Intent; 28 import android.hardware.biometrics.BiometricConstants; 29 import android.hardware.fingerprint.FingerprintManager; 30 import android.os.Bundle; 31 32 import androidx.appcompat.app.AlertDialog; 33 import androidx.fragment.app.FragmentManager; 34 35 import com.android.settings.R; 36 import com.android.settings.biometrics.BiometricEnrollBase; 37 import com.android.settings.core.instrumentation.InstrumentedDialogFragment; 38 39 /** Fingerprint error dialog, will be shown when an error occurs during fingerprint enrollment. */ 40 public class FingerprintErrorDialog extends InstrumentedDialogFragment { 41 42 public static final String KEY_ERROR_MSG = "error_msg"; 43 public static final String KEY_ERROR_TITLE = "error_title"; 44 public static final String KEY_ERROR_ID = "error_id"; 45 public static final String KEY_UDFPS = "is_udfps"; 46 47 @Override onCreateDialog(Bundle savedInstanceState)48 public Dialog onCreateDialog(Bundle savedInstanceState) { 49 final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 50 final CharSequence errorString = getArguments().getCharSequence(KEY_ERROR_MSG); 51 final CharSequence errorTitle = getArguments().getCharSequence(KEY_ERROR_TITLE); 52 final int errMsgId = getArguments().getInt(KEY_ERROR_ID); 53 final boolean canAssumeUdfps = getArguments().getBoolean(KEY_UDFPS, false); 54 final boolean wasTimeout = errMsgId == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT; 55 56 builder.setTitle(errorTitle) 57 .setMessage(errorString) 58 .setCancelable(false) 59 .setPositiveButton( 60 R.string.security_settings_fingerprint_enroll_dialog_ok, 61 new DialogInterface.OnClickListener() { 62 @Override 63 public void onClick(DialogInterface dialog, int which) { 64 dialog.dismiss(); 65 final Activity activity = getActivity(); 66 if (wasTimeout && !canAssumeUdfps) { 67 activity.setResult(RESULT_TIMEOUT); 68 } else { 69 activity.setResult(RESULT_FINISHED); 70 } 71 activity.finish(); 72 } 73 }); 74 if (wasTimeout && canAssumeUdfps) { 75 builder.setPositiveButton( 76 R.string.security_settings_fingerprint_enroll_dialog_try_again, 77 new DialogInterface.OnClickListener() { 78 @Override 79 public void onClick(DialogInterface dialog, int which) { 80 dialog.dismiss(); 81 final Activity activity = getActivity(); 82 final Intent intent = activity.getIntent(); 83 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); 84 intent.putExtra(KEY_STATE_CANCELED, false); 85 activity.startActivity(intent); 86 activity.finish(); 87 } 88 }) 89 .setNegativeButton( 90 R.string.security_settings_fingerprint_enroll_dialog_ok, 91 new DialogInterface.OnClickListener() { 92 @Override 93 public void onClick(DialogInterface dialog, int which) { 94 dialog.dismiss(); 95 final Activity activity = getActivity(); 96 activity.setResult(RESULT_TIMEOUT); 97 activity.finish(); 98 } 99 }); 100 } 101 final AlertDialog dialog = builder.create(); 102 dialog.setCanceledOnTouchOutside(false); 103 return dialog; 104 } 105 showErrorDialog(BiometricEnrollBase host, int errMsgId, boolean canAssumeUdfps)106 public static void showErrorDialog(BiometricEnrollBase host, int errMsgId, 107 boolean canAssumeUdfps) { 108 if (host.isFinishing()) { 109 return; 110 } 111 final FragmentManager fragmentManager = host.getSupportFragmentManager(); 112 if (fragmentManager.isDestroyed() || fragmentManager.isStateSaved()) { 113 return; 114 } 115 CharSequence errMsg = host.getText(getErrorMessage(errMsgId)); 116 final CharSequence errTitle = host.getText(getErrorTitle(errMsgId)); 117 if (!canAssumeUdfps 118 && errMsgId == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT) { 119 errMsg = host.getText(getErrorMessage(BiometricConstants.BIOMETRIC_ERROR_CANCELED)); 120 } 121 final FingerprintErrorDialog dialog = newInstance(errMsg, errTitle, 122 errMsgId, canAssumeUdfps); 123 dialog.show(fragmentManager, FingerprintErrorDialog.class.getName()); 124 } 125 getErrorMessage(int errMsgId)126 private static int getErrorMessage(int errMsgId) { 127 switch (errMsgId) { 128 case FingerprintManager.FINGERPRINT_ERROR_TIMEOUT: 129 // This message happens when the underlying crypto layer decides to revoke 130 // the enrollment auth token. 131 return R.string.security_settings_fingerprint_enroll_error_timeout_dialog_message; 132 case FingerprintManager.FINGERPRINT_ERROR_BAD_CALIBRATION: 133 return R.string.security_settings_fingerprint_bad_calibration; 134 default: 135 // There's nothing specific to tell the user about. Ask them to try again. 136 return R.string.security_settings_fingerprint_enroll_error_generic_dialog_message; 137 } 138 } 139 getErrorTitle(int errMsgId)140 private static int getErrorTitle(int errMsgId) { 141 switch (errMsgId) { 142 case FingerprintManager.FINGERPRINT_ERROR_UNABLE_TO_PROCESS: 143 return R.string 144 .security_settings_fingerprint_enroll_error_unable_to_process_dialog_title; 145 default: 146 return R.string.security_settings_fingerprint_enroll_error_dialog_title; 147 } 148 } 149 newInstance(CharSequence msg, CharSequence title, int msgId, boolean canAssumeUdfps)150 private static FingerprintErrorDialog newInstance(CharSequence msg, CharSequence title, 151 int msgId, boolean canAssumeUdfps) { 152 final FingerprintErrorDialog dialog = new FingerprintErrorDialog(); 153 final Bundle args = new Bundle(); 154 args.putCharSequence(KEY_ERROR_MSG, msg); 155 args.putCharSequence(KEY_ERROR_TITLE, title); 156 args.putInt(KEY_ERROR_ID, msgId); 157 args.putBoolean(KEY_UDFPS, canAssumeUdfps); 158 dialog.setArguments(args); 159 return dialog; 160 } 161 162 @Override getMetricsCategory()163 public int getMetricsCategory() { 164 return SettingsEnums.DIALOG_FINGERPINT_ERROR; 165 } 166 } 167