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
This commit is contained in:
Grace Cheng
2023-08-14 21:19:04 +00:00
parent 68d69d636e
commit 3d9a78c05c
13 changed files with 147 additions and 116 deletions

View File

@@ -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<PromptCredentialInteractor> mPromptCredentialInteractor;
private final Provider<AuthBiometricFingerprintViewModel>
mAuthBiometricFingerprintViewModelProvider;
private final @NonNull Provider<PromptSelectorInteractor> mPromptSelectorInteractorProvider;
// TODO(b/251476085): these should be migrated out of the view
private final Provider<CredentialViewModel> mCredentialViewModelProvider;
@@ -283,8 +279,6 @@ public class AuthContainerView extends LinearLayout
@NonNull UserManager userManager,
@NonNull LockPatternUtils lockPatternUtils,
@NonNull InteractionJankMonitor jankMonitor,
@NonNull Provider<AuthBiometricFingerprintViewModel>
authBiometricFingerprintViewModelProvider,
@NonNull Provider<PromptCredentialInteractor> promptCredentialInteractor,
@NonNull Provider<PromptSelectorInteractor> 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<AuthBiometricFingerprintViewModel>
authBiometricFingerprintViewModelProvider,
@NonNull Provider<PromptSelectorInteractor> promptSelectorInteractorProvider,
@NonNull Provider<PromptCredentialInteractor> 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(

View File

@@ -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<AuthBiometricFingerprintViewModel>
mAuthBiometricFingerprintViewModelProvider;
@NonNull private final Provider<PromptCredentialInteractor> mPromptCredentialInteractor;
@NonNull private final Provider<PromptSelectorInteractor> mPromptSelectorInteractor;
@NonNull private final Provider<CredentialViewModel> mCredentialViewModelProvider;
@@ -765,8 +762,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
@NonNull LockPatternUtils lockPatternUtils,
@NonNull UdfpsLogger udfpsLogger,
@NonNull LogContextInteractor logContextInteractor,
@NonNull Provider<AuthBiometricFingerprintViewModel>
authBiometricFingerprintViewModelProvider,
@NonNull Provider<PromptCredentialInteractor> promptCredentialInteractorProvider,
@NonNull Provider<PromptSelectorInteractor> promptSelectorInteractorProvider,
@NonNull Provider<CredentialViewModel> 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

View File

@@ -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<Boolean>
/** Fingerprint sensor type */
val sensorType: StateFlow<FingerprintSensorType>
/** 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<FingerprintSensorType> =
fingerprintPropertyRepository.sensorType
override fun useBiometricsForAuthentication(
promptInfo: PromptInfo,
userId: Int,

View File

@@ -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)
}
}
}

View File

@@ -108,6 +108,9 @@ object BiometricViewBinder {
val iconViewOverlay = view.requireViewById<LottieAnimationView>(R.id.biometric_icon_overlay)
val iconView = view.requireViewById<LottieAnimationView>(R.id.biometric_icon)
PromptFingerprintIconViewBinder.bind(iconView, viewModel.fingerprintIconViewModel)
val indicatorMessageView = view.requireViewById<TextView>(R.id.indicator)
// Negative-side (left) buttons

View File

@@ -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)
}
}
}
}
}
}

View File

@@ -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<Int> =
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) {

View File

@@ -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<BiometricModalities> =
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<Int> = _legacyState.asStateFlow()
private val _isAuthenticating: MutableStateFlow<Boolean> = MutableStateFlow(false)
@@ -75,17 +83,18 @@ constructor(
* successful authentication.
*/
val isConfirmationRequired: Flow<Boolean> =
combine(_isOverlayTouched, interactor.isConfirmationRequired) {
combine(_isOverlayTouched, promptSelectorInteractor.isConfirmationRequired) {
isOverlayTouched,
isConfirmationRequired ->
!isOverlayTouched && isConfirmationRequired
}
/** The kind of credential the user has. */
val credentialKind: Flow<PromptKind> = interactor.credentialKind
val credentialKind: Flow<PromptKind> = promptSelectorInteractor.credentialKind
/** The label to use for the cancel button. */
val negativeButtonText: Flow<String> = interactor.prompt.map { it?.negativeButtonText ?: "" }
val negativeButtonText: Flow<String> =
promptSelectorInteractor.prompt.map { it?.negativeButtonText ?: "" }
private val _message: MutableStateFlow<PromptMessage> = 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<String> = interactor.prompt.map { it?.title ?: "" }.distinctUntilChanged()
val title: Flow<String> =
promptSelectorInteractor.prompt.map { it?.title ?: "" }.distinctUntilChanged()
/** Subtitle for the prompt. */
val subtitle: Flow<String> = interactor.prompt.map { it?.subtitle ?: "" }.distinctUntilChanged()
val subtitle: Flow<String> =
promptSelectorInteractor.prompt.map { it?.subtitle ?: "" }.distinctUntilChanged()
/** Description for the prompt. */
val description: Flow<String> =
interactor.prompt.map { it?.description ?: "" }.distinctUntilChanged()
promptSelectorInteractor.prompt.map { it?.description ?: "" }.distinctUntilChanged()
/** If the indicator (help, error) message should be shown. */
val isIndicatorMessageVisible: Flow<Boolean> =
@@ -160,7 +171,9 @@ constructor(
/** If the icon can be used as a confirmation button. */
val isIconConfirmButton: Flow<Boolean> =
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
}

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)