From 3d9a78c05c23063ee416b693dffa0560e648d076 Mon Sep 17 00:00:00 2001 From: Grace Cheng Date: Mon, 14 Aug 2023 21:19:04 +0000 Subject: [PATCH] Fix missing BP icon Bind SFPS BiometricPrompt iconView to ViewModel, introduce BiometricSensorPropertiesInteractor for accessing FingerprintPropertyRepository, fix initial BiometricState and state after device rotation, and rename ViewModel and ViewBinder files to match BP refactor Fixes: 286983554 Test: (manual) Observe BP icon is visible and plays animation upon opening and after device rotations Test: atest AuthContainerViewTest Test: atest AuthControllerTest Test: atest PromptFingerprintIconViewModelTest Test: atest PromptViewModelTest Change-Id: Id51e8bfa15b2db929499a46437d0a8c77405435f Merged-In: Id51e8bfa15b2db929499a46437d0a8c77405435f --- .../biometrics/AuthContainerView.java | 21 ++-------- .../systemui/biometrics/AuthController.java | 11 +----- .../interactor/PromptSelectorInteractor.kt | 10 +++++ .../AuthBiometricFingerprintViewBinder.kt | 34 ---------------- .../ui/binder/BiometricViewBinder.kt | 3 ++ ....kt => PromptFingerprintIconViewBinder.kt} | 21 +++++----- ...l.kt => PromptFingerprintIconViewModel.kt} | 30 +++++++++----- .../ui/viewmodel/PromptViewModel.kt | 39 ++++++++++++------- .../biometrics/AuthContainerViewTest.kt | 17 +++++--- .../biometrics/AuthControllerTest.java | 12 ++---- .../PromptSelectorInteractorImplTest.kt | 5 ++- ... => PromptFingerprintIconViewModelTest.kt} | 37 +++++++++++++++--- .../ui/viewmodel/PromptViewModelTest.kt | 23 +++++++++-- 13 files changed, 147 insertions(+), 116 deletions(-) delete mode 100644 packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintViewBinder.kt rename packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/{AuthBiometricFingerprintIconViewBinder.kt => PromptFingerprintIconViewBinder.kt} (68%) rename packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/{AuthBiometricFingerprintViewModel.kt => PromptFingerprintIconViewModel.kt} (70%) rename packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/{AuthBiometricFingerprintViewModelTest.kt => PromptFingerprintIconViewModelTest.kt} (56%) diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index 58c8000a23287..802a550c4d297 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -73,9 +73,7 @@ import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteracto import com.android.systemui.biometrics.domain.model.BiometricModalities; import com.android.systemui.biometrics.ui.BiometricPromptLayout; import com.android.systemui.biometrics.ui.CredentialView; -import com.android.systemui.biometrics.ui.binder.AuthBiometricFingerprintViewBinder; import com.android.systemui.biometrics.ui.binder.BiometricViewBinder; -import com.android.systemui.biometrics.ui.viewmodel.AuthBiometricFingerprintViewModel; import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel; import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel; import com.android.systemui.dagger.qualifiers.Background; @@ -142,8 +140,6 @@ public class AuthContainerView extends LinearLayout // TODO: these should be migrated out once ready private final Provider mPromptCredentialInteractor; - private final Provider - mAuthBiometricFingerprintViewModelProvider; private final @NonNull Provider mPromptSelectorInteractorProvider; // TODO(b/251476085): these should be migrated out of the view private final Provider mCredentialViewModelProvider; @@ -283,8 +279,6 @@ public class AuthContainerView extends LinearLayout @NonNull UserManager userManager, @NonNull LockPatternUtils lockPatternUtils, @NonNull InteractionJankMonitor jankMonitor, - @NonNull Provider - authBiometricFingerprintViewModelProvider, @NonNull Provider promptCredentialInteractor, @NonNull Provider promptSelectorInteractor, @NonNull PromptViewModel promptViewModel, @@ -293,9 +287,9 @@ public class AuthContainerView extends LinearLayout @NonNull VibratorHelper vibratorHelper) { this(config, featureFlags, applicationCoroutineScope, fpProps, faceProps, wakefulnessLifecycle, panelInteractionDetector, userManager, lockPatternUtils, - jankMonitor, authBiometricFingerprintViewModelProvider, promptSelectorInteractor, - promptCredentialInteractor, promptViewModel, credentialViewModelProvider, - new Handler(Looper.getMainLooper()), bgExecutor, vibratorHelper); + jankMonitor, promptSelectorInteractor, promptCredentialInteractor, promptViewModel, + credentialViewModelProvider, new Handler(Looper.getMainLooper()), bgExecutor, + vibratorHelper); } @VisibleForTesting @@ -309,8 +303,6 @@ public class AuthContainerView extends LinearLayout @NonNull UserManager userManager, @NonNull LockPatternUtils lockPatternUtils, @NonNull InteractionJankMonitor jankMonitor, - @NonNull Provider - authBiometricFingerprintViewModelProvider, @NonNull Provider promptSelectorInteractorProvider, @NonNull Provider credentialInteractor, @NonNull PromptViewModel promptViewModel, @@ -359,7 +351,6 @@ public class AuthContainerView extends LinearLayout mBackgroundExecutor = bgExecutor; mInteractionJankMonitor = jankMonitor; mPromptCredentialInteractor = credentialInteractor; - mAuthBiometricFingerprintViewModelProvider = authBiometricFingerprintViewModelProvider; mPromptSelectorInteractorProvider = promptSelectorInteractorProvider; mCredentialViewModelProvider = credentialViewModelProvider; mPromptViewModel = promptViewModel; @@ -442,9 +433,6 @@ public class AuthContainerView extends LinearLayout fingerprintAndFaceView.updateOverrideIconLayoutParamsSize(); fingerprintAndFaceView.setFaceClass3( faceProperties.sensorStrength == STRENGTH_STRONG); - final AuthBiometricFingerprintViewModel fpAndFaceViewModel = - mAuthBiometricFingerprintViewModelProvider.get(); - AuthBiometricFingerprintViewBinder.bind(fingerprintAndFaceView, fpAndFaceViewModel); mBiometricView = fingerprintAndFaceView; } else if (fpProperties != null) { final AuthBiometricFingerprintView fpView = @@ -453,9 +441,6 @@ public class AuthContainerView extends LinearLayout fpView.setSensorProperties(fpProperties); fpView.setScaleFactorProvider(config.mScaleProvider); fpView.updateOverrideIconLayoutParamsSize(); - final AuthBiometricFingerprintViewModel fpViewModel = - mAuthBiometricFingerprintViewModelProvider.get(); - AuthBiometricFingerprintViewBinder.bind(fpView, fpViewModel); mBiometricView = fpView; } else if (faceProperties != null) { mBiometricView = (AuthBiometricFaceView) layoutInflater.inflate( diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 7b288a8d49f1c..d5289a49be516 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -73,7 +73,6 @@ 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.ui.viewmodel.AuthBiometricFingerprintViewModel; import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel; import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel; import com.android.systemui.dagger.SysUISingleton; @@ -134,8 +133,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, private final CoroutineScope mApplicationCoroutineScope; // TODO: these should be migrated out once ready - @NonNull private final Provider - mAuthBiometricFingerprintViewModelProvider; @NonNull private final Provider mPromptCredentialInteractor; @NonNull private final Provider mPromptSelectorInteractor; @NonNull private final Provider mCredentialViewModelProvider; @@ -765,8 +762,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, @NonNull LockPatternUtils lockPatternUtils, @NonNull UdfpsLogger udfpsLogger, @NonNull LogContextInteractor logContextInteractor, - @NonNull Provider - authBiometricFingerprintViewModelProvider, @NonNull Provider promptCredentialInteractorProvider, @NonNull Provider promptSelectorInteractorProvider, @NonNull Provider credentialViewModelProvider, @@ -801,7 +796,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, mVibratorHelper = vibratorHelper; mLogContextInteractor = logContextInteractor; - mAuthBiometricFingerprintViewModelProvider = authBiometricFingerprintViewModelProvider; mPromptSelectorInteractor = promptSelectorInteractorProvider; mPromptCredentialInteractor = promptCredentialInteractorProvider; mPromptViewModelProvider = promptViewModelProvider; @@ -1344,9 +1338,8 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, config.mScaleProvider = this::getScaleFactor; return new AuthContainerView(config, mFeatureFlags, mApplicationCoroutineScope, mFpProps, mFaceProps, wakefulnessLifecycle, panelInteractionDetector, userManager, lockPatternUtils, - mInteractionJankMonitor, mAuthBiometricFingerprintViewModelProvider, - mPromptCredentialInteractor, mPromptSelectorInteractor, viewModel, - mCredentialViewModelProvider, bgExecutor, mVibratorHelper); + mInteractionJankMonitor, mPromptCredentialInteractor, mPromptSelectorInteractor, + viewModel, mCredentialViewModelProvider, bgExecutor, mVibratorHelper); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt index bb87dca1cdc44..5badcaf060031 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt @@ -21,15 +21,18 @@ import com.android.internal.widget.LockPatternUtils import com.android.systemui.biometrics.Utils import com.android.systemui.biometrics.Utils.getCredentialType import com.android.systemui.biometrics.Utils.isDeviceCredentialAllowed +import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository import com.android.systemui.biometrics.data.repository.PromptRepository import com.android.systemui.biometrics.domain.model.BiometricModalities import com.android.systemui.biometrics.domain.model.BiometricOperationInfo import com.android.systemui.biometrics.domain.model.BiometricPromptRequest import com.android.systemui.biometrics.shared.model.BiometricUserInfo +import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.PromptKind import com.android.systemui.dagger.SysUISingleton import javax.inject.Inject import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map @@ -65,6 +68,9 @@ interface PromptSelectorInteractor { */ val isConfirmationRequired: Flow + /** Fingerprint sensor type */ + val sensorType: StateFlow + /** Use biometrics for authentication. */ fun useBiometricsForAuthentication( promptInfo: PromptInfo, @@ -89,6 +95,7 @@ interface PromptSelectorInteractor { class PromptSelectorInteractorImpl @Inject constructor( + private val fingerprintPropertyRepository: FingerprintPropertyRepository, private val promptRepository: PromptRepository, lockPatternUtils: LockPatternUtils, ) : PromptSelectorInteractor { @@ -140,6 +147,9 @@ constructor( } } + override val sensorType: StateFlow = + fingerprintPropertyRepository.sensorType + override fun useBiometricsForAuthentication( promptInfo: PromptInfo, userId: Int, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintViewBinder.kt deleted file mode 100644 index 9c1bcec2f396d..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintViewBinder.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2023 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.systemui.biometrics.ui.binder - -import com.android.systemui.biometrics.AuthBiometricFingerprintView -import com.android.systemui.biometrics.ui.viewmodel.AuthBiometricFingerprintViewModel - -object AuthBiometricFingerprintViewBinder { - - /** - * Binds a [AuthBiometricFingerprintView.mIconView] to a [AuthBiometricFingerprintViewModel]. - */ - @JvmStatic - fun bind(view: AuthBiometricFingerprintView, viewModel: AuthBiometricFingerprintViewModel) { - if (view.isSfps) { - AuthBiometricFingerprintIconViewBinder.bind(view.getIconView(), viewModel) - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt index d054751b760ba..b1439fd7421d7 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt @@ -108,6 +108,9 @@ object BiometricViewBinder { val iconViewOverlay = view.requireViewById(R.id.biometric_icon_overlay) val iconView = view.requireViewById(R.id.biometric_icon) + + PromptFingerprintIconViewBinder.bind(iconView, viewModel.fingerprintIconViewModel) + val indicatorMessageView = view.requireViewById(R.id.indicator) // Negative-side (left) buttons diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptFingerprintIconViewBinder.kt similarity index 68% rename from packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintIconViewBinder.kt rename to packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptFingerprintIconViewBinder.kt index bd0907e588ca6..188c82b523749 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintIconViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptFingerprintIconViewBinder.kt @@ -21,26 +21,29 @@ import android.view.DisplayInfo import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.airbnb.lottie.LottieAnimationView -import com.android.systemui.biometrics.AuthBiometricFingerprintView -import com.android.systemui.biometrics.ui.viewmodel.AuthBiometricFingerprintViewModel +import com.android.systemui.biometrics.ui.viewmodel.PromptFingerprintIconViewModel import com.android.systemui.lifecycle.repeatWhenAttached import kotlinx.coroutines.launch -/** Sub-binder for [AuthBiometricFingerprintView.mIconView]. */ -object AuthBiometricFingerprintIconViewBinder { +/** Sub-binder for [BiometricPromptLayout.iconView]. */ +object PromptFingerprintIconViewBinder { - /** - * Binds a [AuthBiometricFingerprintView.mIconView] to a [AuthBiometricFingerprintViewModel]. - */ + /** Binds [BiometricPromptLayout.iconView] to [PromptFingerprintIconViewModel]. */ @JvmStatic - fun bind(view: LottieAnimationView, viewModel: AuthBiometricFingerprintViewModel) { + fun bind(view: LottieAnimationView, viewModel: PromptFingerprintIconViewModel) { view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.STARTED) { val displayInfo = DisplayInfo() view.context.display?.getDisplayInfo(displayInfo) viewModel.setRotation(displayInfo.rotation) viewModel.onConfigurationChanged(view.context.resources.configuration) - launch { viewModel.iconAsset.collect { iconAsset -> view.setAnimation(iconAsset) } } + launch { + viewModel.iconAsset.collect { iconAsset -> + if (iconAsset != -1) { + view.setAnimation(iconAsset) + } + } + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/AuthBiometricFingerprintViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt similarity index 70% rename from packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/AuthBiometricFingerprintViewModel.kt rename to packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt index 617d80cee09dd..9b30acb84428d 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/AuthBiometricFingerprintViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt @@ -22,23 +22,35 @@ import android.content.res.Configuration import android.view.Surface import com.android.systemui.R import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor +import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor +import com.android.systemui.biometrics.shared.model.FingerprintSensorType import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine -/** Models UI of AuthBiometricFingerprintView to support rear display state changes. */ -class AuthBiometricFingerprintViewModel +/** Models UI of [BiometricPromptLayout.iconView] */ +class PromptFingerprintIconViewModel @Inject -constructor(private val interactor: DisplayStateInteractor) { +constructor( + private val displayStateInteractor: DisplayStateInteractor, + private val promptSelectorInteractor: PromptSelectorInteractor, +) { /** Current device rotation. */ private var rotation: Int = Surface.ROTATION_0 - /** Current AuthBiometricFingerprintView asset. */ + /** Current BiometricPromptLayout.iconView asset. */ val iconAsset: Flow = - combine(interactor.isFolded, interactor.isInRearDisplayMode) { - isFolded: Boolean, - isInRearDisplayMode: Boolean -> - getSideFpsAnimationAsset(isFolded, isInRearDisplayMode) + combine( + displayStateInteractor.isFolded, + displayStateInteractor.isInRearDisplayMode, + promptSelectorInteractor.sensorType, + ) { isFolded: Boolean, isInRearDisplayMode: Boolean, sensorType: FingerprintSensorType -> + when (sensorType) { + FingerprintSensorType.POWER_BUTTON -> + getSideFpsAnimationAsset(isFolded, isInRearDisplayMode) + // Replace below when non-SFPS iconAsset logic is migrated to this ViewModel + else -> -1 + } } @RawRes @@ -75,7 +87,7 @@ constructor(private val interactor: DisplayStateInteractor) { /** Called on configuration changes */ fun onConfigurationChanged(newConfig: Configuration) { - interactor.onConfigurationChanged(newConfig) + displayStateInteractor.onConfigurationChanged(newConfig) } fun setRotation(newRotation: Int) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt index 89561a5a212bc..4dc7720ef447a 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt @@ -20,6 +20,7 @@ import android.util.Log import android.view.HapticFeedbackConstants import android.view.MotionEvent import com.android.systemui.biometrics.AuthBiometricView +import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor import com.android.systemui.biometrics.domain.model.BiometricModalities import com.android.systemui.biometrics.shared.model.BiometricModality @@ -45,16 +46,23 @@ import kotlinx.coroutines.launch class PromptViewModel @Inject constructor( - private val interactor: PromptSelectorInteractor, + private val displayStateInteractor: DisplayStateInteractor, + private val promptSelectorInteractor: PromptSelectorInteractor, private val vibrator: VibratorHelper, private val featureFlags: FeatureFlags, ) { + /** Models UI of [BiometricPromptLayout.iconView] */ + val fingerprintIconViewModel: PromptFingerprintIconViewModel = + PromptFingerprintIconViewModel(displayStateInteractor, promptSelectorInteractor) + /** The set of modalities available for this prompt */ val modalities: Flow = - interactor.prompt.map { it?.modalities ?: BiometricModalities() }.distinctUntilChanged() + promptSelectorInteractor.prompt + .map { it?.modalities ?: BiometricModalities() } + .distinctUntilChanged() // TODO(b/251476085): remove after icon controllers are migrated - do not keep this state - private var _legacyState = MutableStateFlow(AuthBiometricView.STATE_AUTHENTICATING_ANIMATING_IN) + private var _legacyState = MutableStateFlow(AuthBiometricView.STATE_IDLE) val legacyState: StateFlow = _legacyState.asStateFlow() private val _isAuthenticating: MutableStateFlow = MutableStateFlow(false) @@ -75,17 +83,18 @@ constructor( * successful authentication. */ val isConfirmationRequired: Flow = - combine(_isOverlayTouched, interactor.isConfirmationRequired) { + combine(_isOverlayTouched, promptSelectorInteractor.isConfirmationRequired) { isOverlayTouched, isConfirmationRequired -> !isOverlayTouched && isConfirmationRequired } /** The kind of credential the user has. */ - val credentialKind: Flow = interactor.credentialKind + val credentialKind: Flow = promptSelectorInteractor.credentialKind /** The label to use for the cancel button. */ - val negativeButtonText: Flow = interactor.prompt.map { it?.negativeButtonText ?: "" } + val negativeButtonText: Flow = + promptSelectorInteractor.prompt.map { it?.negativeButtonText ?: "" } private val _message: MutableStateFlow = MutableStateFlow(PromptMessage.Empty) @@ -113,7 +122,7 @@ constructor( _forceLargeSize, _forceMediumSize, modalities, - interactor.isConfirmationRequired, + promptSelectorInteractor.isConfirmationRequired, fingerprintStartMode, ) { forceLarge, forceMedium, modalities, confirmationRequired, fpStartMode -> when { @@ -129,14 +138,16 @@ constructor( .distinctUntilChanged() /** Title for the prompt. */ - val title: Flow = interactor.prompt.map { it?.title ?: "" }.distinctUntilChanged() + val title: Flow = + promptSelectorInteractor.prompt.map { it?.title ?: "" }.distinctUntilChanged() /** Subtitle for the prompt. */ - val subtitle: Flow = interactor.prompt.map { it?.subtitle ?: "" }.distinctUntilChanged() + val subtitle: Flow = + promptSelectorInteractor.prompt.map { it?.subtitle ?: "" }.distinctUntilChanged() /** Description for the prompt. */ val description: Flow = - interactor.prompt.map { it?.description ?: "" }.distinctUntilChanged() + promptSelectorInteractor.prompt.map { it?.description ?: "" }.distinctUntilChanged() /** If the indicator (help, error) message should be shown. */ val isIndicatorMessageVisible: Flow = @@ -160,7 +171,9 @@ constructor( /** If the icon can be used as a confirmation button. */ val isIconConfirmButton: Flow = - combine(size, interactor.isConfirmationRequired) { size, isConfirmationRequired -> + combine(size, promptSelectorInteractor.isConfirmationRequired) { + size, + isConfirmationRequired -> size.isNotSmall && isConfirmationRequired } @@ -169,7 +182,7 @@ constructor( combine( size, isAuthenticated, - interactor.isCredentialAllowed, + promptSelectorInteractor.isCredentialAllowed, ) { size, authState, credentialAllowed -> size.isNotSmall && authState.isNotAuthenticated && !credentialAllowed } @@ -221,7 +234,7 @@ constructor( combine( size, isAuthenticated, - interactor.isCredentialAllowed, + promptSelectorInteractor.isCredentialAllowed, ) { size, authState, credentialAllowed -> size.isNotSmall && authState.isNotAuthenticated && credentialAllowed } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt index 4e52e64a8af13..9584d888b01f3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt @@ -39,13 +39,13 @@ import com.android.internal.jank.InteractionJankMonitor import com.android.internal.widget.LockPatternUtils import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository import com.android.systemui.biometrics.data.repository.FakePromptRepository import com.android.systemui.biometrics.data.repository.FakeRearDisplayStateRepository import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl import com.android.systemui.biometrics.domain.interactor.FakeCredentialInteractor import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl -import com.android.systemui.biometrics.ui.viewmodel.AuthBiometricFingerprintViewModel import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel import com.android.systemui.flags.FakeFeatureFlags @@ -109,6 +109,7 @@ open class AuthContainerViewTest : SysuiTestCase() { private val testScope = TestScope(StandardTestDispatcher()) private val fakeExecutor = FakeExecutor(FakeSystemClock()) private val biometricPromptRepository = FakePromptRepository() + private val fingerprintRepository = FakeFingerprintPropertyRepository() private val rearDisplayStateRepository = FakeRearDisplayStateRepository() private val credentialInteractor = FakeCredentialInteractor() private val bpCredentialInteractor = PromptCredentialInteractor( @@ -118,10 +119,12 @@ open class AuthContainerViewTest : SysuiTestCase() { ) private val promptSelectorInteractor by lazy { PromptSelectorInteractorImpl( + fingerprintRepository, biometricPromptRepository, lockPatternUtils, ) } + private val displayStateInteractor = DisplayStateInteractorImpl( testScope.backgroundScope, mContext, @@ -129,9 +132,7 @@ open class AuthContainerViewTest : SysuiTestCase() { rearDisplayStateRepository ) - private val authBiometricFingerprintViewModel = AuthBiometricFingerprintViewModel( - displayStateInteractor - ) + private val credentialViewModel = CredentialViewModel(mContext, bpCredentialInteractor) private var authContainer: TestAuthContainerView? = null @@ -524,10 +525,14 @@ open class AuthContainerViewTest : SysuiTestCase() { userManager, lockPatternUtils, interactionJankMonitor, - { authBiometricFingerprintViewModel }, { promptSelectorInteractor }, { bpCredentialInteractor }, - PromptViewModel(promptSelectorInteractor, vibrator, featureFlags), + PromptViewModel( + displayStateInteractor, + promptSelectorInteractor, + vibrator, + featureFlags + ), { credentialViewModel }, Handler(TestableLooper.get(this).looper), fakeExecutor, diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index 48e513140c3a4..6d71dd5cd8ba7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -92,7 +92,6 @@ 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.AuthBiometricFingerprintViewModel; import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel; import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel; import com.android.systemui.flags.FakeFeatureFlags; @@ -177,8 +176,6 @@ public class AuthControllerTest extends SysuiTestCase { @Mock private PromptSelectorInteractor mPromptSelectionInteractor; @Mock - private AuthBiometricFingerprintViewModel mAuthBiometricFingerprintViewModel; - @Mock private CredentialViewModel mCredentialViewModel; @Mock private PromptViewModel mPromptViewModel; @@ -1095,11 +1092,10 @@ public class AuthControllerTest extends SysuiTestCase { mFingerprintManager, mFaceManager, () -> mUdfpsController, () -> mSideFpsController, mDisplayManager, mWakefulnessLifecycle, mPanelInteractionDetector, mUserManager, mLockPatternUtils, mUdfpsLogger, - mLogContextInteractor, () -> mAuthBiometricFingerprintViewModel, - () -> mBiometricPromptCredentialInteractor, () -> mPromptSelectionInteractor, - () -> mCredentialViewModel, () -> mPromptViewModel, - mInteractionJankMonitor, mHandler, - mBackgroundExecutor, mUdfpsUtils, mVibratorHelper); + mLogContextInteractor, () -> mBiometricPromptCredentialInteractor, + () -> mPromptSelectionInteractor, () -> mCredentialViewModel, + () -> mPromptViewModel, mInteractionJankMonitor, mHandler, mBackgroundExecutor, + mUdfpsUtils, mVibratorHelper); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt index 81cbaeab2a328..4d5e1b7de60f7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt @@ -23,6 +23,7 @@ import androidx.test.filters.SmallTest import com.android.internal.widget.LockPatternUtils import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.Utils +import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository import com.android.systemui.biometrics.data.repository.FakePromptRepository import com.android.systemui.biometrics.domain.model.BiometricModalities import com.android.systemui.biometrics.faceSensorPropertiesInternal @@ -61,13 +62,15 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() { @Mock private lateinit var lockPatternUtils: LockPatternUtils private val testScope = TestScope() + private val fingerprintRepository = FakeFingerprintPropertyRepository() private val promptRepository = FakePromptRepository() private lateinit var interactor: PromptSelectorInteractor @Before fun setup() { - interactor = PromptSelectorInteractorImpl(promptRepository, lockPatternUtils) + interactor = + PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/AuthBiometricFingerprintViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModelTest.kt similarity index 56% rename from packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/AuthBiometricFingerprintViewModelTest.kt rename to packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModelTest.kt index 0c210e51cb904..7697c098ed3dd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/AuthBiometricFingerprintViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModelTest.kt @@ -2,10 +2,17 @@ package com.android.systemui.biometrics.ui.viewmodel import android.content.res.Configuration import androidx.test.filters.SmallTest +import com.android.internal.widget.LockPatternUtils import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository +import com.android.systemui.biometrics.data.repository.FakePromptRepository import com.android.systemui.biometrics.data.repository.FakeRearDisplayStateRepository import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl +import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor +import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl +import com.android.systemui.biometrics.shared.model.FingerprintSensorType +import com.android.systemui.biometrics.shared.model.SensorStrength import com.android.systemui.coroutines.collectLastValue import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.time.FakeSystemClock @@ -16,38 +23,52 @@ import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +import org.mockito.Mock +import org.mockito.junit.MockitoJUnit @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(JUnit4::class) -class AuthBiometricFingerprintViewModelTest : SysuiTestCase() { +class PromptFingerprintIconViewModelTest : SysuiTestCase() { + @JvmField @Rule var mockitoRule = MockitoJUnit.rule() + + @Mock private lateinit var lockPatternUtils: LockPatternUtils + + private val fingerprintRepository = FakeFingerprintPropertyRepository() + private val promptRepository = FakePromptRepository() private val rearDisplayStateRepository = FakeRearDisplayStateRepository() + private val testScope = TestScope(StandardTestDispatcher()) private val fakeExecutor = FakeExecutor(FakeSystemClock()) - private lateinit var interactor: DisplayStateInteractor - private lateinit var viewModel: AuthBiometricFingerprintViewModel + private lateinit var promptSelectorInteractor: PromptSelectorInteractor + private lateinit var displayStateInteractor: DisplayStateInteractor + private lateinit var viewModel: PromptFingerprintIconViewModel @Before fun setup() { - interactor = + promptSelectorInteractor = + PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils) + displayStateInteractor = DisplayStateInteractorImpl( testScope.backgroundScope, mContext, fakeExecutor, rearDisplayStateRepository ) - viewModel = AuthBiometricFingerprintViewModel(interactor) + viewModel = PromptFingerprintIconViewModel(displayStateInteractor, promptSelectorInteractor) } @Test - fun iconUpdates_onConfigurationChanged() { + fun sfpsIconUpdates_onConfigurationChanged() { testScope.runTest { runCurrent() + configureFingerprintPropertyRepository(FingerprintSensorType.POWER_BUTTON) val testConfig = Configuration() val folded = INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP - 1 val unfolded = INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP + 1 @@ -64,6 +85,10 @@ class AuthBiometricFingerprintViewModelTest : SysuiTestCase() { assertThat(foldedIcon).isNotEqualTo(unfoldedIcon) } } + + private fun configureFingerprintPropertyRepository(sensorType: FingerprintSensorType) { + fingerprintRepository.setProperties(0, SensorStrength.STRONG, sensorType, mapOf()) + } } internal const val INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP = 600 diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt index 4d19543d41ff5..11b0b0798ebc7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt @@ -24,7 +24,10 @@ import androidx.test.filters.SmallTest import com.android.internal.widget.LockPatternUtils import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.AuthBiometricView +import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository import com.android.systemui.biometrics.data.repository.FakePromptRepository +import com.android.systemui.biometrics.data.repository.FakeRearDisplayStateRepository +import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl import com.android.systemui.biometrics.domain.model.BiometricModalities @@ -37,7 +40,9 @@ import com.android.systemui.coroutines.collectValues import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION import com.android.systemui.statusbar.VibratorHelper +import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any +import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.first @@ -69,8 +74,19 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa @Mock private lateinit var lockPatternUtils: LockPatternUtils @Mock private lateinit var vibrator: VibratorHelper + private val fakeExecutor = FakeExecutor(FakeSystemClock()) private val testScope = TestScope() + private val fingerprintRepository = FakeFingerprintPropertyRepository() private val promptRepository = FakePromptRepository() + private val rearDisplayStateRepository = FakeRearDisplayStateRepository() + + private val displayStateInteractor = + DisplayStateInteractorImpl( + testScope.backgroundScope, + mContext, + fakeExecutor, + rearDisplayStateRepository + ) private lateinit var selector: PromptSelectorInteractor private lateinit var viewModel: PromptViewModel @@ -78,10 +94,11 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa @Before fun setup() { - selector = PromptSelectorInteractorImpl(promptRepository, lockPatternUtils) + selector = + PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils) selector.resetPrompt() - viewModel = PromptViewModel(selector, vibrator, featureFlags) + viewModel = PromptViewModel(displayStateInteractor, selector, vibrator, featureFlags) featureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false) } @@ -105,7 +122,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa } assertThat(message).isEqualTo(PromptMessage.Empty) assertThat(size).isEqualTo(expectedSize) - assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_AUTHENTICATING_ANIMATING_IN) + assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_IDLE) val startMessage = "here we go" viewModel.showAuthenticating(startMessage, isRetry = false)