Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a585bebc authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge changes from topic "qpr.biometric.2panels" into tm-qpr-dev am: c8f45f75

parents 7856ab05 c8f45f75
Loading
Loading
Loading
Loading
+15 −6
Original line number Original line Diff line number Diff line
@@ -134,6 +134,9 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements
            setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title);
            setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title);
            setDescriptionText(R.string.security_settings_fingerprint_enroll_find_sensor_message);
            setDescriptionText(R.string.security_settings_fingerprint_enroll_find_sensor_message);
        }
        }
        if (savedInstanceState != null) {
            mNextClicked = savedInstanceState.getBoolean(SAVED_STATE_IS_NEXT_CLICKED, mNextClicked);
        }


        // This is an entry point for SetNewPasswordController, e.g.
        // This is an entry point for SetNewPasswordController, e.g.
        // adb shell am start -a android.app.action.SET_NEW_PASSWORD
        // adb shell am start -a android.app.action.SET_NEW_PASSWORD
@@ -148,11 +151,19 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements
                // it passed in.
                // it passed in.
                getIntent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
                getIntent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);


                // Do not start looking for fingerprint if this activity is re-created because it is
                // waiting for activity result from enrolling activity.
                if (!mNextClicked) {
                    startLookingForFingerprint();
                    startLookingForFingerprint();
                }
            });
            });
        } else if (mToken != null) {
        } else if (mToken != null) {
            // Do not start looking for fingerprint if this activity is re-created because it is
            // waiting for activity result from enrolling activity.
            if (!mNextClicked) {
                // HAT passed in from somewhere else, such as FingerprintEnrollIntroduction
                // HAT passed in from somewhere else, such as FingerprintEnrollIntroduction
                startLookingForFingerprint();
                startLookingForFingerprint();
            }
        } else {
        } else {
            // There's something wrong with the enrollment flow, this should never happen.
            // There's something wrong with the enrollment flow, this should never happen.
            throw new IllegalStateException("HAT and GkPwHandle both missing...");
            throw new IllegalStateException("HAT and GkPwHandle both missing...");
@@ -173,9 +184,6 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements
                mAnimation = (FingerprintFindSensorAnimation) animationView;
                mAnimation = (FingerprintFindSensorAnimation) animationView;
            }
            }
        }
        }
        if (savedInstanceState != null) {
            mNextClicked = savedInstanceState.getBoolean(SAVED_STATE_IS_NEXT_CLICKED, mNextClicked);
        }
    }
    }


    @Override
    @Override
@@ -297,6 +305,7 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements
                    return;
                    return;
                }
                }
            }
            }
            mSidecar.setListener(null);
            getSupportFragmentManager().beginTransaction().remove(mSidecar).
            getSupportFragmentManager().beginTransaction().remove(mSidecar).
                    commitAllowingStateLoss();
                    commitAllowingStateLoss();
            mSidecar = null;
            mSidecar = null;
+20 −3
Original line number Original line Diff line number Diff line
@@ -50,6 +50,8 @@ public class FingerprintEnrollFinish extends BiometricEnrollBase {
    static final String FINGERPRINT_SUGGESTION_ACTIVITY =
    static final String FINGERPRINT_SUGGESTION_ACTIVITY =
            "com.android.settings.SetupFingerprintSuggestionActivity";
            "com.android.settings.SetupFingerprintSuggestionActivity";


    private boolean mIsAddAnotherOrFinish;

    @Override
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        super.onCreate(savedInstanceState);
@@ -107,9 +109,23 @@ public class FingerprintEnrollFinish extends BiometricEnrollBase {
        }
        }
    }
    }


    @Override
    protected void onStart() {
        super.onStart();

        // Reset it to false every time activity back to fg because this flag is stateless between
        // different life cycle.
        mIsAddAnotherOrFinish = false;
    }

    @Override
    @Override
    protected void onNextButtonClick(View view) {
    protected void onNextButtonClick(View view) {
        updateFingerprintSuggestionEnableState();
        updateFingerprintSuggestionEnableState();
        finishAndToNext();
    }

    private void finishAndToNext() {
        mIsAddAnotherOrFinish = true;
        setResult(RESULT_FINISHED);
        setResult(RESULT_FINISHED);
        if (WizardManagerHelper.isAnySetupWizard(getIntent())) {
        if (WizardManagerHelper.isAnySetupWizard(getIntent())) {
            postEnroll();
            postEnroll();
@@ -145,20 +161,21 @@ public class FingerprintEnrollFinish extends BiometricEnrollBase {
    }
    }


    private void onAddAnotherButtonClick(View view) {
    private void onAddAnotherButtonClick(View view) {
        mIsAddAnotherOrFinish = true;
        startActivityForResult(getFingerprintEnrollingIntent(), BiometricUtils.REQUEST_ADD_ANOTHER);
        startActivityForResult(getFingerprintEnrollingIntent(), BiometricUtils.REQUEST_ADD_ANOTHER);
    }
    }


    @Override
    @Override
    protected boolean shouldFinishWhenBackgrounded() {
    protected boolean shouldFinishWhenBackgrounded() {
        return !isFinishing() && super.shouldFinishWhenBackgrounded();
        return !mIsAddAnotherOrFinish && super.shouldFinishWhenBackgrounded();
    }
    }


    @Override
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        updateFingerprintSuggestionEnableState();
        updateFingerprintSuggestionEnableState();
        if (requestCode == BiometricUtils.REQUEST_ADD_ANOTHER && resultCode != RESULT_CANCELED) {
        if (requestCode == BiometricUtils.REQUEST_ADD_ANOTHER && resultCode != RESULT_CANCELED) {
            setResult(resultCode, data);
            // If user cancel during "Add another", just use similar flow on "Next" button
            finish();
            finishAndToNext();
        } else {
        } else {
            super.onActivityResult(requestCode, resultCode, data);
            super.onActivityResult(requestCode, resultCode, data);
        }
        }
+277 −29
Original line number Original line Diff line number Diff line
@@ -19,6 +19,11 @@ package com.android.settings.biometrics.fingerprint;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;


import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED;
import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_SKIP;
import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_TIMEOUT;
import static com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling.TAG_SIDECAR;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.common.truth.Truth.assertWithMessage;


@@ -29,6 +34,7 @@ import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verify;
import static org.robolectric.RuntimeEnvironment.application;
import static org.robolectric.RuntimeEnvironment.application;


import android.annotation.NonNull;
import android.app.Activity;
import android.app.Activity;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Intent;
import android.content.Intent;
@@ -38,9 +44,12 @@ import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.EnrollmentCallback;
import android.hardware.fingerprint.FingerprintManager.EnrollmentCallback;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.CancellationSignal;
import android.view.View;
import android.view.View;


import androidx.fragment.app.Fragment;

import com.android.settings.R;
import com.android.settings.R;
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.password.ChooseLockSettingsHelper;
@@ -82,12 +91,7 @@ public class FingerprintEnrollFindSensorTest {


    private FingerprintEnrollFindSensor mActivity;
    private FingerprintEnrollFindSensor mActivity;


    @Before
    private void buildActivity() {
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        ShadowUtils.setFingerprintManager(mFingerprintManager);
        FakeFeatureFactory.setupForTest();

        mActivityController = Robolectric.buildActivity(
        mActivityController = Robolectric.buildActivity(
                FingerprintEnrollFindSensor.class,
                FingerprintEnrollFindSensor.class,
                new Intent()
                new Intent()
@@ -97,6 +101,14 @@ public class FingerprintEnrollFindSensorTest {
        mActivity = mActivityController.get();
        mActivity = mActivityController.get();
    }
    }


    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        ShadowUtils.setFingerprintManager(mFingerprintManager);
        FakeFeatureFactory.setupForTest();
        buildActivity();
    }

    private void setupActivity_onRearDevice() {
    private void setupActivity_onRearDevice() {
        final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
        final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
        props.add(newFingerprintSensorPropertiesInternal(TYPE_REAR));
        props.add(newFingerprintSensorPropertiesInternal(TYPE_REAR));
@@ -187,7 +199,7 @@ public class FingerprintEnrollFindSensorTest {


        ShadowActivity shadowActivity = Shadows.shadowOf(mActivity);
        ShadowActivity shadowActivity = Shadows.shadowOf(mActivity);
        assertWithMessage("result code").that(shadowActivity.getResultCode())
        assertWithMessage("result code").that(shadowActivity.getResultCode())
                .isEqualTo(BiometricEnrollBase.RESULT_SKIP);
                .isEqualTo(RESULT_SKIP);
    }
    }


    private EnrollmentCallback verifyAndCaptureEnrollmentCallback() {
    private EnrollmentCallback verifyAndCaptureEnrollmentCallback() {
@@ -214,123 +226,320 @@ public class FingerprintEnrollFindSensorTest {
    }
    }


    @Test
    @Test
    public void enrollingFinishResultShallSentBack_onRearDevice() {
    public void resultFinishShallForward_onRearDevice() {
        setupActivity_onRearDevice();
        setupActivity_onRearDevice();
        triggerEnrollProgressAndError_onRearDevice();
        triggerEnrollProgressAndError_onRearDevice();
        verifyStartEnrollingActivity();
        verifyStartEnrollingActivity();


        // pause activity
        mActivityController.pause().stop();

        // onStop shall not change default activity result
        // onStop shall not change default activity result
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);

        gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_FINISHED);
    }

    @Test
    public void resultFinishShallForward_onRearDevice_recreate() {
        setupActivity_onRearDevice();
        triggerEnrollProgressAndError_onRearDevice();
        verifyStartEnrollingActivity();

        // recycle activity
        final Bundle bundle = new Bundle();
        mActivityController.pause().stop().saveInstanceState(bundle).destroy();

        // onStop shall not change default activity result
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);

        gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_FINISHED, bundle);
    }

    @Test
    public void resultSkipShallForward_onRearDevice() {
        setupActivity_onRearDevice();
        verifySidecar_onRearOrSfpsDevice();

        triggerEnrollProgressAndError_onRearDevice();
        verifyStartEnrollingActivity();

        // pause activity
        mActivityController.pause().stop();
        mActivityController.pause().stop();

        // onStop shall not change default activity result
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);


        gotEnrollingResult_verifyResultSentBack(BiometricEnrollBase.RESULT_FINISHED);
        gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_SKIP);
    }
    }


    @Test
    @Test
    public void enrollingSkipResultShallSentBack_onRearDevice() {
    public void resultSkipShallForward_onRearDevice_recreate() {
        setupActivity_onRearDevice();
        setupActivity_onRearDevice();
        verifySidecar_onRearOrSfpsDevice();

        triggerEnrollProgressAndError_onRearDevice();
        triggerEnrollProgressAndError_onRearDevice();
        verifyStartEnrollingActivity();
        verifyStartEnrollingActivity();


        // recycle activity
        final Bundle bundle = new Bundle();
        mActivityController.pause().stop().saveInstanceState(bundle).destroy();

        // onStop shall not change default activity result
        // onStop shall not change default activity result
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);

        gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_SKIP, bundle);
    }

    @Test
    public void resultTimeoutShallForward_onRearDevice() {
        setupActivity_onRearDevice();
        verifySidecar_onRearOrSfpsDevice();

        triggerEnrollProgressAndError_onRearDevice();
        verifyStartEnrollingActivity();

        // pause activity
        mActivityController.pause().stop();
        mActivityController.pause().stop();

        // onStop shall not change default activity result
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);


        gotEnrollingResult_verifyResultSentBack(BiometricEnrollBase.RESULT_SKIP);
        gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_TIMEOUT);
    }
    }


    @Test
    @Test
    public void enrollingTimeoutResultShallSentBack_onRearDevice() {
    public void resultTimeoutShallForward_onRearDevice_recreate() {
        setupActivity_onRearDevice();
        setupActivity_onRearDevice();
        verifySidecar_onRearOrSfpsDevice();

        triggerEnrollProgressAndError_onRearDevice();
        triggerEnrollProgressAndError_onRearDevice();
        verifyStartEnrollingActivity();
        verifyStartEnrollingActivity();


        // recycle activity
        final Bundle bundle = new Bundle();
        mActivityController.pause().stop().saveInstanceState(bundle).destroy();

        // onStop shall not change default activity result
        // onStop shall not change default activity result
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);

        gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_TIMEOUT, bundle);
    }

    @Test
    public void clickLottieResultFinishShallForward_onUdfpsDevice() {
        setupActivity_onUdfpsDevice();
        verifyNoSidecar();

        clickLottieView_onUdfpsDevice();
        verifyStartEnrollingActivity();
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);

        // pause activity
        mActivityController.pause().stop();
        mActivityController.pause().stop();

        // onStop shall not change default activity result
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);


        gotEnrollingResult_verifyResultSentBack(BiometricEnrollBase.RESULT_TIMEOUT);
        gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_FINISHED);
    }
    }


    @Test
    @Test
    public void enrollingFinishResultShallSentBack_onUdfpsDevice_triggeredByLottieClick() {
    public void clickLottieResultFinishShallForward_onUdfpsDevice_ifActivityRecycled() {
        setupActivity_onUdfpsDevice();
        setupActivity_onUdfpsDevice();
        verifyNoSidecar();

        clickLottieView_onUdfpsDevice();
        clickLottieView_onUdfpsDevice();
        verifyStartEnrollingActivity();
        verifyStartEnrollingActivity();
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);


        // recycle activity
        final Bundle bundle = new Bundle();
        mActivityController.pause().stop().saveInstanceState(bundle).destroy();

        // onStop shall not change default activity result
        // onStop shall not change default activity result
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);

        gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_FINISHED, bundle);
    }

    @Test
    public void clickLottieResultSkipShallForward_onUdfpsDevice() {
        setupActivity_onUdfpsDevice();
        verifyNoSidecar();

        clickLottieView_onUdfpsDevice();
        verifyStartEnrollingActivity();
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);

        // pause activity
        mActivityController.pause().stop();
        mActivityController.pause().stop();

        // onStop shall not change default activity result
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);


        gotEnrollingResult_verifyResultSentBack(BiometricEnrollBase.RESULT_FINISHED);
        gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_SKIP);
    }
    }


    @Test
    @Test
    public void enrollingSkipResultShallSentBack_onUdfpsDevice_triggeredByLottieClick() {
    public void clickLottieResultSkipShallForward_onUdfpsDevice_ifActivityRecycled() {
        setupActivity_onUdfpsDevice();
        setupActivity_onUdfpsDevice();
        verifyNoSidecar();

        clickLottieView_onUdfpsDevice();
        clickLottieView_onUdfpsDevice();
        verifyStartEnrollingActivity();
        verifyStartEnrollingActivity();
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);


        // recycle activity
        final Bundle bundle = new Bundle();
        mActivityController.pause().stop().saveInstanceState(bundle).destroy();

        // onStop shall not change default activity result
        // onStop shall not change default activity result
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);

        gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_SKIP, bundle);
    }

    @Test
    public void clickLottieResultTimeoutShallForward_onUdfpsDevice() {
        setupActivity_onUdfpsDevice();
        verifyNoSidecar();

        clickLottieView_onUdfpsDevice();
        verifyStartEnrollingActivity();
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);

        // pause activity
        mActivityController.pause().stop();
        mActivityController.pause().stop();

        // onStop shall not change default activity result
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);


        gotEnrollingResult_verifyResultSentBack(BiometricEnrollBase.RESULT_SKIP);
        gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_TIMEOUT);
    }
    }


    @Test
    @Test
    public void enrollingTimeoutResultShallSentBack_onUdfpsDevice_triggeredByLottieClick() {
    public void clickLottieResultTimeoutShallForward_onUdfpsDevice_ifActivityRecycled() {
        setupActivity_onUdfpsDevice();
        setupActivity_onUdfpsDevice();
        verifyNoSidecar();

        clickLottieView_onUdfpsDevice();
        clickLottieView_onUdfpsDevice();
        verifyStartEnrollingActivity();
        verifyStartEnrollingActivity();
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);


        // recycle activity
        final Bundle bundle = new Bundle();
        mActivityController.pause().stop().saveInstanceState(bundle).destroy();

        // onStop shall not change default activity result
        // onStop shall not change default activity result
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);

        gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_TIMEOUT, bundle);
    }

    @Test
    public void clickPrimiaryButtonResultFinishShallForward_onUdfpsDevice() {
        setupActivity_onUdfpsDevice();
        verifyNoSidecar();

        clickPrimaryButton_onUdfpsDevice();
        verifyStartEnrollingActivity();

        // pause activity
        mActivityController.pause().stop();
        mActivityController.pause().stop();

        // onStop shall not change default activity result
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);


        gotEnrollingResult_verifyResultSentBack(BiometricEnrollBase.RESULT_TIMEOUT);
        gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_FINISHED);
    }
    }


    @Test
    @Test
    public void enrollingFinishResultShallSentBack_onUdfpsDevice_triggeredByPrimaryButtonClick() {
    public void clickPrimiaryButtonResultFinishShallForward_onUdfpsDevice_ifActivityRecycled() {
        setupActivity_onUdfpsDevice();
        setupActivity_onUdfpsDevice();
        verifyNoSidecar();

        clickPrimaryButton_onUdfpsDevice();
        clickPrimaryButton_onUdfpsDevice();
        verifyStartEnrollingActivity();
        verifyStartEnrollingActivity();


        // recycle activity
        final Bundle bundle = new Bundle();
        mActivityController.pause().stop().saveInstanceState(bundle).destroy();

        // onStop shall not change default activity result
        // onStop shall not change default activity result
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);

        gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_FINISHED, bundle);
    }

    @Test
    public void clickPrimiaryButtonResultSkipShallForward_onUdfpsDevice() {
        setupActivity_onUdfpsDevice();
        verifyNoSidecar();

        clickPrimaryButton_onUdfpsDevice();
        verifyStartEnrollingActivity();

        // pause activity
        mActivityController.pause().stop();
        mActivityController.pause().stop();

        // onStop shall not change default activity result
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);


        gotEnrollingResult_verifyResultSentBack(BiometricEnrollBase.RESULT_FINISHED);
        gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_SKIP);
    }
    }


    @Test
    @Test
    public void enrollingSkipResultShallSentBack_onUdfpsDevice_triggeredByPrimaryButtonClick() {
    public void clickPrimaryButtonResultSkipShallForward_onUdfpsDevice_ifActivityRecycled() {
        setupActivity_onUdfpsDevice();
        setupActivity_onUdfpsDevice();
        verifyNoSidecar();

        clickPrimaryButton_onUdfpsDevice();
        clickPrimaryButton_onUdfpsDevice();
        verifyStartEnrollingActivity();
        verifyStartEnrollingActivity();


        // recycle activity
        final Bundle bundle = new Bundle();
        mActivityController.pause().stop().saveInstanceState(bundle).destroy();

        // onStop shall not change default activity result
        // onStop shall not change default activity result
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);

        gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_SKIP, bundle);
    }

    @Test
    public void clickPrimaryButtonResultTimeoutShallForward_onUdfpsDevice() {
        setupActivity_onUdfpsDevice();
        verifyNoSidecar();

        clickPrimaryButton_onUdfpsDevice();
        verifyStartEnrollingActivity();

        // pause activity
        mActivityController.pause().stop();
        mActivityController.pause().stop();

        // onStop shall not change default activity result
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);


        gotEnrollingResult_verifyResultSentBack(BiometricEnrollBase.RESULT_SKIP);
        gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_TIMEOUT);
    }
    }


    @Test
    @Test
    public void enrollingTimeoutResultShallSentBack_onUdfpsDevice_triggeredByPrimaryButtonClick() {
    public void clickPrimaryButtonResultTimeoutShallForward_onUdfpsDevice_ifActivityRecycled() {
        setupActivity_onUdfpsDevice();
        setupActivity_onUdfpsDevice();
        verifyNoSidecar();

        clickPrimaryButton_onUdfpsDevice();
        clickPrimaryButton_onUdfpsDevice();
        verifyStartEnrollingActivity();
        verifyStartEnrollingActivity();


        // recycle activity
        final Bundle bundle = new Bundle();
        mActivityController.pause().stop().saveInstanceState(bundle).destroy();

        // onStop shall not change default activity result
        // onStop shall not change default activity result
        mActivityController.pause().stop();
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);


        gotEnrollingResult_verifyResultSentBack(BiometricEnrollBase.RESULT_TIMEOUT);
        gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_TIMEOUT, bundle);
    }
    }


    private void triggerEnrollProgressAndError_onRearDevice() {
    private void triggerEnrollProgressAndError_onRearDevice() {
@@ -355,9 +564,13 @@ public class FingerprintEnrollFindSensorTest {
        lottieView.performClick();
        lottieView.performClick();
    }
    }


    private void gotEnrollingResult_verifyResultSentBack(int testActivityResult) {
    private void gotEnrollingResult_resumeActivityAndVerifyResultThenForward(
        // onActivityResult from Enrolling activity shall be sent back
            int testActivityResult) {
        // resume activity
        mActivityController.start().resume().visible();
        mActivityController.start().resume().visible();
        verifyNoSidecar();

        // onActivityResult from Enrolling activity shall be forward back
        Shadows.shadowOf(mActivity).receiveResult(
        Shadows.shadowOf(mActivity).receiveResult(
                new Intent(mActivity, FingerprintEnrollEnrolling.class),
                new Intent(mActivity, FingerprintEnrollEnrolling.class),
                testActivityResult,
                testActivityResult,
@@ -366,7 +579,42 @@ public class FingerprintEnrollFindSensorTest {
        assertThat(mActivity.isFinishing()).isEqualTo(true);
        assertThat(mActivity.isFinishing()).isEqualTo(true);


        // onStop shall not change last activity result
        // onStop shall not change last activity result
        mActivityController.pause().stop();
        mActivityController.pause().stop().destroy();
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(testActivityResult);
    }

    private void gotEnrollingResult_recreateActivityAndVerifyResultThenForward(
            int testActivityResult, @NonNull Bundle savedInstance) {
        // Rebuild activity and use savedInstance to restore.
        buildActivity();
        mActivityController.setup(savedInstance);
        verifyNoSidecar();

        // onActivityResult from Enrolling activity shall be forward back
        Shadows.shadowOf(mActivity).receiveResult(
                new Intent(mActivity, FingerprintEnrollEnrolling.class),
                testActivityResult,
                null);
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(testActivityResult);
        assertThat(mActivity.isFinishing()).isEqualTo(true);

        // onStop shall not change last activity result
        mActivityController.pause().stop().destroy();
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(testActivityResult);
        assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(testActivityResult);
    }
    }

    private void verifySidecar_onRearOrSfpsDevice() {
        final Fragment sidecar = mActivity.getSupportFragmentManager().findFragmentByTag(
                TAG_SIDECAR);
        assertThat(sidecar).isNotNull();
        assertThat(sidecar.isAdded()).isTrue();
    }

    private void verifyNoSidecar() {
        final Fragment sidecar = mActivity.getSupportFragmentManager().findFragmentByTag(
                TAG_SIDECAR);
        if (sidecar != null) {
            assertThat(sidecar.isAdded()).isFalse();
        }
    }
}
}