Move CredentialEnrolledTests to regular CTS

Bug: 152240892
Test: atest CtsBiometricsTestCases
Change-Id: I5434526c856bbc794823122d11262be9095c420f
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 611e911..721410a 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1435,27 +1435,6 @@
         </activity>
 
         <activity
-            android:name=".biometrics.CredentialEnrolledTests"
-            android:configChanges="keyboardHidden|orientation|screenSize"
-            android:exported="true"
-            android:label="@string/biometric_test_credential_enrolled_label" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-
-            <meta-data android:name="test_category" android:value="@string/biometric_test_category_credential" />
-            <meta-data android:name="test_parent"
-                       android:value="com.android.cts.verifier.biometrics.BiometricTestList" />
-            <meta-data android:name="test_required_features" android:value="android.software.secure_lock_screen" />
-            <meta-data android:name="test_excluded_features"
-                       android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
-            <meta-data android:name="display_mode"
-                       android:value="multi_display_mode" />
-        </activity>
-
-        <activity
             android:name=".biometrics.CredentialCryptoTests"
             android:configChanges="keyboardHidden|orientation|screenSize"
             android:exported="true"
diff --git a/apps/CtsVerifier/res/layout/biometric_test_credential_enrolled_tests.xml b/apps/CtsVerifier/res/layout/biometric_test_credential_enrolled_tests.xml
deleted file mode 100644
index 41c4e53..0000000
--- a/apps/CtsVerifier/res/layout/biometric_test_credential_enrolled_tests.xml
+++ /dev/null
@@ -1,76 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-  ~ Copyright (C) 2020 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.
-  -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-    <TextView
-        style="@style/InstructionsFont"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_alignParentTop="true"
-        android:gravity="center"
-        android:text="@string/biometric_test_credential_enrolled_instructions" />
-
-    <Button
-        android:id="@+id/enroll_credential_button"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_centerInParent="true"
-        android:text="@string/biometric_test_credential_enroll_button"/>
-
-    <Button
-        android:id="@+id/bm_button"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_centerInParent="true"
-        android:enabled="false"
-        android:text="@string/biometric_test_credential_enrolled_bm_button"/>
-
-    <Button
-        android:id="@+id/setAllowedAuthenticators_button"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_centerInParent="true"
-        android:enabled="false"
-        android:text="@string/biometric_test_credential_enrolled_bp_setAllowedAuthenticators_button"/>
-
-    <Button
-        android:id="@+id/setDeviceCredentialAllowed_button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_centerInParent="true"
-        android:enabled="false"
-        android:text="@string/biometric_test_credential_enrolled_bp_setDeviceCredentialAllowed_button"/>
-    <Button
-        android:id="@+id/authenticate_cancellation_button"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_centerInParent="true"
-        android:text="@string/biometric_test_cancellation_button"
-        android:enabled="false"/>
-
-    <Space
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_weight="1"/>
-
-    <include
-        layout="@layout/pass_fail_buttons"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"/>
-
-</LinearLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index abce310..6755439 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -252,14 +252,6 @@
     <string name="biometric_test_category_weak">3) Weak Biometric Tests</string>
     <string name="biometric_test_category_combination">4) setUserAuthParams Tests</string>
 
-    <string name="biometric_test_credential_enrolled_label">1b: Credential Enrolled Tests</string>
-    <string name="biometric_test_credential_enrolled_instructions">This test checks that apps are able to request credential enrollment, and that the BiometricManager/BiometricPrompt
-        APIs return results consistent with credential (PIN/Pattern/Password) state.</string>
-    <string name="biometric_test_credential_enroll_button">Enroll credential</string>
-    <string name="biometric_test_credential_enrolled_bm_button">Check BiometricManager</string>
-    <string name="biometric_test_credential_enrolled_bp_setAllowedAuthenticators_button">Check BiometricPrompt setAllowedAuthenticators(DEVICE_CREDENTIAL)</string>
-    <string name="biometric_test_credential_enrolled_bp_setDeviceCredentialAllowed_button">Check BiometricPrompt setDeviceCredentialAllowed(true)</string>
-
     <string name="biometric_test_credential_crypto_label">1c: Credential Crypto</string>
     <string name="biometric_test_credential_crypto_instructions">This test checks that PIN/Pattern/Password successfully unlocks the relevant KeyStore operations. Please
         ensure that you have a PIN/Pattern/Password set up.</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/CredentialEnrolledTests.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/CredentialEnrolledTests.java
deleted file mode 100644
index ee866eb..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/CredentialEnrolledTests.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright (C) 2020 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.cts.verifier.biometrics;
-
-import android.content.Intent;
-import android.hardware.biometrics.BiometricManager;
-import android.hardware.biometrics.BiometricManager.Authenticators;
-import android.hardware.biometrics.BiometricPrompt;
-import android.os.Bundle;
-import android.os.CancellationSignal;
-import android.os.Handler;
-import android.os.Looper;
-import android.provider.Settings;
-import android.widget.Button;
-
-import com.android.cts.verifier.R;
-
-import java.util.concurrent.Executor;
-
-/**
- * This test checks that when a credential is enrolled, and biometrics are not enrolled,
- * BiometricManager and BiometricPrompt receive the correct results.
- */
-public class CredentialEnrolledTests extends AbstractBaseTest {
-    private static final String TAG = "CredentialEnrolledTests";
-
-    private static final int REQUEST_ENROLL = 1;
-
-    private Button mEnrollButton;
-    private Button mBiometricManagerButton;
-    private Button mBPSetAllowedAuthenticatorsButton;
-    private Button mBPSetDeviceCredentialAllowedButton;
-    private Button mCancellationButton;
-
-    private boolean mEnrollPass;
-    private boolean mBiometricManagerPass;
-    private boolean mBiometricPromptSetAllowedAuthenticatorsPass;
-    private boolean mBiometricPromptSetDeviceCredentialAllowedPass;
-    private boolean mCancellationPass;
-
-    private final Handler mHandler = new Handler(Looper.getMainLooper());
-    private final Executor mExecutor = mHandler::post;
-
-    @Override
-    protected String getTag() {
-        return TAG;
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.biometric_test_credential_enrolled_tests);
-        setPassFailButtonClickListeners();
-        getPassButton().setEnabled(false);
-
-        final BiometricManager bm = getSystemService(BiometricManager.class);
-
-        mEnrollButton = findViewById(R.id.enroll_credential_button);
-        mEnrollButton.setOnClickListener((view) -> {
-            final int biometricResult = bm.canAuthenticate(Authenticators.DEVICE_CREDENTIAL);
-            if (biometricResult != BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED) {
-                showToastAndLog("Please ensure you do not have a PIN/Pattern/Password set");
-                return;
-            }
-
-            requestCredentialEnrollment(REQUEST_ENROLL);
-        });
-
-        // Test BiometricManager#canAuthenticate(DEVICE_CREDENTIAL)
-        mBiometricManagerButton = findViewById(R.id.bm_button);
-        mBiometricManagerButton.setOnClickListener((view) -> {
-
-            final int biometricResult = bm.canAuthenticate(Authenticators.BIOMETRIC_WEAK);
-            switch (biometricResult) {
-                case BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE:
-                case BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED:
-                    // OK
-                    break;
-                case BiometricManager.BIOMETRIC_SUCCESS:
-                    showToastAndLog("Unexpected result: " + biometricResult +
-                            ". Please make sure the device does not have a biometric enrolled");
-                    return;
-                default:
-                    showToastAndLog("Unexpected result: " + biometricResult);
-                    return;
-            }
-
-            final int credentialResult = bm.canAuthenticate(Authenticators.DEVICE_CREDENTIAL);
-            if (credentialResult == BiometricManager.BIOMETRIC_SUCCESS) {
-                mBiometricManagerButton.setEnabled(false);
-                mBiometricManagerPass = true;
-                updatePassButton();
-            } else {
-                showToastAndLog("Unexpected result: " + credentialResult
-                        + ". Please make sure the device"
-                        + " has a PIN/Pattern/Password set");
-            }
-        });
-
-        // Test setAllowedAuthenticators(DEVICE_CREDENTIAL)
-        mBPSetAllowedAuthenticatorsButton = findViewById(R.id.setAllowedAuthenticators_button);
-        mBPSetAllowedAuthenticatorsButton.setOnClickListener((view) -> {
-            BiometricPrompt.Builder builder = new BiometricPrompt.Builder(this);
-            builder.setTitle("Title");
-            builder.setSubtitle("Subtitle");
-            builder.setDescription("Description");
-            builder.setAllowedAuthenticators(Authenticators.DEVICE_CREDENTIAL);
-            BiometricPrompt bp = builder.build();
-            bp.authenticate(new CancellationSignal(), mExecutor,
-                    new BiometricPrompt.AuthenticationCallback() {
-                        @Override
-                        public void onAuthenticationSucceeded(
-                                BiometricPrompt.AuthenticationResult result) {
-                            final int authenticator = result.getAuthenticationType();
-                            if (authenticator ==
-                                    BiometricPrompt.AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL) {
-                                mBPSetAllowedAuthenticatorsButton.setEnabled(false);
-                                mBiometricPromptSetAllowedAuthenticatorsPass = true;
-                                updatePassButton();
-                            } else {
-                                showToastAndLog("Unexpected authenticator: " + authenticator);
-                            }
-                        }
-
-                        @Override
-                        public void onAuthenticationError(int errorCode, CharSequence errString) {
-                            showToastAndLog("Unexpected error: " + errorCode + ", " + errString);
-                        }
-                    });
-        });
-
-        // Test setDeviceCredentialAllowed(true)
-        mBPSetDeviceCredentialAllowedButton = findViewById(R.id.setDeviceCredentialAllowed_button);
-        mBPSetDeviceCredentialAllowedButton.setOnClickListener((view) -> {
-            BiometricPrompt.Builder builder = new BiometricPrompt.Builder(this);
-            builder.setTitle("Title");
-            builder.setSubtitle("Subtitle");
-            builder.setDescription("Description");
-            builder.setDeviceCredentialAllowed(true);
-            BiometricPrompt bp = builder.build();
-            bp.authenticate(new CancellationSignal(), mExecutor,
-                    new BiometricPrompt.AuthenticationCallback() {
-                        @Override
-                        public void onAuthenticationSucceeded(
-                                BiometricPrompt.AuthenticationResult result) {
-                            final int authenticator = result.getAuthenticationType();
-                            if (authenticator ==
-                                    BiometricPrompt.AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL) {
-                                mBPSetDeviceCredentialAllowedButton.setEnabled(false);
-                                mBiometricPromptSetDeviceCredentialAllowedPass = true;
-                                updatePassButton();
-                            } else {
-                                showToastAndLog("Unexpected authenticator: " + authenticator
-                                        + ". Please ensure the device does not have a biometric"
-                                        + " enrolled.");
-                            }
-                        }
-
-                        @Override
-                        public void onAuthenticationError(int errorCode, CharSequence errString) {
-                            showToastAndLog("Unexpected error: " + errorCode + ", " + errString);
-                        }
-                    });
-        });
-
-        mCancellationButton = findViewById(R.id.authenticate_cancellation_button);
-        mCancellationButton.setOnClickListener((view) -> {
-           testCancellationSignal(Authenticators.DEVICE_CREDENTIAL, () -> {
-               mCancellationButton.setEnabled(false);
-               mCancellationPass = true;
-               updatePassButton();
-           });
-        });
-    }
-
-    @Override
-    protected boolean isOnPauseAllowed() {
-        // Allow user to go to Settings, etc to figure out why this test isn't passing.
-        return !mBiometricManagerPass;
-    }
-
-    @Override
-    public void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (requestCode == REQUEST_ENROLL) {
-            final BiometricManager bm = getSystemService(BiometricManager.class);
-            final int result = bm.canAuthenticate(Authenticators.DEVICE_CREDENTIAL);
-            if (result == BiometricManager.BIOMETRIC_SUCCESS) {
-                mEnrollPass = true;
-                mEnrollButton.setEnabled(false);
-                mBiometricManagerButton.setEnabled(true);
-                mBPSetAllowedAuthenticatorsButton.setEnabled(true);
-                mBPSetDeviceCredentialAllowedButton.setEnabled(true);
-                mCancellationButton.setEnabled(true);
-            } else {
-                showToastAndLog("Unexpected result: " + result + ". Please ensure that tapping"
-                        + " the button sends you to credential enrollment, and that you have"
-                        + " enrolled a credential.");
-            }
-        }
-    }
-
-    private void requestCredentialEnrollment(int requestCode) {
-        final Intent enrollIntent = new Intent(Settings.ACTION_BIOMETRIC_ENROLL);
-        enrollIntent.putExtra(Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED,
-                Authenticators.DEVICE_CREDENTIAL);
-
-        startActivityForResult(enrollIntent, requestCode);
-    }
-
-    private void updatePassButton() {
-        if (mEnrollPass && mBiometricManagerPass && mBiometricPromptSetAllowedAuthenticatorsPass
-                && mBiometricPromptSetDeviceCredentialAllowedPass && mCancellationPass) {
-            showToastAndLog("All tests passed");
-            getPassButton().setEnabled(true);
-        }
-    }
-}
diff --git a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricActivityTests.java b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricActivityTests.java
index c14cc0e..eccc471 100644
--- a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricActivityTests.java
+++ b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricActivityTests.java
@@ -19,7 +19,6 @@
 import static android.server.biometrics.Components.CLASS_2_BIOMETRIC_ACTIVITY;
 import static android.server.biometrics.Components.CLASS_2_BIOMETRIC_OR_CREDENTIAL_ACTIVITY;
 
-import static com.android.server.biometrics.nano.BiometricServiceStateProto.STATE_AUTH_IDLE;
 import static com.android.server.biometrics.nano.BiometricServiceStateProto.STATE_AUTH_PAUSED;
 import static com.android.server.biometrics.nano.BiometricServiceStateProto.STATE_AUTH_STARTED_UI_SHOWING;
 import static com.android.server.biometrics.nano.BiometricServiceStateProto.STATE_SHOWING_DEVICE_CREDENTIAL;
@@ -36,7 +35,6 @@
 import android.platform.test.annotations.Presubmit;
 import android.server.wm.TestJournalProvider;
 import android.server.wm.WindowManagerState;
-import android.support.test.uiautomator.UiObject2;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
@@ -307,26 +305,8 @@
             waitForState(STATE_SHOWING_DEVICE_CREDENTIAL);
         }
 
-        // All sensors are idle, BiometricService is waiting for device credential
-        state = getCurrentState();
-        assertTrue(state.toString(), state.mSensorStates.areAllSensorsIdle());
-        assertEquals(state.toString(), STATE_SHOWING_DEVICE_CREDENTIAL, state.mState);
+        successfullyEnterCredential();
 
-        // Wait for any animations to complete. Ideally, this should be reflected in
-        // STATE_SHOWING_DEVICE_CREDENTIAL, but SysUI and BiometricService are different processes
-        // so we'd need to add some additional plumbing. We can improve this in the future.
-        Thread.sleep(1000);
-
-        // Enter credential. AuthSession done, authentication callback received
-        final UiObject2 passwordField = findView(VIEW_ID_PASSWORD_FIELD);
-        Log.d(TAG, "Focusing, entering, submitting credential");
-        passwordField.click();
-        passwordField.setText(LOCK_CREDENTIAL);
-        mDevice.pressEnter();
-        waitForState(STATE_AUTH_IDLE);
-
-        state = getCurrentState();
-        assertEquals(state.toString(), STATE_AUTH_IDLE, state.mState);
         callbackState = getCallbackState(journal);
         assertEquals(callbackState.toString(), 0, callbackState.mNumAuthRejected);
         assertEquals(callbackState.toString(), 1, callbackState.mNumAuthAccepted);
diff --git a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricSimpleTests.java b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricSimpleTests.java
index 3594a5d..fb454fc 100644
--- a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricSimpleTests.java
+++ b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricSimpleTests.java
@@ -28,6 +28,7 @@
 import android.hardware.biometrics.BiometricPrompt;
 import android.hardware.biometrics.BiometricTestSession;
 import android.hardware.biometrics.SensorProperties;
+import android.os.CancellationSignal;
 import android.platform.test.annotations.Presubmit;
 
 import com.android.server.biometrics.nano.SensorStateProto;
@@ -91,9 +92,8 @@
         // Second case above
         BiometricPrompt.AuthenticationCallback callback =
                 mock(BiometricPrompt.AuthenticationCallback.class);
-        showCredentialOnlyBiometricPrompt(callback);
-        mInstrumentation.waitForIdleSync();
-        Utils.waitForIdleService(this::getSensorStates);
+        showCredentialOnlyBiometricPrompt(callback, new CancellationSignal(),
+                false /* shouldShow */);
         verify(callback).onAuthenticationError(
                 eq(BiometricPrompt.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL),
                 any());
@@ -101,12 +101,62 @@
         // Third case above. Since the deprecated API is intended to allow credential in addition
         // to biometrics, we should be receiving BIOMETRIC_ERROR_NO_BIOMETRICS.
         callback = mock(BiometricPrompt.AuthenticationCallback.class);
-        showDeviceCredentialAllowedBiometricPrompt(callback);
-        mInstrumentation.waitForIdleSync();
-        Utils.waitForIdleService(this::getSensorStates);
+        showDeviceCredentialAllowedBiometricPrompt(callback, new CancellationSignal(),
+                false /* shouldShow */);
         verify(callback).onAuthenticationError(
                 eq(BiometricPrompt.BIOMETRIC_ERROR_NO_BIOMETRICS),
                 any());
     }
 
+    /**
+     * When device credential is enrolled, check the behavior for
+     * 1) BiometricManager#canAuthenticate(DEVICE_CREDENTIAL)
+     * 2a) Successfully authenticating BiometricPrompt#setAllowedAuthenticators(DEVICE_CREDENTIAL)
+     * 2b) Cancelling authentication for the above
+     * 3a) @deprecated BiometricPrompt#setDeviceCredentialALlowed(true)
+     * 3b) Cancelling authentication for the above
+     * 4) Cancelling auth for options 2) and 3)
+     */
+    @Test
+    public void testWhenCredentialEnrolled() throws Exception {
+        try (CredentialSession session = new CredentialSession()) {
+            session.setCredential();
+
+            // First case above
+            final int result = mBiometricManager.canAuthenticate(BiometricManager
+                    .Authenticators.DEVICE_CREDENTIAL);
+            assertEquals(BiometricManager.BIOMETRIC_SUCCESS, result);
+
+            // 2a above
+            BiometricPrompt.AuthenticationCallback callback =
+                    mock(BiometricPrompt.AuthenticationCallback.class);
+            showCredentialOnlyBiometricPrompt(callback, new CancellationSignal(),
+                    true /* shouldShow */);
+            successfullyEnterCredential();
+            verify(callback).onAuthenticationSucceeded(any());
+
+            // 2b above
+            CancellationSignal cancel = new CancellationSignal();
+            callback = mock(BiometricPrompt.AuthenticationCallback.class);
+            showCredentialOnlyBiometricPrompt(callback, cancel, true /* shouldShow */);
+            cancelAuthentication(cancel);
+            verify(callback).onAuthenticationError(eq(BiometricPrompt.BIOMETRIC_ERROR_CANCELED),
+                    any());
+
+            // 3a above
+            callback = mock(BiometricPrompt.AuthenticationCallback.class);
+            showDeviceCredentialAllowedBiometricPrompt(callback, new CancellationSignal(),
+                    true /* shouldShow */);
+            successfullyEnterCredential();
+            verify(callback).onAuthenticationSucceeded(any());
+
+            // 3b above
+            cancel = new CancellationSignal();
+            callback = mock(BiometricPrompt.AuthenticationCallback.class);
+            showDeviceCredentialAllowedBiometricPrompt(callback, cancel, true /* shouldShow */);
+            cancelAuthentication(cancel);
+            verify(callback).onAuthenticationError(eq(BiometricPrompt.BIOMETRIC_ERROR_CANCELED),
+                    any());
+        }
+    }
 }
diff --git a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java
index 4724232..0484357 100644
--- a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java
+++ b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java
@@ -25,9 +25,11 @@
 import static com.android.server.biometrics.nano.BiometricServiceStateProto.STATE_AUTH_IDLE;
 import static com.android.server.biometrics.nano.BiometricServiceStateProto.STATE_AUTH_PENDING_CONFIRM;
 import static com.android.server.biometrics.nano.BiometricServiceStateProto.STATE_AUTH_STARTED_UI_SHOWING;
+import static com.android.server.biometrics.nano.BiometricServiceStateProto.STATE_SHOWING_DEVICE_CREDENTIAL;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
@@ -196,6 +198,37 @@
         }
     }
 
+    protected void successfullyEnterCredential() throws Exception {
+        waitForState(STATE_SHOWING_DEVICE_CREDENTIAL);
+        BiometricServiceState state = getCurrentState();
+        assertTrue(state.toString(), state.mSensorStates.areAllSensorsIdle());
+        assertEquals(state.toString(), STATE_SHOWING_DEVICE_CREDENTIAL, state.mState);
+
+        // Wait for any animations to complete. Ideally, this should be reflected in
+        // STATE_SHOWING_DEVICE_CREDENTIAL, but SysUI and BiometricService are different processes
+        // so we'd need to add some additional plumbing. We can improve this in the future.
+        Thread.sleep(1000);
+
+        // Enter credential. AuthSession done, authentication callback received
+        final UiObject2 passwordField = findView(VIEW_ID_PASSWORD_FIELD);
+        Log.d(TAG, "Focusing, entering, submitting credential");
+        passwordField.click();
+        passwordField.setText(LOCK_CREDENTIAL);
+        mDevice.pressEnter();
+        waitForState(STATE_AUTH_IDLE);
+
+        state = getCurrentState();
+        assertEquals(state.toString(), STATE_AUTH_IDLE, state.mState);
+    }
+
+    protected void cancelAuthentication(@NonNull CancellationSignal cancel) throws Exception {
+        cancel.cancel();
+        mInstrumentation.waitForIdleSync();
+        waitForState(STATE_AUTH_IDLE);
+        BiometricServiceState state = getCurrentState();
+        assertEquals("Not idle after requesting cancellation", state.mState, STATE_AUTH_IDLE);
+    }
+
     protected void waitForAllUnenrolled() throws Exception {
         for (int i = 0; i < 20; i++) {
             if (anyEnrollmentsExist()) {
@@ -212,7 +245,9 @@
      * Shows a BiometricPrompt that specifies {@link Authenticators#DEVICE_CREDENTIAL}.
      */
     protected void showCredentialOnlyBiometricPrompt(
-            @NonNull BiometricPrompt.AuthenticationCallback callback) {
+            @NonNull BiometricPrompt.AuthenticationCallback callback,
+            @NonNull CancellationSignal cancellationSignal,
+            boolean shouldShow) throws Exception {
         final Handler handler = new Handler(Looper.getMainLooper());
         final Executor executor = handler::post;
         final BiometricPrompt prompt = new BiometricPrompt.Builder(mContext)
@@ -223,7 +258,16 @@
                 .setAllowBackgroundAuthentication(true)
                 .build();
 
-        prompt.authenticate(new CancellationSignal(), executor, callback);
+        prompt.authenticate(cancellationSignal, executor, callback);
+
+        mInstrumentation.waitForIdleSync();
+        if (shouldShow) {
+            waitForState(STATE_SHOWING_DEVICE_CREDENTIAL);
+            BiometricServiceState state = getCurrentState();
+            assertEquals(state.toString(), STATE_SHOWING_DEVICE_CREDENTIAL, state.mState);
+        } else {
+            Utils.waitForIdleService(this::getSensorStates);
+        }
     }
 
     /**
@@ -231,7 +275,9 @@
      * {@link BiometricPrompt.Builder#setDeviceCredentialAllowed(boolean)} to true.
      */
     protected void showDeviceCredentialAllowedBiometricPrompt(
-            @NonNull BiometricPrompt.AuthenticationCallback callback) {
+            @NonNull BiometricPrompt.AuthenticationCallback callback,
+            @NonNull CancellationSignal cancellationSignal,
+            boolean shouldShow) throws Exception {
         final Handler handler = new Handler(Looper.getMainLooper());
         final Executor executor = handler::post;
         final BiometricPrompt prompt = new BiometricPrompt.Builder(mContext)
@@ -242,7 +288,16 @@
                 .setAllowBackgroundAuthentication(true)
                 .build();
 
-        prompt.authenticate(new CancellationSignal(), executor, callback);
+        prompt.authenticate(cancellationSignal, executor, callback);
+
+        mInstrumentation.waitForIdleSync();
+        if (shouldShow) {
+            waitForState(STATE_SHOWING_DEVICE_CREDENTIAL);
+            BiometricServiceState state = getCurrentState();
+            assertEquals(state.toString(), STATE_SHOWING_DEVICE_CREDENTIAL, state.mState);
+        } else {
+            Utils.waitForIdleService(this::getSensorStates);
+        }
     }
 
     /**