Merge "Tests for SUW in work mode" into tm-qpr-dev
diff --git a/src/com/android/settings/biometrics/MultiBiometricEnrollHelper.java b/src/com/android/settings/biometrics/MultiBiometricEnrollHelper.java
index a994b95..d85f446 100644
--- a/src/com/android/settings/biometrics/MultiBiometricEnrollHelper.java
+++ b/src/com/android/settings/biometrics/MultiBiometricEnrollHelper.java
@@ -24,8 +24,11 @@
 import androidx.annotation.NonNull;
 import androidx.fragment.app.FragmentActivity;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.password.ChooseLockSettingsHelper;
 
+import java.util.function.Function;
+
 /**
  * Helper for {@link BiometricEnrollActivity} when multiple sensors exist on a device.
  */
@@ -45,14 +48,39 @@
     private final int mUserId;
     private final boolean mRequestEnrollFace;
     private final boolean mRequestEnrollFingerprint;
+    private final FingerprintManager mFingerprintManager;
+    private final FaceManager mFaceManager;
+    private final Intent mFingerprintEnrollIntroductionIntent;
+    private final Intent mFaceEnrollIntroductionIntent;
+    private Function<Long, byte[]> mGatekeeperHatSupplier;
 
+    @VisibleForTesting
     MultiBiometricEnrollHelper(@NonNull FragmentActivity activity, int userId,
-            boolean enrollFace, boolean enrollFingerprint, long gkPwHandle) {
+            boolean enrollFace, boolean enrollFingerprint, long gkPwHandle,
+            FingerprintManager fingerprintManager,
+            FaceManager faceManager, Intent fingerprintEnrollIntroductionIntent,
+            Intent faceEnrollIntroductionIntent, Function<Long, byte[]> gatekeeperHatSupplier) {
         mActivity = activity;
         mUserId = userId;
         mGkPwHandle = gkPwHandle;
         mRequestEnrollFace = enrollFace;
         mRequestEnrollFingerprint = enrollFingerprint;
+        mFingerprintManager = fingerprintManager;
+        mFaceManager = faceManager;
+        mFingerprintEnrollIntroductionIntent = fingerprintEnrollIntroductionIntent;
+        mFaceEnrollIntroductionIntent = faceEnrollIntroductionIntent;
+        mGatekeeperHatSupplier = gatekeeperHatSupplier;
+    }
+
+    MultiBiometricEnrollHelper(@NonNull FragmentActivity activity, int userId,
+            boolean enrollFace, boolean enrollFingerprint, long gkPwHandle) {
+        this(activity, userId, enrollFace, enrollFingerprint, gkPwHandle,
+                activity.getSystemService(FingerprintManager.class),
+                activity.getSystemService(FaceManager.class),
+                BiometricUtils.getFingerprintIntroIntent(activity, activity.getIntent()),
+                BiometricUtils.getFaceIntroIntent(activity, activity.getIntent()),
+                (challenge) ->  BiometricUtils.requestGatekeeperHat(activity, gkPwHandle,
+                        userId, challenge));
     }
 
     void startNextStep() {
@@ -67,45 +95,39 @@
     }
 
     private void launchFaceEnroll() {
-        final FaceManager faceManager = mActivity.getSystemService(FaceManager.class);
-        faceManager.generateChallenge(mUserId, (sensorId, userId, challenge) -> {
-            final byte[] hardwareAuthToken = BiometricUtils.requestGatekeeperHat(mActivity,
-                    mGkPwHandle, mUserId, challenge);
-            final Intent faceIntent = BiometricUtils.getFaceIntroIntent(mActivity,
-                    mActivity.getIntent());
-            faceIntent.putExtra(BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, sensorId);
-            faceIntent.putExtra(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge);
-            BiometricUtils.launchEnrollForResult(mActivity, faceIntent, REQUEST_FACE_ENROLL,
-                    hardwareAuthToken, mGkPwHandle, mUserId);
+        mFaceManager.generateChallenge(mUserId, (sensorId, userId, challenge) -> {
+            final byte[] hardwareAuthToken = mGatekeeperHatSupplier.apply(challenge);
+            mFaceEnrollIntroductionIntent.putExtra(
+                    BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, sensorId);
+            mFaceEnrollIntroductionIntent.putExtra(
+                    BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge);
+            BiometricUtils.launchEnrollForResult(mActivity, mFaceEnrollIntroductionIntent,
+                    REQUEST_FACE_ENROLL, hardwareAuthToken, mGkPwHandle, mUserId);
         });
     }
 
     private void launchFingerprintEnroll() {
-        final FingerprintManager fingerprintManager = mActivity
-                .getSystemService(FingerprintManager.class);
-        fingerprintManager.generateChallenge(mUserId, ((sensorId, userId, challenge) -> {
-            final byte[] hardwareAuthToken = BiometricUtils.requestGatekeeperHat(mActivity,
-                    mGkPwHandle, mUserId, challenge);
-            final Intent intent = BiometricUtils.getFingerprintIntroIntent(mActivity,
-                    mActivity.getIntent());
-            intent.putExtra(BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, sensorId);
-            intent.putExtra(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge);
+        mFingerprintManager.generateChallenge(mUserId, ((sensorId, userId, challenge) -> {
+            final byte[] hardwareAuthToken = mGatekeeperHatSupplier.apply(challenge);
+            mFingerprintEnrollIntroductionIntent.putExtra(
+                    BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, sensorId);
+            mFingerprintEnrollIntroductionIntent.putExtra(
+                    BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge);
             if (mRequestEnrollFace) {
                 // Give FingerprintEnroll a pendingIntent pointing to face enrollment, so that it
                 // can be started when user skips or finishes fingerprint enrollment.
                 // FLAG_UPDATE_CURRENT ensures it is launched with the most recent values.
-                final Intent faceIntent = BiometricUtils.getFaceIntroIntent(mActivity,
-                        mActivity.getIntent());
-                faceIntent.putExtra(Intent.EXTRA_USER_ID, mUserId);
-                faceIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
-                        mGkPwHandle);
+                mFaceEnrollIntroductionIntent.putExtra(Intent.EXTRA_USER_ID, mUserId);
+                mFaceEnrollIntroductionIntent.putExtra(
+                        ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, mGkPwHandle);
                 final PendingIntent faceAfterFp = PendingIntent.getActivity(mActivity,
-                        0 /* requestCode */, faceIntent,
+                        0 /* requestCode */, mFaceEnrollIntroductionIntent,
                         PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
-                intent.putExtra(EXTRA_ENROLL_AFTER_FINGERPRINT, faceAfterFp);
+                mFingerprintEnrollIntroductionIntent.putExtra(EXTRA_ENROLL_AFTER_FINGERPRINT,
+                        faceAfterFp);
             }
-            BiometricUtils.launchEnrollForResult(mActivity, intent, REQUEST_FINGERPRINT_ENROLL,
-                    hardwareAuthToken, mGkPwHandle, mUserId);
+            BiometricUtils.launchEnrollForResult(mActivity, mFingerprintEnrollIntroductionIntent,
+                    REQUEST_FINGERPRINT_ENROLL, hardwareAuthToken, mGkPwHandle, mUserId);
         }));
     }
 }
diff --git a/tests/robotests/src/com/android/settings/biometrics/MultiBiometricEnrollHelperTest.java b/tests/robotests/src/com/android/settings/biometrics/MultiBiometricEnrollHelperTest.java
new file mode 100644
index 0000000..03b3b48
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/biometrics/MultiBiometricEnrollHelperTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.robolectric.Shadows.shadowOf;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.hardware.face.FaceManager;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.RemoteException;
+
+import androidx.fragment.app.FragmentActivity;
+
+import com.android.settings.biometrics.face.FaceEnrollIntroduction;
+import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
+import com.android.settings.password.ChooseLockSettingsHelper;
+import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
+import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
+import com.android.settings.testutils.shadow.ShadowSensorPrivacyManager;
+import com.android.settings.testutils.shadow.ShadowUserManager;
+import com.android.settings.testutils.shadow.ShadowUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.android.controller.ActivityController;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowPackageManager;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        ShadowUtils.class,
+        ShadowUserManager.class,
+        ShadowRestrictedLockUtilsInternal.class,
+        ShadowSensorPrivacyManager.class,
+        ShadowLockPatternUtils.class
+})
+public class MultiBiometricEnrollHelperTest {
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+
+    @Mock
+    private FragmentActivity mActivity;
+    @Mock
+    private FingerprintManager mFingerprintManager;
+    @Mock
+    private FaceManager mFaceManager;
+
+    private Context mContext;
+
+    @Captor
+    private ArgumentCaptor<FingerprintManager.GenerateChallengeCallback> mFingerprintCaptor;
+
+    private final int mUserId = 10;
+    private final long mChallenge = 0L;
+    private final int mSensorId = 0;
+    private final long mGkPwHandle = 0L;
+
+    private MultiBiometricEnrollHelper mMultiBiometricEnrollHelper;
+    private Intent mFingerprintIntent;
+    private Intent mFaceIntent;
+
+    @Before
+    public void setUp() throws RemoteException {
+        mContext = RuntimeEnvironment.application.getApplicationContext();
+        mFingerprintIntent = new Intent(mContext, FingerprintEnrollIntroduction.class);
+        mFaceIntent = new Intent(mContext, FaceEnrollIntroduction.class);
+        mMultiBiometricEnrollHelper = new MultiBiometricEnrollHelper(
+                mActivity, mUserId, true /* enrollFace */, true /* enrollFingerprint */,
+                mGkPwHandle, mFingerprintManager, mFaceManager, mFingerprintIntent, mFaceIntent,
+                (challenge) -> null);
+    }
+
+    @Test
+    public void launchFaceAndFingerprintEnroll_testFingerprint() {
+        mMultiBiometricEnrollHelper.startNextStep();
+
+        verify(mFingerprintManager).generateChallenge(anyInt(), mFingerprintCaptor.capture());
+
+        FingerprintManager.GenerateChallengeCallback generateChallengeCallback =
+                mFingerprintCaptor.getValue();
+        generateChallengeCallback.onChallengeGenerated(mSensorId, mUserId, mChallenge);
+
+        assertThat(mFingerprintIntent.hasExtra(
+                MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FINGERPRINT)).isTrue();
+        assertThat(mFingerprintIntent.getExtra(BiometricEnrollBase.EXTRA_KEY_SENSOR_ID,
+                -1 /* defaultValue */)).isEqualTo(mSensorId);
+        assertThat(mFingerprintIntent.getExtra(BiometricEnrollBase.EXTRA_KEY_CHALLENGE,
+                -1 /* defaultValue */)).isEqualTo(mChallenge);
+        assertThat(mFingerprintIntent.getExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
+                -1 /* defaultValue */)).isEqualTo(mGkPwHandle);
+    }
+
+    @Test
+    public void launchFaceAndFingerprintEnroll_testFace() {
+        mMultiBiometricEnrollHelper.startNextStep();
+
+        verify(mFingerprintManager).generateChallenge(anyInt(), mFingerprintCaptor.capture());
+
+        FingerprintManager.GenerateChallengeCallback fingerprintGenerateChallengeCallback =
+                mFingerprintCaptor.getValue();
+        fingerprintGenerateChallengeCallback.onChallengeGenerated(
+                mSensorId, mUserId, mChallenge);
+
+        assertThat(mFaceIntent.getExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
+                -1 /* defaultValue */)).isEqualTo(mGkPwHandle);
+        assertThat(mFaceIntent.getIntExtra(Intent.EXTRA_USER_ID, -1 /* defaultValue */))
+                .isEqualTo(mUserId);
+
+        final ShadowPackageManager shadowPackageManager = shadowOf(mContext.getPackageManager());
+        shadowPackageManager.setSystemFeature(PackageManager.FEATURE_FACE, true);
+        ShadowUtils.setFaceManager(mFaceManager);
+        ActivityController.of(new FaceEnrollIntroduction(), mFaceIntent)
+                .create(mFaceIntent.getExtras()).get();
+
+        verify(mFaceManager).generateChallenge(eq(mUserId), any());
+    }
+}