Fix flicker of “touch to unlock anytime” toggle

Fixes flicker of toggle by setting not visible when launching confirm
pin/pattern/password or enrollment prior to displaying
FingerprintSettings. Also cleans up FingerprintSettings and
security_settings_fingerprint.xml to better separate SFPS and non-SFPS
logic and rename methods for clarity

Test: (manual) navigate to sfps fp settings and observe toggle doesn’t flicker
Test: make RunSettingsRoboTests ROBOTEST_FILTER=FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest
Test: make RunSettingsRoboTests ROBOTEST_FILTER=FingerprintSettingsUnlockCategoryControllerTest
Fixes: 263843645
Change-Id: Ide3a666fc31b926ac14645dc22d090f77d81f901
diff --git a/res/xml/security_settings_fingerprint.xml b/res/xml/security_settings_fingerprint.xml
index a4ce545..0156ef9 100644
--- a/res/xml/security_settings_fingerprint.xml
+++ b/res/xml/security_settings_fingerprint.xml
@@ -20,9 +20,20 @@
     android:title="@string/security_settings_fingerprint_preference_title">
 
     <PreferenceCategory
+        android:key="security_settings_fingerprints_enrolled"
+        settings:controller="com.android.settings.biometrics.fingerprint.FingerprintsEnrolledCategoryPreferenceController">
+    </PreferenceCategory>
+
+    <androidx.preference.Preference
+        android:key="key_fingerprint_add"
+        android:title="@string/fingerprint_add_title"
+        android:icon="@drawable/ic_add_24dp"/>
+
+    <PreferenceCategory
         android:key="security_settings_fingerprint_unlock_category"
         android:title="@string/security_settings_fingerprint_settings_preferences_category"
-        settings:controller="com.android.settings.biometrics.fingerprint.FingerprintUnlockCategoryPreferenceController">
+        settings:controller="com.android.settings.biometrics.fingerprint.FingerprintUnlockCategoryController"
+        settings:isPreferenceVisible="false">
 
         <com.android.settingslib.RestrictedSwitchPreference
             android:key="security_settings_require_screen_on_to_auth"
@@ -32,4 +43,8 @@
             settings:controller="com.android.settings.biometrics.fingerprint.FingerprintSettingsRequireScreenOnToAuthPreferenceController" />
     </PreferenceCategory>
 
+    <PreferenceCategory
+        android:key="security_settings_fingerprint_footer">
+    </PreferenceCategory>
+
 </PreferenceScreen>
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index 40a719a..a5e5f57 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -171,8 +171,12 @@
         private static final String KEY_IS_ENROLLING = "is_enrolled";
         private static final String KEY_REQUIRE_SCREEN_ON_TO_AUTH =
                 "security_settings_require_screen_on_to_auth";
+        private static final String KEY_FINGERPRINTS_ENROLLED_CATEGORY =
+                "security_settings_fingerprints_enrolled";
         private static final String KEY_FINGERPRINT_UNLOCK_CATEGORY =
                 "security_settings_fingerprint_unlock_category";
+        private static final String KEY_FINGERPRINT_UNLOCK_FOOTER =
+                "security_settings_fingerprint_footer";
 
         private static final int MSG_REFRESH_FINGERPRINT_TEMPLATES = 1000;
         private static final int MSG_FINGER_AUTH_SUCCESS = 1001;
@@ -189,10 +193,15 @@
         protected static final boolean DEBUG = false;
 
         private List<AbstractPreferenceController> mControllers;
+        private FingerprintUnlockCategoryController
+                mFingerprintUnlockCategoryPreferenceController;
         private FingerprintSettingsRequireScreenOnToAuthPreferenceController
                 mRequireScreenOnToAuthPreferenceController;
+        private Preference mAddFingerprintPreference;
         private RestrictedSwitchPreference mRequireScreenOnToAuthPreference;
+        private PreferenceCategory mFingerprintsEnrolledCategory;
         private PreferenceCategory mFingerprintUnlockCategory;
+        private PreferenceCategory mFingerprintUnlockFooter;
 
         private FingerprintManager mFingerprintManager;
         private FingerprintUpdater mFingerprintUpdater;
@@ -259,9 +268,6 @@
                     }
 
                     private void updateDialog() {
-                        if (isSfps()) {
-                            setRequireScreenOnToAuthVisibility();
-                        }
                         RenameDialog renameDialog = (RenameDialog) getFragmentManager().
                                 findFragmentByTag(RenameDialog.class.getName());
                         if (renameDialog != null) {
@@ -277,7 +283,8 @@
                     case MSG_REFRESH_FINGERPRINT_TEMPLATES:
                         removeFingerprintPreference(msg.arg1);
                         updateAddPreference();
-                        retryFingerprint();
+                        updateFingerprintUnlockCategoryVisibility();
+                        updatePreferences();
                         break;
                     case MSG_FINGER_AUTH_SUCCESS:
                         highlightFingerprintItem(msg.arg1);
@@ -423,6 +430,9 @@
                     addFirstFingerprint(null);
                 }
             }
+            final PreferenceScreen root = getPreferenceScreen();
+            root.removeAll();
+            addPreferencesFromResource(getPreferenceScreenResId());
             updateFooterColumns(activity);
         }
 
@@ -512,48 +522,33 @@
          */
         private PreferenceScreen createPreferenceHierarchy() {
             PreferenceScreen root = getPreferenceScreen();
-            if (root != null) {
-                root.removeAll();
-            }
-            final String fpPrefKey = addFingerprintItemPreferences(root);
-            if (isSfps()) {
-                scrollToPreference(fpPrefKey);
-            }
-            addPreferencesFromResource(getPreferenceScreenResId());
-            mRequireScreenOnToAuthPreference = findPreference(KEY_REQUIRE_SCREEN_ON_TO_AUTH);
-            mFingerprintUnlockCategory = findPreference(KEY_FINGERPRINT_UNLOCK_CATEGORY);
-            for (AbstractPreferenceController controller : mControllers) {
-                ((FingerprintSettingsPreferenceController) controller).setUserId(mUserId);
-            }
-            mRequireScreenOnToAuthPreference.setChecked(
-                    mRequireScreenOnToAuthPreferenceController.isChecked());
-            mRequireScreenOnToAuthPreference.setOnPreferenceChangeListener(
-                    (preference, newValue) -> {
-                        boolean isChecked = ((SwitchPreference) preference).isChecked();
-                        mRequireScreenOnToAuthPreferenceController.setChecked(!isChecked);
-                        return true;
-                    });
-            mFingerprintUnlockCategory.setVisible(false);
-            if (isSfps()) {
-                setRequireScreenOnToAuthVisibility();
-            }
+            addFingerprintPreferences(root);
             setPreferenceScreen(root);
             return root;
         }
 
-        private void setRequireScreenOnToAuthVisibility() {
-            int fingerprintsEnrolled = mFingerprintManager.getEnrolledFingerprints(mUserId).size();
-            final boolean removalInProgress = mRemovalSidecar.inProgress();
-            // Removing last remaining fingerprint
-            if (fingerprintsEnrolled == 0 && removalInProgress) {
-                mFingerprintUnlockCategory.setVisible(false);
-            } else {
-                mFingerprintUnlockCategory.setVisible(true);
+        private void addFingerprintPreferences(PreferenceGroup root) {
+            final String fpPrefKey = addFingerprintItemPreferences(root);
+            if (isSfps()) {
+                scrollToPreference(fpPrefKey);
+                addFingerprintUnlockCategory();
             }
+            for (AbstractPreferenceController controller : mControllers) {
+                if (controller instanceof FingerprintSettingsPreferenceController) {
+                    ((FingerprintSettingsPreferenceController) controller).setUserId(mUserId);
+                } else if (controller instanceof FingerprintUnlockCategoryController) {
+                    ((FingerprintUnlockCategoryController) controller).setUserId(mUserId);
+                }
+            }
+            createFooterPreference(root);
         }
 
         private String addFingerprintItemPreferences(PreferenceGroup root) {
-            root.removeAll();
+            mFingerprintsEnrolledCategory = findPreference(KEY_FINGERPRINTS_ENROLLED_CATEGORY);
+            if (mFingerprintsEnrolledCategory != null) {
+                mFingerprintsEnrolledCategory.removeAll();
+            }
+
             String keyToReturn = KEY_FINGERPRINT_ADD;
             final List<Fingerprint> items = mFingerprintManager.getEnrolledFingerprints(mUserId);
             final int fingerprintCount = items.size();
@@ -576,22 +571,46 @@
                 if (mFingerprintsRenaming.containsKey(item.getBiometricId())) {
                     pref.setTitle(mFingerprintsRenaming.get(item.getBiometricId()));
                 }
-                root.addPreference(pref);
+                mFingerprintsEnrolledCategory.addPreference(pref);
                 pref.setOnPreferenceChangeListener(this);
             }
-
-            Preference addPreference = new Preference(root.getContext());
-            addPreference.setKey(KEY_FINGERPRINT_ADD);
-            addPreference.setTitle(R.string.fingerprint_add_title);
-            addPreference.setIcon(R.drawable.ic_add_24dp);
-            root.addPreference(addPreference);
-            addPreference.setOnPreferenceChangeListener(this);
-            updateAddPreference();
-            createFooterPreference(root);
-
+            mAddFingerprintPreference = findPreference(KEY_FINGERPRINT_ADD);
+            setupAddFingerprintPreference();
             return keyToReturn;
         }
 
+        private void setupAddFingerprintPreference() {
+            mAddFingerprintPreference.setOnPreferenceChangeListener(this);
+            updateAddPreference();
+        }
+
+        private void addFingerprintUnlockCategory() {
+            mFingerprintUnlockCategory = findPreference(KEY_FINGERPRINT_UNLOCK_CATEGORY);
+            setupFingerprintUnlockCategoryPreferences();
+            updateFingerprintUnlockCategoryVisibility();
+        }
+
+        private void updateFingerprintUnlockCategoryVisibility() {
+            final boolean mFingerprintUnlockCategoryAvailable =
+                    mFingerprintUnlockCategoryPreferenceController.isAvailable();
+            if (mFingerprintUnlockCategory.isVisible() != mFingerprintUnlockCategoryAvailable) {
+                mFingerprintUnlockCategory.setVisible(
+                        mFingerprintUnlockCategoryAvailable);
+            }
+        }
+
+        private void setupFingerprintUnlockCategoryPreferences() {
+            mRequireScreenOnToAuthPreference = findPreference(KEY_REQUIRE_SCREEN_ON_TO_AUTH);
+            mRequireScreenOnToAuthPreference.setChecked(
+                    mRequireScreenOnToAuthPreferenceController.isChecked());
+            mRequireScreenOnToAuthPreference.setOnPreferenceChangeListener(
+                    (preference, newValue) -> {
+                        final boolean isChecked = ((SwitchPreference) preference).isChecked();
+                        mRequireScreenOnToAuthPreferenceController.setChecked(!isChecked);
+                        return true;
+                    });
+        }
+
         private void updateAddPreference() {
             if (getActivity() == null) {
                 return; // Activity went away
@@ -612,8 +631,8 @@
             final boolean removalInProgress = mRemovalSidecar.inProgress();
             CharSequence maxSummary = tooMany ?
                     getContext().getString(R.string.fingerprint_add_max, max) : "";
-            addPreference.setSummary(maxSummary);
-            addPreference.setEnabled(!tooMany && !removalInProgress && mToken != null);
+            mAddFingerprintPreference.setSummary(maxSummary);
+            mAddFingerprintPreference.setEnabled(!tooMany && !removalInProgress && mToken != null);
         }
 
         private void createFooterPreference(PreferenceGroup root) {
@@ -621,6 +640,10 @@
             if (context == null) {
                 return;
             }
+            mFingerprintUnlockFooter = findPreference(KEY_FINGERPRINT_UNLOCK_FOOTER);
+            if (mFingerprintUnlockFooter != null) {
+                mFingerprintUnlockFooter.removeAll();
+            }
             for (int i = 0; i < mFooterColumns.size(); ++i) {
                 final FooterColumn column = mFooterColumns.get(i);
                 final FooterPreference footer = new FooterPreference.Builder(context)
@@ -634,7 +657,7 @@
                         footer.setLearnMoreText(column.mLearnMoreOverrideText);
                     }
                 }
-                root.addPreference(footer);
+                mFingerprintUnlockFooter.addPreference(footer);
             }
         }
 
@@ -815,11 +838,17 @@
 
         private List<AbstractPreferenceController> buildPreferenceControllers(Context context) {
             final List<AbstractPreferenceController> controllers = new ArrayList<>();
+            mFingerprintUnlockCategoryPreferenceController =
+                    new FingerprintUnlockCategoryController(
+                            context,
+                            KEY_FINGERPRINT_UNLOCK_CATEGORY
+                    );
             mRequireScreenOnToAuthPreferenceController =
                     new FingerprintSettingsRequireScreenOnToAuthPreferenceController(
                             context,
                             KEY_REQUIRE_SCREEN_ON_TO_AUTH
                     );
+            controllers.add(mFingerprintUnlockCategoryPreferenceController);
             controllers.add(mRequireScreenOnToAuthPreferenceController);
             return controllers;
         }
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceController.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceController.java
index 52e6d13..87396dd 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceController.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceController.java
@@ -94,7 +94,7 @@
                 && mFingerprintManager.isHardwareDetected()
                 && mFingerprintManager.isPowerbuttonFps()) {
             return mFingerprintManager.hasEnrolledTemplates(getUserId())
-                    ? AVAILABLE : DISABLED_DEPENDENT_SETTING;
+                    ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
         } else {
             return UNSUPPORTED_ON_DEVICE;
         }
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintUnlockCategoryController.java b/src/com/android/settings/biometrics/fingerprint/FingerprintUnlockCategoryController.java
new file mode 100644
index 0000000..674a0df
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintUnlockCategoryController.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 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.fingerprint.FingerprintManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.Utils;
+import com.android.settings.core.BasePreferenceController;
+
+/**
+ * Preference controller that controls the fingerprint unlock features to be shown / be hidden.
+ */
+public class FingerprintUnlockCategoryController extends BasePreferenceController {
+    private static final String TAG = "FingerprintUnlockCategoryPreferenceController";
+
+    private int mUserId;
+    @VisibleForTesting
+    protected FingerprintManager mFingerprintManager;
+
+    public FingerprintUnlockCategoryController(Context context, String key) {
+        super(context, key);
+        mFingerprintManager = Utils.getFingerprintManagerOrNull(context);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        if (mFingerprintManager != null
+                && mFingerprintManager.isHardwareDetected()
+                && mFingerprintManager.isPowerbuttonFps()) {
+            return mFingerprintManager.hasEnrolledTemplates(getUserId())
+                    ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+        } else {
+            return UNSUPPORTED_ON_DEVICE;
+        }
+    }
+
+    public void setUserId(int userId) {
+        mUserId = userId;
+    }
+
+    protected int getUserId() {
+        return mUserId;
+    }
+}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintsEnrolledCategoryPreferenceController.java b/src/com/android/settings/biometrics/fingerprint/FingerprintsEnrolledCategoryPreferenceController.java
new file mode 100644
index 0000000..53d5379
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintsEnrolledCategoryPreferenceController.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 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.fingerprint.FingerprintManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.Utils;
+import com.android.settings.core.BasePreferenceController;
+
+/**
+ * Preference controller that controls the enrolled fingerprints to be shown / be hidden.
+ */
+public class FingerprintsEnrolledCategoryPreferenceController extends BasePreferenceController {
+    private static final String TAG = "FingerprintsEnrolledCategoryPreferenceController";
+
+    private int mUserId;
+    @VisibleForTesting
+    protected FingerprintManager mFingerprintManager;
+
+    public FingerprintsEnrolledCategoryPreferenceController(Context context, String key) {
+        super(context, key);
+        mFingerprintManager = Utils.getFingerprintManagerOrNull(context);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        if (mFingerprintManager != null
+                && mFingerprintManager.isHardwareDetected()) {
+            return mFingerprintManager.hasEnrolledTemplates(getUserId())
+                    ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+        } else {
+            return UNSUPPORTED_ON_DEVICE;
+        }
+    }
+
+    public void setUserId(int userId) {
+        mUserId = userId;
+    }
+
+    protected int getUserId() {
+        return mUserId;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest.java
index b6df62e..ebfa6d5 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest.java
@@ -17,7 +17,7 @@
 package com.android.settings.biometrics.fingerprint;
 
 import static com.android.settings.core.BasePreferenceController.AVAILABLE;
-import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
 import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -103,15 +103,15 @@
     }
 
     @Test
-    public void isAvailable_isDisabled_whenSfpsHardwareDetected_AndNoEnrolledFingerprints() {
+    public void isUnavailable_isDisabled_whenSfpsHardwareDetected_AndNoEnrolledFingerprints() {
         assertThat(mController.isAvailable()).isEqualTo(false);
         assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
         configure_hardwareDetected_isSfps_hasEnrolledTemplates(
                 true /* isHardwareDetected */,
                 true /* isPowerbuttonFps */,
                 false /* hasEnrolledTemplates */);
-        assertThat(mController.isAvailable()).isEqualTo(true);
-        assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
+        assertThat(mController.isAvailable()).isEqualTo(false);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
     }
 
     @Test
@@ -122,7 +122,7 @@
                 false /* isHardwareDetected */,
                 true /* isPowerbuttonFps */,
                 true /* hasEnrolledTemplates */);
-        assertThat(mController.isAvailable()).isFalse();
+        assertThat(mController.isAvailable()).isEqualTo(false);
         assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
     }
 
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsUnlockCategoryControllerTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsUnlockCategoryControllerTest.java
new file mode 100644
index 0000000..7b6a70e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsUnlockCategoryControllerTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2023 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.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.fingerprint.FingerprintManager;
+
+import com.android.settings.testutils.shadow.ShadowUtils;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowUtils.class})
+public class FingerprintSettingsUnlockCategoryControllerTest {
+
+    @Mock
+    private FingerprintManager mFingerprintManager;
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private RestrictedSwitchPreference mPreference;
+
+    private Context mContext;
+    private FingerprintSettingsRequireScreenOnToAuthPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        when(mContext.getSystemService(eq(Context.FINGERPRINT_SERVICE))).thenReturn(
+                mFingerprintManager);
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+
+        mController = spy(new FingerprintSettingsRequireScreenOnToAuthPreferenceController(mContext,
+                "test_key"));
+        ReflectionHelpers.setField(mController, "mFingerprintManager", mFingerprintManager);
+    }
+
+    @After
+    public void tearDown() {
+        ShadowUtils.reset();
+    }
+
+    @Test
+    public void isAvailable_isEnabled_whenSfpsHardwareDetected_AndHasEnrolledFingerprints() {
+        assertThat(mController.isAvailable()).isEqualTo(false);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+        configure_hardwareDetected_isSfps_hasEnrolledTemplates(
+                true /* isHardwareDetected */,
+                true /* isPowerbuttonFps */,
+                true /* hasEnrolledTemplates */);
+        assertThat(mController.isAvailable()).isEqualTo(true);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+    }
+
+    @Test
+    public void isUnavailable_isDisabled_whenSfpsHardwareDetected_AndNoEnrolledFingerprints() {
+        assertThat(mController.isAvailable()).isEqualTo(false);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+        configure_hardwareDetected_isSfps_hasEnrolledTemplates(
+                true /* isHardwareDetected */,
+                true /* isPowerbuttonFps */,
+                false /* hasEnrolledTemplates */);
+        assertThat(mController.isAvailable()).isEqualTo(false);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+    }
+
+    @Test
+    public void isUnavailable_whenHardwareNotDetected() {
+        assertThat(mController.isAvailable()).isFalse();
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+        configure_hardwareDetected_isSfps_hasEnrolledTemplates(
+                false /* isHardwareDetected */,
+                true /* isPowerbuttonFps */,
+                true /* hasEnrolledTemplates */);
+        assertThat(mController.isAvailable()).isEqualTo(false);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+    }
+
+    @Test
+    public void isUnavailable_onNonSfpsDevice() {
+        assertThat(mController.isAvailable()).isFalse();
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+        configure_hardwareDetected_isSfps_hasEnrolledTemplates(
+                true /* isHardwareDetected */,
+                false /* isPowerbuttonFps */,
+                true /* hasEnrolledTemplates */);
+        assertThat(mController.isAvailable()).isFalse();
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+    }
+
+    private void configure_hardwareDetected_isSfps_hasEnrolledTemplates(
+            boolean isHardwareDetected, boolean isPowerbuttonFps, boolean hasEnrolledTemplates) {
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(isHardwareDetected);
+        when(mFingerprintManager.isPowerbuttonFps()).thenReturn(isPowerbuttonFps);
+        when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(hasEnrolledTemplates);
+    }
+
+}