1 /* 2 * Copyright (C) 2022 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.safetycenter; 18 19 import android.app.PendingIntent; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.hardware.face.FaceManager; 23 import android.hardware.fingerprint.FingerprintManager; 24 import android.os.Bundle; 25 import android.os.Process; 26 import android.os.UserHandle; 27 import android.os.UserManager; 28 import android.safetycenter.SafetyEvent; 29 import android.safetycenter.SafetySourceData; 30 import android.safetycenter.SafetySourceStatus; 31 32 import com.android.settings.Utils; 33 import com.android.settings.biometrics.BiometricNavigationUtils; 34 import com.android.settings.biometrics.activeunlock.ActiveUnlockStatusUtils; 35 import com.android.settings.biometrics.combination.CombinedBiometricStatusUtils; 36 import com.android.settings.biometrics.face.FaceStatusUtils; 37 import com.android.settings.biometrics.fingerprint.FingerprintStatusUtils; 38 import com.android.settingslib.RestrictedLockUtils; 39 40 /** Combined Biometrics Safety Source for Safety Center. */ 41 public final class BiometricsSafetySource { 42 43 public static final String SAFETY_SOURCE_ID = "AndroidBiometrics"; 44 private static final int REQUEST_CODE_COMBINED_BIOMETRIC_SETTING = 10; 45 private static final int REQUEST_CODE_FACE_SETTING = 20; 46 private static final int REQUEST_CODE_FINGERPRINT_SETTING = 30; 47 BiometricsSafetySource()48 private BiometricsSafetySource() {} 49 50 /** Sets biometric safety data for Safety Center. */ setSafetySourceData(Context context, SafetyEvent safetyEvent)51 public static void setSafetySourceData(Context context, SafetyEvent safetyEvent) { 52 if (!SafetyCenterManagerWrapper.get().isEnabled(context)) { 53 return; 54 } 55 56 final UserHandle userHandle = Process.myUserHandle(); 57 final int userId = userHandle.getIdentifier(); 58 final UserManager userManager = UserManager.get(context); 59 UserHandle profileParentUserHandle = userManager.getProfileParent(userHandle); 60 if (profileParentUserHandle == null) { 61 profileParentUserHandle = userHandle; 62 } 63 final Context profileParentContext = 64 context.createContextAsUser(profileParentUserHandle, 0); 65 if (android.os.Flags.allowPrivateProfile() 66 && android.multiuser.Flags.enablePrivateSpaceFeatures() 67 && userManager.isPrivateProfile()) { 68 // SC always expects a response from the source if the broadcast has been sent for this 69 // source, therefore, we need to send a null SafetySourceData. 70 SafetyCenterManagerWrapper.get().setSafetySourceData( 71 context, 72 SAFETY_SOURCE_ID, 73 /* safetySourceData= */ null, 74 safetyEvent); 75 return; 76 } 77 78 final BiometricNavigationUtils biometricNavigationUtils = 79 new BiometricNavigationUtils(userId); 80 final CombinedBiometricStatusUtils combinedBiometricStatusUtils = 81 new CombinedBiometricStatusUtils(context, userId); 82 final ActiveUnlockStatusUtils activeUnlockStatusUtils = 83 new ActiveUnlockStatusUtils(context); 84 if (!userManager.isProfile() && activeUnlockStatusUtils.isAvailable()) { 85 final RestrictedLockUtils.EnforcedAdmin disablingAdmin = 86 combinedBiometricStatusUtils.getDisablingAdmin(); 87 setBiometricSafetySourceData( 88 context, 89 activeUnlockStatusUtils.getTitleForActiveUnlock(), 90 combinedBiometricStatusUtils.getSummary(), 91 createPendingIntent( 92 context, 93 biometricNavigationUtils.getBiometricSettingsIntent( 94 context, 95 combinedBiometricStatusUtils.getSettingsClassName(), 96 disablingAdmin, 97 Bundle.EMPTY), 98 REQUEST_CODE_COMBINED_BIOMETRIC_SETTING), 99 disablingAdmin == null /* enabled */, 100 combinedBiometricStatusUtils.hasEnrolled(), 101 safetyEvent); 102 return; 103 } 104 if (combinedBiometricStatusUtils.isAvailable()) { 105 final RestrictedLockUtils.EnforcedAdmin disablingAdmin = 106 combinedBiometricStatusUtils.getDisablingAdmin(); 107 setBiometricSafetySourceData( 108 context, 109 combinedBiometricStatusUtils.getTitle(), 110 combinedBiometricStatusUtils.getSummary(), 111 createPendingIntent( 112 profileParentContext, 113 biometricNavigationUtils 114 .getBiometricSettingsIntent( 115 context, 116 combinedBiometricStatusUtils 117 .getSettingsClassNameBasedOnUser(), 118 disablingAdmin, 119 Bundle.EMPTY) 120 .setIdentifier(Integer.toString(userId)), 121 REQUEST_CODE_COMBINED_BIOMETRIC_SETTING), 122 disablingAdmin == null /* enabled */, 123 combinedBiometricStatusUtils.hasEnrolled(), 124 safetyEvent); 125 return; 126 } 127 128 final FaceManager faceManager = Utils.getFaceManagerOrNull(context); 129 final FaceStatusUtils faceStatusUtils = new FaceStatusUtils(context, faceManager, userId); 130 131 if (faceStatusUtils.isAvailable()) { 132 final RestrictedLockUtils.EnforcedAdmin disablingAdmin = 133 faceStatusUtils.getDisablingAdmin(); 134 setBiometricSafetySourceData( 135 context, 136 faceStatusUtils.getTitle(), 137 faceStatusUtils.getSummary(), 138 createPendingIntent( 139 profileParentContext, 140 biometricNavigationUtils 141 .getBiometricSettingsIntent( 142 context, 143 faceStatusUtils.getSettingsClassName(), 144 disablingAdmin, 145 Bundle.EMPTY) 146 .setIdentifier(Integer.toString(userId)), 147 REQUEST_CODE_FACE_SETTING), 148 disablingAdmin == null /* enabled */, 149 faceStatusUtils.hasEnrolled(), 150 safetyEvent); 151 152 return; 153 } 154 155 final FingerprintManager fingerprintManager = Utils.getFingerprintManagerOrNull(context); 156 final FingerprintStatusUtils fingerprintStatusUtils = 157 new FingerprintStatusUtils(context, fingerprintManager, userId); 158 159 if (fingerprintStatusUtils.isAvailable()) { 160 final RestrictedLockUtils.EnforcedAdmin disablingAdmin = 161 fingerprintStatusUtils.getDisablingAdmin(); 162 setBiometricSafetySourceData( 163 context, 164 fingerprintStatusUtils.getTitle(), 165 fingerprintStatusUtils.getSummary(), 166 createPendingIntent( 167 profileParentContext, 168 biometricNavigationUtils 169 .getBiometricSettingsIntent( 170 context, 171 fingerprintStatusUtils.getSettingsClassName(), 172 disablingAdmin, 173 Bundle.EMPTY) 174 .setIdentifier(Integer.toString(userId)), 175 REQUEST_CODE_FINGERPRINT_SETTING), 176 disablingAdmin == null /* enabled */, 177 fingerprintStatusUtils.hasEnrolled(), 178 safetyEvent); 179 return; 180 } 181 182 SafetyCenterManagerWrapper.get() 183 .setSafetySourceData( 184 context, SAFETY_SOURCE_ID, /* safetySourceData= */ null, safetyEvent); 185 } 186 187 /** Notifies Safety Center of a change in biometrics settings. */ onBiometricsChanged(Context context)188 public static void onBiometricsChanged(Context context) { 189 setSafetySourceData( 190 context, 191 new SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED) 192 .build()); 193 } 194 setBiometricSafetySourceData( Context context, String title, String summary, PendingIntent pendingIntent, boolean enabled, boolean hasEnrolled, SafetyEvent safetyEvent)195 private static void setBiometricSafetySourceData( 196 Context context, 197 String title, 198 String summary, 199 PendingIntent pendingIntent, 200 boolean enabled, 201 boolean hasEnrolled, 202 SafetyEvent safetyEvent) { 203 final int severityLevel = 204 enabled && hasEnrolled 205 ? SafetySourceData.SEVERITY_LEVEL_INFORMATION 206 : SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED; 207 208 final SafetySourceStatus status = 209 new SafetySourceStatus.Builder(title, summary, severityLevel) 210 .setPendingIntent(pendingIntent) 211 .setEnabled(enabled) 212 .build(); 213 final SafetySourceData safetySourceData = 214 new SafetySourceData.Builder().setStatus(status).build(); 215 216 SafetyCenterManagerWrapper.get() 217 .setSafetySourceData(context, SAFETY_SOURCE_ID, safetySourceData, safetyEvent); 218 } 219 createPendingIntent( Context context, Intent intent, int requestCode)220 private static PendingIntent createPendingIntent( 221 Context context, Intent intent, int requestCode) { 222 return PendingIntent.getActivity( 223 context, requestCode, intent, PendingIntent.FLAG_IMMUTABLE); 224 } 225 } 226