1 /* 2 * Copyright (C) 2023 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.systemui.biometrics; 18 19 import android.app.Dialog; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.hardware.biometrics.BiometricSourceType; 23 import android.hardware.face.Face; 24 import android.hardware.face.FaceManager; 25 import android.hardware.fingerprint.Fingerprint; 26 import android.hardware.fingerprint.FingerprintManager; 27 import android.provider.Settings; 28 import android.util.Log; 29 30 import com.android.systemui.R; 31 import com.android.systemui.dagger.SysUISingleton; 32 import com.android.systemui.statusbar.phone.SystemUIDialog; 33 34 import javax.inject.Inject; 35 36 /** 37 * Manages the creation of dialogs to be shown for biometric re enroll notifications. 38 */ 39 @SysUISingleton 40 public class BiometricNotificationDialogFactory { 41 private static final String TAG = "BiometricNotificationDialogFactory"; 42 43 @Inject BiometricNotificationDialogFactory()44 BiometricNotificationDialogFactory() {} 45 createReenrollDialog(final Context context, final SystemUIDialog sysuiDialog, BiometricSourceType biometricSourceType)46 Dialog createReenrollDialog(final Context context, final SystemUIDialog sysuiDialog, 47 BiometricSourceType biometricSourceType) { 48 if (biometricSourceType == BiometricSourceType.FACE) { 49 sysuiDialog.setTitle(context.getString(R.string.face_re_enroll_dialog_title)); 50 sysuiDialog.setMessage(context.getString(R.string.face_re_enroll_dialog_content)); 51 } else if (biometricSourceType == BiometricSourceType.FINGERPRINT) { 52 FingerprintManager fingerprintManager = context.getSystemService( 53 FingerprintManager.class); 54 sysuiDialog.setTitle(context.getString(R.string.fingerprint_re_enroll_dialog_title)); 55 if (fingerprintManager.getEnrolledFingerprints().size() == 1) { 56 sysuiDialog.setMessage(context.getString( 57 R.string.fingerprint_re_enroll_dialog_content_singular)); 58 } else { 59 sysuiDialog.setMessage(context.getString( 60 R.string.fingerprint_re_enroll_dialog_content)); 61 } 62 } 63 64 sysuiDialog.setPositiveButton(R.string.biometric_re_enroll_dialog_confirm, 65 (dialog, which) -> onReenrollDialogConfirm(context, biometricSourceType)); 66 sysuiDialog.setNegativeButton(R.string.biometric_re_enroll_dialog_cancel, 67 (dialog, which) -> {}); 68 return sysuiDialog; 69 } 70 createReenrollFailureDialog(Context context, BiometricSourceType biometricType)71 private static Dialog createReenrollFailureDialog(Context context, 72 BiometricSourceType biometricType) { 73 final SystemUIDialog sysuiDialog = new SystemUIDialog(context); 74 75 if (biometricType == BiometricSourceType.FACE) { 76 sysuiDialog.setMessage(context.getString( 77 R.string.face_reenroll_failure_dialog_content)); 78 } else if (biometricType == BiometricSourceType.FINGERPRINT) { 79 sysuiDialog.setMessage(context.getString( 80 R.string.fingerprint_reenroll_failure_dialog_content)); 81 } 82 83 sysuiDialog.setPositiveButton(R.string.ok, (dialog, which) -> {}); 84 return sysuiDialog; 85 } 86 onReenrollDialogConfirm(final Context context, BiometricSourceType biometricType)87 private static void onReenrollDialogConfirm(final Context context, 88 BiometricSourceType biometricType) { 89 if (biometricType == BiometricSourceType.FACE) { 90 reenrollFace(context); 91 } else if (biometricType == BiometricSourceType.FINGERPRINT) { 92 reenrollFingerprint(context); 93 } 94 } 95 reenrollFingerprint(Context context)96 private static void reenrollFingerprint(Context context) { 97 FingerprintManager fingerprintManager = context.getSystemService(FingerprintManager.class); 98 if (fingerprintManager == null) { 99 Log.e(TAG, "Not launching enrollment. Fingerprint manager was null!"); 100 createReenrollFailureDialog(context, BiometricSourceType.FINGERPRINT).show(); 101 return; 102 } 103 104 if (!fingerprintManager.hasEnrolledTemplates(context.getUserId())) { 105 createReenrollFailureDialog(context, BiometricSourceType.FINGERPRINT).show(); 106 return; 107 } 108 109 // Remove all enrolled fingerprint. Launch enrollment if successful. 110 fingerprintManager.removeAll(context.getUserId(), 111 new FingerprintManager.RemovalCallback() { 112 boolean mDidShowFailureDialog; 113 114 @Override 115 public void onRemovalError(Fingerprint fingerprint, int errMsgId, 116 CharSequence errString) { 117 Log.e(TAG, "Not launching enrollment." 118 + "Failed to remove existing face(s)."); 119 if (!mDidShowFailureDialog) { 120 mDidShowFailureDialog = true; 121 createReenrollFailureDialog(context, BiometricSourceType.FINGERPRINT) 122 .show(); 123 } 124 } 125 126 @Override 127 public void onRemovalSucceeded(Fingerprint fingerprint, int remaining) { 128 if (!mDidShowFailureDialog && remaining == 0) { 129 Intent intent = new Intent(Settings.ACTION_FINGERPRINT_ENROLL); 130 intent.setPackage("com.android.settings"); 131 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 132 context.startActivity(intent); 133 } 134 } 135 }); 136 } 137 reenrollFace(Context context)138 private static void reenrollFace(Context context) { 139 FaceManager faceManager = context.getSystemService(FaceManager.class); 140 if (faceManager == null) { 141 Log.e(TAG, "Not launching enrollment. Face manager was null!"); 142 createReenrollFailureDialog(context, BiometricSourceType.FACE).show(); 143 return; 144 } 145 146 if (!faceManager.hasEnrolledTemplates(context.getUserId())) { 147 createReenrollFailureDialog(context, BiometricSourceType.FACE).show(); 148 return; 149 } 150 151 // Remove all enrolled faces. Launch enrollment if successful. 152 faceManager.removeAll(context.getUserId(), 153 new FaceManager.RemovalCallback() { 154 boolean mDidShowFailureDialog; 155 156 @Override 157 public void onRemovalError(Face face, int errMsgId, CharSequence errString) { 158 Log.e(TAG, "Not launching enrollment." 159 + "Failed to remove existing face(s)."); 160 if (!mDidShowFailureDialog) { 161 mDidShowFailureDialog = true; 162 createReenrollFailureDialog(context, BiometricSourceType.FACE).show(); 163 } 164 } 165 166 @Override 167 public void onRemovalSucceeded(Face face, int remaining) { 168 if (!mDidShowFailureDialog && remaining == 0) { 169 Intent intent = new Intent("android.settings.FACE_ENROLL"); 170 intent.setPackage("com.android.settings"); 171 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 172 context.startActivity(intent); 173 } 174 } 175 }); 176 } 177 } 178