Provide data for BiometricsSafetySource

Test: atest SettingsUnitTests

Bug: 215517420
Bug: 221449065
Change-Id: Id635a02443295757aab277971c4d95a9a62f5576
diff --git a/src/com/android/settings/biometrics/BiometricNavigationUtils.java b/src/com/android/settings/biometrics/BiometricNavigationUtils.java
index e4f2b7f..b747faf 100644
--- a/src/com/android/settings/biometrics/BiometricNavigationUtils.java
+++ b/src/com/android/settings/biometrics/BiometricNavigationUtils.java
@@ -19,14 +19,17 @@
 import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
 import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY;
 
+import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
 
-import com.android.settings.Utils;
+import com.android.internal.app.UnlaunchableAppActivity;
 import com.android.settings.core.SettingsBaseActivity;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 import com.android.settingslib.transition.SettingsTransitionHelper;
 
 /**
@@ -41,15 +44,62 @@
      * for managed profile, otherwise shows a dialog to disable the Quiet Mode.
      *
      * @param className The class name of Settings screen to launch.
-     * @param extras Extras to put into the launching {@link Intent}.
+     * @param extras    Extras to put into the launching {@link Intent}.
      * @return true if the Settings screen is launching.
      */
     public boolean launchBiometricSettings(Context context, String className, Bundle extras) {
-        final UserManager userManager = UserManager.get(context);
-        if (Utils.startQuietModeDialogIfNecessary(context, userManager, mUserId)) {
+        final Intent quietModeDialogIntent = getQuietModeDialogIntent(context);
+        if (quietModeDialogIntent != null) {
+            context.startActivity(quietModeDialogIntent);
             return false;
         }
+        context.startActivity(getSettingsPageIntent(className, extras));
+        return true;
+    }
 
+    /**
+     * Returns {@link Intent} to launch an appropriate Settings screen.
+     *
+     * <p>If the Setting is disabled by admin, returns {@link Intent} to launch an explanation.
+     * If Quiet Mode is enabled for managed profile, returns {@link Intent} to launch a dialog
+     * to disable the Quiet Mode. Otherwise, returns {@link Intent} to launch the Settings screen.
+     *
+     * @param className     The class name of Settings screen to launch.
+     * @param enforcedAdmin Details of admin account that disables changing the setting.
+     * @param extras        Extras to put into the result {@link Intent}.
+     */
+    public Intent getBiometricSettingsIntent(Context context, String className,
+            EnforcedAdmin enforcedAdmin, Bundle extras) {
+        if (enforcedAdmin != null) {
+            return getRestrictedDialogIntent(context, enforcedAdmin);
+        }
+        final Intent quietModeDialogIntent = getQuietModeDialogIntent(context);
+        return quietModeDialogIntent != null ? quietModeDialogIntent
+                : getSettingsPageIntent(className, extras);
+    }
+
+    private Intent getQuietModeDialogIntent(Context context) {
+        final UserManager userManager = UserManager.get(context);
+        if (userManager.isQuietModeEnabled(UserHandle.of(mUserId))) {
+            return UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId);
+        }
+        return null;
+    }
+
+    private Intent getRestrictedDialogIntent(Context context, EnforcedAdmin enforcedAdmin) {
+        final Intent intent = RestrictedLockUtils
+                .getShowAdminSupportDetailsIntent(context, enforcedAdmin);
+        int targetUserId = mUserId;
+        if (enforcedAdmin.user != null && RestrictedLockUtils
+                .isCurrentUserOrProfile(context, enforcedAdmin.user.getIdentifier())) {
+            targetUserId = enforcedAdmin.user.getIdentifier();
+        }
+        intent.putExtra(DevicePolicyManager.EXTRA_RESTRICTION, enforcedAdmin.enforcedRestriction);
+        intent.putExtra(Intent.EXTRA_USER_ID, targetUserId);
+        return intent;
+    }
+
+    private Intent getSettingsPageIntent(String className, Bundle extras) {
         final Intent intent = new Intent();
         intent.setClassName(SETTINGS_PACKAGE_NAME, className);
         if (!extras.isEmpty()) {
@@ -59,7 +109,7 @@
         intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
         intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE,
                 SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE);
-        context.startActivity(intent);
-        return true;
+
+        return intent;
     }
 }
diff --git a/src/com/android/settings/safetycenter/BiometricsSafetySource.java b/src/com/android/settings/safetycenter/BiometricsSafetySource.java
index bfe2fb0..6a93bda 100644
--- a/src/com/android/settings/safetycenter/BiometricsSafetySource.java
+++ b/src/com/android/settings/safetycenter/BiometricsSafetySource.java
@@ -16,14 +16,30 @@
 
 package com.android.settings.safetycenter;
 
+import android.app.PendingIntent;
 import android.content.Context;
+import android.content.Intent;
+import android.hardware.face.FaceManager;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Bundle;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceStatus;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.biometrics.BiometricNavigationUtils;
+import com.android.settings.biometrics.combination.CombinedBiometricStatusUtils;
+import com.android.settings.biometrics.face.FaceStatusUtils;
+import com.android.settings.biometrics.fingerprint.FingerprintStatusUtils;
+import com.android.settingslib.RestrictedLockUtils;
 
 /** Combined Biometrics Safety Source for Safety Center. */
 public final class BiometricsSafetySource {
 
     public static final String SAFETY_SOURCE_ID = "Biometrics";
 
-    private BiometricsSafetySource() {}
+    private BiometricsSafetySource() {
+    }
 
     /** Sends biometric safety data to Safety Center. */
     public static void sendSafetyData(Context context) {
@@ -31,7 +47,75 @@
             return;
         }
 
-        // TODO(b/215517420): Send biometric data to Safety Center if there are biometrics available
-        // on this device.
+        final BiometricNavigationUtils biometricNavigationUtils = new BiometricNavigationUtils();
+        final CombinedBiometricStatusUtils combinedBiometricStatusUtils =
+                new CombinedBiometricStatusUtils(context);
+
+        if (combinedBiometricStatusUtils.isAvailable()) {
+            final RestrictedLockUtils.EnforcedAdmin disablingAdmin =
+                    combinedBiometricStatusUtils.getDisablingAdmin();
+            sendBiometricSafetySourceData(context,
+                    context.getString(R.string.security_settings_biometric_preference_title),
+                    combinedBiometricStatusUtils.getSummary(),
+                    biometricNavigationUtils.getBiometricSettingsIntent(context,
+                            combinedBiometricStatusUtils.getSettingsClassName(), disablingAdmin,
+                            Bundle.EMPTY),
+                    disablingAdmin == null /* enabled */);
+            return;
+        }
+
+        final FaceManager faceManager = Utils.getFaceManagerOrNull(context);
+        final FaceStatusUtils faceStatusUtils = new FaceStatusUtils(context, faceManager);
+
+        if (faceStatusUtils.isAvailable()) {
+            final RestrictedLockUtils.EnforcedAdmin disablingAdmin =
+                    faceStatusUtils.getDisablingAdmin();
+            sendBiometricSafetySourceData(context,
+                    context.getString(R.string.security_settings_face_preference_title),
+                    faceStatusUtils.getSummary(),
+                    biometricNavigationUtils.getBiometricSettingsIntent(context,
+                            faceStatusUtils.getSettingsClassName(), disablingAdmin,
+                            Bundle.EMPTY),
+                    disablingAdmin == null /* enabled */);
+            return;
+        }
+
+        final FingerprintManager fingerprintManager = Utils.getFingerprintManagerOrNull(context);
+        final FingerprintStatusUtils fingerprintStatusUtils = new FingerprintStatusUtils(context,
+                fingerprintManager);
+
+        if (fingerprintStatusUtils.isAvailable()) {
+            final RestrictedLockUtils.EnforcedAdmin disablingAdmin =
+                    fingerprintStatusUtils.getDisablingAdmin();
+            sendBiometricSafetySourceData(context,
+                    context.getString(R.string.security_settings_fingerprint_preference_title),
+                    fingerprintStatusUtils.getSummary(),
+                    biometricNavigationUtils.getBiometricSettingsIntent(context,
+                            fingerprintStatusUtils.getSettingsClassName(), disablingAdmin,
+                            Bundle.EMPTY),
+                    disablingAdmin == null /* enabled */);
+        }
+    }
+
+    private static void sendBiometricSafetySourceData(Context context, String title, String summary,
+            Intent clickIntent, boolean enabled) {
+        final PendingIntent pendingIntent = createPendingIntent(context, clickIntent);
+
+        final SafetySourceStatus status = new SafetySourceStatus.Builder(title, summary,
+                SafetySourceStatus.STATUS_LEVEL_NONE, pendingIntent)
+                .setEnabled(enabled).build();
+        final SafetySourceData safetySourceData = new SafetySourceData.Builder(SAFETY_SOURCE_ID)
+                .setStatus(status).build();
+
+        SafetyCenterManagerWrapper.get().sendSafetyCenterUpdate(context, safetySourceData);
+    }
+
+    private static PendingIntent createPendingIntent(Context context, Intent intent) {
+        return PendingIntent
+                .getActivity(
+                        context,
+                        0 /* requestCode */,
+                        intent,
+                        PendingIntent.FLAG_IMMUTABLE);
     }
 }
diff --git a/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java b/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java
index 3e6ac09..c767c32 100644
--- a/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java
+++ b/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java
@@ -24,14 +24,20 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -44,6 +50,8 @@
 
     private static final String SETTINGS_CLASS_NAME = "SettingsClassName";
     private static final String EXTRA_KEY = "EXTRA_KEY";
+    private static final ComponentName COMPONENT_NAME = new ComponentName("package", "class");
+    private static final int ADMIN_USER_ID = 2;
 
     @Mock
     private UserManager mUserManager;
@@ -60,7 +68,7 @@
     }
 
     @Test
-    public void openBiometricSettings_quietMode_launchesQuiteModeDialog() {
+    public void launchBiometricSettings_quietMode_launchesQuiteModeDialog() {
         when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
 
         mBiometricNavigationUtils.launchBiometricSettings(mContext, SETTINGS_CLASS_NAME,
@@ -70,7 +78,7 @@
     }
 
     @Test
-    public void openBiometricSettings_quietMode_returnsFalse() {
+    public void launchBiometricSettings_quietMode_returnsFalse() {
         when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
 
         assertThat(mBiometricNavigationUtils.launchBiometricSettings(
@@ -78,7 +86,7 @@
     }
 
     @Test
-    public void openBiometricSettings_noQuietMode_emptyExtras_launchesFragmentWithoutExtras() {
+    public void launchBiometricSettings_noQuietMode_emptyExtras_launchesFragmentWithoutExtras() {
         when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
 
         mBiometricNavigationUtils.launchBiometricSettings(
@@ -88,7 +96,7 @@
     }
 
     @Test
-    public void openBiometricSettings_noQuietMode_emptyExtras_returnsTrue() {
+    public void launchBiometricSettings_noQuietMode_emptyExtras_returnsTrue() {
         when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
 
         assertThat(mBiometricNavigationUtils.launchBiometricSettings(
@@ -96,7 +104,7 @@
     }
 
     @Test
-    public void openBiometricSettings_noQuietMode_withExtras_launchesFragmentWithExtras() {
+    public void launchBiometricSettings_noQuietMode_withExtras_launchesFragmentWithExtras() {
         when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
 
         final Bundle extras = createNotEmptyExtras();
@@ -106,13 +114,79 @@
     }
 
     @Test
-    public void openBiometricSettings_noQuietMode_withExtras_returnsTrue() {
+    public void launchBiometricSettings_noQuietMode_withExtras_returnsTrue() {
         when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
 
         assertThat(mBiometricNavigationUtils.launchBiometricSettings(
                 mContext, SETTINGS_CLASS_NAME, createNotEmptyExtras())).isTrue();
     }
 
+    @Test
+    public void getBiometricSettingsIntent_quietMode_returnsQuiteModeDialogIntent() {
+        when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
+
+        final Intent intent = mBiometricNavigationUtils.getBiometricSettingsIntent(
+                mContext, SETTINGS_CLASS_NAME, null /* enforcedAdmin */, Bundle.EMPTY);
+
+        assertQuietModeDialogIntent(intent);
+    }
+
+    @Test
+    public void getBiometricSettingsIntent_noQuietMode_emptyExtras_returnsSettingsIntent() {
+        when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
+
+        final Intent intent = mBiometricNavigationUtils.getBiometricSettingsIntent(
+                mContext, SETTINGS_CLASS_NAME, null /* enforcedAdmin */, Bundle.EMPTY);
+
+        assertSettingsPageIntent(intent, false /* shouldContainExtras */);
+    }
+
+    @Test
+    public void getBiometricSettingsIntent_noQuietMode_withExtras_returnsSettingsIntent() {
+        when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
+
+        final Intent intent = mBiometricNavigationUtils.getBiometricSettingsIntent(
+                mContext, SETTINGS_CLASS_NAME, null /* enforcedAdmin */, createNotEmptyExtras());
+
+        assertSettingsPageIntent(intent, true /* shouldContainExtras */);
+    }
+
+    @Test
+    public void getBiometricSettingsIntent_whenDisabledByAdmin_quietMode_returnsBlockedIntent() {
+        when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
+        final EnforcedAdmin enforcedAdmin = new EnforcedAdmin(
+                COMPONENT_NAME, UserHandle.of(ADMIN_USER_ID));
+
+        final Intent intent = mBiometricNavigationUtils.getBiometricSettingsIntent(
+                mContext, SETTINGS_CLASS_NAME, enforcedAdmin, Bundle.EMPTY);
+
+        assertBlockedByAdminDialogIntent(intent);
+    }
+
+    @Test
+    public void getBiometricSettingsIntent_whenDisabledByAdmin_emptyExtras_returnsBlockedIntent() {
+        when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
+        final EnforcedAdmin enforcedAdmin = new EnforcedAdmin(
+                COMPONENT_NAME, UserHandle.of(ADMIN_USER_ID));
+
+        final Intent intent = mBiometricNavigationUtils.getBiometricSettingsIntent(
+                mContext, SETTINGS_CLASS_NAME, enforcedAdmin, Bundle.EMPTY);
+
+        assertBlockedByAdminDialogIntent(intent);
+    }
+
+    @Test
+    public void getBiometricSettingsIntent_whenDisabledByAdmin_withExtras_returnsBlockedIntent() {
+        when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
+        final EnforcedAdmin enforcedAdmin = new EnforcedAdmin(
+                COMPONENT_NAME, UserHandle.of(ADMIN_USER_ID));
+
+        final Intent intent = mBiometricNavigationUtils.getBiometricSettingsIntent(
+                mContext, SETTINGS_CLASS_NAME, enforcedAdmin, Bundle.EMPTY);
+
+        assertBlockedByAdminDialogIntent(intent);
+    }
+
     private Bundle createNotEmptyExtras() {
         final Bundle bundle = new Bundle();
         bundle.putInt(EXTRA_KEY, 0);
@@ -124,17 +198,32 @@
         verify(mContext).startActivity(intentCaptor.capture());
 
         Intent intent = intentCaptor.getValue();
+        assertQuietModeDialogIntent(intent);
+    }
+
+    private void assertQuietModeDialogIntent(Intent intent) {
         assertThat(intent.getComponent().getPackageName())
                 .isEqualTo("android");
         assertThat(intent.getComponent().getClassName())
                 .isEqualTo("com.android.internal.app.UnlaunchableAppActivity");
     }
 
+    private void assertBlockedByAdminDialogIntent(Intent intent) {
+        assertThat(intent.getAction()).isEqualTo(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
+        assertThat(
+                (ComponentName) intent.getParcelableExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN))
+                .isEqualTo(COMPONENT_NAME);
+    }
+
     private void assertSettingsPageLaunchRequested(boolean shouldContainExtras) {
         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
         verify(mContext).startActivity(intentCaptor.capture());
 
         Intent intent = intentCaptor.getValue();
+        assertSettingsPageIntent(intent, shouldContainExtras);
+    }
+
+    private void assertSettingsPageIntent(Intent intent, boolean shouldContainExtras) {
         assertThat(intent.getComponent().getPackageName())
                 .isEqualTo("com.android.settings");
         assertThat(intent.getComponent().getClassName())
diff --git a/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
index 2627d24..4a91e8f 100644
--- a/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
+++ b/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
@@ -16,35 +16,84 @@
 
 package com.android.settings.safetycenter;
 
+import static android.provider.Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS;
+
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.hardware.face.FaceManager;
+import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.UserHandle;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceStatus;
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
+import com.android.settings.Settings;
+import com.android.settings.biometrics.face.FaceEnrollIntroduction;
+import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
+import com.android.settings.biometrics.fingerprint.FingerprintSettings;
+import com.android.settings.testutils.ResourcesUtils;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
 @RunWith(AndroidJUnit4.class)
 public class BiometricsSafetySourceTest {
 
+    private static final ComponentName COMPONENT_NAME =
+            new ComponentName("package", "class");
+    private static final UserHandle USER_HANDLE = new UserHandle(UserHandle.myUserId());
+
     private Context mApplicationContext;
 
     @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private DevicePolicyManager mDevicePolicyManager;
+    @Mock
+    private FingerprintManager mFingerprintManager;
+    @Mock
+    private FaceManager mFaceManager;
+    @Mock
     private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mApplicationContext = ApplicationProvider.getApplicationContext();
+        mApplicationContext = spy(ApplicationProvider.getApplicationContext());
+        when(mApplicationContext.getPackageManager()).thenReturn(mPackageManager);
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true);
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
+        when(mDevicePolicyManager.getProfileOwnerOrDeviceOwnerSupervisionComponent(USER_HANDLE))
+                .thenReturn(COMPONENT_NAME);
+        when(mApplicationContext.getSystemService(Context.FINGERPRINT_SERVICE))
+                .thenReturn(mFingerprintManager);
+        when(mApplicationContext.getSystemService(Context.DEVICE_POLICY_SERVICE))
+                .thenReturn(mDevicePolicyManager);
+        when(mApplicationContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mFaceManager);
         SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
     }
 
@@ -63,12 +112,371 @@
     }
 
     @Test
-    // TODO(b/215517420): Adapt this test when method is implemented.
-    public void sendSafetyData_whenSafetyCenterIsEnabled_sendsNoData() {
-        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+    public void sendSafetyData_whenSafetyCenterIsEnabled_withoutBiometrics_sendsNoData() {
+        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(false);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+        when(mFaceManager.isHardwareDetected()).thenReturn(false);
 
         BiometricsSafetySource.sendSafetyData(mApplicationContext);
 
         verify(mSafetyCenterManagerWrapper, never()).sendSafetyCenterUpdate(any(), any());
     }
+
+    @Test
+    public void sendSafetyData_withFingerprintNotEnrolled_whenDisabledByAdmin_sendsData() {
+        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(false);
+        when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+                .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
+
+        BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+        assertSafetySourceDisabledDataSentWithSingularSummary(
+                "security_settings_fingerprint_preference_title",
+                "security_settings_fingerprint_preference_summary_none");
+    }
+
+    @Test
+    public void sendSafetyData_withFingerprintNotEnrolled_whenNotDisabledByAdmin_sendsData() {
+        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(false);
+        when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+        BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+        assertSafetySourceEnabledDataSentWithSingularSummary(
+                "security_settings_fingerprint_preference_title",
+                "security_settings_fingerprint_preference_summary_none",
+                FingerprintEnrollIntroduction.class.getName());
+    }
+
+    @Test
+    public void sendSafetyData_withFingerprintsEnrolled_whenDisabledByAdmin_sendsData() {
+        final int enrolledFingerprintsCount = 2;
+        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(false);
+        when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(true);
+        when(mFingerprintManager.getEnrolledFingerprints(anyInt()))
+                .thenReturn(createFingerprintList(enrolledFingerprintsCount));
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+                .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
+
+        BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+        assertSafetySourceDisabledDataSentWithPluralSummary(
+                "security_settings_fingerprint_preference_title",
+                "security_settings_fingerprint_preference_summary",
+                enrolledFingerprintsCount);
+    }
+
+    @Test
+    public void sendSafetyData_withFingerprintsEnrolled_whenNotDisabledByAdmin_sendsData() {
+        final int enrolledFingerprintsCount = 2;
+        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(false);
+        when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(true);
+        when(mFingerprintManager.getEnrolledFingerprints(anyInt()))
+                .thenReturn(createFingerprintList(enrolledFingerprintsCount));
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+        BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+        assertSafetySourceEnabledDataSentWithPluralSummary(
+                "security_settings_fingerprint_preference_title",
+                "security_settings_fingerprint_preference_summary", enrolledFingerprintsCount,
+                FingerprintSettings.class.getName());
+    }
+
+    @Test
+    public void sendSafetyData_withFaceNotEnrolled_whenDisabledByAdmin_sendsData() {
+        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+                .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE);
+
+        BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+        assertSafetySourceDisabledDataSentWithSingularSummary(
+                "security_settings_face_preference_title",
+                "security_settings_face_preference_summary_none");
+    }
+
+    @Test
+    public void sendSafetyData_withFaceNotEnrolled_whenNotDisabledByAdmin_sendsData() {
+        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+        BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+        assertSafetySourceEnabledDataSentWithSingularSummary(
+                "security_settings_face_preference_title",
+                "security_settings_face_preference_summary_none",
+                FaceEnrollIntroduction.class.getName());
+    }
+
+    @Test
+    public void sendSafetyData_withFaceEnrolled_whenDisabledByAdmin_sendsData() {
+        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+                .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE);
+
+        BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+        assertSafetySourceDisabledDataSentWithSingularSummary(
+                "security_settings_face_preference_title",
+                "security_settings_face_preference_summary");
+    }
+
+    @Test
+    public void sendSafetyData_withFaceEnrolled_whenNotDisabledByAdmin_sendsData() {
+        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+        BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+        assertSafetySourceEnabledDataSentWithSingularSummary(
+                "security_settings_face_preference_title",
+                "security_settings_face_preference_summary",
+                Settings.FaceSettingsActivity.class.getName());
+    }
+
+    @Test
+    public void sandSafetyData_withFaceAndFingerprint_whenBothNotDisabledByAdmin_sendsData() {
+        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+        BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+        assertSafetySourceEnabledDataSentWithSingularSummary(
+                "security_settings_biometric_preference_title",
+                "security_settings_biometric_preference_summary_none_enrolled",
+                Settings.CombinedBiometricSettingsActivity.class.getName());
+    }
+
+    @Test
+    public void sandSafetyData_withFaceAndFingerprint_whenFaceDisabledByAdmin_sendsData() {
+        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+                .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE);
+
+        BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+        assertSafetySourceEnabledDataSentWithSingularSummary(
+                "security_settings_biometric_preference_title",
+                "security_settings_biometric_preference_summary_none_enrolled",
+                Settings.CombinedBiometricSettingsActivity.class.getName());
+    }
+
+    @Test
+    public void sandSafetyData_withFaceAndFingerprint_whenFingerprintDisabledByAdmin_sendsData() {
+        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+                .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
+
+        BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+        assertSafetySourceEnabledDataSentWithSingularSummary(
+                "security_settings_biometric_preference_title",
+                "security_settings_biometric_preference_summary_none_enrolled",
+                Settings.CombinedBiometricSettingsActivity.class.getName());
+    }
+
+    @Test
+    public void sandSafetyData_withFaceAndFingerprint_whenBothDisabledByAdmin_sendsData() {
+        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+                .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE
+                        | DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
+
+        BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+        assertSafetySourceDisabledDataSentWithSingularSummary(
+                "security_settings_biometric_preference_title",
+                "security_settings_biometric_preference_summary_none_enrolled");
+    }
+
+    @Test
+    public void sandSafetyData_withFaceAndFingerprint_whenFaceEnrolled_withMpFingers_sendsData() {
+        final int enrolledFingerprintsCount = 2;
+        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+        when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(
+                createFingerprintList(enrolledFingerprintsCount));
+
+        BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+        assertSafetySourceEnabledDataSentWithSingularSummary(
+                "security_settings_biometric_preference_title",
+                "security_settings_biometric_preference_summary_both_fp_multiple",
+                Settings.CombinedBiometricSettingsActivity.class.getName());
+    }
+
+    @Test
+    public void sandSafetyData_withFaceAndFingerprint_whenFaceEnrolled_withOneFinger_sendsData() {
+        final int enrolledFingerprintsCount = 1;
+        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+        when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(
+                createFingerprintList(enrolledFingerprintsCount));
+
+        BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+        assertSafetySourceEnabledDataSentWithSingularSummary(
+                "security_settings_biometric_preference_title",
+                "security_settings_biometric_preference_summary_both_fp_single",
+                Settings.CombinedBiometricSettingsActivity.class.getName());
+    }
+
+    @Test
+    public void sandSafetyData_withFaceAndFingerprint_whenFaceEnrolled_withNoFingers_sendsData() {
+        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+        when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(
+                Collections.emptyList());
+
+        BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+        assertSafetySourceEnabledDataSentWithSingularSummary(
+                "security_settings_biometric_preference_title",
+                "security_settings_face_preference_summary",
+                Settings.CombinedBiometricSettingsActivity.class.getName());
+    }
+
+    @Test
+    public void sandSafetyData_withFaceAndFingerprint_whenNoFaceEnrolled_withFingers_sendsData() {
+        final int enrolledFingerprintsCount = 1;
+        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+        when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(
+                createFingerprintList(enrolledFingerprintsCount));
+
+        BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+        assertSafetySourceEnabledDataSentWithPluralSummary(
+                "security_settings_biometric_preference_title",
+                "security_settings_fingerprint_preference_summary", enrolledFingerprintsCount,
+                Settings.CombinedBiometricSettingsActivity.class.getName());
+    }
+
+    private void assertSafetySourceDisabledDataSentWithSingularSummary(String expectedTitleResName,
+            String expectedSummaryResName) {
+        assertSafetySourceDisabledDataSent(
+                ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName),
+                ResourcesUtils.getResourcesString(mApplicationContext, expectedSummaryResName)
+        );
+    }
+
+    private void assertSafetySourceEnabledDataSentWithSingularSummary(String expectedTitleResName,
+            String expectedSummaryResName,
+            String expectedSettingsClassName) {
+        assertSafetySourceEnabledDataSent(
+                ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName),
+                ResourcesUtils.getResourcesString(mApplicationContext, expectedSummaryResName),
+                expectedSettingsClassName
+        );
+    }
+
+    private void assertSafetySourceDisabledDataSentWithPluralSummary(String expectedTitleResName,
+            String expectedSummaryResName, int expectedSummaryQuantity) {
+        final int stringResId = ResourcesUtils.getResourcesId(
+                ApplicationProvider.getApplicationContext(), "plurals",
+                expectedSummaryResName);
+        assertSafetySourceDisabledDataSent(
+                ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName),
+                mApplicationContext.getResources().getQuantityString(stringResId,
+                        expectedSummaryQuantity /* quantity */,
+                        expectedSummaryQuantity /* formatArgs */)
+        );
+    }
+
+    private void assertSafetySourceEnabledDataSentWithPluralSummary(String expectedTitleResName,
+            String expectedSummaryResName, int expectedSummaryQuantity,
+            String expectedSettingsClassName) {
+        final int stringResId = ResourcesUtils.getResourcesId(
+                ApplicationProvider.getApplicationContext(), "plurals",
+                expectedSummaryResName);
+        assertSafetySourceEnabledDataSent(
+                ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName),
+                mApplicationContext.getResources().getQuantityString(stringResId,
+                        expectedSummaryQuantity /* quantity */,
+                        expectedSummaryQuantity /* formatArgs */),
+                expectedSettingsClassName
+        );
+    }
+
+    private void assertSafetySourceDisabledDataSent(String expectedTitle, String expectedSummary) {
+        ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
+        verify(mSafetyCenterManagerWrapper).sendSafetyCenterUpdate(any(), captor.capture());
+        SafetySourceData safetySourceData = captor.getValue();
+        SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
+
+        assertThat(safetySourceData.getId()).isEqualTo(BiometricsSafetySource.SAFETY_SOURCE_ID);
+        assertThat(safetySourceStatus.getTitle().toString()).isEqualTo(expectedTitle);
+        assertThat(safetySourceStatus.getSummary().toString()).isEqualTo(expectedSummary);
+        assertThat(safetySourceStatus.isEnabled()).isFalse();
+        final Intent clickIntent = safetySourceStatus.getPendingIntent().getIntent();
+        assertThat(clickIntent).isNotNull();
+        assertThat(clickIntent.getAction()).isEqualTo(ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
+    }
+
+    private void assertSafetySourceEnabledDataSent(String expectedTitle, String expectedSummary,
+            String expectedSettingsClassName) {
+        ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
+        verify(mSafetyCenterManagerWrapper).sendSafetyCenterUpdate(any(), captor.capture());
+        SafetySourceData safetySourceData = captor.getValue();
+        SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
+
+        assertThat(safetySourceData.getId()).isEqualTo(BiometricsSafetySource.SAFETY_SOURCE_ID);
+        assertThat(safetySourceStatus.getTitle().toString()).isEqualTo(expectedTitle);
+        assertThat(safetySourceStatus.getSummary().toString()).isEqualTo(expectedSummary);
+        assertThat(safetySourceStatus.isEnabled()).isTrue();
+        final Intent clickIntent = safetySourceStatus.getPendingIntent().getIntent();
+        assertThat(clickIntent).isNotNull();
+        assertThat(clickIntent.getComponent().getPackageName())
+                .isEqualTo("com.android.settings");
+        assertThat(clickIntent.getComponent().getClassName())
+                .isEqualTo(expectedSettingsClassName);
+    }
+
+
+    private List<Fingerprint> createFingerprintList(int size) {
+        final List<Fingerprint> fingerprintList = new ArrayList<>(size);
+        for (int i = 0; i < size; i++) {
+            fingerprintList.add(new Fingerprint("fingerprint" + i, 0, 0));
+        }
+        return fingerprintList;
+    }
 }
diff --git a/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java b/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java
index f2a28ff..f042c22 100644
--- a/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java
+++ b/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java
@@ -45,6 +45,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.List;
+
 @RunWith(AndroidJUnit4.class)
 public class SafetySourceBroadcastReceiverTest {
 
@@ -149,9 +151,12 @@
                                 new String[]{ BiometricsSafetySource.SAFETY_SOURCE_ID });
 
         new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
+        ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
+        verify(mSafetyCenterManagerWrapper, times(1))
+                .sendSafetyCenterUpdate(any(), captor.capture());
+        SafetySourceData safetySourceData = captor.getValue();
 
-        // TODO(b/215517420): Update this test when BiometricSafetySource is implemented.
-        verify(mSafetyCenterManagerWrapper, never()).sendSafetyCenterUpdate(any(), any());
+        assertThat(safetySourceData.getId()).isEqualTo(BiometricsSafetySource.SAFETY_SOURCE_ID);
     }
 
     @Test
@@ -159,14 +164,15 @@
         when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
         Intent intent = new Intent().setAction(Intent.ACTION_BOOT_COMPLETED);
 
-        // TODO(b/215517420): Update this test when BiometricSafetySource is implemented to test
-        // that biometrics data is also sent.
         new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
         ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
-        verify(mSafetyCenterManagerWrapper, times(1))
+        verify(mSafetyCenterManagerWrapper, times(2))
                 .sendSafetyCenterUpdate(any(), captor.capture());
-        SafetySourceData safetySourceData = captor.getValue();
+        List<SafetySourceData> safetySourceDataList = captor.getAllValues();
 
-        assertThat(safetySourceData.getId()).isEqualTo(LockScreenSafetySource.SAFETY_SOURCE_ID);
+        assertThat(safetySourceDataList.stream().anyMatch(
+                data -> data.getId().equals(LockScreenSafetySource.SAFETY_SOURCE_ID))).isTrue();
+        assertThat(safetySourceDataList.stream().anyMatch(
+                data -> data.getId().equals(BiometricsSafetySource.SAFETY_SOURCE_ID))).isTrue();
     }
 }