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

Commit 69f72fae authored by Hao Dong's avatar Hao Dong
Browse files

Use PromptKind to decide which layout to show.

1. Update PromptKind and use it to decide which layout to show.
In this way, we could know what PromptKind is before rendering the
layout. This enables us to use PromptKind to decide show one-pane or
two-pane layout as a follow-up step.

2. Do some clean ups.

Test: atest PromptSelectorInteractorImplTest
Test: atest PromptViewModelTest
Bug: 330908557
Flag: ACONFIG android.hardware.biometrics.custom_biometric_prompt NEXTFOOD

Change-Id: I2facb1e722c9f58475de92d685deddb3df055270
parent 47a93786
Loading
Loading
Loading
Loading
+2 −8
Original line number Diff line number Diff line
@@ -84,7 +84,6 @@ import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.domain.interactor.LogContextInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor;
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel;
@@ -161,8 +160,6 @@ public class AuthControllerTest extends SysuiTestCase {
    @Mock
    private InteractionJankMonitor mInteractionJankMonitor;
    @Mock
    private PromptCredentialInteractor mBiometricPromptCredentialInteractor;
    @Mock
    private PromptSelectorInteractor mPromptSelectionInteractor;
    @Mock
    private CredentialViewModel mCredentialViewModel;
@@ -1057,7 +1054,6 @@ public class AuthControllerTest extends SysuiTestCase {

    private final class TestableAuthController extends AuthController {
        private int mBuildCount = 0;
        private PromptInfo mLastBiometricPromptInfo;

        TestableAuthController(Context context) {
            super(context, null /* applicationCoroutineScope */,
@@ -1065,8 +1061,8 @@ public class AuthControllerTest extends SysuiTestCase {
                    mFingerprintManager, mFaceManager, () -> mUdfpsController, mDisplayManager,
                    mWakefulnessLifecycle, mPanelInteractionDetector, mUserManager,
                    mLockPatternUtils, () -> mUdfpsLogger, () -> mLogContextInteractor,
                    () -> mBiometricPromptCredentialInteractor, () -> mPromptSelectionInteractor,
                    () -> mCredentialViewModel, () -> mPromptViewModel, mInteractionJankMonitor,
                    () -> mPromptSelectionInteractor, () -> mCredentialViewModel,
                    () -> mPromptViewModel, mInteractionJankMonitor,
                    mHandler, mBackgroundExecutor, mUdfpsUtils, mVibratorHelper);
        }

@@ -1079,8 +1075,6 @@ public class AuthControllerTest extends SysuiTestCase {
                UserManager userManager,
                LockPatternUtils lockPatternUtils, PromptViewModel viewModel) {

            mLastBiometricPromptInfo = promptInfo;

            AuthDialog dialog;
            if (mBuildCount == 0) {
                dialog = mDialog1;
+2 −1
Original line number Diff line number Diff line
@@ -20,10 +20,11 @@ sealed interface PromptKind {
    object None : PromptKind

    data class Biometric(
        /** The available modalities for the authentication on the prompt. */
        val activeModalities: BiometricModalities = BiometricModalities(),
        // TODO(b/330908557): Use this value to decide whether to show two pane layout, instead of
        // simply depending on rotations.
        val showTwoPane: Boolean = false
        val showTwoPane: Boolean = false,
    ) : PromptKind

    object Pin : PromptKind
+18 −29
Original line number Diff line number Diff line
@@ -73,7 +73,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.biometrics.AuthController.ScaleFactorProvider;
import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor;
import com.android.systemui.biometrics.shared.model.BiometricModalities;
import com.android.systemui.biometrics.shared.model.PromptKind;
@@ -150,7 +149,6 @@ public class AuthContainerView extends LinearLayout
    private final CoroutineScope mApplicationCoroutineScope;

    // TODO(b/287311775): these should be migrated out once ready
    private final Provider<PromptCredentialInteractor> mPromptCredentialInteractor;
    private final @NonNull Provider<PromptSelectorInteractor> mPromptSelectorInteractorProvider;
    // TODO(b/287311775): these should be migrated out of the view
    private final Provider<CredentialViewModel> mCredentialViewModelProvider;
@@ -311,7 +309,6 @@ public class AuthContainerView extends LinearLayout
            @NonNull UserManager userManager,
            @NonNull LockPatternUtils lockPatternUtils,
            @NonNull InteractionJankMonitor jankMonitor,
            @NonNull Provider<PromptCredentialInteractor> promptCredentialInteractor,
            @NonNull Provider<PromptSelectorInteractor> promptSelectorInteractor,
            @NonNull PromptViewModel promptViewModel,
            @NonNull Provider<CredentialViewModel> credentialViewModelProvider,
@@ -319,7 +316,7 @@ public class AuthContainerView extends LinearLayout
            @NonNull VibratorHelper vibratorHelper) {
        this(config, applicationCoroutineScope, fpProps, faceProps,
                wakefulnessLifecycle, panelInteractionDetector, userManager, lockPatternUtils,
                jankMonitor, promptSelectorInteractor, promptCredentialInteractor, promptViewModel,
                jankMonitor, promptSelectorInteractor, promptViewModel,
                credentialViewModelProvider, new Handler(Looper.getMainLooper()), bgExecutor,
                vibratorHelper);
    }
@@ -335,7 +332,6 @@ public class AuthContainerView extends LinearLayout
            @NonNull LockPatternUtils lockPatternUtils,
            @NonNull InteractionJankMonitor jankMonitor,
            @NonNull Provider<PromptSelectorInteractor> promptSelectorInteractorProvider,
            @NonNull Provider<PromptCredentialInteractor> credentialInteractor,
            @NonNull PromptViewModel promptViewModel,
            @NonNull Provider<CredentialViewModel> credentialViewModelProvider,
            @NonNull Handler mainHandler,
@@ -358,13 +354,19 @@ public class AuthContainerView extends LinearLayout
        mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN;
        mBiometricCallback = new BiometricCallback();

        mFpProps = fpProps;
        mFaceProps = faceProps;
        final BiometricModalities biometricModalities = new BiometricModalities(
                Utils.findFirstSensorProperties(fpProps, mConfig.mSensorIds),
                Utils.findFirstSensorProperties(faceProps, mConfig.mSensorIds));

        mPromptSelectorInteractorProvider = promptSelectorInteractorProvider;
        mPromptSelectorInteractorProvider.get().setShouldShowBpWithoutIconForCredential(
                config.mPromptInfo);
        mPromptSelectorInteractorProvider.get().setPrompt(mConfig.mPromptInfo, mEffectiveUserId,
                biometricModalities, mConfig.mOperationId, mConfig.mOpPackageName,
                false /*onSwitchToCredential*/);

        final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
        if (constraintBp() && (Utils.isBiometricAllowed(config.mPromptInfo)
                || mPromptViewModel.getShowBpWithoutIconForCredential().getValue())) {
        if (constraintBp() && mPromptViewModel.getPromptKind().getValue().isBiometric()) {
            mLayout = (ConstraintLayout) layoutInflater.inflate(
                    R.layout.biometric_prompt_constraint_layout, this, false /* attachToRoot */);
        } else {
@@ -398,10 +400,7 @@ public class AuthContainerView extends LinearLayout
        mPanelController = new AuthPanelController(mContext, mPanelView);
        mBackgroundExecutor = bgExecutor;
        mInteractionJankMonitor = jankMonitor;
        mPromptCredentialInteractor = credentialInteractor;
        mCredentialViewModelProvider = credentialViewModelProvider;
        mFpProps = fpProps;
        mFaceProps = faceProps;

        showPrompt(config, layoutInflater, promptViewModel,
                Utils.findFirstSensorProperties(fpProps, mConfig.mSensorIds),
@@ -430,11 +429,12 @@ public class AuthContainerView extends LinearLayout
            @Nullable FaceSensorPropertiesInternal faceProps,
            @NonNull VibratorHelper vibratorHelper
    ) {
        if (Utils.isBiometricAllowed(config.mPromptInfo)
                || mPromptViewModel.getShowBpWithoutIconForCredential().getValue()) {
        if (mPromptViewModel.getPromptKind().getValue().isBiometric()) {
            addBiometricView(config, layoutInflater, viewModel, fpProps, faceProps, vibratorHelper);
        } else if (constraintBp() && Utils.isDeviceCredentialAllowed(mConfig.mPromptInfo)) {
        } else if (mPromptViewModel.getPromptKind().getValue().isCredential()) {
            if (constraintBp()) {
                addCredentialView(true, false);
            }
        } else {
            mPromptSelectorInteractorProvider.get().resetPrompt();
        }
@@ -445,12 +445,6 @@ public class AuthContainerView extends LinearLayout
            @Nullable FingerprintSensorPropertiesInternal fpProps,
            @Nullable FaceSensorPropertiesInternal faceProps,
            @NonNull VibratorHelper vibratorHelper) {
        mPromptSelectorInteractorProvider.get().useBiometricsForAuthentication(
                config.mPromptInfo,
                config.mUserId,
                config.mOperationId,
                new BiometricModalities(fpProps, faceProps),
                config.mOpPackageName);

        if (constraintBp()) {
            mBiometricView = BiometricViewBinder.bind(mLayout, viewModel, null,
@@ -519,10 +513,6 @@ public class AuthContainerView extends LinearLayout
        // disable it.
        mBackgroundView.setOnClickListener(null);
        mBackgroundView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);

        mPromptSelectorInteractorProvider.get().useCredentialsForAuthentication(
                mConfig.mPromptInfo, credentialType, mConfig.mUserId, mConfig.mOperationId,
                mConfig.mOpPackageName);
        final CredentialViewModel vm = mCredentialViewModelProvider.get();
        vm.setAnimateContents(animateContents);
        ((CredentialView) mCredentialView).init(vm, this, mPanelController, animatePanel,
@@ -557,10 +547,9 @@ public class AuthContainerView extends LinearLayout
                () -> animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED));
        if (constraintBp()) {
            // Do nothing on attachment with constraintLayout
        } else if (Utils.isBiometricAllowed(mConfig.mPromptInfo)
                || mPromptViewModel.getShowBpWithoutIconForCredential().getValue()) {
        } else if (mPromptViewModel.getPromptKind().getValue().isBiometric()) {
            mBiometricScrollView.addView(mBiometricView.asView());
        } else if (Utils.isDeviceCredentialAllowed(mConfig.mPromptInfo)) {
        } else if (mPromptViewModel.getPromptKind().getValue().isCredential()) {
            addCredentialView(true /* animatePanel */, false /* animateContents */);
        } else {
            throw new IllegalStateException("Unknown configuration: "
+2 −6
Original line number Diff line number Diff line
@@ -69,7 +69,6 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.CoreStartable;
import com.android.systemui.biometrics.domain.interactor.LogContextInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor;
import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
@@ -139,7 +138,6 @@ public class AuthController implements
    private Job mBiometricContextListenerJob = null;

    // TODO: these should be migrated out once ready
    @NonNull private final Provider<PromptCredentialInteractor> mPromptCredentialInteractor;
    @NonNull private final Provider<PromptSelectorInteractor> mPromptSelectorInteractor;
    @NonNull private final Provider<CredentialViewModel> mCredentialViewModelProvider;
    @NonNull private final Provider<PromptViewModel> mPromptViewModelProvider;
@@ -735,7 +733,6 @@ public class AuthController implements
            @NonNull LockPatternUtils lockPatternUtils,
            @NonNull Lazy<UdfpsLogger> udfpsLogger,
            @NonNull Lazy<LogContextInteractor> logContextInteractor,
            @NonNull Provider<PromptCredentialInteractor> promptCredentialInteractorProvider,
            @NonNull Provider<PromptSelectorInteractor> promptSelectorInteractorProvider,
            @NonNull Provider<CredentialViewModel> credentialViewModelProvider,
            @NonNull Provider<PromptViewModel> promptViewModelProvider,
@@ -768,7 +765,6 @@ public class AuthController implements

        mLogContextInteractor = logContextInteractor;
        mPromptSelectorInteractor = promptSelectorInteractorProvider;
        mPromptCredentialInteractor = promptCredentialInteractorProvider;
        mPromptViewModelProvider = promptViewModelProvider;
        mCredentialViewModelProvider = credentialViewModelProvider;

@@ -1316,8 +1312,8 @@ public class AuthController implements
        config.mScaleProvider = this::getScaleFactor;
        return new AuthContainerView(config, mApplicationCoroutineScope, mFpProps, mFaceProps,
                wakefulnessLifecycle, panelInteractionDetector, userManager, lockPatternUtils,
                mInteractionJankMonitor, mPromptCredentialInteractor, mPromptSelectorInteractor,
                viewModel, mCredentialViewModelProvider, bgExecutor, mVibratorHelper);
                mInteractionJankMonitor, mPromptSelectorInteractor, viewModel,
                mCredentialViewModelProvider, bgExecutor, mVibratorHelper);
    }

    @Override
+6 −37
Original line number Diff line number Diff line
@@ -16,12 +16,8 @@

package com.android.systemui.biometrics.data.repository

import android.hardware.biometrics.Flags
import android.hardware.biometrics.PromptInfo
import com.android.systemui.Flags.constraintBp
import com.android.systemui.biometrics.AuthController
import com.android.systemui.biometrics.Utils
import com.android.systemui.biometrics.Utils.isDeviceCredentialAllowed
import com.android.systemui.biometrics.shared.model.PromptKind
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
@@ -56,8 +52,8 @@ interface PromptRepository {
    /** The gatekeeper challenge, if one is associated with this prompt. */
    val challenge: StateFlow<Long?>

    /** The kind of credential to use (biometric, pin, pattern, etc.). */
    val kind: StateFlow<PromptKind>
    /** The kind of prompt to use (biometric, pin, pattern, etc.). */
    val promptKind: StateFlow<PromptKind>

    /** The package name that the prompt is called from. */
    val opPackageName: StateFlow<String?>
@@ -69,18 +65,6 @@ interface PromptRepository {
     */
    val isConfirmationRequired: Flow<Boolean>

    /**
     * If biometric prompt without icon needs to show for displaying content prior to credential
     * view.
     */
    val showBpWithoutIconForCredential: StateFlow<Boolean>

    /**
     * Update whether biometric prompt without icon needs to show for displaying content prior to
     * credential view, which should be set before [setPrompt].
     */
    fun setShouldShowBpWithoutIconForCredential(promptInfo: PromptInfo)

    /** Update the prompt configuration, which should be set before [isShowing]. */
    fun setPrompt(
        promptInfo: PromptInfo,
@@ -125,8 +109,8 @@ constructor(
    private val _userId: MutableStateFlow<Int?> = MutableStateFlow(null)
    override val userId = _userId.asStateFlow()

    private val _kind: MutableStateFlow<PromptKind> = MutableStateFlow(PromptKind.None)
    override val kind = _kind.asStateFlow()
    private val _promptKind: MutableStateFlow<PromptKind> = MutableStateFlow(PromptKind.None)
    override val promptKind = _promptKind.asStateFlow()

    private val _opPackageName: MutableStateFlow<String?> = MutableStateFlow(null)
    override val opPackageName = _opPackageName.asStateFlow()
@@ -145,21 +129,6 @@ constructor(
            }
            .distinctUntilChanged()

    private val _showBpWithoutIconForCredential: MutableStateFlow<Boolean> = MutableStateFlow(false)
    override val showBpWithoutIconForCredential = _showBpWithoutIconForCredential.asStateFlow()

    override fun setShouldShowBpWithoutIconForCredential(promptInfo: PromptInfo) {
        val hasCredentialViewShown = kind.value.isCredential()
        val showBpForCredential =
            Flags.customBiometricPrompt() &&
                constraintBp() &&
                !Utils.isBiometricAllowed(promptInfo) &&
                isDeviceCredentialAllowed(promptInfo) &&
                promptInfo.contentView != null &&
                !promptInfo.isContentViewMoreOptionsButtonUsed
        _showBpWithoutIconForCredential.value = showBpForCredential && !hasCredentialViewShown
    }

    override fun setPrompt(
        promptInfo: PromptInfo,
        userId: Int,
@@ -167,7 +136,7 @@ constructor(
        kind: PromptKind,
        opPackageName: String,
    ) {
        _kind.value = kind
        _promptKind.value = kind
        _userId.value = userId
        _challenge.value = gatekeeperChallenge
        _promptInfo.value = promptInfo
@@ -178,7 +147,7 @@ constructor(
        _promptInfo.value = null
        _userId.value = null
        _challenge.value = null
        _kind.value = PromptKind.None
        _promptKind.value = PromptKind.None
        _opPackageName.value = null
    }

Loading