• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 static com.android.settings.biometrics.BiometricEnrollActivity.EXTRA_LAUNCH_FACE_ENROLL_FIRST;
20 import static com.android.settings.safetycenter.BiometricSourcesUtils.REQUEST_CODE_FACE_SETTING;
21 
22 import android.content.Context;
23 import android.hardware.face.FaceManager;
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 
30 import com.android.settings.Utils;
31 import com.android.settings.biometrics.BiometricEnrollActivity;
32 import com.android.settings.biometrics.BiometricNavigationUtils;
33 import com.android.settings.biometrics.face.FaceStatusUtils;
34 import com.android.settings.flags.Flags;
35 import com.android.settings.overlay.FeatureFactory;
36 import com.android.settingslib.RestrictedLockUtils;
37 
38 /** Face biometrics Safety Source for Safety Center. */
39 public final class FaceSafetySource {
40 
41     public static final String SAFETY_SOURCE_ID = "AndroidFaceUnlock";
42 
FaceSafetySource()43     private FaceSafetySource() {}
44 
45     /** Sets biometric safety data for Safety Center. */
setSafetySourceData(Context context, SafetyEvent safetyEvent)46     public static void setSafetySourceData(Context context, SafetyEvent safetyEvent) {
47         if (!SafetyCenterManagerWrapper.get().isEnabled(context)) {
48             return;
49         }
50         if (!Flags.biometricsOnboardingEducation()) { // this source is effectively turned off
51             sendNullData(context, safetyEvent);
52             return;
53         }
54 
55         // Handle private profile case
56         UserManager userManager = UserManager.get(context);
57         if (android.os.Flags.allowPrivateProfile()
58                 && android.multiuser.Flags.enablePrivateSpaceFeatures()
59                 && userManager.isPrivateProfile()) {
60             // SC always expects a response from the source if the broadcast has been sent for this
61             // source, therefore, we need to send a null SafetySourceData.
62             sendNullData(context, safetyEvent);
63             return;
64         }
65 
66         UserHandle userHandle = Process.myUserHandle();
67         int userId = userHandle.getIdentifier();
68         FaceManager faceManager = Utils.getFaceManagerOrNull(context);
69         FaceStatusUtils faceStatusUtils = new FaceStatusUtils(context, faceManager, userId);
70         BiometricNavigationUtils biometricNavigationUtils = new BiometricNavigationUtils(userId);
71         UserHandle profileParentUserHandle = userManager.getProfileParent(userHandle);
72         if (profileParentUserHandle == null) {
73             profileParentUserHandle = userHandle;
74         }
75         Context profileParentContext = context.createContextAsUser(profileParentUserHandle, 0);
76 
77         if (Utils.hasFaceHardware(context)) {
78             boolean isMultipleBiometricsEnrollmentNeeded =
79                     BiometricSourcesUtils.isMultipleBiometricsEnrollmentNeeded(context, userId);
80             String settingClassName = isMultipleBiometricsEnrollmentNeeded
81                     ? BiometricEnrollActivity.InternalActivity.class.getName()
82                     : faceStatusUtils.getSettingsClassName();
83             Bundle bundle = new Bundle();
84             if (isMultipleBiometricsEnrollmentNeeded) {
85                 // Launch face enrollment first then fingerprint enrollment.
86                 bundle.putBoolean(EXTRA_LAUNCH_FACE_ENROLL_FIRST, true);
87             }
88             RestrictedLockUtils.EnforcedAdmin disablingAdmin = faceStatusUtils.getDisablingAdmin();
89             BiometricSourcesUtils.setBiometricSafetySourceData(
90                     SAFETY_SOURCE_ID,
91                     context,
92                     faceStatusUtils.getTitle(),
93                     faceStatusUtils.getSummary(),
94                     BiometricSourcesUtils.createPendingIntent(
95                             profileParentContext,
96                             biometricNavigationUtils
97                                     .getBiometricSettingsIntent(
98                                             context,
99                                             settingClassName,
100                                             disablingAdmin,
101                                             bundle)
102                                     .setIdentifier(Integer.toString(userId)),
103                             REQUEST_CODE_FACE_SETTING),
104                     disablingAdmin == null /* enabled */,
105                     faceStatusUtils.hasEnrolled(),
106                     safetyEvent,
107                     FeatureFactory.getFeatureFactory().getBiometricsFeatureProvider()
108                             .getSafetySourceIssue(SAFETY_SOURCE_ID));
109 
110             return;
111         }
112 
113         sendNullData(context, safetyEvent);
114     }
115 
sendNullData(Context context, SafetyEvent safetyEvent)116     private static void sendNullData(Context context, SafetyEvent safetyEvent) {
117         SafetyCenterManagerWrapper.get()
118                 .setSafetySourceData(
119                         context, SAFETY_SOURCE_ID, /* safetySourceData= */ null, safetyEvent);
120     }
121 
122     /** Notifies Safety Center of a change in face biometrics settings. */
onBiometricsChanged(Context context)123     public static void onBiometricsChanged(Context context) {
124         setSafetySourceData(
125                 context,
126                 new SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED)
127                         .build());
128     }
129 }
130