From 54d1cfdae0cefe758b80f06017dd8f0f847ff7c7 Mon Sep 17 00:00:00 2001 From: Grace Cheng Date: Thu, 23 Feb 2023 23:05:36 +0000 Subject: [PATCH] =?UTF-8?q?Fix=20flicker=20of=20=E2=80=9Ctouch=20to=20unlo?= =?UTF-8?q?ck=20anytime=E2=80=9D=20toggle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- res/xml/security_settings_fingerprint.xml | 17 ++- .../fingerprint/FingerprintSettings.java | 133 ++++++++++------- ...ireScreenOnToAuthPreferenceController.java | 2 +- .../FingerprintUnlockCategoryController.java | 60 ++++++++ ...sEnrolledCategoryPreferenceController.java | 59 ++++++++ ...creenOnToAuthPreferenceControllerTest.java | 10 +- ...tSettingsUnlockCategoryControllerTest.java | 135 ++++++++++++++++++ 7 files changed, 357 insertions(+), 59 deletions(-) create mode 100644 src/com/android/settings/biometrics/fingerprint/FingerprintUnlockCategoryController.java create mode 100644 src/com/android/settings/biometrics/fingerprint/FingerprintsEnrolledCategoryPreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsUnlockCategoryControllerTest.java diff --git a/res/xml/security_settings_fingerprint.xml b/res/xml/security_settings_fingerprint.xml index a4ce545a7ff..0156ef97ac6 100644 --- a/res/xml/security_settings_fingerprint.xml +++ b/res/xml/security_settings_fingerprint.xml @@ -19,10 +19,21 @@ xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/security_settings_fingerprint_preference_title"> + + + + + + settings:controller="com.android.settings.biometrics.fingerprint.FingerprintUnlockCategoryController" + settings:isPreferenceVisible="false"> + + + diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java index 40a719a35d4..a5e5f579c02 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java @@ -171,8 +171,12 @@ public class FingerprintSettings extends SubSettings { 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 @@ public class FingerprintSettings extends SubSettings { protected static final boolean DEBUG = false; private List 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 @@ public class FingerprintSettings extends SubSettings { } private void updateDialog() { - if (isSfps()) { - setRequireScreenOnToAuthVisibility(); - } RenameDialog renameDialog = (RenameDialog) getFragmentManager(). findFragmentByTag(RenameDialog.class.getName()); if (renameDialog != null) { @@ -277,7 +283,8 @@ public class FingerprintSettings extends SubSettings { 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 @@ public class FingerprintSettings extends SubSettings { addFirstFingerprint(null); } } + final PreferenceScreen root = getPreferenceScreen(); + root.removeAll(); + addPreferencesFromResource(getPreferenceScreenResId()); updateFooterColumns(activity); } @@ -512,48 +522,33 @@ public class FingerprintSettings extends SubSettings { */ 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 items = mFingerprintManager.getEnrolledFingerprints(mUserId); final int fingerprintCount = items.size(); @@ -576,22 +571,46 @@ public class FingerprintSettings extends SubSettings { 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 @@ public class FingerprintSettings extends SubSettings { 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 @@ public class FingerprintSettings extends SubSettings { 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 @@ public class FingerprintSettings extends SubSettings { footer.setLearnMoreText(column.mLearnMoreOverrideText); } } - root.addPreference(footer); + mFingerprintUnlockFooter.addPreference(footer); } } @@ -815,11 +838,17 @@ public class FingerprintSettings extends SubSettings { private List buildPreferenceControllers(Context context) { final List 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 52e6d135abc..87396dd91d5 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceController.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceController.java @@ -94,7 +94,7 @@ public class FingerprintSettingsRequireScreenOnToAuthPreferenceController && 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 00000000000..674a0dfa758 --- /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 00000000000..53d53797515 --- /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 b6df62eeff7..ebfa6d5d62d 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 @@ public class FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest { } @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 @@ public class FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest { 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 00000000000..7b6a70ed7ef --- /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); + } + +}