diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java index fd589f46dbc..9abf38d3aa1 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java @@ -134,6 +134,9 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title); 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. // adb shell am start -a android.app.action.SET_NEW_PASSWORD @@ -148,11 +151,19 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements // it passed in. getIntent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken); - startLookingForFingerprint(); + // 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(); + } }); } else if (mToken != null) { - // HAT passed in from somewhere else, such as FingerprintEnrollIntroduction - startLookingForFingerprint(); + // 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 + startLookingForFingerprint(); + } } else { // There's something wrong with the enrollment flow, this should never happen. throw new IllegalStateException("HAT and GkPwHandle both missing..."); @@ -173,9 +184,6 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements mAnimation = (FingerprintFindSensorAnimation) animationView; } } - if (savedInstanceState != null) { - mNextClicked = savedInstanceState.getBoolean(SAVED_STATE_IS_NEXT_CLICKED, mNextClicked); - } } @Override @@ -297,6 +305,7 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements return; } } + mSidecar.setListener(null); getSupportFragmentManager().beginTransaction().remove(mSidecar). commitAllowingStateLoss(); mSidecar = null; diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java index b606b607a5a..c24e9f0d5e7 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java @@ -50,6 +50,8 @@ public class FingerprintEnrollFinish extends BiometricEnrollBase { static final String FINGERPRINT_SUGGESTION_ACTIVITY = "com.android.settings.SetupFingerprintSuggestionActivity"; + private boolean mIsAddAnotherOrFinish; + @Override protected void onCreate(Bundle 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 protected void onNextButtonClick(View view) { updateFingerprintSuggestionEnableState(); + finishAndToNext(); + } + + private void finishAndToNext() { + mIsAddAnotherOrFinish = true; setResult(RESULT_FINISHED); if (WizardManagerHelper.isAnySetupWizard(getIntent())) { postEnroll(); @@ -145,20 +161,21 @@ public class FingerprintEnrollFinish extends BiometricEnrollBase { } private void onAddAnotherButtonClick(View view) { + mIsAddAnotherOrFinish = true; startActivityForResult(getFingerprintEnrollingIntent(), BiometricUtils.REQUEST_ADD_ANOTHER); } @Override protected boolean shouldFinishWhenBackgrounded() { - return !isFinishing() && super.shouldFinishWhenBackgrounded(); + return !mIsAddAnotherOrFinish && super.shouldFinishWhenBackgrounded(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { updateFingerprintSuggestionEnableState(); if (requestCode == BiometricUtils.REQUEST_ADD_ANOTHER && resultCode != RESULT_CANCELED) { - setResult(resultCode, data); - finish(); + // If user cancel during "Add another", just use similar flow on "Next" button + finishAndToNext(); } else { super.onActivityResult(requestCode, resultCode, data); } diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensorTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensorTest.java index 49a16cbc77b..fad3abf2a3a 100644 --- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensorTest.java +++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensorTest.java @@ -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_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.assertWithMessage; @@ -29,6 +34,7 @@ import static org.mockito.Mockito.eq; import static org.mockito.Mockito.verify; import static org.robolectric.RuntimeEnvironment.application; +import android.annotation.NonNull; import android.app.Activity; import android.content.ComponentName; import android.content.Intent; @@ -38,9 +44,12 @@ import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager.EnrollmentCallback; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; +import android.os.Bundle; import android.os.CancellationSignal; import android.view.View; +import androidx.fragment.app.Fragment; + import com.android.settings.R; import com.android.settings.biometrics.BiometricEnrollBase; import com.android.settings.password.ChooseLockSettingsHelper; @@ -82,12 +91,7 @@ public class FingerprintEnrollFindSensorTest { private FingerprintEnrollFindSensor mActivity; - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - ShadowUtils.setFingerprintManager(mFingerprintManager); - FakeFeatureFactory.setupForTest(); - + private void buildActivity() { mActivityController = Robolectric.buildActivity( FingerprintEnrollFindSensor.class, new Intent() @@ -97,6 +101,14 @@ public class FingerprintEnrollFindSensorTest { mActivity = mActivityController.get(); } + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + ShadowUtils.setFingerprintManager(mFingerprintManager); + FakeFeatureFactory.setupForTest(); + buildActivity(); + } + private void setupActivity_onRearDevice() { final ArrayList props = new ArrayList<>(); props.add(newFingerprintSensorPropertiesInternal(TYPE_REAR)); @@ -187,7 +199,7 @@ public class FingerprintEnrollFindSensorTest { ShadowActivity shadowActivity = Shadows.shadowOf(mActivity); assertWithMessage("result code").that(shadowActivity.getResultCode()) - .isEqualTo(BiometricEnrollBase.RESULT_SKIP); + .isEqualTo(RESULT_SKIP); } private EnrollmentCallback verifyAndCaptureEnrollmentCallback() { @@ -214,123 +226,320 @@ public class FingerprintEnrollFindSensorTest { } @Test - public void enrollingFinishResultShallSentBack_onRearDevice() { + public void resultFinishShallForward_onRearDevice() { setupActivity_onRearDevice(); triggerEnrollProgressAndError_onRearDevice(); verifyStartEnrollingActivity(); - // onStop shall not change default activity result + // pause activity mActivityController.pause().stop(); + + // onStop shall not change default activity result assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT); - gotEnrollingResult_verifyResultSentBack(BiometricEnrollBase.RESULT_FINISHED); + gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_FINISHED); } @Test - public void enrollingSkipResultShallSentBack_onRearDevice() { + 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 - mActivityController.pause().stop(); assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT); - gotEnrollingResult_verifyResultSentBack(BiometricEnrollBase.RESULT_SKIP); + gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_FINISHED, bundle); } @Test - public void enrollingTimeoutResultShallSentBack_onRearDevice() { + public void resultSkipShallForward_onRearDevice() { setupActivity_onRearDevice(); + verifySidecar_onRearOrSfpsDevice(); + triggerEnrollProgressAndError_onRearDevice(); verifyStartEnrollingActivity(); - // onStop shall not change default activity result + // pause activity mActivityController.pause().stop(); + + // onStop shall not change default activity result assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT); - gotEnrollingResult_verifyResultSentBack(BiometricEnrollBase.RESULT_TIMEOUT); + gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_SKIP); } @Test - public void enrollingFinishResultShallSentBack_onUdfpsDevice_triggeredByLottieClick() { + public void resultSkipShallForward_onRearDevice_recreate() { + setupActivity_onRearDevice(); + verifySidecar_onRearOrSfpsDevice(); + + 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_SKIP, bundle); + } + + @Test + public void resultTimeoutShallForward_onRearDevice() { + setupActivity_onRearDevice(); + verifySidecar_onRearOrSfpsDevice(); + + triggerEnrollProgressAndError_onRearDevice(); + verifyStartEnrollingActivity(); + + // pause activity + mActivityController.pause().stop(); + + // onStop shall not change default activity result + assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT); + + gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_TIMEOUT); + } + + @Test + public void resultTimeoutShallForward_onRearDevice_recreate() { + setupActivity_onRearDevice(); + verifySidecar_onRearOrSfpsDevice(); + + 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_TIMEOUT, bundle); + } + + @Test + public void clickLottieResultFinishShallForward_onUdfpsDevice() { setupActivity_onUdfpsDevice(); + verifyNoSidecar(); + clickLottieView_onUdfpsDevice(); verifyStartEnrollingActivity(); assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT); - // onStop shall not change default activity result + // pause activity mActivityController.pause().stop(); + + // onStop shall not change default activity result assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT); - gotEnrollingResult_verifyResultSentBack(BiometricEnrollBase.RESULT_FINISHED); + gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_FINISHED); } @Test - public void enrollingSkipResultShallSentBack_onUdfpsDevice_triggeredByLottieClick() { + public void clickLottieResultFinishShallForward_onUdfpsDevice_ifActivityRecycled() { setupActivity_onUdfpsDevice(); + verifyNoSidecar(); + clickLottieView_onUdfpsDevice(); verifyStartEnrollingActivity(); 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 - mActivityController.pause().stop(); assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT); - gotEnrollingResult_verifyResultSentBack(BiometricEnrollBase.RESULT_SKIP); + gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_FINISHED, bundle); } @Test - public void enrollingTimeoutResultShallSentBack_onUdfpsDevice_triggeredByLottieClick() { + public void clickLottieResultSkipShallForward_onUdfpsDevice() { setupActivity_onUdfpsDevice(); + verifyNoSidecar(); + clickLottieView_onUdfpsDevice(); verifyStartEnrollingActivity(); assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT); - // onStop shall not change default activity result + // pause activity mActivityController.pause().stop(); + + // onStop shall not change default activity result assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT); - gotEnrollingResult_verifyResultSentBack(BiometricEnrollBase.RESULT_TIMEOUT); + gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_SKIP); } @Test - public void enrollingFinishResultShallSentBack_onUdfpsDevice_triggeredByPrimaryButtonClick() { + public void clickLottieResultSkipShallForward_onUdfpsDevice_ifActivityRecycled() { setupActivity_onUdfpsDevice(); - clickPrimaryButton_onUdfpsDevice(); - verifyStartEnrollingActivity(); + verifyNoSidecar(); - // onStop shall not change default activity result - mActivityController.pause().stop(); + clickLottieView_onUdfpsDevice(); + verifyStartEnrollingActivity(); assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT); - gotEnrollingResult_verifyResultSentBack(BiometricEnrollBase.RESULT_FINISHED); + // 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_SKIP, bundle); } @Test - public void enrollingSkipResultShallSentBack_onUdfpsDevice_triggeredByPrimaryButtonClick() { + public void clickLottieResultTimeoutShallForward_onUdfpsDevice() { setupActivity_onUdfpsDevice(); - clickPrimaryButton_onUdfpsDevice(); - verifyStartEnrollingActivity(); + verifyNoSidecar(); - // onStop shall not change default activity result - mActivityController.pause().stop(); + clickLottieView_onUdfpsDevice(); + verifyStartEnrollingActivity(); assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT); - gotEnrollingResult_verifyResultSentBack(BiometricEnrollBase.RESULT_SKIP); + // pause activity + mActivityController.pause().stop(); + + // onStop shall not change default activity result + assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT); + + gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_TIMEOUT); } @Test - public void enrollingTimeoutResultShallSentBack_onUdfpsDevice_triggeredByPrimaryButtonClick() { + public void clickLottieResultTimeoutShallForward_onUdfpsDevice_ifActivityRecycled() { setupActivity_onUdfpsDevice(); + verifyNoSidecar(); + + clickLottieView_onUdfpsDevice(); + verifyStartEnrollingActivity(); + 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 + 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(); - // onStop shall not change default activity result + // pause activity mActivityController.pause().stop(); + + // onStop shall not change default activity result assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT); - gotEnrollingResult_verifyResultSentBack(BiometricEnrollBase.RESULT_TIMEOUT); + gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_FINISHED); + } + + @Test + public void clickPrimiaryButtonResultFinishShallForward_onUdfpsDevice_ifActivityRecycled() { + setupActivity_onUdfpsDevice(); + verifyNoSidecar(); + + clickPrimaryButton_onUdfpsDevice(); + 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 clickPrimiaryButtonResultSkipShallForward_onUdfpsDevice() { + setupActivity_onUdfpsDevice(); + verifyNoSidecar(); + + clickPrimaryButton_onUdfpsDevice(); + verifyStartEnrollingActivity(); + + // pause activity + mActivityController.pause().stop(); + + // onStop shall not change default activity result + assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT); + + gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_SKIP); + } + + @Test + public void clickPrimaryButtonResultSkipShallForward_onUdfpsDevice_ifActivityRecycled() { + setupActivity_onUdfpsDevice(); + verifyNoSidecar(); + + clickPrimaryButton_onUdfpsDevice(); + 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_SKIP, bundle); + } + + @Test + public void clickPrimaryButtonResultTimeoutShallForward_onUdfpsDevice() { + setupActivity_onUdfpsDevice(); + verifyNoSidecar(); + + clickPrimaryButton_onUdfpsDevice(); + verifyStartEnrollingActivity(); + + // pause activity + mActivityController.pause().stop(); + + // onStop shall not change default activity result + assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT); + + gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_TIMEOUT); + } + + @Test + public void clickPrimaryButtonResultTimeoutShallForward_onUdfpsDevice_ifActivityRecycled() { + setupActivity_onUdfpsDevice(); + verifyNoSidecar(); + + clickPrimaryButton_onUdfpsDevice(); + 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_TIMEOUT, bundle); } private void triggerEnrollProgressAndError_onRearDevice() { @@ -355,9 +564,13 @@ public class FingerprintEnrollFindSensorTest { lottieView.performClick(); } - private void gotEnrollingResult_verifyResultSentBack(int testActivityResult) { - // onActivityResult from Enrolling activity shall be sent back + private void gotEnrollingResult_resumeActivityAndVerifyResultThenForward( + int testActivityResult) { + // resume activity mActivityController.start().resume().visible(); + verifyNoSidecar(); + + // onActivityResult from Enrolling activity shall be forward back Shadows.shadowOf(mActivity).receiveResult( new Intent(mActivity, FingerprintEnrollEnrolling.class), testActivityResult, @@ -366,7 +579,42 @@ public class FingerprintEnrollFindSensorTest { assertThat(mActivity.isFinishing()).isEqualTo(true); // 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); + } + + 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(); + } + } }