1 /* 2 * Copyright (C) 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.server.biometrics.sensors; 18 19 import android.annotation.NonNull; 20 import android.app.Notification; 21 import android.app.NotificationChannel; 22 import android.app.NotificationManager; 23 import android.app.PendingIntent; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.os.SystemClock; 27 import android.os.UserHandle; 28 import android.util.Slog; 29 30 import com.android.internal.R; 31 32 /** 33 * Biometric notification helper class. 34 */ 35 public class BiometricNotificationUtils { 36 37 private static final String TAG = "BiometricNotificationUtils"; 38 private static final String FACE_RE_ENROLL_NOTIFICATION_TAG = "FaceReEnroll"; 39 private static final String FACE_ENROLL_NOTIFICATION_TAG = "FaceEnroll"; 40 private static final String FINGERPRINT_ENROLL_NOTIFICATION_TAG = "FingerprintEnroll"; 41 private static final String BAD_CALIBRATION_NOTIFICATION_TAG = "FingerprintBadCalibration"; 42 private static final String KEY_RE_ENROLL_FACE = "re_enroll_face_unlock"; 43 private static final String FACE_SETTINGS_ACTION = "android.settings.FACE_SETTINGS"; 44 private static final String FINGERPRINT_SETTINGS_ACTION = 45 "android.settings.FINGERPRINT_SETTINGS"; 46 private static final String FACE_ENROLL_ACTION = "android.settings.FACE_ENROLL"; 47 private static final String FINGERPRINT_ENROLL_ACTION = "android.settings.FINGERPRINT_ENROLL"; 48 private static final String SETTINGS_PACKAGE = "com.android.settings"; 49 private static final String FACE_ENROLL_CHANNEL = "FaceEnrollNotificationChannel"; 50 private static final String FACE_RE_ENROLL_CHANNEL = "FaceReEnrollNotificationChannel"; 51 private static final String FINGERPRINT_ENROLL_CHANNEL = "FingerprintEnrollNotificationChannel"; 52 private static final String FINGERPRINT_BAD_CALIBRATION_CHANNEL = 53 "FingerprintBadCalibrationNotificationChannel"; 54 private static final int NOTIFICATION_ID = 1; 55 private static final long NOTIFICATION_INTERVAL_MS = 24 * 60 * 60 * 1000; 56 private static long sLastAlertTime = 0; 57 58 /** 59 * Shows a face re-enrollment notification. 60 */ showReEnrollmentNotification(@onNull Context context)61 public static void showReEnrollmentNotification(@NonNull Context context) { 62 final NotificationManager notificationManager = 63 context.getSystemService(NotificationManager.class); 64 65 final String name = 66 context.getString(R.string.face_recalibrate_notification_name); 67 final String title = 68 context.getString(R.string.face_recalibrate_notification_title); 69 final String content = 70 context.getString(R.string.face_recalibrate_notification_content); 71 72 final Intent intent = new Intent(FACE_SETTINGS_ACTION); 73 intent.setPackage(SETTINGS_PACKAGE); 74 intent.putExtra(KEY_RE_ENROLL_FACE, true); 75 76 final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context, 77 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */, 78 null /* options */, UserHandle.CURRENT); 79 80 showNotificationHelper(context, name, title, content, pendingIntent, FACE_RE_ENROLL_CHANNEL, 81 Notification.CATEGORY_SYSTEM, FACE_RE_ENROLL_NOTIFICATION_TAG, 82 Notification.VISIBILITY_SECRET); 83 } 84 85 /** 86 * Shows a face enrollment notification. 87 */ showFaceEnrollNotification(@onNull Context context)88 public static void showFaceEnrollNotification(@NonNull Context context) { 89 90 final String name = 91 context.getString(R.string.device_unlock_notification_name); 92 final String title = 93 context.getString(R.string.alternative_unlock_setup_notification_title); 94 final String content = 95 context.getString(R.string.alternative_face_setup_notification_content); 96 97 final Intent intent = new Intent(FACE_ENROLL_ACTION); 98 intent.setPackage(SETTINGS_PACKAGE); 99 100 final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context, 101 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */, 102 null /* options */, UserHandle.CURRENT); 103 104 showNotificationHelper(context, name, title, content, pendingIntent, FACE_ENROLL_CHANNEL, 105 Notification.CATEGORY_RECOMMENDATION, FACE_ENROLL_NOTIFICATION_TAG, 106 Notification.VISIBILITY_PUBLIC); 107 } 108 109 /** 110 * Shows a fingerprint enrollment notification. 111 */ showFingerprintEnrollNotification(@onNull Context context)112 public static void showFingerprintEnrollNotification(@NonNull Context context) { 113 114 final String name = 115 context.getString(R.string.device_unlock_notification_name); 116 final String title = 117 context.getString(R.string.alternative_unlock_setup_notification_title); 118 final String content = 119 context.getString(R.string.alternative_fp_setup_notification_content); 120 121 final Intent intent = new Intent(FINGERPRINT_ENROLL_ACTION); 122 intent.setPackage(SETTINGS_PACKAGE); 123 124 final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context, 125 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */, 126 null /* options */, UserHandle.CURRENT); 127 128 showNotificationHelper(context, name, title, content, pendingIntent, 129 Notification.CATEGORY_RECOMMENDATION, FINGERPRINT_ENROLL_CHANNEL, 130 FINGERPRINT_ENROLL_NOTIFICATION_TAG, Notification.VISIBILITY_PUBLIC); 131 } 132 133 /** 134 * Shows a fingerprint bad calibration notification. 135 */ showBadCalibrationNotification(@onNull Context context)136 public static void showBadCalibrationNotification(@NonNull Context context) { 137 final long currentTime = SystemClock.elapsedRealtime(); 138 final long timeSinceLastAlert = currentTime - sLastAlertTime; 139 140 // Only show the notification if not previously shown or a day has 141 // passed since the last notification. 142 if (sLastAlertTime != 0 && (timeSinceLastAlert < NOTIFICATION_INTERVAL_MS)) { 143 Slog.v(TAG, "Skipping calibration notification : " + timeSinceLastAlert); 144 return; 145 } 146 147 sLastAlertTime = currentTime; 148 149 final String name = 150 context.getString(R.string.fingerprint_recalibrate_notification_name); 151 final String title = 152 context.getString(R.string.fingerprint_recalibrate_notification_title); 153 final String content = 154 context.getString(R.string.fingerprint_recalibrate_notification_content); 155 156 final Intent intent = new Intent(FINGERPRINT_SETTINGS_ACTION); 157 intent.setPackage(SETTINGS_PACKAGE); 158 159 final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context, 160 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */, 161 null /* options */, UserHandle.CURRENT); 162 163 showNotificationHelper(context, name, title, content, pendingIntent, 164 Notification.CATEGORY_SYSTEM, FINGERPRINT_BAD_CALIBRATION_CHANNEL, 165 BAD_CALIBRATION_NOTIFICATION_TAG, Notification.VISIBILITY_SECRET); 166 } 167 showNotificationHelper(Context context, String name, String title, String content, PendingIntent pendingIntent, String category, String channelName, String notificationTag, int visibility)168 private static void showNotificationHelper(Context context, String name, String title, 169 String content, PendingIntent pendingIntent, String category, 170 String channelName, String notificationTag, int visibility) { 171 final NotificationManager notificationManager = 172 context.getSystemService(NotificationManager.class); 173 final NotificationChannel channel = new NotificationChannel(channelName, name, 174 NotificationManager.IMPORTANCE_HIGH); 175 final Notification notification = new Notification.Builder(context, channelName) 176 .setSmallIcon(R.drawable.ic_lock) 177 .setContentTitle(title) 178 .setContentText(content) 179 .setStyle(new Notification.BigTextStyle().bigText(content)) 180 .setSubText(name) 181 .setOnlyAlertOnce(true) 182 .setLocalOnly(true) 183 .setAutoCancel(true) 184 .setCategory(category) 185 .setContentIntent(pendingIntent) 186 .setVisibility(visibility) 187 .build(); 188 189 notificationManager.createNotificationChannel(channel); 190 notificationManager.notifyAsUser(notificationTag, NOTIFICATION_ID, notification, 191 UserHandle.CURRENT); 192 } 193 194 /** 195 * Cancels a face re-enrollment notification 196 */ cancelFaceReEnrollNotification(@onNull Context context)197 public static void cancelFaceReEnrollNotification(@NonNull Context context) { 198 final NotificationManager notificationManager = 199 context.getSystemService(NotificationManager.class); 200 notificationManager.cancelAsUser(FACE_RE_ENROLL_NOTIFICATION_TAG, NOTIFICATION_ID, 201 UserHandle.CURRENT); 202 } 203 204 /** 205 * Cancels a face enrollment notification 206 */ cancelFaceEnrollNotification(@onNull Context context)207 public static void cancelFaceEnrollNotification(@NonNull Context context) { 208 final NotificationManager notificationManager = 209 context.getSystemService(NotificationManager.class); 210 notificationManager.cancelAsUser(FACE_ENROLL_NOTIFICATION_TAG, NOTIFICATION_ID, 211 UserHandle.CURRENT); 212 } 213 214 /** 215 * Cancels a fingerprint enrollment notification 216 */ cancelFingerprintEnrollNotification(@onNull Context context)217 public static void cancelFingerprintEnrollNotification(@NonNull Context context) { 218 final NotificationManager notificationManager = 219 context.getSystemService(NotificationManager.class); 220 notificationManager.cancelAsUser(FINGERPRINT_ENROLL_NOTIFICATION_TAG, NOTIFICATION_ID, 221 UserHandle.CURRENT); 222 } 223 224 /** 225 * Cancels a fingerprint bad calibration notification 226 */ cancelBadCalibrationNotification(@onNull Context context)227 public static void cancelBadCalibrationNotification(@NonNull Context context) { 228 final NotificationManager notificationManager = 229 context.getSystemService(NotificationManager.class); 230 notificationManager.cancelAsUser(BAD_CALIBRATION_NOTIFICATION_TAG, NOTIFICATION_ID, 231 UserHandle.CURRENT); 232 } 233 234 } 235