Merge "Refresh templates when fp removal fails" into main
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintRemoveSidecar.java b/src/com/android/settings/biometrics/fingerprint/FingerprintRemoveSidecar.java
index 73eccdc..2737d38 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintRemoveSidecar.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintRemoveSidecar.java
@@ -23,6 +23,7 @@
 import android.util.Log;
 
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.settings.core.InstrumentedFragment;
 
@@ -51,7 +52,8 @@
         }
     }
 
-    private FingerprintManager.RemovalCallback
+    @VisibleForTesting
+    FingerprintManager.RemovalCallback
             mRemoveCallback = new FingerprintManager.RemovalCallback() {
         @Override
         public void onRemovalSucceeded(Fingerprint fingerprint, int remaining) {
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index cb7d617..9a4e657 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -226,6 +226,7 @@
         private static final int MSG_FINGER_AUTH_FAIL = 1002;
         private static final int MSG_FINGER_AUTH_ERROR = 1003;
         private static final int MSG_FINGER_AUTH_HELP = 1004;
+        private static final int MSG_RELOAD_FINGERPRINT_TEMPLATES = 1005;
 
         private static final int CONFIRM_REQUEST = 101;
         @VisibleForTesting
@@ -313,6 +314,8 @@
                         if (activity != null) {
                             Toast.makeText(activity, errString, Toast.LENGTH_SHORT);
                         }
+                        mHandler.obtainMessage(MSG_RELOAD_FINGERPRINT_TEMPLATES)
+                                .sendToTarget();
                         updateDialog();
                     }
 
@@ -331,11 +334,7 @@
                 switch (msg.what) {
                     case MSG_REFRESH_FINGERPRINT_TEMPLATES:
                         removeFingerprintPreference(msg.arg1);
-                        updateAddPreference();
-                        if (isSfps()) {
-                            updateFingerprintUnlockCategoryVisibility();
-                        }
-                        updatePreferences();
+                        updatePreferencesAfterFingerprintRemoved();
                         break;
                     case MSG_FINGER_AUTH_SUCCESS:
                         highlightFingerprintItem(msg.arg1);
@@ -347,6 +346,9 @@
                     case MSG_FINGER_AUTH_ERROR:
                         handleError(msg.arg1 /* errMsgId */, (CharSequence) msg.obj /* errStr */);
                         break;
+                    case MSG_RELOAD_FINGERPRINT_TEMPLATES:
+                        updatePreferencesAfterFingerprintRemoved();
+                        break;
                     case MSG_FINGER_AUTH_HELP: {
                         // Not used
                     }
@@ -568,6 +570,7 @@
 
         protected void removeFingerprintPreference(int fingerprintId) {
             String name = genKey(fingerprintId);
+            Log.e(TAG, "removeFingerprintPreference : " + fingerprintId);
             Preference prefToRemove = findPreference(name);
             if (prefToRemove != null) {
                 if (!getPreferenceScreen().removePreference(prefToRemove)) {
@@ -692,6 +695,13 @@
                     });
         }
 
+        private void updatePreferencesAfterFingerprintRemoved() {
+            updateAddPreference();
+            if (isSfps()) {
+                updateFingerprintUnlockCategoryVisibility();
+            }
+        }
+
         private void updateAddPreference() {
             if (getActivity() == null) {
                 return; // Activity went away
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
index 4ef3223..a34b6de 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
@@ -36,6 +36,7 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
 
 import android.content.Context;
 import android.content.Intent;
@@ -44,11 +45,13 @@
 import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.Flags;
 import android.hardware.biometrics.SensorProperties;
+import android.hardware.fingerprint.Fingerprint;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.FingerprintSensorProperties;
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
 import android.os.Bundle;
 import android.os.CancellationSignal;
+import android.os.Looper;
 import android.os.UserHandle;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
@@ -59,6 +62,7 @@
 import androidx.fragment.app.FragmentActivity;
 import androidx.fragment.app.FragmentManager;
 import androidx.fragment.app.FragmentTransaction;
+import androidx.preference.Preference;
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.password.ChooseLockSettingsHelper;
@@ -87,6 +91,7 @@
 import org.robolectric.annotation.Config;
 
 import java.util.ArrayList;
+import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {ShadowSettingsPreferenceFragment.class, ShadowUtils.class, ShadowFragment.class,
@@ -120,6 +125,7 @@
             FingerprintManager.AuthenticationCallback.class);
 
     private FingerprintAuthenticateSidecar mFingerprintAuthenticateSidecar;
+    private FingerprintRemoveSidecar mFingerprintRemoveSidecar;
 
     @Before
     public void setUp() {
@@ -216,7 +222,7 @@
                 1,
                 UserHandle.of(GUEST_USER_ID).getIdentifier());
 
-        setUpFragment(false, GUEST_USER_ID, TYPE_POWER_BUTTON);
+        setUpFragment(false, GUEST_USER_ID, TYPE_POWER_BUTTON, 1);
 
         final RestrictedSwitchPreference requireScreenOnToAuthPreference = mFragment.findPreference(
                 KEY_REQUIRE_SCREEN_ON_TO_AUTH);
@@ -224,11 +230,15 @@
     }
 
     private void setUpFragment(boolean showChooseLock) {
-        setUpFragment(showChooseLock, PRIMARY_USER_ID, TYPE_UDFPS_OPTICAL);
+        setUpFragment(showChooseLock, PRIMARY_USER_ID, TYPE_UDFPS_OPTICAL, 1);
+    }
+
+    private void setUpFragment(boolean showChooseLock, int maxFingerprints) {
+        setUpFragment(showChooseLock, PRIMARY_USER_ID, TYPE_UDFPS_OPTICAL, maxFingerprints);
     }
 
     private void setUpFragment(boolean showChooseLock, int userId,
-            @FingerprintSensorProperties.SensorType int sensorType) {
+            @FingerprintSensorProperties.SensorType int sensorType, int maxFingerprints) {
         ShadowUserManager.getShadow().addProfile(new UserInfo(userId, "", 0));
 
         Intent intent = new Intent();
@@ -250,9 +260,13 @@
         doReturn(mFingerprintAuthenticateSidecar).when(fragmentManager).findFragmentByTag(
                 "authenticate_sidecar");
 
+        mFingerprintRemoveSidecar = new FingerprintRemoveSidecar();
+        doReturn(mFingerprintRemoveSidecar).when(fragmentManager).findFragmentByTag(
+                "removal_sidecar");
+
         doNothing().when(mFragment).startActivityForResult(any(Intent.class), anyInt());
 
-        setSensor(sensorType);
+        setSensor(sensorType, maxFingerprints);
 
         // Start fragment
         mFragment.onAttach(mContext);
@@ -269,12 +283,38 @@
         assertThat(mFragment.isVisible()).isTrue();
     }
 
-    private void setSensor(@FingerprintSensorProperties.SensorType int sensorType) {
+    @Ignore("b/353726774")
+    @Test
+    public void testAddButtonWorksAfterRemovalError() {
+        final Fingerprint fingerprint = new Fingerprint("Test", 0, 0);
+        doReturn(List.of(fingerprint)).when(mFingerprintManager).getEnrolledFingerprints(anyInt());
+        setUpFragment(false, 5);
+        shadowOf(Looper.getMainLooper()).idle();
+        final Preference addPref = mFragment.findPreference("key_fingerprint_add");
+        final FingerprintSettings.FingerprintPreference fpPref =
+                mFragment.findPreference("key_fingerprint_item_0");
+        assertThat(fpPref).isNotNull();
+        assertThat(addPref).isNotNull();
+        assertThat(addPref.isEnabled()).isTrue();
+
+        mFingerprintRemoveSidecar.setListener(mFragment.mRemovalListener);
+        mFragment.deleteFingerPrint(fingerprint);
+        verify(mFingerprintManager).remove(any(), anyInt(), any());
+        assertThat(addPref.isEnabled()).isFalse();
+
+        mFingerprintRemoveSidecar.mRemoveCallback.onRemovalError(fingerprint, 0, "failure");
+
+        shadowOf(Looper.getMainLooper()).idle();
+        assertThat(addPref.isEnabled()).isTrue();
+    }
+
+    private void setSensor(@FingerprintSensorProperties.SensorType int sensorType,
+            int maxFingerprints) {
         final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
         props.add(new FingerprintSensorPropertiesInternal(
                 0 /* sensorId */,
                 SensorProperties.STRENGTH_STRONG,
-                1 /* maxEnrollmentsPerUser */,
+                maxFingerprints /* maxEnrollmentsPerUser */,
                 new ArrayList<ComponentInfoInternal>(),
                 sensorType,
                 true /* resetLockoutRequiresHardwareAuthToken */));