Merge "Provide data to LockScreenSafetySource" into tm-dev
diff --git a/res/drawable/accessibility_auto_added_qs_tooltips_illustration.xml b/res/drawable/accessibility_auto_added_qs_tooltips_illustration.xml
new file mode 100644
index 0000000..2583b6f
--- /dev/null
+++ b/res/drawable/accessibility_auto_added_qs_tooltips_illustration.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="178dp"
+    android:height="150dp"
+    android:viewportWidth="178"
+    android:viewportHeight="150">
+  <path
+      android:pathData="M161.612,147.208L16.619,147.208A13,13 0,0 1,3.619 134.208L3.619,-442.725A13,13 0,0 1,16.619 -455.725L161.612,-455.725A13,13 0,0 1,174.612 -442.725L174.612,134.208A13,13 0,0 1,161.612 147.208z"
+      android:strokeWidth="6"
+      android:fillColor="#ffffff"
+      android:strokeColor="#EDEDED"/>
+  <path
+      android:pathData="M28.47,103.945L48.47,103.945A12,12 0,0 1,60.47 115.945L60.47,115.945A12,12 0,0 1,48.47 127.945L28.47,127.945A12,12 0,0 1,16.47 115.945L16.47,115.945A12,12 0,0 1,28.47 103.945z"
+      android:fillColor="#797272"/>
+  <path
+      android:pathData="M38.5,115.5m-15.5,0a15.5,15.5 0,1 1,31 0a15.5,15.5 0,1 1,-31 0"
+      android:fillColor="#BCEDDF"
+      android:fillAlpha="0.5"/>
+  <path
+      android:pathData="M45.279,108.52L46.48,109.72C47.182,110.414 47.182,111.543 46.48,112.237L34.717,124H31V120.283L42.763,108.52C43.457,107.827 44.586,107.827 45.279,108.52ZM32.778,122.222L34.032,122.275L42.763,113.535L41.51,112.281L32.778,121.013V122.222Z"
+      android:fillColor="#ffffff"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M79,104L99,104A12,12 0,0 1,111 116L111,116A12,12 0,0 1,99 128L79,128A12,12 0,0 1,67 116L67,116A12,12 0,0 1,79 104z"
+      android:fillColor="#E0DCDC"/>
+  <path
+      android:pathData="M79,104L99,104A12,12 0,0 1,111 116L111,116A12,12 0,0 1,99 128L79,128A12,12 0,0 1,67 116L67,116A12,12 0,0 1,79 104z"
+      android:fillColor="#E7E7E7"/>
+  <path
+      android:pathData="M129,104L149,104A12,12 0,0 1,161 116L161,116A12,12 0,0 1,149 128L129,128A12,12 0,0 1,117 116L117,116A12,12 0,0 1,129 104z"
+      android:fillColor="#E0DCDC"/>
+  <path
+      android:pathData="M129,104L149,104A12,12 0,0 1,161 116L161,116A12,12 0,0 1,149 128L129,128A12,12 0,0 1,117 116L117,116A12,12 0,0 1,129 104z"
+      android:fillColor="#E7E7E7"/>
+  <path
+      android:pathData="M22,14L76.49,14A6,6 0,0 1,82.49 20L82.49,38.782A6,6 0,0 1,76.49 44.782L22,44.782A6,6 0,0 1,16 38.782L16,20A6,6 0,0 1,22 14z"
+      android:fillColor="#EDEDED"/>
+  <path
+      android:pathData="M22,56L76.49,56A6,6 0,0 1,82.49 62L82.49,80.782A6,6 0,0 1,76.49 86.782L22,86.782A6,6 0,0 1,16 80.782L16,62A6,6 0,0 1,22 56z"
+      android:fillColor="#EDEDED"/>
+  <path
+      android:pathData="M101,14L155.49,14A6,6 0,0 1,161.49 20L161.49,38.782A6,6 0,0 1,155.49 44.782L101,44.782A6,6 0,0 1,95 38.782L95,20A6,6 0,0 1,101 14z"
+      android:fillColor="#EDEDED"/>
+  <path
+      android:pathData="M101,56L155.49,56A6,6 0,0 1,161.49 62L161.49,80.782A6,6 0,0 1,155.49 86.782L101,86.782A6,6 0,0 1,95 80.782L95,62A6,6 0,0 1,101 56z"
+      android:fillColor="#EDEDED"/>
+</vector>
diff --git a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
index 5798723..59618d6 100644
--- a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
@@ -509,7 +509,9 @@
                 ? R.string.accessibility_service_qs_tooltips_content
                 : R.string.accessibility_service_auto_added_qs_tooltips_content;
         final String title = getString(titleResId, tileName);
-        final int imageResId = R.drawable.accessibility_qs_tooltips_illustration;
+        final int imageResId = mNeedsQSTooltipType == QuickSettingsTooltipType.GUIDE_TO_EDIT
+                ? R.drawable.accessibility_qs_tooltips_illustration
+                : R.drawable.accessibility_auto_added_qs_tooltips_illustration;
         mTooltipWindow = new AccessibilityQuickSettingsTooltipWindow(getContext());
         mTooltipWindow.setup(title, imageResId);
         mTooltipWindow.showAtTopCenter(getView());
diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
index 5992ceb..69b8f75 100644
--- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
@@ -79,6 +79,7 @@
 public abstract class ToggleFeaturePreferenceFragment extends SettingsPreferenceFragment
         implements ShortcutPreference.OnClickCallback, OnMainSwitchChangeListener {
 
+    protected TopIntroPreference mTopIntroPreference;
     protected SettingsMainSwitchPreference mToggleServiceSwitchPreference;
     protected ShortcutPreference mShortcutPreference;
     protected Preference mSettingsPreference;
@@ -483,10 +484,10 @@
         if (TextUtils.isEmpty(mTopIntroTitle)) {
             return;
         }
-        final TopIntroPreference topIntroPreference = new TopIntroPreference(getPrefContext());
-        topIntroPreference.setKey(KEY_TOP_INTRO_PREFERENCE);
-        topIntroPreference.setTitle(mTopIntroTitle);
-        getPreferenceScreen().addPreference(topIntroPreference);
+        mTopIntroPreference = new TopIntroPreference(getPrefContext());
+        mTopIntroPreference.setKey(KEY_TOP_INTRO_PREFERENCE);
+        mTopIntroPreference.setTitle(mTopIntroTitle);
+        getPreferenceScreen().addPreference(mTopIntroPreference);
     }
 
     private void initToggleServiceSwitchPreference() {
@@ -879,7 +880,9 @@
                 ? R.string.accessibility_service_qs_tooltips_content
                 : R.string.accessibility_service_auto_added_qs_tooltips_content;
         final String title = getString(titleResId, tileName);
-        final int imageResId = R.drawable.accessibility_qs_tooltips_illustration;
+        final int imageResId = mNeedsQSTooltipType == QuickSettingsTooltipType.GUIDE_TO_EDIT
+                ? R.drawable.accessibility_qs_tooltips_illustration
+                : R.drawable.accessibility_auto_added_qs_tooltips_illustration;
         mTooltipWindow = new AccessibilityQuickSettingsTooltipWindow(getContext());
         mTooltipWindow.setup(title, imageResId);
         mTooltipWindow.showAtTopCenter(getView());
diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizard.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizard.java
index d92fd51..cb5ca75 100644
--- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizard.java
+++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizard.java
@@ -40,7 +40,7 @@
         final String title = getContext().getString(
                 R.string.accessibility_screen_magnification_title);
         final String description = getContext().getString(
-                R.string.accessibility_preference_magnification_summary);
+                R.string.accessibility_screen_magnification_intro_text);
         final Drawable icon = getContext().getDrawable(R.drawable.ic_accessibility_visibility);
         AccessibilitySetupWizardUtils.updateGlifPreferenceLayout(getContext(), layout, title,
                 description, icon);
@@ -51,6 +51,8 @@
      * Hide the magnification preference settings in the SuW's vision settings.
      */
     private void hidePreferenceSettingComponents() {
+        // Intro
+        mTopIntroPreference.setVisible(false);
         // Setting of magnification type
         mSettingsPreference.setVisible(false);
         // Setting of following typing
diff --git a/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizard.java b/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizard.java
index 7adddf9..f9a1113 100644
--- a/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizard.java
+++ b/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizard.java
@@ -46,6 +46,9 @@
                 description, icon);
 
         mToggleSwitchWasInitiallyChecked = mToggleServiceSwitchPreference.isChecked();
+        if (mTopIntroPreference != null) {
+            mTopIntroPreference.setVisible(false);
+        }
     }
 
     @Override
diff --git a/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizard.java b/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizard.java
index b5c1123..a460419 100644
--- a/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizard.java
+++ b/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizard.java
@@ -46,6 +46,9 @@
                 description, icon);
 
         mToggleSwitchWasInitiallyChecked = mToggleServiceSwitchPreference.isChecked();
+        if (mTopIntroPreference != null) {
+            mTopIntroPreference.setVisible(false);
+        }
     }
 
     @Override
diff --git a/src/com/android/settings/biometrics/BiometricNavigationUtils.java b/src/com/android/settings/biometrics/BiometricNavigationUtils.java
new file mode 100644
index 0000000..e4f2b7f
--- /dev/null
+++ b/src/com/android/settings/biometrics/BiometricNavigationUtils.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics;
+
+import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
+import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY;
+
+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.settings.core.SettingsBaseActivity;
+import com.android.settingslib.transition.SettingsTransitionHelper;
+
+/**
+ * Utilities for navigation shared between Security Settings and Safety Center.
+ */
+public class BiometricNavigationUtils {
+
+    private final int mUserId = UserHandle.myUserId();
+
+    /**
+     * Tries to launch the Settings screen if Quiet Mode is not enabled
+     * 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}.
+     * @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)) {
+            return false;
+        }
+
+        final Intent intent = new Intent();
+        intent.setClassName(SETTINGS_PACKAGE_NAME, className);
+        if (!extras.isEmpty()) {
+            intent.putExtras(extras);
+        }
+        intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, true);
+        intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
+        intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE,
+                SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE);
+        context.startActivity(intent);
+        return true;
+    }
+}
diff --git a/src/com/android/settings/biometrics/BiometricStatusPreferenceController.java b/src/com/android/settings/biometrics/BiometricStatusPreferenceController.java
index 801dd03..617529f 100644
--- a/src/com/android/settings/biometrics/BiometricStatusPreferenceController.java
+++ b/src/com/android/settings/biometrics/BiometricStatusPreferenceController.java
@@ -16,11 +16,7 @@
 
 package com.android.settings.biometrics;
 
-import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
-import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY;
-
 import android.content.Context;
-import android.content.Intent;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.text.TextUtils;
@@ -30,9 +26,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.settings.Utils;
 import com.android.settings.core.BasePreferenceController;
-import com.android.settings.core.SettingsBaseActivity;
 import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.transition.SettingsTransitionHelper;
 
 public abstract class BiometricStatusPreferenceController extends BasePreferenceController {
 
@@ -42,36 +36,23 @@
     private final int mUserId = UserHandle.myUserId();
     protected final int mProfileChallengeUserId;
 
+    private final BiometricNavigationUtils mBiometricNavigationUtils;
+
     /**
      * @return true if the manager is not null and the hardware is detected.
      */
     protected abstract boolean isDeviceSupported();
 
     /**
-     * @return true if the user has enrolled biometrics of the subclassed type.
+     * @return the summary text.
      */
-    protected abstract boolean hasEnrolledBiometrics();
-
-    /**
-     * @return the summary text if biometrics are enrolled.
-     */
-    protected abstract String getSummaryTextEnrolled();
-
-    /**
-     * @return the summary text if no biometrics are enrolled.
-     */
-    protected abstract String getSummaryTextNoneEnrolled();
+    protected abstract String getSummaryText();
 
     /**
      * @return the class name for the settings page.
      */
     protected abstract String getSettingsClassName();
 
-    /**
-     * @return the class name for entry to enrollment.
-     */
-    protected abstract String getEnrollClassName();
-
     public BiometricStatusPreferenceController(Context context, String key) {
         super(context, key);
         mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
@@ -79,6 +60,7 @@
                 .getSecurityFeatureProvider()
                 .getLockPatternUtils(context);
         mProfileChallengeUserId = Utils.getManagedProfileId(mUm, mUserId);
+        mBiometricNavigationUtils = new BiometricNavigationUtils();
     }
 
     @Override
@@ -103,8 +85,7 @@
         } else {
             preference.setVisible(true);
         }
-        preference.setSummary(hasEnrolledBiometrics() ? getSummaryTextEnrolled()
-                : getSummaryTextNoneEnrolled());
+        preference.setSummary(getSummaryText());
     }
 
     @Override
@@ -113,26 +94,8 @@
             return super.handlePreferenceTreeClick(preference);
         }
 
-        final Context context = preference.getContext();
-        final UserManager userManager = UserManager.get(context);
-        final int userId = getUserId();
-        if (Utils.startQuietModeDialogIfNecessary(context, userManager, userId)) {
-            return false;
-        }
-
-        final Intent intent = new Intent();
-        final String clazz = hasEnrolledBiometrics() ? getSettingsClassName()
-                : getEnrollClassName();
-        intent.setClassName(SETTINGS_PACKAGE_NAME, clazz);
-        if (!preference.getExtras().isEmpty()) {
-            intent.putExtras(preference.getExtras());
-        }
-        intent.putExtra(Intent.EXTRA_USER_ID, userId);
-        intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, true);
-        intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE,
-                SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE);
-        context.startActivity(intent);
-        return true;
+        return mBiometricNavigationUtils.launchBiometricSettings(
+                preference.getContext(), getSettingsClassName(), preference.getExtras());
     }
 
     protected int getUserId() {
diff --git a/src/com/android/settings/biometrics/combination/BiometricFaceStatusPreferenceController.java b/src/com/android/settings/biometrics/combination/BiometricFaceStatusPreferenceController.java
index 3ac14a1..800139c 100644
--- a/src/com/android/settings/biometrics/combination/BiometricFaceStatusPreferenceController.java
+++ b/src/com/android/settings/biometrics/combination/BiometricFaceStatusPreferenceController.java
@@ -29,7 +29,7 @@
 public class BiometricFaceStatusPreferenceController extends FaceStatusPreferenceController {
 
     public BiometricFaceStatusPreferenceController(Context context, String key) {
-        super(context, key);
+        super(context, key, null /* lifecycle */);
     }
 
     public BiometricFaceStatusPreferenceController(
diff --git a/src/com/android/settings/biometrics/combination/BiometricFingerprintStatusPreferenceController.java b/src/com/android/settings/biometrics/combination/BiometricFingerprintStatusPreferenceController.java
index 782d889..be19cb5 100644
--- a/src/com/android/settings/biometrics/combination/BiometricFingerprintStatusPreferenceController.java
+++ b/src/com/android/settings/biometrics/combination/BiometricFingerprintStatusPreferenceController.java
@@ -30,7 +30,7 @@
         FingerprintStatusPreferenceController {
 
     public BiometricFingerprintStatusPreferenceController(Context context, String key) {
-        super(context, key);
+        super(context, key, null /* lifecycle */);
     }
 
     public BiometricFingerprintStatusPreferenceController(
diff --git a/src/com/android/settings/biometrics/combination/CombinedBiometricProfileStatusPreferenceController.java b/src/com/android/settings/biometrics/combination/CombinedBiometricProfileStatusPreferenceController.java
index ddc69e1..b8706a5 100644
--- a/src/com/android/settings/biometrics/combination/CombinedBiometricProfileStatusPreferenceController.java
+++ b/src/com/android/settings/biometrics/combination/CombinedBiometricProfileStatusPreferenceController.java
@@ -20,8 +20,6 @@
 
 import androidx.lifecycle.Lifecycle;
 
-import com.android.settings.Settings;
-
 /**
  * Preference controller for biometrics settings page of work profile, controlling the ability to
  * unlock the phone with face and fingerprint.
@@ -62,11 +60,6 @@
 
     @Override
     protected String getSettingsClassName() {
-        return Settings.CombinedBiometricProfileSettingsActivity.class.getName();
-    }
-
-    @Override
-    protected String getEnrollClassName() {
-        return Settings.CombinedBiometricProfileSettingsActivity.class.getName();
+        return mCombinedBiometricStatusUtils.getProfileSettingsClassName();
     }
 }
diff --git a/src/com/android/settings/biometrics/combination/CombinedBiometricStatusPreferenceController.java b/src/com/android/settings/biometrics/combination/CombinedBiometricStatusPreferenceController.java
index 32fb3a0..27e3ae7 100644
--- a/src/com/android/settings/biometrics/combination/CombinedBiometricStatusPreferenceController.java
+++ b/src/com/android/settings/biometrics/combination/CombinedBiometricStatusPreferenceController.java
@@ -16,9 +16,6 @@
 package com.android.settings.biometrics.combination;
 
 import android.content.Context;
-import android.hardware.biometrics.BiometricAuthenticator;
-import android.hardware.face.FaceManager;
-import android.hardware.fingerprint.FingerprintManager;
 
 import androidx.annotation.Nullable;
 import androidx.lifecycle.Lifecycle;
@@ -28,11 +25,7 @@
 import androidx.preference.PreferenceScreen;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.settings.R;
-import com.android.settings.Settings;
-import com.android.settings.Utils;
 import com.android.settings.biometrics.BiometricStatusPreferenceController;
-import com.android.settings.biometrics.ParentalControlsUtils;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedPreference;
 
@@ -44,12 +37,9 @@
         BiometricStatusPreferenceController implements LifecycleObserver {
     private static final String KEY_BIOMETRIC_SETTINGS = "biometric_settings";
 
-    @Nullable
-    FingerprintManager mFingerprintManager;
-    @Nullable
-    FaceManager mFaceManager;
     @VisibleForTesting
     RestrictedPreference mPreference;
+    protected final CombinedBiometricStatusUtils mCombinedBiometricStatusUtils;
 
     public CombinedBiometricStatusPreferenceController(Context context) {
         this(context, KEY_BIOMETRIC_SETTINGS, null /* lifecycle */);
@@ -66,8 +56,7 @@
     public CombinedBiometricStatusPreferenceController(
             Context context, String key, Lifecycle lifecycle) {
         super(context, key);
-        mFingerprintManager = Utils.getFingerprintManagerOrNull(context);
-        mFaceManager = Utils.getFaceManagerOrNull(context);
+        mCombinedBiometricStatusUtils = new CombinedBiometricStatusUtils(context);
 
         if (lifecycle != null) {
             lifecycle.addObserver(this);
@@ -87,12 +76,7 @@
 
     @Override
     protected boolean isDeviceSupported() {
-        return Utils.hasFingerprintHardware(mContext) && Utils.hasFaceHardware(mContext);
-    }
-
-    @Override
-    protected boolean hasEnrolledBiometrics() {
-        return false;
+        return mCombinedBiometricStatusUtils.isAvailable();
     }
 
     @Override
@@ -102,80 +86,35 @@
     }
 
     private void updateStateInternal() {
-        // This controller currently is shown if fingerprint&face exist on the device. If this
-        // changes in the future, the modalities passed into the below will need to be updated.
+        final RestrictedLockUtils.EnforcedAdmin admin =
+                mCombinedBiometricStatusUtils.getDisablingAdmin();
 
-        final RestrictedLockUtils.EnforcedAdmin faceAdmin = ParentalControlsUtils
-                .parentConsentRequired(mContext, BiometricAuthenticator.TYPE_FACE);
-        final RestrictedLockUtils.EnforcedAdmin fpAdmin = ParentalControlsUtils
-                .parentConsentRequired(mContext, BiometricAuthenticator.TYPE_FINGERPRINT);
-
-        // If the admins are non-null, they are actually always the same. Just the helper class
-        // we create above always return the admin, instead of a boolean.
-        final boolean faceConsentRequired = faceAdmin != null;
-        final boolean fpConsentRequired = fpAdmin != null;
-        final RestrictedLockUtils.EnforcedAdmin admin = faceAdmin != null ? faceAdmin : fpAdmin;
-
-        updateStateInternal(admin, faceConsentRequired, fpConsentRequired);
+        updateStateInternal(admin);
     }
 
+    /**
+     *   Disables the preference and shows the consent flow only if consent is required for all
+     *   modalities.
+     *
+     *   <p>Otherwise, users will not be able to enter and modify settings for modalities which have
+     *   already been consented. In any case, the controllers for the modalities which have not yet
+     *   been consented will be disabled in the combined page anyway - users can go through the
+     *   consent+enrollment flow from there.
+     */
     @VisibleForTesting
-    void updateStateInternal(@Nullable RestrictedLockUtils.EnforcedAdmin enforcedAdmin,
-            boolean faceConsentRequired, boolean fpConsentRequired) {
-        // Disable the preference (and show the consent flow) only if consent is required for all
-        // modalities. Otherwise, users will not be able to enter and modify settings for modalities
-        // which have already been consented. In any case, the controllers for the modalities which
-        // have not yet been consented will be disabled in the combined page anyway - users can
-        // go through the consent+enrollment flow from there.
-        final boolean disablePreference = faceConsentRequired && fpConsentRequired;
-        if (!disablePreference) {
-            enforcedAdmin = null;
-        }
-
+    void updateStateInternal(@Nullable RestrictedLockUtils.EnforcedAdmin enforcedAdmin) {
         if (mPreference != null) {
             mPreference.setDisabledByAdmin(enforcedAdmin);
         }
     }
 
     @Override
-    protected String getSummaryTextEnrolled() {
-        // Note that this is currently never called (see the super class)
-        return mContext.getString(
-                R.string.security_settings_biometric_preference_summary_none_enrolled);
-    }
-
-    @Override
-    protected String getSummaryTextNoneEnrolled() {
-        final int numFingerprintsEnrolled = mFingerprintManager != null ?
-                mFingerprintManager.getEnrolledFingerprints(getUserId()).size() : 0;
-        final boolean faceEnrolled = mFaceManager != null
-                && mFaceManager.hasEnrolledTemplates(getUserId());
-
-        if (faceEnrolled && numFingerprintsEnrolled > 1) {
-            return mContext.getString(
-                    R.string.security_settings_biometric_preference_summary_both_fp_multiple);
-        } else if (faceEnrolled && numFingerprintsEnrolled == 1) {
-            return mContext.getString(
-                    R.string.security_settings_biometric_preference_summary_both_fp_single);
-        } else if (faceEnrolled) {
-            return mContext.getString(R.string.security_settings_face_preference_summary);
-        } else if (numFingerprintsEnrolled > 0) {
-            return mContext.getResources().getQuantityString(
-                    R.plurals.security_settings_fingerprint_preference_summary,
-                    numFingerprintsEnrolled, numFingerprintsEnrolled);
-        } else {
-            return mContext.getString(
-                    R.string.security_settings_biometric_preference_summary_none_enrolled);
-        }
+    protected String getSummaryText() {
+        return mCombinedBiometricStatusUtils.getSummary();
     }
 
     @Override
     protected String getSettingsClassName() {
-        return Settings.CombinedBiometricSettingsActivity.class.getName();
-    }
-
-    @Override
-    protected String getEnrollClassName() {
-        return Settings.CombinedBiometricSettingsActivity.class.getName();
+        return mCombinedBiometricStatusUtils.getSettingsClassName();
     }
 }
diff --git a/src/com/android/settings/biometrics/combination/CombinedBiometricStatusUtils.java b/src/com/android/settings/biometrics/combination/CombinedBiometricStatusUtils.java
new file mode 100644
index 0000000..a7554c8
--- /dev/null
+++ b/src/com/android/settings/biometrics/combination/CombinedBiometricStatusUtils.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics.combination;
+
+import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.face.FaceManager;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.UserHandle;
+
+import androidx.annotation.Nullable;
+
+import com.android.settings.R;
+import com.android.settings.Settings;
+import com.android.settings.Utils;
+import com.android.settings.biometrics.ParentalControlsUtils;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
+/**
+ * Utilities for combined biometric details shared between Security Settings and Safety Center.
+ */
+public class CombinedBiometricStatusUtils {
+
+    private final int mUserId = UserHandle.myUserId();
+    private final Context mContext;
+    @Nullable
+    FingerprintManager mFingerprintManager;
+    @Nullable
+    FaceManager mFaceManager;
+
+    public CombinedBiometricStatusUtils(Context context) {
+        mContext = context;
+        mFingerprintManager = Utils.getFingerprintManagerOrNull(context);
+        mFaceManager = Utils.getFaceManagerOrNull(context);
+    }
+
+    /**
+     * Returns whether the combined biometric settings entity should be shown.
+     */
+    public boolean isAvailable() {
+        return Utils.hasFingerprintHardware(mContext) && Utils.hasFaceHardware(mContext);
+    }
+
+    /**
+     * Returns the {@link EnforcedAdmin} in case parental consent is required to change both
+     * face and fingerprint settings.
+     *
+     * @return null if either face or fingerprint settings do not require a parental consent.
+     */
+    public EnforcedAdmin getDisablingAdmin() {
+        // This controller currently is shown if fingerprint&face exist on the device. If this
+        // changes in the future, the modalities passed into the below will need to be updated.
+
+        final EnforcedAdmin faceAdmin = ParentalControlsUtils
+                .parentConsentRequired(mContext, BiometricAuthenticator.TYPE_FACE);
+        final EnforcedAdmin fpAdmin = ParentalControlsUtils
+                .parentConsentRequired(mContext, BiometricAuthenticator.TYPE_FINGERPRINT);
+
+        final boolean faceConsentRequired = faceAdmin != null;
+        final boolean fpConsentRequired = fpAdmin != null;
+
+        // Result is only required if all modalities require consent.
+        // If the admins are non-null, they are actually always the same.
+        return faceConsentRequired && fpConsentRequired ? faceAdmin : null;
+    }
+
+    /**
+     * Returns the summary of combined biometric settings entity.
+     */
+    public String getSummary() {
+        final int numFingerprintsEnrolled = mFingerprintManager != null
+                ? mFingerprintManager.getEnrolledFingerprints(mUserId).size() : 0;
+        final boolean faceEnrolled = mFaceManager != null
+                && mFaceManager.hasEnrolledTemplates(mUserId);
+
+        if (faceEnrolled && numFingerprintsEnrolled > 1) {
+            return mContext.getString(
+                    R.string.security_settings_biometric_preference_summary_both_fp_multiple);
+        } else if (faceEnrolled && numFingerprintsEnrolled == 1) {
+            return mContext.getString(
+                    R.string.security_settings_biometric_preference_summary_both_fp_single);
+        } else if (faceEnrolled) {
+            return mContext.getString(R.string.security_settings_face_preference_summary);
+        } else if (numFingerprintsEnrolled > 0) {
+            return mContext.getResources().getQuantityString(
+                    R.plurals.security_settings_fingerprint_preference_summary,
+                    numFingerprintsEnrolled, numFingerprintsEnrolled);
+        } else {
+            return mContext.getString(
+                    R.string.security_settings_biometric_preference_summary_none_enrolled);
+        }
+    }
+
+    /**
+     * Returns the class name of the Settings page corresponding to combined biometric settings.
+     */
+    public String getSettingsClassName() {
+        return Settings.CombinedBiometricSettingsActivity.class.getName();
+    }
+
+    /**
+     * Returns the class name of the Settings page corresponding to combined biometric settings
+     * for work profile.
+     */
+    public String getProfileSettingsClassName() {
+        return Settings.CombinedBiometricProfileSettingsActivity.class.getName();
+    }
+}
diff --git a/src/com/android/settings/biometrics/face/FaceStatusPreferenceController.java b/src/com/android/settings/biometrics/face/FaceStatusPreferenceController.java
index 319166e..cd0bc15 100644
--- a/src/com/android/settings/biometrics/face/FaceStatusPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceStatusPreferenceController.java
@@ -17,7 +17,6 @@
 package com.android.settings.biometrics.face;
 
 import android.content.Context;
-import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.face.FaceManager;
 
 import androidx.annotation.Nullable;
@@ -28,11 +27,8 @@
 import androidx.preference.PreferenceScreen;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.settings.R;
-import com.android.settings.Settings;
 import com.android.settings.Utils;
 import com.android.settings.biometrics.BiometricStatusPreferenceController;
-import com.android.settings.biometrics.ParentalControlsUtils;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedPreference;
 
@@ -44,6 +40,7 @@
     protected final FaceManager mFaceManager;
     @VisibleForTesting
     RestrictedPreference mPreference;
+    private final FaceStatusUtils mFaceStatusUtils;
 
     public FaceStatusPreferenceController(Context context) {
         this(context, KEY_FACE_SETTINGS, null /* lifecycle */);
@@ -60,6 +57,7 @@
     public FaceStatusPreferenceController(Context context, String key, Lifecycle lifecycle) {
         super(context, key);
         mFaceManager = Utils.getFaceManagerOrNull(context);
+        mFaceStatusUtils = new FaceStatusUtils(context, mFaceManager);
 
         if (lifecycle != null) {
             lifecycle.addObserver(this);
@@ -79,12 +77,7 @@
 
     @Override
     protected boolean isDeviceSupported() {
-        return !Utils.isMultipleBiometricsSupported(mContext) && Utils.hasFaceHardware(mContext);
-    }
-
-    @Override
-    protected boolean hasEnrolledBiometrics() {
-        return mFaceManager.hasEnrolledTemplates(getUserId());
+        return mFaceStatusUtils.isAvailable();
     }
 
     @Override
@@ -94,8 +87,7 @@
     }
 
     private void updateStateInternal() {
-        updateStateInternal(ParentalControlsUtils.parentConsentRequired(
-                mContext, BiometricAuthenticator.TYPE_FACE));
+        updateStateInternal(mFaceStatusUtils.getDisablingAdmin());
     }
 
     @VisibleForTesting
@@ -106,25 +98,12 @@
     }
 
     @Override
-    protected String getSummaryTextEnrolled() {
-        return mContext.getResources()
-                .getString(R.string.security_settings_face_preference_summary);
-    }
-
-    @Override
-    protected String getSummaryTextNoneEnrolled() {
-        return mContext.getResources()
-                .getString(R.string.security_settings_face_preference_summary_none);
+    protected String getSummaryText() {
+        return mFaceStatusUtils.getSummary();
     }
 
     @Override
     protected String getSettingsClassName() {
-        return Settings.FaceSettingsActivity.class.getName();
+        return mFaceStatusUtils.getSettingsClassName();
     }
-
-    @Override
-    protected String getEnrollClassName() {
-        return FaceEnrollIntroduction.class.getName();
-    }
-
 }
diff --git a/src/com/android/settings/biometrics/face/FaceStatusUtils.java b/src/com/android/settings/biometrics/face/FaceStatusUtils.java
new file mode 100644
index 0000000..dd32708
--- /dev/null
+++ b/src/com/android/settings/biometrics/face/FaceStatusUtils.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics.face;
+
+import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.face.FaceManager;
+import android.os.UserHandle;
+
+import com.android.settings.R;
+import com.android.settings.Settings;
+import com.android.settings.Utils;
+import com.android.settings.biometrics.ParentalControlsUtils;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
+/**
+ * Utilities for face details shared between Security Settings and Safety Center.
+ */
+public class FaceStatusUtils {
+
+    private final int mUserId = UserHandle.myUserId();
+    private final Context mContext;
+    private final FaceManager mFaceManager;
+
+    public FaceStatusUtils(Context context, FaceManager faceManager) {
+        mContext = context;
+        mFaceManager = faceManager;
+    }
+
+    /**
+     * Returns whether the face settings entity should be shown.
+     */
+    public boolean isAvailable() {
+        return !Utils.isMultipleBiometricsSupported(mContext) && Utils.hasFaceHardware(mContext);
+    }
+
+    /**
+     * Returns the {@link EnforcedAdmin} if parental consent is required to change face settings.
+     *
+     * @return null if face settings does not require a parental consent.
+     */
+    public EnforcedAdmin getDisablingAdmin() {
+        return ParentalControlsUtils.parentConsentRequired(
+                mContext, BiometricAuthenticator.TYPE_FACE);
+    }
+
+    /**
+     * Returns the summary of face settings entity.
+     */
+    public String getSummary() {
+        return mContext.getResources().getString(hasEnrolled()
+                ? R.string.security_settings_face_preference_summary
+                : R.string.security_settings_face_preference_summary_none);
+    }
+
+    /**
+     * Returns the class name of the Settings page corresponding to face settings.
+     */
+    public String getSettingsClassName() {
+        return hasEnrolled() ? Settings.FaceSettingsActivity.class.getName()
+                : FaceEnrollIntroduction.class.getName();
+    }
+
+    private boolean hasEnrolled() {
+        return mFaceManager.hasEnrolledTemplates(mUserId);
+    }
+}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintStatusPreferenceController.java b/src/com/android/settings/biometrics/fingerprint/FingerprintStatusPreferenceController.java
index 76c809c..646af4d 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintStatusPreferenceController.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintStatusPreferenceController.java
@@ -17,7 +17,6 @@
 package com.android.settings.biometrics.fingerprint;
 
 import android.content.Context;
-import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.fingerprint.FingerprintManager;
 
 import androidx.annotation.Nullable;
@@ -28,10 +27,8 @@
 import androidx.preference.PreferenceScreen;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.settings.R;
 import com.android.settings.Utils;
 import com.android.settings.biometrics.BiometricStatusPreferenceController;
-import com.android.settings.biometrics.ParentalControlsUtils;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedPreference;
 
@@ -43,6 +40,7 @@
     protected final FingerprintManager mFingerprintManager;
     @VisibleForTesting
     RestrictedPreference mPreference;
+    private final FingerprintStatusUtils mFingerprintStatusUtils;
 
     public FingerprintStatusPreferenceController(Context context) {
         this(context, KEY_FINGERPRINT_SETTINGS);
@@ -59,6 +57,8 @@
     public FingerprintStatusPreferenceController(Context context, String key, Lifecycle lifecycle) {
         super(context, key);
         mFingerprintManager = Utils.getFingerprintManagerOrNull(context);
+        mFingerprintStatusUtils =
+                new FingerprintStatusUtils(context, mFingerprintManager);
 
         if (lifecycle != null) {
             lifecycle.addObserver(this);
@@ -78,13 +78,7 @@
 
     @Override
     protected boolean isDeviceSupported() {
-        return !Utils.isMultipleBiometricsSupported(mContext)
-                && Utils.hasFingerprintHardware(mContext);
-    }
-
-    @Override
-    protected boolean hasEnrolledBiometrics() {
-        return mFingerprintManager.hasEnrolledFingerprints(getUserId());
+        return mFingerprintStatusUtils.isAvailable();
     }
 
     @Override
@@ -94,8 +88,17 @@
     }
 
     private void updateStateInternal() {
-        updateStateInternal(ParentalControlsUtils.parentConsentRequired(
-                mContext, BiometricAuthenticator.TYPE_FINGERPRINT));
+        updateStateInternal(mFingerprintStatusUtils.getDisablingAdmin());
+    }
+
+    @Override
+    protected String getSummaryText() {
+        return mFingerprintStatusUtils.getSummary();
+    }
+
+    @Override
+    protected String getSettingsClassName() {
+        return mFingerprintStatusUtils.getSettingsClassName();
     }
 
     @VisibleForTesting
@@ -104,28 +107,4 @@
             mPreference.setDisabledByAdmin(enforcedAdmin);
         }
     }
-
-    @Override
-    protected String getSummaryTextEnrolled() {
-        final int numEnrolled = mFingerprintManager.getEnrolledFingerprints(getUserId()).size();
-        return mContext.getResources().getQuantityString(
-                R.plurals.security_settings_fingerprint_preference_summary,
-                numEnrolled, numEnrolled);
-    }
-
-    @Override
-    protected String getSummaryTextNoneEnrolled() {
-        return mContext.getString(R.string.security_settings_fingerprint_preference_summary_none);
-    }
-
-    @Override
-    protected String getSettingsClassName() {
-        return FingerprintSettings.class.getName();
-    }
-
-    @Override
-    protected String getEnrollClassName() {
-        return FingerprintEnrollIntroduction.class.getName();
-    }
-
 }
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java b/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java
new file mode 100644
index 0000000..36edd2e
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics.fingerprint;
+
+import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.UserHandle;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.biometrics.ParentalControlsUtils;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
+/**
+ * Utilities for fingerprint details shared between Security Settings and Safety Center.
+ */
+public class FingerprintStatusUtils {
+
+    private final int mUserId = UserHandle.myUserId();
+    private final Context mContext;
+    private final FingerprintManager mFingerprintManager;
+
+    public FingerprintStatusUtils(Context context, FingerprintManager fingerprintManager) {
+        mContext = context;
+        mFingerprintManager = fingerprintManager;
+    }
+
+    /**
+     * Returns whether the fingerprint settings entity should be shown.
+     */
+    public boolean isAvailable() {
+        return !Utils.isMultipleBiometricsSupported(mContext)
+                && Utils.hasFingerprintHardware(mContext);
+    }
+
+    /**
+     * Returns the {@link EnforcedAdmin} if parental consent is required to change face settings.
+     *
+     * @return null if face settings does not require a parental consent.
+     */
+    public EnforcedAdmin getDisablingAdmin() {
+        return ParentalControlsUtils.parentConsentRequired(
+                mContext, BiometricAuthenticator.TYPE_FINGERPRINT);
+    }
+
+    /**
+     * Returns the summary of fingerprint settings entity.
+     */
+    public String getSummary() {
+        if (hasEnrolled()) {
+            final int numEnrolled = mFingerprintManager.getEnrolledFingerprints(mUserId).size();
+            return mContext.getResources().getQuantityString(
+                    R.plurals.security_settings_fingerprint_preference_summary,
+                    numEnrolled, numEnrolled);
+        } else {
+            return mContext.getString(
+                    R.string.security_settings_fingerprint_preference_summary_none);
+        }
+    }
+
+    /**
+     * Returns the class name of the Settings page corresponding to fingerprint settings.
+     */
+    public String getSettingsClassName() {
+        return hasEnrolled() ? FingerprintSettings.class.getName()
+                : FingerprintEnrollIntroduction.class.getName();
+    }
+
+    private boolean hasEnrolled() {
+        return mFingerprintManager.hasEnrolledFingerprints(mUserId);
+    }
+}
diff --git a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
index b60f1b6..1c12c6a 100644
--- a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
+++ b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
@@ -99,6 +99,10 @@
     @VisibleForTesting
     boolean mIsRegisterCallback = false;
     @VisibleForTesting
+    boolean mIsLeftDeviceEstimateReady;
+    @VisibleForTesting
+    boolean mIsRightDeviceEstimateReady;
+    @VisibleForTesting
     final BluetoothAdapter.OnMetadataChangedListener mMetadataListener =
             new BluetoothAdapter.OnMetadataChangedListener() {
                 @Override
@@ -226,6 +230,8 @@
                         BluetoothDevice.METADATA_UNTETHERED_RIGHT_CHARGING,
                         R.string.bluetooth_right_name,
                         RIGHT_DEVICE_ID);
+
+                showBothDevicesBatteryPredictionIfNecessary();
             }
         }
     }
@@ -365,8 +371,13 @@
                                 + ", ESTIMATE_READY : " + estimateReady
                                 + ", BATTERY_ESTIMATE : " + batteryEstimate);
                     }
-                    showBatteryPredictionIfNecessary(estimateReady, batteryEstimate,
-                            linearLayout);
+
+                    showBatteryPredictionIfNecessary(estimateReady, batteryEstimate, linearLayout);
+                    if (batteryId == LEFT_DEVICE_ID) {
+                        mIsLeftDeviceEstimateReady = estimateReady == 1;
+                    } else if (batteryId == RIGHT_DEVICE_ID) {
+                        mIsRightDeviceEstimateReady = estimateReady == 1;
+                    }
                 }
             } finally {
                 cursor.close();
@@ -380,7 +391,6 @@
         ThreadUtils.postOnMainThread(() -> {
             final TextView textView = linearLayout.findViewById(R.id.bt_battery_prediction);
             if (estimateReady == 1) {
-                textView.setVisibility(View.VISIBLE);
                 textView.setText(
                         StringUtil.formatElapsedTime(
                                 mContext,
@@ -393,6 +403,24 @@
         });
     }
 
+    @VisibleForTesting
+    void showBothDevicesBatteryPredictionIfNecessary() {
+        TextView leftDeviceTextView =
+                mLayoutPreference.findViewById(R.id.layout_left)
+                        .findViewById(R.id.bt_battery_prediction);
+        TextView rightDeviceTextView =
+                mLayoutPreference.findViewById(R.id.layout_right)
+                        .findViewById(R.id.bt_battery_prediction);
+
+        boolean isBothDevicesEstimateReady =
+                mIsLeftDeviceEstimateReady && mIsRightDeviceEstimateReady;
+        int visibility = isBothDevicesEstimateReady ? View.VISIBLE : View.GONE;
+        ThreadUtils.postOnMainThread(() -> {
+            leftDeviceTextView.setVisibility(visibility);
+            rightDeviceTextView.setVisibility(visibility);
+        });
+    }
+
     private void showBatteryIcon(LinearLayout linearLayout, int level, int lowBatteryLevel,
             boolean charging) {
         final boolean enableLowBattery = level <= lowBatteryLevel && !charging;
diff --git a/src/com/android/settings/development/tare/TareFactorController.java b/src/com/android/settings/development/tare/TareFactorController.java
index 50531a0..c05abdb 100644
--- a/src/com/android/settings/development/tare/TareFactorController.java
+++ b/src/com/android/settings/development/tare/TareFactorController.java
@@ -83,9 +83,9 @@
                 new TareFactorData(mResources.getString(R.string.tare_max_satiated_balance),
                         EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE,
                         POLICY_ALARM_MANAGER));
-        mAlarmManagerMap.put(EconomyManager.KEY_AM_MAX_CIRCULATION,
+        mAlarmManagerMap.put(EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT,
                 new TareFactorData(mResources.getString(R.string.tare_max_circulation),
-                        EconomyManager.DEFAULT_AM_MAX_CIRCULATION,
+                        EconomyManager.DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT,
                         POLICY_ALARM_MANAGER));
         mAlarmManagerMap.put(EconomyManager.KEY_AM_REWARD_TOP_ACTIVITY_INSTANT,
                 new TareFactorData(mResources.getString(R.string.tare_top_activity),
@@ -265,9 +265,9 @@
                 new TareFactorData(mResources.getString(R.string.tare_max_satiated_balance),
                         EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE,
                         POLICY_JOB_SCHEDULER));
-        mJobSchedulerMap.put(EconomyManager.KEY_JS_MAX_CIRCULATION,
+        mJobSchedulerMap.put(EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT,
                 new TareFactorData(mResources.getString(R.string.tare_max_circulation),
-                        EconomyManager.DEFAULT_JS_MAX_CIRCULATION,
+                        EconomyManager.DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT,
                         POLICY_JOB_SCHEDULER));
         mJobSchedulerMap.put(EconomyManager.KEY_JS_REWARD_TOP_ACTIVITY_INSTANT,
                 new TareFactorData(mResources.getString(R.string.tare_top_activity),
diff --git a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
index 71e65bf..436cde8 100644
--- a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
@@ -112,7 +112,8 @@
         if (intent != null && mBatteryListener != null) {
             if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
                 final String batteryLevel = Utils.getBatteryPercentage(intent);
-                final String batteryStatus = Utils.getBatteryStatus(mContext, intent);
+                final String batteryStatus =
+                        Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false);
                 final int batteryHealth = intent.getIntExtra(
                         BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN);
                 if (!Utils.isBatteryPresent(intent)) {
diff --git a/src/com/android/settings/fuelgauge/BatteryInfo.java b/src/com/android/settings/fuelgauge/BatteryInfo.java
index 4e90710..98f19fe 100644
--- a/src/com/android/settings/fuelgauge/BatteryInfo.java
+++ b/src/com/android/settings/fuelgauge/BatteryInfo.java
@@ -37,7 +37,6 @@
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.widget.UsageView;
 import com.android.settingslib.R;
-import com.android.settingslib.fuelgauge.BatteryStatus;
 import com.android.settingslib.fuelgauge.Estimate;
 import com.android.settingslib.fuelgauge.EstimateKt;
 import com.android.settingslib.utils.PowerUtil;
@@ -244,6 +243,8 @@
             @NonNull BatteryUsageStats batteryUsageStats, Estimate estimate,
             long elapsedRealtimeUs, boolean shortString) {
         final long startTime = System.currentTimeMillis();
+        final boolean isCompactStatus = context.getResources().getBoolean(
+                com.android.settings.R.bool.config_use_compact_battery_status);
         BatteryInfo info = new BatteryInfo();
         info.mBatteryUsageStats = batteryUsageStats;
         info.batteryLevel = Utils.getBatteryLevel(batteryBroadcast);
@@ -254,21 +255,21 @@
                 BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN)
                 == BatteryManager.BATTERY_HEALTH_OVERHEAT;
 
-        info.statusLabel = getBatteryStatus(context, batteryBroadcast);
+        info.statusLabel = Utils.getBatteryStatus(context, batteryBroadcast, isCompactStatus);
         info.batteryStatus = batteryBroadcast.getIntExtra(
                 BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN);
         if (!info.mCharging) {
             updateBatteryInfoDischarging(context, shortString, estimate, info);
         } else {
             updateBatteryInfoCharging(context, batteryBroadcast, batteryUsageStats,
-                    info);
+                    info, isCompactStatus);
         }
         BatteryUtils.logRuntime(LOG_TAG, "time for getBatteryInfo", startTime);
         return info;
     }
 
     private static void updateBatteryInfoCharging(Context context, Intent batteryBroadcast,
-            BatteryUsageStats stats, BatteryInfo info) {
+            BatteryUsageStats stats, BatteryInfo info, boolean compactStatus) {
         final Resources resources = context.getResources();
         final long chargeTimeMs = stats.getChargeTimeRemainingMs();
         final int status = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_STATUS,
@@ -292,7 +293,8 @@
                     R.string.power_remaining_charging_duration_only, timeString);
             info.chargeLabel = context.getString(resId, info.batteryPercentString, timeString);
         } else {
-            final String chargeStatusLabel = getBatteryStatus(context, batteryBroadcast);
+            final String chargeStatusLabel =
+                    Utils.getBatteryStatus(context, batteryBroadcast, compactStatus);
             info.remainingLabel = null;
             info.chargeLabel = info.batteryLevel == 100 ? info.batteryPercentString :
                     resources.getString(R.string.power_charging, info.batteryPercentString,
@@ -326,35 +328,6 @@
         }
     }
 
-    private static String getBatteryStatus(Context context, Intent batteryChangedIntent) {
-        final Resources res = context.getResources();
-        final boolean isShortStatus =
-                res.getBoolean(com.android.settings.R.bool.config_use_compact_battery_status);
-
-        if (!isShortStatus) {
-            return Utils.getBatteryStatus(context, batteryChangedIntent);
-        }
-
-        final int status = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_STATUS,
-                BatteryManager.BATTERY_STATUS_UNKNOWN);
-        final BatteryStatus batteryStatus = new BatteryStatus(batteryChangedIntent);
-        String statusString = res.getString(R.string.battery_info_status_unknown);
-
-        if (batteryStatus.isCharged()) {
-            statusString = res.getString(R.string.battery_info_status_full);
-        } else {
-            if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
-                statusString = res.getString(R.string.battery_info_status_charging);
-            } else if (status == BatteryManager.BATTERY_STATUS_DISCHARGING) {
-                statusString = res.getString(R.string.battery_info_status_discharging);
-            } else if (status == BatteryManager.BATTERY_STATUS_NOT_CHARGING) {
-                statusString = res.getString(R.string.battery_info_status_not_charging);
-            }
-        }
-
-        return statusString;
-    }
-
     public interface BatteryDataParser {
         void onParsingStarted(long startTime, long endTime);
 
diff --git a/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricStatusPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricStatusPreferenceControllerTest.java
index 00cf052..c9bb687 100644
--- a/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricStatusPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricStatusPreferenceControllerTest.java
@@ -18,10 +18,7 @@
 
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -42,7 +39,6 @@
 import com.android.settingslib.core.lifecycle.Lifecycle;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -96,7 +92,6 @@
                 mContext, TEST_PREF_KEY, mLifecycle);
     }
 
-    @Ignore
     @Test
     public void updateState_parentalConsentRequired_preferenceDisabled() {
         when(mFaceManager.isHardwareDetected()).thenReturn(true);
@@ -106,16 +101,10 @@
         RestrictedLockUtils.EnforcedAdmin admin = mock(RestrictedLockUtils.EnforcedAdmin.class);
 
         mController.mPreference = restrictedPreference;
-        mController.updateStateInternal(admin, true, true);
+        mController.updateStateInternal(admin);
         verify(restrictedPreference).setDisabledByAdmin(eq(admin));
 
-        mController.updateStateInternal(admin, true, false);
-        verify(restrictedPreference).setDisabledByAdmin(eq(null));
-
-        mController.updateStateInternal(admin, false, true);
-        verify(restrictedPreference).setDisabledByAdmin(eq(null));
-
-        mController.updateStateInternal(admin, false, false);
+        mController.updateStateInternal(null);
         verify(restrictedPreference).setDisabledByAdmin(eq(null));
     }
 }
diff --git a/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java
index 6087ef2..51cad70 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java
@@ -387,34 +387,52 @@
     }
 
     @Test
-    public void showBatteryPredictionIfNecessary_estimateReadyIsAvailable_showView() {
-        mController.showBatteryPredictionIfNecessary(1, 14218009,
-                mLayoutPreference.findViewById(R.id.layout_left));
-        mController.showBatteryPredictionIfNecessary(1, 14218009,
-                mLayoutPreference.findViewById(R.id.layout_middle));
-        mController.showBatteryPredictionIfNecessary(1, 14218009,
-                mLayoutPreference.findViewById(R.id.layout_right));
+    public void estimateReadyIsBothAvailable_showsView() {
+        mController.mIsLeftDeviceEstimateReady = true;
+        mController.mIsRightDeviceEstimateReady = true;
+
+        mController.showBothDevicesBatteryPredictionIfNecessary();
 
         assertBatteryPredictionVisible(mLayoutPreference.findViewById(R.id.layout_left),
                 View.VISIBLE);
-        assertBatteryPredictionVisible(mLayoutPreference.findViewById(R.id.layout_middle),
-                View.VISIBLE);
         assertBatteryPredictionVisible(mLayoutPreference.findViewById(R.id.layout_right),
                 View.VISIBLE);
     }
 
     @Test
-    public void showBatteryPredictionIfNecessary_estimateReadyIsNotAvailable_notShowView() {
-        mController.showBatteryPredictionIfNecessary(0, 14218009,
-                mLayoutPreference.findViewById(R.id.layout_left));
-        mController.showBatteryPredictionIfNecessary(0, 14218009,
-                mLayoutPreference.findViewById(R.id.layout_middle));
-        mController.showBatteryPredictionIfNecessary(0, 14218009,
-                mLayoutPreference.findViewById(R.id.layout_right));
+    public void leftDeviceEstimateIsReadyRightDeviceIsNotReady_notShowView() {
+        mController.mIsLeftDeviceEstimateReady = true;
+        mController.mIsRightDeviceEstimateReady = false;
+
+        mController.showBothDevicesBatteryPredictionIfNecessary();
 
         assertBatteryPredictionVisible(mLayoutPreference.findViewById(R.id.layout_left),
                 View.GONE);
-        assertBatteryPredictionVisible(mLayoutPreference.findViewById(R.id.layout_middle),
+        assertBatteryPredictionVisible(mLayoutPreference.findViewById(R.id.layout_right),
+                View.GONE);
+    }
+
+    @Test
+    public void leftDeviceEstimateIsNotReadyRightDeviceIsReady_notShowView() {
+        mController.mIsLeftDeviceEstimateReady = false;
+        mController.mIsRightDeviceEstimateReady = true;
+
+        mController.showBothDevicesBatteryPredictionIfNecessary();
+
+        assertBatteryPredictionVisible(mLayoutPreference.findViewById(R.id.layout_left),
+                View.GONE);
+        assertBatteryPredictionVisible(mLayoutPreference.findViewById(R.id.layout_right),
+                View.GONE);
+    }
+
+    @Test
+    public void bothDevicesEstimateIsNotReady_notShowView() {
+        mController.mIsLeftDeviceEstimateReady = false;
+        mController.mIsRightDeviceEstimateReady = false;
+
+        mController.showBothDevicesBatteryPredictionIfNecessary();
+
+        assertBatteryPredictionVisible(mLayoutPreference.findViewById(R.id.layout_left),
                 View.GONE);
         assertBatteryPredictionVisible(mLayoutPreference.findViewById(R.id.layout_right),
                 View.GONE);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
index 5f08698..d446930 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
@@ -85,8 +85,8 @@
 
         assertThat(mBatteryBroadcastReceiver.mBatteryLevel)
                 .isEqualTo(Utils.getBatteryPercentage(mChargingIntent));
-        assertThat(mBatteryBroadcastReceiver.mBatteryStatus)
-                .isEqualTo(Utils.getBatteryStatus(mContext, mChargingIntent));
+        assertThat(mBatteryBroadcastReceiver.mBatteryStatus).isEqualTo(
+                Utils.getBatteryStatus(mContext, mChargingIntent, /* compactStatus= */ false));
         verify(mBatteryListener).onBatteryChanged(BatteryUpdateType.BATTERY_LEVEL);
     }
 
@@ -134,7 +134,7 @@
     public void testOnReceive_batteryDataNotChanged_listenerNotInvoked() {
         final String batteryLevel = Utils.getBatteryPercentage(mChargingIntent);
         final String batteryStatus =
-                Utils.getBatteryStatus(mContext, mChargingIntent);
+                Utils.getBatteryStatus(mContext, mChargingIntent, /* compactStatus= */ false);
         mBatteryBroadcastReceiver.mBatteryLevel = batteryLevel;
         mBatteryBroadcastReceiver.mBatteryStatus = batteryStatus;
 
@@ -159,8 +159,8 @@
 
         assertThat(mBatteryBroadcastReceiver.mBatteryLevel)
                 .isEqualTo(Utils.getBatteryPercentage(mChargingIntent));
-        assertThat(mBatteryBroadcastReceiver.mBatteryStatus)
-                .isEqualTo(Utils.getBatteryStatus(mContext, mChargingIntent));
+        assertThat(mBatteryBroadcastReceiver.mBatteryStatus).isEqualTo(
+                Utils.getBatteryStatus(mContext, mChargingIntent, /* compactStatus= */ false));
         assertThat(mBatteryBroadcastReceiver.mBatteryHealth)
                 .isEqualTo(BatteryManager.BATTERY_HEALTH_UNKNOWN);
         // 2 times because register will force update the battery
diff --git a/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java b/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java
new file mode 100644
index 0000000..3e6ac09
--- /dev/null
+++ b/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserManager;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+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;
+
+@RunWith(AndroidJUnit4.class)
+public class BiometricNavigationUtilsTest {
+
+    private static final String SETTINGS_CLASS_NAME = "SettingsClassName";
+    private static final String EXTRA_KEY = "EXTRA_KEY";
+
+    @Mock
+    private UserManager mUserManager;
+    private Context mContext;
+    private BiometricNavigationUtils mBiometricNavigationUtils;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+        doNothing().when(mContext).startActivity(any());
+        mBiometricNavigationUtils = new BiometricNavigationUtils();
+    }
+
+    @Test
+    public void openBiometricSettings_quietMode_launchesQuiteModeDialog() {
+        when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
+
+        mBiometricNavigationUtils.launchBiometricSettings(mContext, SETTINGS_CLASS_NAME,
+                Bundle.EMPTY);
+
+        assertQuietModeDialogLaunchRequested();
+    }
+
+    @Test
+    public void openBiometricSettings_quietMode_returnsFalse() {
+        when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
+
+        assertThat(mBiometricNavigationUtils.launchBiometricSettings(
+                mContext, SETTINGS_CLASS_NAME, Bundle.EMPTY)).isFalse();
+    }
+
+    @Test
+    public void openBiometricSettings_noQuietMode_emptyExtras_launchesFragmentWithoutExtras() {
+        when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
+
+        mBiometricNavigationUtils.launchBiometricSettings(
+                mContext, SETTINGS_CLASS_NAME, Bundle.EMPTY);
+
+        assertSettingsPageLaunchRequested(false /* shouldContainExtras */);
+    }
+
+    @Test
+    public void openBiometricSettings_noQuietMode_emptyExtras_returnsTrue() {
+        when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
+
+        assertThat(mBiometricNavigationUtils.launchBiometricSettings(
+                mContext, SETTINGS_CLASS_NAME, Bundle.EMPTY)).isTrue();
+    }
+
+    @Test
+    public void openBiometricSettings_noQuietMode_withExtras_launchesFragmentWithExtras() {
+        when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
+
+        final Bundle extras = createNotEmptyExtras();
+        mBiometricNavigationUtils.launchBiometricSettings(mContext, SETTINGS_CLASS_NAME, extras);
+
+        assertSettingsPageLaunchRequested(true /* shouldContainExtras */);
+    }
+
+    @Test
+    public void openBiometricSettings_noQuietMode_withExtras_returnsTrue() {
+        when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
+
+        assertThat(mBiometricNavigationUtils.launchBiometricSettings(
+                mContext, SETTINGS_CLASS_NAME, createNotEmptyExtras())).isTrue();
+    }
+
+    private Bundle createNotEmptyExtras() {
+        final Bundle bundle = new Bundle();
+        bundle.putInt(EXTRA_KEY, 0);
+        return bundle;
+    }
+
+    private void assertQuietModeDialogLaunchRequested() {
+        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        verify(mContext).startActivity(intentCaptor.capture());
+
+        Intent intent = intentCaptor.getValue();
+        assertThat(intent.getComponent().getPackageName())
+                .isEqualTo("android");
+        assertThat(intent.getComponent().getClassName())
+                .isEqualTo("com.android.internal.app.UnlaunchableAppActivity");
+    }
+
+    private void assertSettingsPageLaunchRequested(boolean shouldContainExtras) {
+        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        verify(mContext).startActivity(intentCaptor.capture());
+
+        Intent intent = intentCaptor.getValue();
+        assertThat(intent.getComponent().getPackageName())
+                .isEqualTo("com.android.settings");
+        assertThat(intent.getComponent().getClassName())
+                .isEqualTo(SETTINGS_CLASS_NAME);
+        assertThat(intent.getExtras().containsKey(EXTRA_KEY)).isEqualTo(shouldContainExtras);
+    }
+
+}
diff --git a/tests/unit/src/com/android/settings/biometrics/combination/CombinedBiometricStatusUtilsTest.java b/tests/unit/src/com/android/settings/biometrics/combination/CombinedBiometricStatusUtilsTest.java
new file mode 100644
index 0000000..55b3fae
--- /dev/null
+++ b/tests/unit/src/com/android/settings/biometrics/combination/CombinedBiometricStatusUtilsTest.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics.combination;
+
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FACE;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+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.os.UserManager;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.Settings;
+import com.android.settings.testutils.ResourcesUtils;
+import com.android.settingslib.RestrictedLockUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class CombinedBiometricStatusUtilsTest {
+
+    private static final ComponentName COMPONENT_NAME =
+            new ComponentName("package", "class");
+    private static final UserHandle USER_HANDLE = new UserHandle(UserHandle.myUserId());
+
+
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private DevicePolicyManager mDevicePolicyManager;
+    @Mock
+    private FingerprintManager mFingerprintManager;
+    @Mock
+    private FaceManager mFaceManager;
+
+    private Context mApplicationContext;
+    private CombinedBiometricStatusUtils mCombinedBiometricStatusUtils;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        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);
+        mCombinedBiometricStatusUtils = new CombinedBiometricStatusUtils(mApplicationContext);
+    }
+
+    @Test
+    public void isAvailable_withoutFingerprint_withoutFace_returnsFalse() {
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+        when(mFaceManager.isHardwareDetected()).thenReturn(false);
+
+        assertThat(mCombinedBiometricStatusUtils.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_withoutFingerprint_whenFace_returnsFalse() {
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+
+        assertThat(mCombinedBiometricStatusUtils.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_whenFingerprint_withoutFace_returnsFalse() {
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(false);
+
+        assertThat(mCombinedBiometricStatusUtils.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_whenFingerprint_whenFace_returnsTrue() {
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+
+        assertThat(mCombinedBiometricStatusUtils.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void getDisabledAdmin_whenFingerprintDisabled_whenFaceDisabled_returnsEnforcedAdmin() {
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+                .thenReturn(KEYGUARD_DISABLE_FACE | KEYGUARD_DISABLE_FINGERPRINT);
+
+        final RestrictedLockUtils.EnforcedAdmin admin =
+                mCombinedBiometricStatusUtils.getDisablingAdmin();
+
+        assertThat(admin).isEqualTo(new RestrictedLockUtils.EnforcedAdmin(
+                COMPONENT_NAME, UserManager.DISALLOW_BIOMETRIC, USER_HANDLE));
+    }
+
+    @Test
+    public void getDisabledAdmin_whenFingerprintDisabled_whenFaceEnabled_returnsNull() {
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+                .thenReturn(KEYGUARD_DISABLE_FINGERPRINT);
+
+        assertThat(mCombinedBiometricStatusUtils.getDisablingAdmin()).isNull();
+    }
+
+    @Test
+    public void getDisabledAdmin_whenFingerprintEnabled_whenFaceDisabled_returnsNull() {
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+                .thenReturn(KEYGUARD_DISABLE_FACE);
+
+        assertThat(mCombinedBiometricStatusUtils.getDisablingAdmin()).isNull();
+    }
+
+    @Test
+    public void getDisabledAdmin_whenFingerprintEnabled_whenFaceEnabled_returnsNull() {
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+        assertThat(mCombinedBiometricStatusUtils.getDisablingAdmin()).isNull();
+    }
+
+    @Test
+    public void getSummary_whenFaceEnrolled_whenMultipleFingerprints_returnsBothFpMultiple() {
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+        when(mFingerprintManager.getEnrolledFingerprints(anyInt()))
+                .thenReturn(createFingerprintList(2));
+
+        assertThat(mCombinedBiometricStatusUtils.getSummary())
+                .isEqualTo(ResourcesUtils.getResourcesString(
+                        mApplicationContext,
+                        "security_settings_biometric_preference_summary_both_fp_multiple"));
+    }
+
+    @Test
+    public void getSummary_whenFaceEnrolled_whenSingleFingerprint_returnsBothFpSingle() {
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+        when(mFingerprintManager.getEnrolledFingerprints(anyInt()))
+                .thenReturn(createFingerprintList(1));
+
+        assertThat(mCombinedBiometricStatusUtils.getSummary())
+                .isEqualTo(ResourcesUtils.getResourcesString(
+                        mApplicationContext,
+                        "security_settings_biometric_preference_summary_both_fp_single"));
+    }
+
+    @Test
+    public void getSummary_whenFaceEnrolled_whenNoFingerprints_returnsFace() {
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+        when(mFingerprintManager.getEnrolledFingerprints(anyInt()))
+                .thenReturn(createFingerprintList(0));
+
+        assertThat(mCombinedBiometricStatusUtils.getSummary())
+                .isEqualTo(ResourcesUtils.getResourcesString(
+                        mApplicationContext,
+                        "security_settings_face_preference_summary"));
+    }
+
+    @Test
+    public void getSummary_whenNoFaceEnrolled_whenMultipleFingerprints_returnsFingerprints() {
+        final int enrolledFingerprintsCount = 2;
+        final int stringResId = ResourcesUtils.getResourcesId(
+                ApplicationProvider.getApplicationContext(), "plurals",
+                "security_settings_fingerprint_preference_summary");
+        final String summary = mApplicationContext.getResources().getQuantityString(
+                stringResId, enrolledFingerprintsCount /* quantity */,
+                enrolledFingerprintsCount /* formatArgs */);
+
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+        when(mFingerprintManager.getEnrolledFingerprints(anyInt()))
+                .thenReturn(createFingerprintList(enrolledFingerprintsCount));
+
+        assertThat(mCombinedBiometricStatusUtils.getSummary()).isEqualTo(summary);
+    }
+
+    @Test
+    public void getSummary_whenNoFaceEnrolled_whenSingleFingerprints_returnsFingerprints() {
+        final int enrolledFingerprintsCount = 1;
+        final int stringResId = ResourcesUtils.getResourcesId(
+                ApplicationProvider.getApplicationContext(), "plurals",
+                "security_settings_fingerprint_preference_summary");
+        final String summary = mApplicationContext.getResources().getQuantityString(
+                stringResId, enrolledFingerprintsCount /* quantity */,
+                enrolledFingerprintsCount /* formatArgs */);
+
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+        when(mFingerprintManager.getEnrolledFingerprints(anyInt()))
+                .thenReturn(createFingerprintList(enrolledFingerprintsCount));
+
+        assertThat(mCombinedBiometricStatusUtils.getSummary()).isEqualTo(summary);
+    }
+
+    @Test
+    public void getSummary_whenNoFaceEnrolled_whenNoFingerprints_returnsNoneEnrolled() {
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+        when(mFingerprintManager.getEnrolledFingerprints(anyInt()))
+                .thenReturn(createFingerprintList(0));
+
+        assertThat(mCombinedBiometricStatusUtils.getSummary())
+                .isEqualTo(ResourcesUtils.getResourcesString(
+                        mApplicationContext,
+                        "security_settings_biometric_preference_summary_none_enrolled"));
+    }
+
+    @Test
+    public void getSettingsClassName_returnsCombinedBiometricSettings() {
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+
+        assertThat(mCombinedBiometricStatusUtils.getSettingsClassName())
+                .isEqualTo(Settings.CombinedBiometricSettingsActivity.class.getName());
+    }
+
+    @Test
+    public void getProfileSettingsClassName_returnsCombinedBiometricProfileSettings() {
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+
+        assertThat(mCombinedBiometricStatusUtils.getProfileSettingsClassName())
+                .isEqualTo(Settings.CombinedBiometricProfileSettingsActivity.class.getName());
+    }
+
+    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/biometrics/face/FaceStatusUtilsTest.java b/tests/unit/src/com/android/settings/biometrics/face/FaceStatusUtilsTest.java
new file mode 100644
index 0000000..f670fad
--- /dev/null
+++ b/tests/unit/src/com/android/settings/biometrics/face/FaceStatusUtilsTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics.face;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.face.FaceManager;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.Settings;
+import com.android.settings.testutils.ResourcesUtils;
+import com.android.settingslib.RestrictedLockUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class FaceStatusUtilsTest {
+
+    private static final ComponentName COMPONENT_NAME =
+            new ComponentName("package", "class");
+    private static final UserHandle USER_HANDLE = new UserHandle(UserHandle.myUserId());
+
+
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private DevicePolicyManager mDevicePolicyManager;
+    @Mock
+    private FingerprintManager mFingerprintManager;
+    @Mock
+    private FaceManager mFaceManager;
+
+    private Context mApplicationContext;
+    private FaceStatusUtils mFaceStatusUtils;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        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);
+        mFaceStatusUtils = new FaceStatusUtils(mApplicationContext, mFaceManager);
+    }
+
+    @Test
+    public void isAvailable_withoutFingerprint_withoutFace_returnsFalse() {
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+        when(mFaceManager.isHardwareDetected()).thenReturn(false);
+
+        assertThat(mFaceStatusUtils.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_withoutFingerprint_withFace_returnsTrue() {
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+
+        assertThat(mFaceStatusUtils.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void isAvailable_withFingerprint_withoutFace_returnsFalse() {
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(false);
+
+        assertThat(mFaceStatusUtils.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_withFingerprint_withFace_returnsFalse() {
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+
+        assertThat(mFaceStatusUtils.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void getDisabledAdmin_whenFaceDisabled_returnsEnforcedAdmin() {
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+                .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE);
+
+        final RestrictedLockUtils.EnforcedAdmin admin = mFaceStatusUtils.getDisablingAdmin();
+
+        assertThat(admin).isEqualTo(new RestrictedLockUtils.EnforcedAdmin(
+                COMPONENT_NAME, UserManager.DISALLOW_BIOMETRIC, USER_HANDLE));
+    }
+
+    @Test
+    public void getDisabledAdmin_withFaceEnabled_returnsNull() {
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+        assertThat(mFaceStatusUtils.getDisablingAdmin()).isNull();
+    }
+
+    @Test
+    public void getSummary_whenNotEnrolled_returnsSummaryNone() {
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+
+        assertThat(mFaceStatusUtils.getSummary())
+                .isEqualTo(ResourcesUtils.getResourcesString(
+                        mApplicationContext,
+                        "security_settings_face_preference_summary_none"));
+    }
+
+    @Test
+    public void getSummary_whenEnrolled_returnsSummary() {
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+
+        assertThat(mFaceStatusUtils.getSummary())
+                .isEqualTo(ResourcesUtils.getResourcesString(
+                        mApplicationContext,
+                        "security_settings_face_preference_summary"));
+    }
+
+    @Test
+    public void getSettingsClassName_whenNotEnrolled_returnsFaceEnrollInduction() {
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+
+        assertThat(mFaceStatusUtils.getSettingsClassName())
+                .isEqualTo(FaceEnrollIntroduction.class.getName());
+    }
+
+    @Test
+    public void getSettingsClassName_whenEnrolled_returnsFaceSettings() {
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+
+        assertThat(mFaceStatusUtils.getSettingsClassName())
+                .isEqualTo(Settings.FaceSettingsActivity.class.getName());
+    }
+}
diff --git a/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtilsTest.java b/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtilsTest.java
new file mode 100644
index 0000000..b4abb5d
--- /dev/null
+++ b/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtilsTest.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics.fingerprint;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+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.os.UserManager;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.testutils.ResourcesUtils;
+import com.android.settingslib.RestrictedLockUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class FingerprintStatusUtilsTest {
+
+    private static final ComponentName COMPONENT_NAME =
+            new ComponentName("package", "class");
+    private static final UserHandle USER_HANDLE = new UserHandle(UserHandle.myUserId());
+
+
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private DevicePolicyManager mDevicePolicyManager;
+    @Mock
+    private FingerprintManager mFingerprintManager;
+    @Mock
+    private FaceManager mFaceManager;
+
+    private Context mApplicationContext;
+    private FingerprintStatusUtils mFingerprintStatusUtils;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        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);
+        mFingerprintStatusUtils =
+                new FingerprintStatusUtils(mApplicationContext, mFingerprintManager);
+    }
+
+    @Test
+    public void isAvailable_withoutFingerprint_withoutFace_returnsFalse() {
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+        when(mFaceManager.isHardwareDetected()).thenReturn(false);
+
+        assertThat(mFingerprintStatusUtils.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_withoutFingerprint_withFace_returnsFalse() {
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+
+        assertThat(mFingerprintStatusUtils.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_withFingerprint_withoutFace_returnsTrue() {
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(false);
+
+        assertThat(mFingerprintStatusUtils.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void isAvailable_withFingerprint_withFace_returnsFalse() {
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+
+        assertThat(mFingerprintStatusUtils.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void getDisabledAdmin_whenFingerprintDisabled_returnsEnforcedAdmin() {
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+                .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
+
+        final RestrictedLockUtils.EnforcedAdmin admin =
+                mFingerprintStatusUtils.getDisablingAdmin();
+
+        assertThat(admin).isEqualTo(new RestrictedLockUtils.EnforcedAdmin(
+                COMPONENT_NAME, UserManager.DISALLOW_BIOMETRIC, USER_HANDLE));
+    }
+
+    @Test
+    public void getDisabledAdmin_withFingerprintEnabled_returnsNull() {
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+        assertThat(mFingerprintStatusUtils.getDisablingAdmin()).isNull();
+    }
+
+    @Test
+    public void getSummary_whenNotEnrolled_returnsSummaryNone() {
+        when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+
+        assertThat(mFingerprintStatusUtils.getSummary())
+                .isEqualTo(ResourcesUtils.getResourcesString(
+                        mApplicationContext,
+                        "security_settings_fingerprint_preference_summary_none"));
+    }
+
+    @Test
+    public void getSummary_whenEnrolled_returnsSummary() {
+        final int enrolledFingerprintsCount = 2;
+        final int stringResId = ResourcesUtils.getResourcesId(
+                ApplicationProvider.getApplicationContext(), "plurals",
+                "security_settings_fingerprint_preference_summary");
+        final String summary = mApplicationContext.getResources().getQuantityString(
+                stringResId, enrolledFingerprintsCount /* quantity */,
+                enrolledFingerprintsCount /* formatArgs */);
+
+        when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(true);
+        when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(
+                createFingerprintList(enrolledFingerprintsCount));
+
+        assertThat(mFingerprintStatusUtils.getSummary()).isEqualTo(summary);
+    }
+
+    @Test
+    public void getSettingsClassName_whenNotEnrolled_returnsFingerprintEnrollInduction() {
+        when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false);
+
+        assertThat(mFingerprintStatusUtils.getSettingsClassName())
+                .isEqualTo(FingerprintEnrollIntroduction.class.getName());
+    }
+
+    @Test
+    public void getSettingsClassName_whenEnrolled_returnsFingerprintSettings() {
+        when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(true);
+
+        assertThat(mFingerprintStatusUtils.getSettingsClassName())
+                .isEqualTo(FingerprintSettings.class.getName());
+    }
+
+    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;
+    }
+}