Merge "Add data layer for the DeviceEntryIcon" into main
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 0e9f8b1..80fd516 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -294,8 +294,6 @@
"tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt",
"tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt",
"tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt",
- "tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt",
- "tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt",
"tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt",
"tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt",
// Keyguard helper
diff --git a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
index 6082fb9..8ad32b4 100644
--- a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
+++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
@@ -25,7 +25,11 @@
UDFPS_ULTRASONIC,
UDFPS_OPTICAL,
POWER_BUTTON,
- HOME_BUTTON
+ HOME_BUTTON;
+
+ fun isUdfps(): Boolean {
+ return (this == UDFPS_OPTICAL) || (this == UDFPS_ULTRASONIC)
+ }
}
/** Convert [this] to corresponding [FingerprintSensorType] */
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
index c3f3529..298811b 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
@@ -29,6 +29,7 @@
import com.android.systemui.scene.shared.model.SceneModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collectLatest
@@ -46,6 +47,7 @@
* Device entry occurs when the user successfully dismisses (or bypasses) the lockscreen, regardless
* of the authentication method used.
*/
+@ExperimentalCoroutinesApi
@SysUISingleton
class DeviceEntryInteractor
@Inject
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt
new file mode 100644
index 0000000..72b9da6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.deviceentry.domain.interactor
+
+import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+
+/** Encapsulates business logic for device entry under-display fingerprint state changes. */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class DeviceEntryUdfpsInteractor
+@Inject
+constructor(
+ // TODO (b/309655554): create & use interactors for these repositories
+ fingerprintPropertyRepository: FingerprintPropertyRepository,
+ fingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
+ biometricSettingsRepository: BiometricSettingsRepository,
+) {
+ /** Whether the device supports an under display fingerprint sensor. */
+ val isUdfpsSupported: Flow<Boolean> =
+ fingerprintPropertyRepository.sensorType.map { it.isUdfps() }
+
+ /** Whether the under-display fingerprint sensor is enrolled and enabled for device entry. */
+ val isUdfpsEnrolledAndEnabled: Flow<Boolean> =
+ combine(isUdfpsSupported, biometricSettingsRepository.isFingerprintEnrolledAndEnabled) {
+ udfps,
+ fpEnrolledAndEnabled ->
+ udfps && fpEnrolledAndEnabled
+ }
+ /** Whether the under display fingerprint sensor is currently running. */
+ val isListeningForUdfps =
+ isUdfpsSupported.flatMapLatest { isUdfps ->
+ if (isUdfps) {
+ fingerprintAuthRepository.isRunning
+ } else {
+ flowOf(false)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 8b93b17..331d892 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -55,6 +55,7 @@
import com.android.systemui.keyguard.domain.interactor.StartKeyguardTransitionModule;
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger;
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLoggerImpl;
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransitionModule;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController;
@@ -94,6 +95,7 @@
KeyguardStatusViewComponent.class,
KeyguardUserSwitcherComponent.class},
includes = {
+ DeviceEntryIconTransitionModule.class,
FalsingModule.class,
KeyguardDataQuickAffordanceModule.class,
KeyguardRepositoryModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt
index 8bf2bc3..cc1cf91 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt
@@ -50,14 +50,18 @@
private val configurationRepository: ConfigurationRepository,
private val keyguardInteractor: KeyguardInteractor,
) {
- val udfpsBurnInXOffset: StateFlow<Int> =
+ val deviceEntryIconXOffset: StateFlow<Int> =
burnInOffsetDefinedInPixels(R.dimen.udfps_burn_in_offset_x, isXAxis = true)
- val udfpsBurnInYOffset: StateFlow<Int> =
+ val deviceEntryIconYOffset: StateFlow<Int> =
burnInOffsetDefinedInPixels(R.dimen.udfps_burn_in_offset_y, isXAxis = false)
- val udfpsBurnInProgress: StateFlow<Float> =
+ val udfpsProgress: StateFlow<Float> =
keyguardInteractor.dozeTimeTick
.mapLatest { burnInHelperWrapper.burnInProgressOffset() }
- .stateIn(scope, SharingStarted.Lazily, burnInHelperWrapper.burnInProgressOffset())
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ burnInHelperWrapper.burnInProgressOffset()
+ )
val keyguardBurnIn: Flow<BurnInModel> =
combine(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
index a331a66..8584401 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
@@ -113,7 +113,9 @@
}
companion object {
- val TO_LOCKSCREEN_DURATION = 500.milliseconds
private val DEFAULT_DURATION = 500.milliseconds
+ val TO_LOCKSCREEN_DURATION = 500.milliseconds
+ val TO_GONE_DURATION = DEFAULT_DURATION
+ val TO_OCCLUDED_DURATION = DEFAULT_DURATION
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index e9719e7..eca7088 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -26,11 +26,11 @@
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
-import javax.inject.Inject
-import kotlin.time.Duration.Companion.milliseconds
@SysUISingleton
class FromDozingTransitionInteractor
@@ -97,5 +97,6 @@
companion object {
private val DEFAULT_DURATION = 500.milliseconds
+ val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
index eace0c7..bd73d60 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
@@ -138,6 +138,6 @@
companion object {
private val DEFAULT_DURATION = 500.milliseconds
val TO_DREAMING_DURATION = 933.milliseconds
- val TO_AOD_DURATION = 1100.milliseconds
+ val TO_AOD_DURATION = 1300.milliseconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index ea40ba0..152d217 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -391,5 +391,7 @@
val TO_DREAMING_DURATION = 933.milliseconds
val TO_OCCLUDED_DURATION = 450.milliseconds
val TO_AOD_DURATION = 500.milliseconds
+ val TO_PRIMARY_BOUNCER_DURATION = DEFAULT_DURATION
+ val TO_GONE_DURATION = DEFAULT_DURATION
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
index dec38b5..6a8555c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
@@ -142,9 +142,7 @@
::toTriple
)
.collect { (isAsleep, lastStartedStep, isAodAvailable) ->
- if (
- lastStartedStep.to == KeyguardState.OCCLUDED && isAsleep
- ) {
+ if (lastStartedStep.to == KeyguardState.OCCLUDED && isAsleep) {
startTransitionTo(
if (isAodAvailable) KeyguardState.AOD else KeyguardState.DOZING
)
@@ -187,5 +185,6 @@
companion object {
private val DEFAULT_DURATION = 500.milliseconds
val TO_LOCKSCREEN_DURATION = 933.milliseconds
+ val TO_AOD_DURATION = DEFAULT_DURATION
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index 24b6661..5f246e1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -255,5 +255,7 @@
private val DEFAULT_DURATION = 300.milliseconds
val TO_GONE_DURATION = 500.milliseconds
val TO_GONE_SHORT_DURATION = 200.milliseconds
+ val TO_AOD_DURATION = DEFAULT_DURATION
+ val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractor.kt
index c0308e6..f5cd767 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractor.kt
@@ -51,14 +51,14 @@
val scaleForResolution = configRepo.scaleForResolution
/** Burn-in offsets for the UDFPS view to mitigate burn-in on AOD. */
- val burnInOffsets: Flow<BurnInOffsets> =
+ val burnInOffsets: Flow<Offsets> =
combine(
keyguardInteractor.dozeAmount,
- burnInInteractor.udfpsBurnInXOffset,
- burnInInteractor.udfpsBurnInYOffset,
- burnInInteractor.udfpsBurnInProgress
+ burnInInteractor.deviceEntryIconXOffset,
+ burnInInteractor.deviceEntryIconYOffset,
+ burnInInteractor.udfpsProgress
) { dozeAmount, fullyDozingBurnInX, fullyDozingBurnInY, fullyDozingBurnInProgress ->
- BurnInOffsets(
+ Offsets(
intEvaluator.evaluate(dozeAmount, 0, fullyDozingBurnInX),
intEvaluator.evaluate(dozeAmount, 0, fullyDozingBurnInY),
floatEvaluator.evaluate(dozeAmount, 0, fullyDozingBurnInProgress),
@@ -86,8 +86,8 @@
.onStart { emit(0f) }
}
-data class BurnInOffsets(
- val burnInXOffset: Int, // current x burn in offset based on the aodTransitionAmount
- val burnInYOffset: Int, // current y burn in offset based on the aodTransitionAmount
- val burnInProgress: Float, // current progress based on the aodTransitionAmount
+data class Offsets(
+ val x: Int, // current x burn in offset based on the aodTransitionAmount
+ val y: Int, // current y burn in offset based on the aodTransitionAmount
+ val progress: Float, // current progress based on the aodTransitionAmount
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
index 9d7477c..d5ad7ab 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
@@ -105,4 +105,9 @@
}
.filterNotNull()
}
+
+ /** Immediately (after 1ms) emits the given value for every step of the KeyguardTransition. */
+ fun immediatelyTransitionTo(value: Float): Flow<Float> {
+ return createFlow(duration = 1.milliseconds, onStep = { value }, onFinish = { value })
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
index e82ea7f..a8b28bc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
@@ -24,6 +24,8 @@
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.common.ui.view.LongPressHandlingView
import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
+import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryBackgroundViewModel
+import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.FalsingManager
@@ -34,19 +36,24 @@
object DeviceEntryIconViewBinder {
/**
- * Updates UI for the device entry icon view (lock, unlock and fingerprint icons) and its
- * background.
+ * Updates UI for:
+ * - device entry containing view (parent view for the below views)
+ * - long-press handling view (transparent, no UI)
+ * - foreground icon view (lock/unlock/fingerprint)
+ * - background view (optional)
*/
@SuppressLint("ClickableViewAccessibility")
@JvmStatic
fun bind(
view: DeviceEntryIconView,
viewModel: DeviceEntryIconViewModel,
+ fgViewModel: DeviceEntryForegroundViewModel,
+ bgViewModel: DeviceEntryBackgroundViewModel,
falsingManager: FalsingManager,
) {
- val iconView = view.iconView
- val bgView = view.bgView
val longPressHandlingView = view.longPressHandlingView
+ val fgIconView = view.iconView
+ val bgView = view.bgView
longPressHandlingView.listener =
object : LongPressHandlingView.Listener {
override fun onLongPressDetected(view: View, x: Int, y: Int) {
@@ -56,37 +63,12 @@
viewModel.onLongPress()
}
}
+
view.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.STARTED) {
- launch {
- viewModel.iconViewModel.collect { iconViewModel ->
- iconView.setImageState(
- view.getIconState(iconViewModel.type, iconViewModel.useAodVariant),
- /* merge */ false
- )
- iconView.imageTintList = ColorStateList.valueOf(iconViewModel.tint)
- iconView.alpha = iconViewModel.alpha
- iconView.setPadding(
- iconViewModel.padding,
- iconViewModel.padding,
- iconViewModel.padding,
- iconViewModel.padding,
- )
- }
- }
- launch {
- viewModel.backgroundViewModel.collect { bgViewModel ->
- bgView.alpha = bgViewModel.alpha
- bgView.imageTintList = ColorStateList.valueOf(bgViewModel.tint)
- }
- }
- launch {
- viewModel.burnInViewModel.collect { burnInViewModel ->
- view.translationX = burnInViewModel.x.toFloat()
- view.translationY = burnInViewModel.y.toFloat()
- view.aodFpDrawable.progress = burnInViewModel.progress
- }
- }
+ // Repeat on CREATED so that the view will always observe the entire
+ // GONE => AOD transition (even though the view may not be visible until the middle
+ // of the transition.
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
launch {
viewModel.isLongPressEnabled.collect { isEnabled ->
longPressHandlingView.setLongPressHandlingEnabled(isEnabled)
@@ -97,6 +79,55 @@
view.accessibilityHintType = hint
}
}
+ launch {
+ viewModel.useBackgroundProtection.collect { useBackgroundProtection ->
+ if (useBackgroundProtection) {
+ bgView.visibility = View.VISIBLE
+ } else {
+ bgView.visibility = View.GONE
+ }
+ }
+ }
+ launch {
+ viewModel.burnInOffsets.collect { burnInOffsets ->
+ view.translationX = burnInOffsets.x.toFloat()
+ view.translationY = burnInOffsets.y.toFloat()
+ view.aodFpDrawable.progress = burnInOffsets.progress
+ }
+ }
+
+ launch { viewModel.deviceEntryViewAlpha.collect { alpha -> view.alpha = alpha } }
+ }
+ }
+
+ fgIconView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ launch {
+ fgViewModel.viewModel.collect { viewModel ->
+ fgIconView.setImageState(
+ view.getIconState(viewModel.type, viewModel.useAodVariant),
+ /* merge */ false
+ )
+ fgIconView.imageTintList = ColorStateList.valueOf(viewModel.tint)
+ fgIconView.setPadding(
+ viewModel.padding,
+ viewModel.padding,
+ viewModel.padding,
+ viewModel.padding,
+ )
+ }
+ }
+ }
+ }
+
+ bgView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ launch {
+ bgViewModel.viewModel.collect { bgViewModel ->
+ bgView.alpha = bgViewModel.alpha
+ bgView.imageTintList = ColorStateList.valueOf(bgViewModel.tint)
+ }
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsAodFingerprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsAodFingerprintViewBinder.kt
index 9872d97..52d87d3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsAodFingerprintViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsAodFingerprintViewBinder.kt
@@ -42,9 +42,9 @@
repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
viewModel.burnInOffsets.collect { burnInOffsets ->
- view.progress = burnInOffsets.burnInProgress
- view.translationX = burnInOffsets.burnInXOffset.toFloat()
- view.translationY = burnInOffsets.burnInYOffset.toFloat()
+ view.progress = burnInOffsets.progress
+ view.translationX = burnInOffsets.x.toFloat()
+ view.translationY = burnInOffsets.y.toFloat()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsFingerprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsFingerprintViewBinder.kt
index bab04f2..d4621e6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsFingerprintViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsFingerprintViewBinder.kt
@@ -59,8 +59,8 @@
launch {
viewModel.burnInOffsets.collect { burnInOffsets ->
- view.translationX = burnInOffsets.burnInXOffset.toFloat()
- view.translationY = burnInOffsets.burnInYOffset.toFloat()
+ view.translationX = burnInOffsets.x.toFloat()
+ view.translationY = burnInOffsets.y.toFloat()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransition.kt
new file mode 100644
index 0000000..b58a80f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransition.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.keyguard.ui.transitions
+
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Each DeviceEntryIconTransition is responsible for updating the given parameters for the current
+ * keyguard transition.
+ * *
+ * MUST list implementing classes in dagger module [DeviceEntryIconTransitionModule].
+ */
+interface DeviceEntryIconTransition {
+ val deviceEntryParentViewAlpha: Flow<Float>
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
new file mode 100644
index 0000000..9d557bb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
@@ -0,0 +1,117 @@
+/*
+ * 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.keyguard.ui.transitions
+
+import com.android.systemui.keyguard.ui.viewmodel.AodToGoneTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.AodToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.DozingToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.GoneToAodTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToAodTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGoneTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToPrimaryBouncerTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.OccludedToAodTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToAodTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToLockscreenTransitionViewModel
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.IntoSet
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@ExperimentalCoroutinesApi
+@Module
+abstract class DeviceEntryIconTransitionModule {
+ @Binds
+ @IntoSet
+ abstract fun aodToLockscreen(
+ impl: AodToLockscreenTransitionViewModel
+ ): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
+ abstract fun aodToGone(impl: AodToGoneTransitionViewModel): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
+ abstract fun dozingToLockscreen(
+ impl: DozingToLockscreenTransitionViewModel
+ ): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
+ abstract fun dreamingToLockscreen(
+ impl: DreamingToLockscreenTransitionViewModel
+ ): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
+ abstract fun lockscreenToAod(
+ impl: LockscreenToAodTransitionViewModel
+ ): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
+ abstract fun lockscreenToDreaming(
+ impl: LockscreenToDreamingTransitionViewModel
+ ): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
+ abstract fun lockscreenToOccluded(
+ impl: LockscreenToOccludedTransitionViewModel
+ ): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
+ abstract fun lockscreenToPrimaryBouncer(
+ impl: LockscreenToPrimaryBouncerTransitionViewModel
+ ): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
+ abstract fun lockscreenToGone(
+ impl: LockscreenToGoneTransitionViewModel
+ ): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
+ abstract fun goneToAod(impl: GoneToAodTransitionViewModel): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
+ abstract fun occludedToAod(impl: OccludedToAodTransitionViewModel): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
+ abstract fun occludedToLockscreen(
+ impl: OccludedToLockscreenTransitionViewModel
+ ): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
+ abstract fun primaryBouncerToAod(
+ impl: PrimaryBouncerToAodTransitionViewModel
+ ): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
+ abstract fun primaryBouncerToLockscreen(
+ impl: PrimaryBouncerToLockscreenTransitionViewModel
+ ): DeviceEntryIconTransition
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/DeviceEntryIconView.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/DeviceEntryIconView.kt
index c9e3954..af1d0df 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/DeviceEntryIconView.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/DeviceEntryIconView.kt
@@ -40,7 +40,10 @@
attrs: AttributeSet?,
defStyleAttrs: Int = 0,
) : FrameLayout(context, attrs, defStyleAttrs) {
- val longPressHandlingView: LongPressHandlingView = LongPressHandlingView(context, attrs)
+ val longPressHandlingView: LongPressHandlingView =
+ LongPressHandlingView(context, attrs) {
+ context.resources.getInteger(R.integer.config_lockIconLongPress).toLong()
+ }
val iconView: ImageView = ImageView(context, attrs).apply { id = R.id.device_entry_icon_fg }
val bgView: ImageView = ImageView(context, attrs).apply { id = R.id.device_entry_icon_bg }
val aodFpDrawable: LottieDrawable = LottieDrawable()
@@ -105,7 +108,7 @@
// FINGERPRINT
animatedIconDrawable.addState(
getIconState(IconType.FINGERPRINT, false),
- context.getDrawable(R.drawable.ic_kg_fingerprint)!!,
+ context.getDrawable(R.drawable.ic_fingerprint)!!,
R.id.locked_fp,
)
@@ -220,7 +223,7 @@
val lp = longPressHandlingView.layoutParams as LayoutParams
lp.height = ViewGroup.LayoutParams.MATCH_PARENT
lp.width = ViewGroup.LayoutParams.MATCH_PARENT
- longPressHandlingView.setLayoutParams(lp)
+ longPressHandlingView.layoutParams = lp
}
private fun addIconImageView() {
@@ -231,7 +234,7 @@
lp.height = ViewGroup.LayoutParams.MATCH_PARENT
lp.width = ViewGroup.LayoutParams.MATCH_PARENT
lp.gravity = Gravity.CENTER
- iconView.setLayoutParams(lp)
+ iconView.layoutParams = lp
}
private fun addBgImageView() {
@@ -240,7 +243,7 @@
val lp = bgView.layoutParams as LayoutParams
lp.height = ViewGroup.LayoutParams.MATCH_PARENT
lp.width = ViewGroup.LayoutParams.MATCH_PARENT
- bgView.setLayoutParams(lp)
+ bgView.layoutParams = lp
}
fun getIconState(icon: IconType, aod: Boolean): IntArray {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt
index ace970a..13ea8ff 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt
@@ -36,6 +36,8 @@
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.binder.DeviceEntryIconViewBinder
import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
+import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryBackgroundViewModel
+import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
@@ -56,12 +58,15 @@
private val featureFlags: FeatureFlags,
private val lockIconViewController: Lazy<LockIconViewController>,
private val deviceEntryIconViewModel: Lazy<DeviceEntryIconViewModel>,
+ private val deviceEntryForegroundViewModel: Lazy<DeviceEntryForegroundViewModel>,
+ private val deviceEntryBackgroundViewModel: Lazy<DeviceEntryBackgroundViewModel>,
private val falsingManager: Lazy<FalsingManager>,
) : KeyguardSection() {
private val deviceEntryIconViewId = R.id.device_entry_icon_view
override fun addViews(constraintLayout: ConstraintLayout) {
- if (!keyguardBottomAreaRefactor() &&
+ if (
+ !keyguardBottomAreaRefactor() &&
!featureFlags.isEnabled(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS)
) {
return
@@ -87,6 +92,8 @@
DeviceEntryIconViewBinder.bind(
it,
deviceEntryIconViewModel.get(),
+ deviceEntryForegroundViewModel.get(),
+ deviceEntryBackgroundViewModel.get(),
falsingManager.get(),
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt
new file mode 100644
index 0000000..4d2af0c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromAodTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+/** Breaks down AOD->GONE transition into discrete steps for corresponding views to consume. */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class AodToGoneTransitionViewModel
+@Inject
+constructor(
+ interactor: KeyguardTransitionInteractor,
+) : DeviceEntryIconTransition {
+
+ private val transitionAnimation =
+ KeyguardTransitionAnimationFlow(
+ transitionDuration = FromAodTransitionInteractor.TO_GONE_DURATION,
+ transitionFlow = interactor.transition(KeyguardState.AOD, KeyguardState.GONE),
+ )
+
+ override val deviceEntryParentViewAlpha = transitionAnimation.immediatelyTransitionTo(0f)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt
index 024707a..14de01b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt
@@ -17,22 +17,29 @@
package com.android.systemui.keyguard.ui.viewmodel
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
import com.android.systemui.keyguard.domain.interactor.FromAodTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
/**
* Breaks down AOD->LOCKSCREEN transition into discrete steps for corresponding views to consume.
*/
+@ExperimentalCoroutinesApi
@SysUISingleton
class AodToLockscreenTransitionViewModel
@Inject
constructor(
- private val interactor: KeyguardTransitionInteractor,
-) {
+ interactor: KeyguardTransitionInteractor,
+ deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+) : DeviceEntryIconTransition {
private val transitionAnimation =
KeyguardTransitionAnimationFlow(
@@ -47,4 +54,21 @@
onStart = { 1f },
onStep = { 1f },
)
+
+ val deviceEntryBackgroundViewAlpha: Flow<Float> =
+ deviceEntryUdfpsInteractor.isUdfpsSupported.flatMapLatest { isUdfps ->
+ if (isUdfps) {
+ // fade in
+ transitionAnimation.createFlow(
+ duration = 250.milliseconds,
+ onStep = { it },
+ onFinish = { 1f },
+ )
+ } else {
+ // background view isn't visible, so return an empty flow
+ emptyFlow()
+ }
+ }
+
+ override val deviceEntryParentViewAlpha: Flow<Float> = lockscreenAlpha
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModel.kt
new file mode 100644
index 0000000..06661d0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModel.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromAodTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+
+/** Breaks down AOD->OCCLUDED transition into discrete steps for corresponding views to consume. */
+@SysUISingleton
+class AodToOccludedTransitionViewModel
+@Inject
+constructor(
+ interactor: KeyguardTransitionInteractor,
+) : DeviceEntryIconTransition {
+ private val transitionAnimation =
+ KeyguardTransitionAnimationFlow(
+ transitionDuration = FromAodTransitionInteractor.TO_OCCLUDED_DURATION,
+ transitionFlow = interactor.transition(KeyguardState.AOD, KeyguardState.OCCLUDED),
+ )
+
+ override val deviceEntryParentViewAlpha = transitionAnimation.immediatelyTransitionTo(0f)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
new file mode 100644
index 0000000..3e8bbb3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
@@ -0,0 +1,83 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import android.content.Context
+import com.android.settingslib.Utils
+import com.android.systemui.common.ui.data.repository.ConfigurationRepository
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.onStart
+
+/** Models the UI state for the device entry icon background view. */
+@ExperimentalCoroutinesApi
+class DeviceEntryBackgroundViewModel
+@Inject
+constructor(
+ val context: Context,
+ configurationRepository: ConfigurationRepository, // TODO (b/309655554): create & use interactor
+ lockscreenToAodTransitionViewModel: LockscreenToAodTransitionViewModel,
+ aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
+ goneToAodTransitionViewModel: GoneToAodTransitionViewModel,
+ primaryBouncerToAodTransitionViewModel: PrimaryBouncerToAodTransitionViewModel,
+ occludedToAodTransitionViewModel: OccludedToAodTransitionViewModel,
+ occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel,
+ dreamingToLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel,
+) {
+ private val color: Flow<Int> =
+ configurationRepository.onAnyConfigurationChange
+ .map {
+ Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.colorSurface)
+ }
+ .onStart {
+ emit(
+ Utils.getColorAttrDefaultColor(
+ context,
+ com.android.internal.R.attr.colorSurface
+ )
+ )
+ }
+ private val alpha: Flow<Float> =
+ setOf(
+ lockscreenToAodTransitionViewModel.deviceEntryBackgroundViewAlpha,
+ aodToLockscreenTransitionViewModel.deviceEntryBackgroundViewAlpha,
+ goneToAodTransitionViewModel.deviceEntryBackgroundViewAlpha,
+ primaryBouncerToAodTransitionViewModel.deviceEntryBackgroundViewAlpha,
+ occludedToAodTransitionViewModel.deviceEntryBackgroundViewAlpha,
+ occludedToLockscreenTransitionViewModel.deviceEntryBackgroundViewAlpha,
+ dreamingToLockscreenTransitionViewModel.deviceEntryBackgroundViewAlpha,
+ )
+ .merge()
+
+ val viewModel: Flow<BackgroundViewModel> =
+ combine(color, alpha) { color, alpha ->
+ BackgroundViewModel(
+ alpha = alpha,
+ tint = color,
+ )
+ }
+
+ data class BackgroundViewModel(
+ val alpha: Float,
+ val tint: Int,
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
new file mode 100644
index 0000000..99529a1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
@@ -0,0 +1,92 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import android.content.Context
+import com.android.settingslib.Utils
+import com.android.systemui.common.ui.data.repository.ConfigurationRepository
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
+import com.android.systemui.res.R
+import javax.inject.Inject
+import kotlin.math.roundToInt
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+
+/** Models the UI state for the device entry icon foreground view (displayed icon). */
+@ExperimentalCoroutinesApi
+class DeviceEntryForegroundViewModel
+@Inject
+constructor(
+ val context: Context,
+ configurationRepository: ConfigurationRepository, // TODO (b/309655554): create & use interactor
+ deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+ transitionInteractor: KeyguardTransitionInteractor,
+ deviceEntryIconViewModel: DeviceEntryIconViewModel,
+) {
+ private val isShowingAod: Flow<Boolean> =
+ transitionInteractor.startedKeyguardState.map { keyguardState ->
+ keyguardState == KeyguardState.AOD
+ }
+ private val color: Flow<Int> =
+ configurationRepository.onAnyConfigurationChange
+ .map { Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary) }
+ .onStart {
+ emit(Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary))
+ }
+ private val useAodIconVariant: Flow<Boolean> =
+ combine(isShowingAod, deviceEntryUdfpsInteractor.isUdfpsSupported) {
+ isTransitionToAod,
+ isUdfps ->
+ isTransitionToAod && isUdfps
+ }
+ .distinctUntilChanged()
+ private val padding: Flow<Int> =
+ configurationRepository.scaleForResolution.map { scale ->
+ (context.resources.getDimensionPixelSize(R.dimen.lock_icon_padding) * scale)
+ .roundToInt()
+ }
+
+ val viewModel: Flow<ForegroundIconViewModel> =
+ combine(
+ deviceEntryIconViewModel.iconType,
+ useAodIconVariant,
+ color,
+ padding,
+ ) { iconType, useAodVariant, color, padding ->
+ ForegroundIconViewModel(
+ type = iconType,
+ useAodVariant = useAodVariant,
+ tint = color,
+ padding = padding,
+ )
+ }
+
+ data class ForegroundIconViewModel(
+ val type: DeviceEntryIconView.IconType,
+ val useAodVariant: Boolean,
+ val tint: Int,
+ val padding: Int,
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
index 842dde3..5b5a103 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
@@ -12,57 +12,202 @@
* 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.keyguard.ui.viewmodel
-import android.graphics.Color
+import android.animation.FloatEvaluator
+import android.animation.IntEvaluator
+import com.android.keyguard.KeyguardViewController
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInteractor
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.onStart
+/** Models the UI state for the containing device entry icon & long-press handling view. */
@ExperimentalCoroutinesApi
-class DeviceEntryIconViewModel @Inject constructor() {
- // TODO: b/305234447 update these states from the data layer
- val iconViewModel: Flow<IconViewModel> =
- flowOf(
- IconViewModel(
- type = DeviceEntryIconView.IconType.LOCK,
- useAodVariant = false,
- tint = Color.WHITE,
- alpha = 1f,
- padding = 48,
+class DeviceEntryIconViewModel
+@Inject
+constructor(
+ transitions: Set<@JvmSuppressWildcards DeviceEntryIconTransition>,
+ burnInInteractor: BurnInInteractor,
+ shadeInteractor: ShadeInteractor,
+ deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+ transitionInteractor: KeyguardTransitionInteractor,
+ val keyguardInteractor: KeyguardInteractor,
+ val viewModel: AodToLockscreenTransitionViewModel,
+ val shadeDependentFlows: ShadeDependentFlows,
+ private val sceneContainerFlags: SceneContainerFlags,
+ private val keyguardViewController: Lazy<KeyguardViewController>,
+ private val deviceEntryHapticsInteractor: DeviceEntryHapticsInteractor,
+ udfpsInteractor: DeviceEntryUdfpsInteractor,
+ private val deviceEntryInteractor: DeviceEntryInteractor,
+) {
+ private val intEvaluator = IntEvaluator()
+ private val floatEvaluator = FloatEvaluator()
+ private val toAodFromState: Flow<KeyguardState> =
+ transitionInteractor.transitionStepsToState(KeyguardState.AOD).map { it.from }
+ private val showingAlternateBouncer: Flow<Boolean> =
+ transitionInteractor.startedKeyguardState.map { keyguardState ->
+ keyguardState == KeyguardState.ALTERNATE_BOUNCER
+ }
+ private val qsProgress: Flow<Float> = shadeInteractor.qsExpansion.onStart { emit(0f) }
+ private val shadeExpansion: Flow<Float> = shadeInteractor.shadeExpansion.onStart { emit(0f) }
+ private val transitionAlpha: Flow<Float> =
+ transitions.map { it.deviceEntryParentViewAlpha }.merge()
+ private val alphaMultiplierFromShadeExpansion: Flow<Float> =
+ combine(
+ showingAlternateBouncer,
+ shadeExpansion,
+ qsProgress,
+ ) { showingAltBouncer, shadeExpansion, qsProgress ->
+ val interpolatedQsProgress = (qsProgress * 2).coerceIn(0f, 1f)
+ if (showingAltBouncer) {
+ 1f
+ } else {
+ (1f - shadeExpansion) * (1f - interpolatedQsProgress)
+ }
+ }
+ // Burn-in offsets in AOD
+ private val nonAnimatedBurnInOffsets: Flow<BurnInOffsets> =
+ combine(
+ burnInInteractor.deviceEntryIconXOffset,
+ burnInInteractor.deviceEntryIconYOffset,
+ burnInInteractor.udfpsProgress
+ ) { fullyDozingBurnInX, fullyDozingBurnInY, fullyDozingBurnInProgress ->
+ BurnInOffsets(
+ fullyDozingBurnInX,
+ fullyDozingBurnInY,
+ fullyDozingBurnInProgress,
)
- )
- val backgroundViewModel: Flow<BackgroundViewModel> =
- flowOf(BackgroundViewModel(alpha = 1f, tint = Color.GRAY))
- val burnInViewModel: Flow<BurnInViewModel> = flowOf(BurnInViewModel(0, 0, 0f))
- val isLongPressEnabled: Flow<Boolean> = flowOf(true)
+ }
+ // Burn-in offsets that animate based on the transition amount to AOD
+ private val animatedBurnInOffsets: Flow<BurnInOffsets> =
+ combine(
+ nonAnimatedBurnInOffsets,
+ transitionInteractor.transitionStepsToState(KeyguardState.AOD)
+ ) { burnInOffsets, transitionStepsToAod ->
+ val dozeAmount = transitionStepsToAod.value
+ BurnInOffsets(
+ intEvaluator.evaluate(dozeAmount, 0, burnInOffsets.x),
+ intEvaluator.evaluate(dozeAmount, 0, burnInOffsets.y),
+ floatEvaluator.evaluate(dozeAmount, 0, burnInOffsets.progress)
+ )
+ }
+
+ val deviceEntryViewAlpha: Flow<Float> =
+ combine(
+ transitionAlpha,
+ alphaMultiplierFromShadeExpansion,
+ ) { alpha, alphaMultiplier ->
+ alpha * alphaMultiplier
+ }
+ val useBackgroundProtection: Flow<Boolean> = deviceEntryUdfpsInteractor.isUdfpsSupported
+ val burnInOffsets: Flow<BurnInOffsets> =
+ deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfpsEnrolled ->
+ if (udfpsEnrolled) {
+ toAodFromState.flatMapLatest { fromState ->
+ when (fromState) {
+ KeyguardState.AOD,
+ KeyguardState.GONE,
+ KeyguardState.OCCLUDED,
+ KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
+ KeyguardState.OFF,
+ KeyguardState.DOZING,
+ KeyguardState.DREAMING,
+ KeyguardState.PRIMARY_BOUNCER -> nonAnimatedBurnInOffsets
+ KeyguardState.ALTERNATE_BOUNCER -> animatedBurnInOffsets
+ KeyguardState.LOCKSCREEN ->
+ shadeDependentFlows.transitionFlow(
+ flowWhenShadeIsExpanded = nonAnimatedBurnInOffsets,
+ flowWhenShadeIsNotExpanded = animatedBurnInOffsets,
+ )
+ }
+ }
+ } else {
+ // If UDFPS isn't enrolled, we don't show any UI on AOD so there's no need
+ // to use burn in offsets at all
+ flowOf(BurnInOffsets(x = 0, y = 0, progress = 0f))
+ }
+ }
+ val iconType: Flow<DeviceEntryIconView.IconType> =
+ combine(
+ udfpsInteractor.isListeningForUdfps,
+ deviceEntryInteractor.isUnlocked,
+ ) { isListeningForUdfps, isUnlocked ->
+ if (isUnlocked) {
+ DeviceEntryIconView.IconType.UNLOCK
+ } else {
+ if (isListeningForUdfps) {
+ DeviceEntryIconView.IconType.FINGERPRINT
+ } else {
+ DeviceEntryIconView.IconType.LOCK
+ }
+ }
+ }
+ val isLongPressEnabled: Flow<Boolean> =
+ combine(
+ iconType,
+ deviceEntryUdfpsInteractor.isUdfpsSupported,
+ ) { deviceEntryStatus, isUdfps ->
+ when (deviceEntryStatus) {
+ DeviceEntryIconView.IconType.LOCK -> isUdfps
+ DeviceEntryIconView.IconType.UNLOCK -> true
+ DeviceEntryIconView.IconType.FINGERPRINT -> false
+ }
+ }
val accessibilityDelegateHint: Flow<DeviceEntryIconView.AccessibilityHintType> =
- flowOf(DeviceEntryIconView.AccessibilityHintType.NONE)
+ combine(iconType, isLongPressEnabled) { deviceEntryStatus, longPressEnabled ->
+ if (longPressEnabled) {
+ deviceEntryStatus.toAccessibilityHintType()
+ } else {
+ DeviceEntryIconView.AccessibilityHintType.NONE
+ }
+ }
fun onLongPress() {
- // TODO() vibrate & perform action based on current lock/unlock state
+ deviceEntryHapticsInteractor.vibrateSuccess()
+
+ // TODO (b/309804148): play auth ripple via an interactor
+
+ if (sceneContainerFlags.isEnabled()) {
+ deviceEntryInteractor.attemptDeviceEntry()
+ } else {
+ keyguardViewController.get().showPrimaryBouncer(/* scrim */ true)
+ }
}
- data class BurnInViewModel(
- val x: Int, // current x burn in offset based on the aodTransitionAmount
- val y: Int, // current y burn in offset based on the aodTransitionAmount
- val progress: Float, // current progress based on the aodTransitionAmount
- )
- class IconViewModel(
- val type: DeviceEntryIconView.IconType,
- val useAodVariant: Boolean,
- val tint: Int,
- val alpha: Float,
- val padding: Int,
- )
-
- class BackgroundViewModel(
- val alpha: Float,
- val tint: Int,
- )
+ private fun DeviceEntryIconView.IconType.toAccessibilityHintType():
+ DeviceEntryIconView.AccessibilityHintType {
+ return when (this) {
+ DeviceEntryIconView.IconType.LOCK ->
+ DeviceEntryIconView.AccessibilityHintType.AUTHENTICATE
+ DeviceEntryIconView.IconType.UNLOCK -> DeviceEntryIconView.AccessibilityHintType.ENTER
+ DeviceEntryIconView.IconType.FINGERPRINT ->
+ DeviceEntryIconView.AccessibilityHintType.NONE
+ }
+ }
}
+
+data class BurnInOffsets(
+ val x: Int, // current x burn in offset based on the aodTransitionAmount
+ val y: Int, // current y burn in offset based on the aodTransitionAmount
+ val progress: Float, // current progress based on the aodTransitionAmount
+)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt
new file mode 100644
index 0000000..27fb8a3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromDozingTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Breaks down DOZING->LOCKSCREEN transition into discrete steps for corresponding views to consume.
+ */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class DozingToLockscreenTransitionViewModel
+@Inject
+constructor(
+ interactor: KeyguardTransitionInteractor,
+) : DeviceEntryIconTransition {
+ private val transitionAnimation: KeyguardTransitionAnimationFlow =
+ KeyguardTransitionAnimationFlow(
+ transitionDuration = FromDozingTransitionInteractor.TO_LOCKSCREEN_DURATION,
+ transitionFlow = interactor.dozingToLockscreenTransition,
+ )
+
+ override val deviceEntryParentViewAlpha: Flow<Float> =
+ transitionAnimation.immediatelyTransitionTo(1f)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
index e24d326..a3b8b85 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
@@ -18,27 +18,34 @@
import com.android.app.animation.Interpolators.EMPHASIZED
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flatMapLatest
/**
* Breaks down DREAMING->LOCKSCREEN transition into discrete steps for corresponding views to
* consume.
*/
+@ExperimentalCoroutinesApi
@SysUISingleton
class DreamingToLockscreenTransitionViewModel
@Inject
constructor(
keyguardTransitionInteractor: KeyguardTransitionInteractor,
- private val fromDreamingTransitionInteractor: FromDreamingTransitionInteractor
-) {
+ private val fromDreamingTransitionInteractor: FromDreamingTransitionInteractor,
+ private val deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+) : DeviceEntryIconTransition {
fun startTransition() = fromDreamingTransitionInteractor.startToLockscreenTransition()
private val transitionAnimation =
@@ -88,4 +95,15 @@
duration = 250.milliseconds,
onStep = { it },
)
+
+ val deviceEntryBackgroundViewAlpha =
+ deviceEntryUdfpsInteractor.isUdfpsSupported.flatMapLatest { isUdfps ->
+ if (isUdfps) {
+ // immediately show; will fade in with deviceEntryParentViewAlpha
+ transitionAnimation.immediatelyTransitionTo(1f)
+ } else {
+ emptyFlow()
+ }
+ }
+ override val deviceEntryParentViewAlpha = lockscreenAlpha
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt
index 601dbcc..62b2281 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt
@@ -18,20 +18,27 @@
import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_AOD_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
/** Breaks down GONE->AOD transition into discrete steps for corresponding views to consume. */
+@ExperimentalCoroutinesApi
@SysUISingleton
class GoneToAodTransitionViewModel
@Inject
constructor(
- private val interactor: KeyguardTransitionInteractor,
-) {
+ interactor: KeyguardTransitionInteractor,
+ deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+) : DeviceEntryIconTransition {
private val transitionAnimation =
KeyguardTransitionAnimationFlow(
@@ -60,4 +67,21 @@
onStart = { 0f },
onStep = { it },
)
+ val deviceEntryBackgroundViewAlpha: Flow<Float> =
+ transitionAnimation.immediatelyTransitionTo(0f)
+ override val deviceEntryParentViewAlpha: Flow<Float> =
+ deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfpsEnrolled ->
+ if (udfpsEnrolled) {
+ // fade in at the end of the transition to give time for FP to start running
+ // and avoid a flicker of the unlocked icon
+ transitionAnimation.createFlow(
+ startTime = 1100.milliseconds,
+ duration = 200.milliseconds,
+ onStep = { it },
+ onFinish = { 1f },
+ )
+ } else {
+ emptyFlow()
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt
new file mode 100644
index 0000000..2bf12e8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt
@@ -0,0 +1,85 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+
+/**
+ * Breaks down LOCKSCREEN->AOD transition into discrete steps for corresponding views to consume.
+ */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class LockscreenToAodTransitionViewModel
+@Inject
+constructor(
+ interactor: KeyguardTransitionInteractor,
+ deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+ shadeDependentFlows: ShadeDependentFlows,
+) : DeviceEntryIconTransition {
+
+ private val transitionAnimation =
+ KeyguardTransitionAnimationFlow(
+ transitionDuration = FromLockscreenTransitionInteractor.TO_AOD_DURATION,
+ transitionFlow = interactor.lockscreenToAodTransition,
+ )
+
+ val deviceEntryBackgroundViewAlpha: Flow<Float> =
+ shadeDependentFlows.transitionFlow(
+ flowWhenShadeIsExpanded = transitionAnimation.immediatelyTransitionTo(0f),
+ flowWhenShadeIsNotExpanded =
+ transitionAnimation.createFlow(
+ duration = 300.milliseconds,
+ onStep = { 1 - it },
+ onFinish = { 0f },
+ ),
+ )
+ override val deviceEntryParentViewAlpha: Flow<Float> =
+ deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest {
+ isUdfpsEnrolledAndEnabled ->
+ if (isUdfpsEnrolledAndEnabled) {
+ shadeDependentFlows.transitionFlow(
+ flowWhenShadeIsExpanded = // fade in
+ transitionAnimation.createFlow(
+ duration = 300.milliseconds,
+ onStep = { it },
+ onFinish = { 1f },
+ ),
+ flowWhenShadeIsNotExpanded = transitionAnimation.immediatelyTransitionTo(1f),
+ )
+ } else {
+ shadeDependentFlows.transitionFlow(
+ flowWhenShadeIsExpanded = transitionAnimation.immediatelyTransitionTo(0f),
+ flowWhenShadeIsNotExpanded = // fade out
+ transitionAnimation.createFlow(
+ duration = 200.milliseconds,
+ onStep = { 1f - it },
+ onFinish = { 0f },
+ ),
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
index a3ae67d..5229613 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
@@ -21,6 +21,7 @@
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_DREAMING_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.flow.Flow
@@ -34,7 +35,8 @@
@Inject
constructor(
interactor: KeyguardTransitionInteractor,
-) {
+ shadeDependentFlows: ShadeDependentFlows,
+) : DeviceEntryIconTransition {
private val transitionAnimation =
KeyguardTransitionAnimationFlow(
transitionDuration = TO_DREAMING_DURATION,
@@ -60,6 +62,12 @@
onStep = { 1f - it },
)
+ override val deviceEntryParentViewAlpha: Flow<Float> =
+ shadeDependentFlows.transitionFlow(
+ flowWhenShadeIsNotExpanded = lockscreenAlpha,
+ flowWhenShadeIsExpanded = transitionAnimation.immediatelyTransitionTo(0f),
+ )
+
companion object {
@JvmField val DREAMING_ANIMATION_DURATION_MS = TO_DREAMING_DURATION.inWholeMilliseconds
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModel.kt
new file mode 100644
index 0000000..59e5aa8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModel.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Breaks down LOCKSCREEN->GONE transition into discrete steps for corresponding views to consume.
+ */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class LockscreenToGoneTransitionViewModel
+@Inject
+constructor(
+ interactor: KeyguardTransitionInteractor,
+) : DeviceEntryIconTransition {
+
+ private val transitionAnimation =
+ KeyguardTransitionAnimationFlow(
+ transitionDuration = FromLockscreenTransitionInteractor.TO_GONE_DURATION,
+ transitionFlow = interactor.transition(KeyguardState.LOCKSCREEN, KeyguardState.GONE),
+ )
+
+ override val deviceEntryParentViewAlpha: Flow<Float> =
+ transitionAnimation.immediatelyTransitionTo(0f)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt
index d3ea89c..d49bc49 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt
@@ -21,6 +21,7 @@
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_OCCLUDED_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.flow.Flow
@@ -33,8 +34,9 @@
class LockscreenToOccludedTransitionViewModel
@Inject
constructor(
- private val interactor: KeyguardTransitionInteractor,
-) {
+ interactor: KeyguardTransitionInteractor,
+ shadeDependentFlows: ShadeDependentFlows,
+) : DeviceEntryIconTransition {
private val transitionAnimation =
KeyguardTransitionAnimationFlow(
transitionDuration = TO_OCCLUDED_DURATION,
@@ -59,4 +61,10 @@
interpolator = EMPHASIZED_ACCELERATE,
)
}
+
+ override val deviceEntryParentViewAlpha: Flow<Float> =
+ shadeDependentFlows.transitionFlow(
+ flowWhenShadeIsNotExpanded = lockscreenAlpha,
+ flowWhenShadeIsExpanded = transitionAnimation.immediatelyTransitionTo(0f),
+ )
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt
new file mode 100644
index 0000000..f04b67a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Breaks down LOCKSCREEN->PRIMARY BOUNCER transition into discrete steps for corresponding views to
+ * consume.
+ */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class LockscreenToPrimaryBouncerTransitionViewModel
+@Inject
+constructor(
+ interactor: KeyguardTransitionInteractor,
+ shadeDependentFlows: ShadeDependentFlows,
+) : DeviceEntryIconTransition {
+ private val transitionAnimation =
+ KeyguardTransitionAnimationFlow(
+ transitionDuration = FromLockscreenTransitionInteractor.TO_PRIMARY_BOUNCER_DURATION,
+ transitionFlow =
+ interactor.transition(KeyguardState.LOCKSCREEN, KeyguardState.PRIMARY_BOUNCER),
+ )
+
+ override val deviceEntryParentViewAlpha: Flow<Float> =
+ shadeDependentFlows.transitionFlow(
+ flowWhenShadeIsNotExpanded =
+ transitionAnimation.createFlow(
+ duration = 250.milliseconds,
+ onStep = { 1f - it },
+ onFinish = { 0f }
+ ),
+ flowWhenShadeIsExpanded = transitionAnimation.immediatelyTransitionTo(0f)
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt
new file mode 100644
index 0000000..f7cff9b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.domain.interactor.FromOccludedTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
+
+/** Breaks down OCCLUDED->AOD transition into discrete steps for corresponding views to consume. */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class OccludedToAodTransitionViewModel
+@Inject
+constructor(
+ interactor: KeyguardTransitionInteractor,
+ deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+) : DeviceEntryIconTransition {
+ private val transitionAnimation =
+ KeyguardTransitionAnimationFlow(
+ transitionDuration = FromOccludedTransitionInteractor.TO_AOD_DURATION,
+ transitionFlow = interactor.transition(KeyguardState.OCCLUDED, KeyguardState.AOD),
+ )
+
+ val deviceEntryBackgroundViewAlpha: Flow<Float> =
+ transitionAnimation.immediatelyTransitionTo(0f)
+
+ override val deviceEntryParentViewAlpha: Flow<Float> =
+ deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfpsEnrolledAndEnabled
+ ->
+ if (udfpsEnrolledAndEnabled) {
+ transitionAnimation.immediatelyTransitionTo(1f)
+ } else {
+ emptyFlow()
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
index 6845c55..0bdc85d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
@@ -18,23 +18,30 @@
import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
import com.android.systemui.keyguard.domain.interactor.FromOccludedTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
/**
* Breaks down OCCLUDED->LOCKSCREEN transition into discrete steps for corresponding views to
* consume.
*/
+@ExperimentalCoroutinesApi
@SysUISingleton
class OccludedToLockscreenTransitionViewModel
@Inject
constructor(
- private val interactor: KeyguardTransitionInteractor,
-) {
+ interactor: KeyguardTransitionInteractor,
+ deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor
+) : DeviceEntryIconTransition {
private val transitionAnimation =
KeyguardTransitionAnimationFlow(
transitionDuration = TO_LOCKSCREEN_DURATION,
@@ -58,4 +65,16 @@
duration = 250.milliseconds,
onStep = { it },
)
+
+ val deviceEntryBackgroundViewAlpha: Flow<Float> =
+ deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest {
+ isUdfpsEnrolledAndEnabled ->
+ if (isUdfpsEnrolledAndEnabled) {
+ transitionAnimation.immediatelyTransitionTo(1f)
+ } else {
+ emptyFlow()
+ }
+ }
+
+ override val deviceEntryParentViewAlpha: Flow<Float> = lockscreenAlpha
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt
new file mode 100644
index 0000000..05a6d58
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
+
+/**
+ * Breaks down PRIMARY BOUNCER->AOD transition into discrete steps for corresponding views to
+ * consume.
+ */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class PrimaryBouncerToAodTransitionViewModel
+@Inject
+constructor(
+ interactor: KeyguardTransitionInteractor,
+ deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+) : DeviceEntryIconTransition {
+ private val transitionAnimation =
+ KeyguardTransitionAnimationFlow(
+ transitionDuration = FromPrimaryBouncerTransitionInteractor.TO_AOD_DURATION,
+ transitionFlow =
+ interactor.transition(KeyguardState.PRIMARY_BOUNCER, KeyguardState.AOD),
+ )
+
+ val deviceEntryBackgroundViewAlpha: Flow<Float> =
+ deviceEntryUdfpsInteractor.isUdfpsSupported.flatMapLatest { isUdfpsEnrolledAndEnabled ->
+ if (isUdfpsEnrolledAndEnabled) {
+ transitionAnimation.immediatelyTransitionTo(0f)
+ } else {
+ emptyFlow()
+ }
+ }
+
+ override val deviceEntryParentViewAlpha: Flow<Float> =
+ deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest {
+ isUdfpsEnrolledAndEnabled ->
+ if (isUdfpsEnrolledAndEnabled) {
+ transitionAnimation.createFlow(
+ duration = 300.milliseconds,
+ onStep = { it },
+ onFinish = { 1f },
+ )
+ } else {
+ emptyFlow()
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt
new file mode 100644
index 0000000..3cf793a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
+
+/**
+ * Breaks down PRIMARY BOUNCER->LOCKSCREEN transition into discrete steps for corresponding views to
+ * consume.
+ */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class PrimaryBouncerToLockscreenTransitionViewModel
+@Inject
+constructor(
+ interactor: KeyguardTransitionInteractor,
+ deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+) : DeviceEntryIconTransition {
+ private val transitionAnimation =
+ KeyguardTransitionAnimationFlow(
+ transitionDuration = FromPrimaryBouncerTransitionInteractor.TO_LOCKSCREEN_DURATION,
+ transitionFlow =
+ interactor.transition(KeyguardState.PRIMARY_BOUNCER, KeyguardState.LOCKSCREEN),
+ )
+
+ val deviceEntryBackgroundViewAlpha: Flow<Float> =
+ deviceEntryUdfpsInteractor.isUdfpsSupported.flatMapLatest { isUdfps ->
+ if (isUdfps) {
+ transitionAnimation.immediatelyTransitionTo(1f)
+ } else {
+ emptyFlow()
+ }
+ }
+
+ override val deviceEntryParentViewAlpha: Flow<Float> =
+ transitionAnimation.immediatelyTransitionTo(1f)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/ShadeDependentFlows.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/ShadeDependentFlows.kt
new file mode 100644
index 0000000..e45d537
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/ShadeDependentFlows.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+
+/** Helper for flows that depend on the shade expansion */
+class ShadeDependentFlows
+@Inject
+constructor(
+ transitionInteractor: KeyguardTransitionInteractor,
+ shadeInteractor: ShadeInteractor,
+) {
+ /** When the last keyguard state transition started, was the shade fully expanded? */
+ private val lastStartedTransitionHadShadeFullyExpanded: Flow<Boolean> =
+ transitionInteractor.startedKeyguardState.sample(shadeInteractor.isAnyFullyExpanded)
+
+ /**
+ * Decide which flow to use depending on the shade expansion state at the start of the last
+ * keyguard state transition.
+ */
+ fun <T> transitionFlow(
+ flowWhenShadeIsExpanded: Flow<T>,
+ flowWhenShadeIsNotExpanded: Flow<T>,
+ ): Flow<T> {
+ val filteredFlowWhenShadeIsExpanded =
+ flowWhenShadeIsExpanded
+ .sample(lastStartedTransitionHadShadeFullyExpanded, ::Pair)
+ .filter { (_, shadeFullyExpanded) -> shadeFullyExpanded }
+ .map { (valueWhenShadeIsExpanded, _) -> valueWhenShadeIsExpanded }
+ val filteredFlowWhenShadeIsNotExpanded =
+ flowWhenShadeIsNotExpanded
+ .sample(lastStartedTransitionHadShadeFullyExpanded, ::Pair)
+ .filter { (_, shadeFullyExpanded) -> !shadeFullyExpanded }
+ .map { (valueWhenShadeIsNotExpanded, _) -> valueWhenShadeIsNotExpanded }
+ return merge(filteredFlowWhenShadeIsExpanded, filteredFlowWhenShadeIsNotExpanded)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModel.kt
index c10a463..6e77e13e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModel.kt
@@ -17,9 +17,9 @@
package com.android.systemui.keyguard.ui.viewmodel
import android.content.Context
-import com.android.systemui.res.R
-import com.android.systemui.keyguard.domain.interactor.BurnInOffsets
+import com.android.systemui.keyguard.domain.interactor.Offsets
import com.android.systemui.keyguard.domain.interactor.UdfpsKeyguardInteractor
+import com.android.systemui.res.R
import javax.inject.Inject
import kotlin.math.roundToInt
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -35,7 +35,7 @@
val context: Context,
) {
val alpha: Flow<Float> = interactor.dozeAmount
- val burnInOffsets: Flow<BurnInOffsets> = interactor.burnInOffsets
+ val burnInOffsets: Flow<Offsets> = interactor.burnInOffsets
val isVisible: Flow<Boolean> = alpha.map { it != 0f }
// Padding between the fingerprint icon and its bounding box in pixels.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt
index 0b1079f..642904d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt
@@ -19,9 +19,9 @@
import android.content.Context
import androidx.annotation.ColorInt
import com.android.settingslib.Utils.getColorAttrDefaultColor
-import com.android.systemui.keyguard.domain.interactor.BurnInOffsets
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.Offsets
import com.android.systemui.keyguard.domain.interactor.UdfpsKeyguardInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.StatusBarState
@@ -185,7 +185,7 @@
keyguardInteractor,
) {
val dozeAmount: Flow<Float> = interactor.dozeAmount
- val burnInOffsets: Flow<BurnInOffsets> = interactor.burnInOffsets
+ val burnInOffsets: Flow<Offsets> = interactor.burnInOffsets
// Padding between the fingerprint icon and its bounding box in pixels.
val padding: Flow<Int> =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt
new file mode 100644
index 0000000..e8eda80
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt
@@ -0,0 +1,119 @@
+/*
+ * 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.deviceentry.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceEntryUdfpsInteractorTest : SysuiTestCase() {
+ private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+ private lateinit var fingerprintAuthRepository: FakeDeviceEntryFingerprintAuthRepository
+ private lateinit var biometricsRepository: FakeBiometricSettingsRepository
+
+ private lateinit var underTest: DeviceEntryUdfpsInteractor
+
+ @Before
+ fun setUp() {
+ fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
+ fingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
+ biometricsRepository = FakeBiometricSettingsRepository()
+
+ underTest =
+ DeviceEntryUdfpsInteractor(
+ fingerprintPropertyRepository = fingerprintPropertyRepository,
+ fingerprintAuthRepository = fingerprintAuthRepository,
+ biometricSettingsRepository = biometricsRepository,
+ )
+ }
+
+ @Test
+ fun udfpsSupported_rearFp_false() = runTest {
+ val isUdfpsSupported by collectLastValue(underTest.isUdfpsSupported)
+ fingerprintPropertyRepository.supportsRearFps()
+ assertThat(isUdfpsSupported).isFalse()
+ }
+
+ @Test
+ fun udfpsSupoprted() = runTest {
+ val isUdfpsSupported by collectLastValue(underTest.isUdfpsSupported)
+ fingerprintPropertyRepository.supportsUdfps()
+ assertThat(isUdfpsSupported).isTrue()
+ }
+
+ @Test
+ fun udfpsEnrolledAndEnabled() = runTest {
+ val isUdfpsEnrolledAndEnabled by collectLastValue(underTest.isUdfpsEnrolledAndEnabled)
+ fingerprintPropertyRepository.supportsUdfps()
+ biometricsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ assertThat(isUdfpsEnrolledAndEnabled).isTrue()
+ }
+
+ @Test
+ fun udfpsEnrolledAndEnabled_rearFp_false() = runTest {
+ val isUdfpsEnrolledAndEnabled by collectLastValue(underTest.isUdfpsEnrolledAndEnabled)
+ fingerprintPropertyRepository.supportsRearFps()
+ biometricsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ assertThat(isUdfpsEnrolledAndEnabled).isFalse()
+ }
+
+ @Test
+ fun udfpsEnrolledAndEnabled_notEnrolledOrEnabled_false() = runTest {
+ val isUdfpsEnrolledAndEnabled by collectLastValue(underTest.isUdfpsEnrolledAndEnabled)
+ fingerprintPropertyRepository.supportsUdfps()
+ biometricsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+ assertThat(isUdfpsEnrolledAndEnabled).isFalse()
+ }
+
+ @Test
+ fun isListeningForUdfps() = runTest {
+ val isListeningForUdfps by collectLastValue(underTest.isListeningForUdfps)
+ fingerprintPropertyRepository.supportsUdfps()
+ fingerprintAuthRepository.setIsRunning(true)
+ assertThat(isListeningForUdfps).isTrue()
+ }
+
+ @Test
+ fun isListeningForUdfps_rearFp_false() = runTest {
+ val isListeningForUdfps by collectLastValue(underTest.isListeningForUdfps)
+ fingerprintPropertyRepository.supportsRearFps()
+ fingerprintAuthRepository.setIsRunning(true)
+ assertThat(isListeningForUdfps).isFalse()
+ }
+
+ @Test
+ fun isListeningForUdfps_notRunning_false() = runTest {
+ val isListeningForUdfps by collectLastValue(underTest.isListeningForUdfps)
+ fingerprintPropertyRepository.supportsUdfps()
+ fingerprintAuthRepository.setIsRunning(false)
+ assertThat(isListeningForUdfps).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt
index 5eab2fc..df52265 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt
@@ -84,8 +84,8 @@
@Test
fun udfpsBurnInOffset_updatesOnResolutionScaleChange() =
testScope.runTest {
- val udfpsBurnInOffsetX by collectLastValue(underTest.udfpsBurnInXOffset)
- val udfpsBurnInOffsetY by collectLastValue(underTest.udfpsBurnInYOffset)
+ val udfpsBurnInOffsetX by collectLastValue(underTest.deviceEntryIconXOffset)
+ val udfpsBurnInOffsetY by collectLastValue(underTest.deviceEntryIconYOffset)
assertThat(udfpsBurnInOffsetX).isEqualTo(burnInOffset)
assertThat(udfpsBurnInOffsetY).isEqualTo(burnInOffset)
@@ -101,7 +101,7 @@
@Test
fun udfpsBurnInProgress_updatesOnDozeTimeTick() =
testScope.runTest {
- val udfpsBurnInProgress by collectLastValue(underTest.udfpsBurnInProgress)
+ val udfpsBurnInProgress by collectLastValue(underTest.udfpsProgress)
assertThat(udfpsBurnInProgress).isEqualTo(burnInProgress)
setBurnInProgress(.88f)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractorTest.kt
index 3442df6..2dfc132 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractorTest.kt
@@ -123,30 +123,30 @@
runCurrent()
// THEN burn in offsets are 0
- assertThat(burnInOffsets?.burnInProgress).isEqualTo(0f)
- assertThat(burnInOffsets?.burnInYOffset).isEqualTo(0)
- assertThat(burnInOffsets?.burnInXOffset).isEqualTo(0)
+ assertThat(burnInOffsets?.progress).isEqualTo(0f)
+ assertThat(burnInOffsets?.y).isEqualTo(0)
+ assertThat(burnInOffsets?.x).isEqualTo(0)
// WHEN we're in the middle of the doze amount change
keyguardRepository.setDozeAmount(.50f)
runCurrent()
// THEN burn in is updated (between 0 and the full offset)
- assertThat(burnInOffsets?.burnInProgress).isGreaterThan(0f)
- assertThat(burnInOffsets?.burnInYOffset).isGreaterThan(0)
- assertThat(burnInOffsets?.burnInXOffset).isGreaterThan(0)
- assertThat(burnInOffsets?.burnInProgress).isLessThan(burnInProgress)
- assertThat(burnInOffsets?.burnInYOffset).isLessThan(burnInYOffset)
- assertThat(burnInOffsets?.burnInXOffset).isLessThan(burnInXOffset)
+ assertThat(burnInOffsets?.progress).isGreaterThan(0f)
+ assertThat(burnInOffsets?.y).isGreaterThan(0)
+ assertThat(burnInOffsets?.x).isGreaterThan(0)
+ assertThat(burnInOffsets?.progress).isLessThan(burnInProgress)
+ assertThat(burnInOffsets?.y).isLessThan(burnInYOffset)
+ assertThat(burnInOffsets?.x).isLessThan(burnInXOffset)
// WHEN we're fully dozing
keyguardRepository.setDozeAmount(1f)
runCurrent()
// THEN burn in offsets are updated to final current values (for the given time)
- assertThat(burnInOffsets?.burnInProgress).isEqualTo(burnInProgress)
- assertThat(burnInOffsets?.burnInYOffset).isEqualTo(burnInYOffset)
- assertThat(burnInOffsets?.burnInXOffset).isEqualTo(burnInXOffset)
+ assertThat(burnInOffsets?.progress).isEqualTo(burnInProgress)
+ assertThat(burnInOffsets?.y).isEqualTo(burnInYOffset)
+ assertThat(burnInOffsets?.x).isEqualTo(burnInXOffset)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt
index 71313c8..75bdcdd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt
@@ -24,12 +24,14 @@
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.LockIconViewController
+import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController
-import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryBackgroundViewModel
+import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
@@ -42,6 +44,7 @@
import org.junit.runners.JUnit4
import org.mockito.Answers
import org.mockito.Mock
+import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations
@ExperimentalCoroutinesApi
@@ -77,7 +80,9 @@
notificationPanelView,
featureFlags,
{ lockIconViewController },
- { DeviceEntryIconViewModel() },
+ { mock(DeviceEntryIconViewModel::class.java) },
+ { mock(DeviceEntryForegroundViewModel::class.java) },
+ { mock(DeviceEntryBackgroundViewModel::class.java) },
{ falsingManager },
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt
new file mode 100644
index 0000000..f282481
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AodToGoneTransitionViewModelTest : SysuiTestCase() {
+ private lateinit var underTest: AodToGoneTransitionViewModel
+ private lateinit var repository: FakeKeyguardTransitionRepository
+
+ @Before
+ fun setUp() {
+ repository = FakeKeyguardTransitionRepository()
+ val interactor =
+ KeyguardTransitionInteractorFactory.create(
+ scope = TestScope().backgroundScope,
+ repository = repository,
+ )
+ .keyguardTransitionInteractor
+ underTest = AodToGoneTransitionViewModel(interactor)
+ }
+
+ @Test
+ fun deviceEntryParentViewHides() = runTest {
+ val deviceEntryParentViewAlpha by collectValues(underTest.deviceEntryParentViewAlpha)
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.1f))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.4f))
+ repository.sendTransitionStep(step(0.5f))
+ repository.sendTransitionStep(step(0.6f))
+ repository.sendTransitionStep(step(0.8f))
+ repository.sendTransitionStep(step(1f))
+ deviceEntryParentViewAlpha.forEach { assertThat(it).isEqualTo(0f) }
+ }
+
+ private fun step(
+ value: Float,
+ state: TransitionState = TransitionState.RUNNING
+ ): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.AOD,
+ to = KeyguardState.GONE,
+ value = value,
+ transitionState = state,
+ ownerName = "AodToGoneTransitionViewModelTest"
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt
new file mode 100644
index 0000000..517149c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt
@@ -0,0 +1,135 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AodToLockscreenTransitionViewModelTest : SysuiTestCase() {
+ private lateinit var underTest: AodToLockscreenTransitionViewModel
+ private lateinit var repository: FakeKeyguardTransitionRepository
+ private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+
+ @Before
+ fun setUp() {
+ repository = FakeKeyguardTransitionRepository()
+ fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
+ underTest =
+ AodToLockscreenTransitionViewModel(
+ interactor =
+ KeyguardTransitionInteractorFactory.create(
+ scope = TestScope().backgroundScope,
+ repository = repository,
+ )
+ .keyguardTransitionInteractor,
+ deviceEntryUdfpsInteractor =
+ DeviceEntryUdfpsInteractor(
+ fingerprintPropertyRepository = fingerprintPropertyRepository,
+ fingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository(),
+ biometricSettingsRepository = FakeBiometricSettingsRepository(),
+ ),
+ )
+ }
+
+ @Test
+ fun deviceEntryParentViewShows() = runTest {
+ val deviceEntryParentViewAlpha by collectValues(underTest.deviceEntryParentViewAlpha)
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.1f))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.5f))
+ repository.sendTransitionStep(step(0.6f))
+ repository.sendTransitionStep(step(1f))
+ deviceEntryParentViewAlpha.forEach { assertThat(it).isEqualTo(1f) }
+ }
+
+ @Test
+ fun deviceEntryBackgroundView_udfps_alphaFadeIn() = runTest {
+ fingerprintPropertyRepository.supportsUdfps()
+ val deviceEntryBackgroundViewAlpha by
+ collectLastValue(underTest.deviceEntryBackgroundViewAlpha)
+
+ // fade in
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(0.1f))
+ assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(.2f)
+
+ repository.sendTransitionStep(step(0.3f))
+ assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(.6f)
+
+ repository.sendTransitionStep(step(0.6f))
+ assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(1f)
+
+ repository.sendTransitionStep(step(1f))
+ assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(1f)
+ }
+
+ @Test
+ fun deviceEntryBackgroundView_rearFp_noUpdates() = runTest {
+ fingerprintPropertyRepository.supportsRearFps()
+ val deviceEntryBackgroundViewAlpha by
+ collectLastValue(underTest.deviceEntryBackgroundViewAlpha)
+ // no updates
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(deviceEntryBackgroundViewAlpha).isNull()
+ repository.sendTransitionStep(step(0.1f))
+ assertThat(deviceEntryBackgroundViewAlpha).isNull()
+ repository.sendTransitionStep(step(0.3f))
+ assertThat(deviceEntryBackgroundViewAlpha).isNull()
+ repository.sendTransitionStep(step(0.6f))
+ assertThat(deviceEntryBackgroundViewAlpha).isNull()
+ repository.sendTransitionStep(step(1f))
+ assertThat(deviceEntryBackgroundViewAlpha).isNull()
+ }
+
+ private fun step(
+ value: Float,
+ state: TransitionState = TransitionState.RUNNING
+ ): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.AOD,
+ to = KeyguardState.LOCKSCREEN,
+ value = value,
+ transitionState = state,
+ ownerName = "AodToLockscreenTransitionViewModelTest"
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelTest.kt
new file mode 100644
index 0000000..96f69462
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelTest.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.google.common.truth.Truth
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AodToOccludedTransitionViewModelTest : SysuiTestCase() {
+ private lateinit var underTest: AodToOccludedTransitionViewModel
+ private lateinit var repository: FakeKeyguardTransitionRepository
+
+ @Before
+ fun setUp() {
+ repository = FakeKeyguardTransitionRepository()
+ val interactor =
+ KeyguardTransitionInteractorFactory.create(
+ scope = TestScope().backgroundScope,
+ repository = repository,
+ )
+ .keyguardTransitionInteractor
+ underTest = AodToOccludedTransitionViewModel(interactor)
+ }
+
+ @Test
+ fun deviceEntryParentViewHides() = runTest {
+ val deviceEntryParentViewAlpha by collectValues(underTest.deviceEntryParentViewAlpha)
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.1f))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.4f))
+ repository.sendTransitionStep(step(0.5f))
+ repository.sendTransitionStep(step(0.6f))
+ repository.sendTransitionStep(step(0.8f))
+ repository.sendTransitionStep(step(1f))
+ deviceEntryParentViewAlpha.forEach { Truth.assertThat(it).isEqualTo(0f) }
+ }
+
+ private fun step(
+ value: Float,
+ state: TransitionState = TransitionState.RUNNING
+ ): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.AOD,
+ to = KeyguardState.OCCLUDED,
+ value = value,
+ transitionState = state,
+ ownerName = "AodToOccludedTransitionViewModelTest"
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt
new file mode 100644
index 0000000..5dccc3b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt
@@ -0,0 +1,82 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DozingToLockscreenTransitionViewModelTest : SysuiTestCase() {
+ private lateinit var testScope: TestScope
+ private lateinit var underTest: DozingToLockscreenTransitionViewModel
+ private lateinit var repository: FakeKeyguardTransitionRepository
+
+ @Before
+ fun setUp() {
+ repository = FakeKeyguardTransitionRepository()
+ underTest =
+ DozingToLockscreenTransitionViewModel(
+ interactor =
+ KeyguardTransitionInteractorFactory.create(
+ scope = TestScope().backgroundScope,
+ repository = repository,
+ )
+ .keyguardTransitionInteractor,
+ )
+ }
+
+ @Test
+ fun deviceEntryParentViewShows() = runTest {
+ val deviceEntryParentViewAlpha by collectValues(underTest.deviceEntryParentViewAlpha)
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.1f))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.5f))
+ repository.sendTransitionStep(step(0.6f))
+ repository.sendTransitionStep(step(1f))
+ deviceEntryParentViewAlpha.forEach { assertThat(it).isEqualTo(1f) }
+ }
+
+ private fun step(
+ value: Float,
+ state: TransitionState = TransitionState.RUNNING
+ ): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.DOZING,
+ to = KeyguardState.LOCKSCREEN,
+ value = value,
+ transitionState = state,
+ ownerName = "DozingToLockscreenTransitionViewModelTest"
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
index 6d47aed..fd125e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
@@ -19,6 +19,12 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.shared.model.FingerprintSensorType
+import com.android.systemui.biometrics.shared.model.SensorStrength
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
@@ -35,6 +41,7 @@
import com.android.systemui.util.mockito.mock
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
@@ -44,22 +51,34 @@
import org.junit.Test
import org.junit.runner.RunWith
+@ExperimentalCoroutinesApi
@SmallTest
@RunWith(AndroidJUnit4::class)
class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {
private lateinit var underTest: DreamingToLockscreenTransitionViewModel
private lateinit var repository: FakeKeyguardTransitionRepository
+ private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
@Before
fun setUp() {
repository = FakeKeyguardTransitionRepository()
+ fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
val interactor =
KeyguardTransitionInteractorFactory.create(
scope = TestScope().backgroundScope,
repository = repository,
)
.keyguardTransitionInteractor
- underTest = DreamingToLockscreenTransitionViewModel(interactor, mock())
+ underTest =
+ DreamingToLockscreenTransitionViewModel(
+ interactor,
+ mock(),
+ DeviceEntryUdfpsInteractor(
+ fingerprintPropertyRepository = fingerprintPropertyRepository,
+ fingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository(),
+ biometricSettingsRepository = FakeBiometricSettingsRepository(),
+ ),
+ )
}
@Test
@@ -129,6 +148,78 @@
}
@Test
+ fun deviceEntryParentViewFadeIn() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Float>()
+
+ val job = underTest.deviceEntryParentViewAlpha.onEach { values.add(it) }.launchIn(this)
+
+ repository.sendTransitionStep(step(0f, STARTED))
+ repository.sendTransitionStep(step(0f))
+ repository.sendTransitionStep(step(0.1f))
+ repository.sendTransitionStep(step(0.2f))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(1f))
+
+ assertThat(values.size).isEqualTo(4)
+ values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
+
+ job.cancel()
+ }
+
+ @Test
+ fun deviceEntryBackgroundViewAppear() =
+ runTest(UnconfinedTestDispatcher()) {
+ fingerprintPropertyRepository.setProperties(
+ sensorId = 0,
+ strength = SensorStrength.STRONG,
+ sensorType = FingerprintSensorType.UDFPS_OPTICAL,
+ sensorLocations = emptyMap(),
+ )
+ val values = mutableListOf<Float>()
+
+ val job =
+ underTest.deviceEntryBackgroundViewAlpha.onEach { values.add(it) }.launchIn(this)
+
+ repository.sendTransitionStep(step(0f, STARTED))
+ repository.sendTransitionStep(step(0f))
+ repository.sendTransitionStep(step(0.1f))
+ repository.sendTransitionStep(step(0.2f))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(1f))
+
+ values.forEach { assertThat(it).isEqualTo(1f) }
+
+ job.cancel()
+ }
+
+ @Test
+ fun deviceEntryBackground_noUdfps_noUpdates() =
+ runTest(UnconfinedTestDispatcher()) {
+ fingerprintPropertyRepository.setProperties(
+ sensorId = 0,
+ strength = SensorStrength.STRONG,
+ sensorType = FingerprintSensorType.REAR,
+ sensorLocations = emptyMap(),
+ )
+ val values = mutableListOf<Float>()
+
+ val job =
+ underTest.deviceEntryBackgroundViewAlpha.onEach { values.add(it) }.launchIn(this)
+
+ repository.sendTransitionStep(step(0f, STARTED))
+ repository.sendTransitionStep(step(0f))
+ repository.sendTransitionStep(step(0.1f))
+ repository.sendTransitionStep(step(0.2f))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(1f))
+
+ assertThat(values.size).isEqualTo(0) // no updates
+
+ job.cancel()
+ }
+
+ @Test
fun lockscreenTranslationY() =
runTest(UnconfinedTestDispatcher()) {
val values = mutableListOf<Float>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelTest.kt
index 255f4df..c1444a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelTest.kt
@@ -19,7 +19,11 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -27,6 +31,7 @@
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
@@ -34,11 +39,14 @@
import org.junit.Test
import org.junit.runner.RunWith
+@ExperimentalCoroutinesApi
@SmallTest
@RunWith(AndroidJUnit4::class)
class GoneToAodTransitionViewModelTest : SysuiTestCase() {
private lateinit var underTest: GoneToAodTransitionViewModel
private lateinit var repository: FakeKeyguardTransitionRepository
+ private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+ private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
private lateinit var testScope: TestScope
@Before
@@ -47,13 +55,24 @@
testScope = TestScope(testDispatcher)
repository = FakeKeyguardTransitionRepository()
- val interactor =
- KeyguardTransitionInteractorFactory.create(
- scope = testScope.backgroundScope,
- repository = repository,
- )
- .keyguardTransitionInteractor
- underTest = GoneToAodTransitionViewModel(interactor)
+ fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
+ biometricSettingsRepository = FakeBiometricSettingsRepository()
+
+ underTest =
+ GoneToAodTransitionViewModel(
+ interactor =
+ KeyguardTransitionInteractorFactory.create(
+ scope = testScope.backgroundScope,
+ repository = repository,
+ )
+ .keyguardTransitionInteractor,
+ deviceEntryUdfpsInteractor =
+ DeviceEntryUdfpsInteractor(
+ fingerprintPropertyRepository = fingerprintPropertyRepository,
+ fingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository(),
+ biometricSettingsRepository = biometricSettingsRepository,
+ ),
+ )
}
@Test
@@ -63,11 +82,11 @@
val enterFromTopTranslationY by
collectLastValue(underTest.enterFromTopTranslationY(pixels.toInt()))
- // The animation should only start > halfway through
+ // The animation should only start > .4f way through
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
assertThat(enterFromTopTranslationY).isEqualTo(pixels)
- repository.sendTransitionStep(step(0.5f))
+ repository.sendTransitionStep(step(0.4f))
assertThat(enterFromTopTranslationY).isEqualTo(pixels)
repository.sendTransitionStep(step(.85f))
@@ -83,11 +102,11 @@
testScope.runTest {
val enterFromTopAnimationAlpha by collectLastValue(underTest.enterFromTopAnimationAlpha)
- // The animation should only start > halfway through
+ // The animation should only start > .4f way through
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
assertThat(enterFromTopAnimationAlpha).isEqualTo(0f)
- repository.sendTransitionStep(step(0.5f))
+ repository.sendTransitionStep(step(0.4f))
assertThat(enterFromTopAnimationAlpha).isEqualTo(0f)
repository.sendTransitionStep(step(.85f))
@@ -97,6 +116,98 @@
assertThat(enterFromTopAnimationAlpha).isEqualTo(1f)
}
+ @Test
+ fun deviceEntryBackgroundViewAlpha() =
+ testScope.runTest {
+ val deviceEntryBackgroundViewAlpha by
+ collectLastValue(underTest.deviceEntryBackgroundViewAlpha)
+
+ // immediately 0f
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(0.4f))
+ assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(.85f))
+ assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(1f))
+ assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f)
+ }
+
+ @Test
+ fun deviceEntryParentViewAlpha_udfpsEnrolled() =
+ testScope.runTest {
+ fingerprintPropertyRepository.supportsUdfps()
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha)
+
+ // animation doesn't start until the end
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(deviceEntryParentViewAlpha).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(0.5f))
+ assertThat(deviceEntryParentViewAlpha).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(.95f))
+ assertThat(deviceEntryParentViewAlpha).isIn(Range.closed(.01f, 1f))
+
+ repository.sendTransitionStep(step(1f))
+ assertThat(deviceEntryParentViewAlpha).isIn(Range.closed(.99f, 1f))
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(deviceEntryParentViewAlpha).isEqualTo(1f)
+ }
+
+ @Test
+ fun deviceEntryParentViewAlpha_rearFpEnrolled() =
+ testScope.runTest {
+ fingerprintPropertyRepository.supportsRearFps()
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha)
+
+ // animation doesn't start until the end
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(0.5f))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(.95f))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(1f))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+ }
+
+ @Test
+ fun deviceEntryParentViewAlpha_udfpsNotEnrolled_noUpdates() =
+ testScope.runTest {
+ fingerprintPropertyRepository.supportsUdfps()
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+ val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha)
+
+ // animation doesn't start until the end
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(0.5f))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(.95f))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(1f))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+ }
+
private fun step(
value: Float,
state: TransitionState = TransitionState.RUNNING
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt
new file mode 100644
index 0000000..4074851
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt
@@ -0,0 +1,251 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
+import com.android.SysUITestModule
+import com.android.TestMocksModule
+import com.android.collectLastValue
+import com.android.collectValues
+import com.android.runCurrent
+import com.android.runTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
+import com.android.systemui.flags.FakeFeatureFlagsClassicModule
+import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
+import com.android.systemui.flags.Flags.FULL_SCREEN_USER_SWITCHER
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.shade.data.repository.FakeShadeRepository
+import com.android.systemui.user.domain.UserDomainLayerModule
+import com.google.common.collect.Range
+import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class LockscreenToAodTransitionViewModelTest : SysuiTestCase() {
+ @SysUISingleton
+ @Component(
+ modules =
+ [
+ SysUITestModule::class,
+ UserDomainLayerModule::class,
+ ]
+ )
+ interface TestComponent : SysUITestComponent<LockscreenToAodTransitionViewModel> {
+ val repository: FakeKeyguardTransitionRepository
+ val deviceEntryRepository: FakeDeviceEntryRepository
+ val keyguardRepository: FakeKeyguardRepository
+ val shadeRepository: FakeShadeRepository
+ val fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+ val biometricSettingsRepository: FakeBiometricSettingsRepository
+
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance test: SysuiTestCase,
+ featureFlags: FakeFeatureFlagsClassicModule,
+ mocks: TestMocksModule,
+ ): TestComponent
+ }
+
+ fun shadeExpanded(expanded: Boolean) {
+ if (expanded) {
+ shadeRepository.setQsExpansion(1f)
+ } else {
+ keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
+ shadeRepository.setQsExpansion(0f)
+ shadeRepository.setLockscreenShadeExpansion(0f)
+ }
+ }
+ }
+
+ private val testComponent: TestComponent =
+ DaggerLockscreenToAodTransitionViewModelTest_TestComponent.factory()
+ .create(
+ test = this,
+ featureFlags =
+ FakeFeatureFlagsClassicModule {
+ set(FACE_AUTH_REFACTOR, true)
+ set(FULL_SCREEN_USER_SWITCHER, true)
+ },
+ mocks = TestMocksModule(),
+ )
+
+ @Test
+ fun backgroundViewAlpha_shadeNotExpanded() =
+ testComponent.runTest {
+ val actual by collectLastValue(underTest.deviceEntryBackgroundViewAlpha)
+ shadeExpanded(false)
+ runCurrent()
+
+ // fade out
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(actual).isEqualTo(1f)
+
+ repository.sendTransitionStep(step(.3f))
+ assertThat(actual).isIn(Range.closed(.1f, .9f))
+
+ // finish fading out before the end of the full transition
+ repository.sendTransitionStep(step(.7f))
+ assertThat(actual).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(actual).isEqualTo(0f)
+ }
+
+ @Test
+ fun backgroundViewAlpha_shadeExpanded() =
+ testComponent.runTest {
+ val actual by collectLastValue(underTest.deviceEntryBackgroundViewAlpha)
+ shadeExpanded(true)
+ runCurrent()
+
+ // immediately 0f
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(actual).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(.3f))
+ assertThat(actual).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(.7f))
+ assertThat(actual).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(actual).isEqualTo(0f)
+ }
+
+ @Test
+ fun deviceEntryParentViewAlpha_udfpsEnrolled_shadeNotExpanded() =
+ testComponent.runTest {
+ val values by collectValues(underTest.deviceEntryParentViewAlpha)
+ fingerprintPropertyRepository.supportsUdfps()
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ shadeExpanded(false)
+ runCurrent()
+
+ repository.sendTransitionSteps(
+ steps =
+ listOf(
+ step(0f, TransitionState.STARTED),
+ step(.3f),
+ step(.7f),
+ step(1f),
+ ),
+ testScope = testScope,
+ )
+ // immediately 1f
+ values.forEach { assertThat(it).isEqualTo(1f) }
+ }
+
+ @Test
+ fun deviceEntryParentViewAlpha_udfpsEnrolled_shadeExpanded() =
+ testComponent.runTest {
+ val actual by collectLastValue(underTest.deviceEntryParentViewAlpha)
+ fingerprintPropertyRepository.supportsUdfps()
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ shadeExpanded(true)
+ runCurrent()
+
+ // fade in
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(actual).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(.3f))
+ assertThat(actual).isIn(Range.closed(.1f, .9f))
+
+ // finish fading in before the end of the full transition
+ repository.sendTransitionStep(step(.7f))
+ assertThat(actual).isEqualTo(1f)
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(actual).isEqualTo(1f)
+ }
+
+ @Test
+ fun deviceEntryParentViewAlpha_rearFp_shadeNotExpanded() =
+ testComponent.runTest {
+ val actual by collectLastValue(underTest.deviceEntryParentViewAlpha)
+ fingerprintPropertyRepository.supportsRearFps()
+ shadeExpanded(false)
+ runCurrent()
+
+ // fade out
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(actual).isEqualTo(1f)
+
+ repository.sendTransitionStep(step(.1f))
+ assertThat(actual).isIn(Range.closed(.1f, .9f))
+
+ // finish fading out before the end of the full transition
+ repository.sendTransitionStep(step(.7f))
+ assertThat(actual).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(actual).isEqualTo(0f)
+ }
+
+ @Test
+ fun deviceEntryParentViewAlpha_rearFp_shadeExpanded() =
+ testComponent.runTest {
+ val values by collectValues(underTest.deviceEntryParentViewAlpha)
+ fingerprintPropertyRepository.supportsRearFps()
+ shadeExpanded(true)
+ runCurrent()
+
+ repository.sendTransitionSteps(
+ steps =
+ listOf(
+ step(0f, TransitionState.STARTED),
+ step(.3f),
+ step(.7f),
+ step(1f),
+ ),
+ testScope = testScope,
+ )
+ // immediately 0f
+ values.forEach { assertThat(it).isEqualTo(0f) }
+ }
+
+ private fun step(
+ value: Float,
+ state: TransitionState = TransitionState.RUNNING
+ ): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.AOD,
+ value = value,
+ transitionState = state,
+ ownerName = "LockscreenToAodTransitionViewModelTest"
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
index 89a1d2b..5c85357 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
@@ -18,88 +18,172 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
+import com.android.SysUITestModule
+import com.android.TestMocksModule
+import com.android.collectLastValue
+import com.android.collectValues
+import com.android.runCurrent
+import com.android.runTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FakeFeatureFlagsClassicModule
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.shade.data.repository.FakeShadeRepository
+import com.android.systemui.user.domain.UserDomainLayerModule
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import dagger.BindsInstance
+import dagger.Component
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() {
- private lateinit var underTest: LockscreenToDreamingTransitionViewModel
- private lateinit var repository: FakeKeyguardTransitionRepository
+ @SysUISingleton
+ @Component(
+ modules =
+ [
+ SysUITestModule::class,
+ UserDomainLayerModule::class,
+ ]
+ )
+ interface TestComponent : SysUITestComponent<LockscreenToDreamingTransitionViewModel> {
+ val repository: FakeKeyguardTransitionRepository
+ val keyguardRepository: FakeKeyguardRepository
+ val shadeRepository: FakeShadeRepository
- @Before
- fun setUp() {
- repository = FakeKeyguardTransitionRepository()
- val interactor =
- KeyguardTransitionInteractorFactory.create(
- scope = TestScope().backgroundScope,
- repository = repository,
- )
- .keyguardTransitionInteractor
- underTest = LockscreenToDreamingTransitionViewModel(interactor)
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance test: SysuiTestCase,
+ featureFlags: FakeFeatureFlagsClassicModule,
+ mocks: TestMocksModule,
+ ): TestComponent
+ }
+
+ fun shadeExpanded(expanded: Boolean) {
+ if (expanded) {
+ shadeRepository.setQsExpansion(1f)
+ } else {
+ keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
+ shadeRepository.setQsExpansion(0f)
+ shadeRepository.setLockscreenShadeExpansion(0f)
+ }
+ }
}
+ private val testComponent: TestComponent =
+ DaggerLockscreenToDreamingTransitionViewModelTest_TestComponent.factory()
+ .create(
+ test = this,
+ featureFlags =
+ FakeFeatureFlagsClassicModule {
+ set(Flags.FACE_AUTH_REFACTOR, true)
+ set(Flags.FULL_SCREEN_USER_SWITCHER, true)
+ },
+ mocks = TestMocksModule(),
+ )
@Test
fun lockscreenFadeOut() =
- runTest(UnconfinedTestDispatcher()) {
- val values = mutableListOf<Float>()
-
- val job = underTest.lockscreenAlpha.onEach { values.add(it) }.launchIn(this)
-
- // Should start running here...
- repository.sendTransitionStep(step(0f, TransitionState.STARTED))
- repository.sendTransitionStep(step(0f))
- repository.sendTransitionStep(step(0.1f))
- repository.sendTransitionStep(step(0.2f))
- repository.sendTransitionStep(step(0.3f))
- // ...up to here
- repository.sendTransitionStep(step(1f))
+ testComponent.runTest {
+ val values by collectValues(underTest.lockscreenAlpha)
+ repository.sendTransitionSteps(
+ steps =
+ listOf(
+ step(0f, TransitionState.STARTED), // Should start running here...
+ step(0f),
+ step(.1f),
+ step(.2f),
+ step(.3f), // ...up to here
+ step(1f),
+ ),
+ testScope = testScope,
+ )
// Only three values should be present, since the dream overlay runs for a small
// fraction of the overall animation time
assertThat(values.size).isEqualTo(5)
values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
-
- job.cancel()
}
@Test
fun lockscreenTranslationY() =
- runTest(UnconfinedTestDispatcher()) {
- val values = mutableListOf<Float>()
-
+ testComponent.runTest {
val pixels = 100
- val job =
- underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
+ val values by collectValues(underTest.lockscreenTranslationY(pixels))
- repository.sendTransitionStep(step(0f, TransitionState.STARTED))
- repository.sendTransitionStep(step(0f))
- repository.sendTransitionStep(step(0.3f))
- repository.sendTransitionStep(step(0.5f))
- repository.sendTransitionStep(step(1f))
- // And a final reset event on FINISHED
- repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ repository.sendTransitionSteps(
+ steps =
+ listOf(
+ step(0f, TransitionState.STARTED), // Should start running here...
+ step(0f),
+ step(.3f),
+ step(.5f),
+ step(1f),
+ step(1f, TransitionState.FINISHED), // Final reset event on FINISHED
+ ),
+ testScope = testScope,
+ )
assertThat(values.size).isEqualTo(6)
values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) }
// Validate finished value
assertThat(values[5]).isEqualTo(0f)
+ }
- job.cancel()
+ @Test
+ fun deviceEntryParentViewAlpha_shadeExpanded() =
+ testComponent.runTest {
+ val values by collectValues(underTest.deviceEntryParentViewAlpha)
+ shadeExpanded(true)
+ runCurrent()
+
+ repository.sendTransitionSteps(
+ steps =
+ listOf(
+ step(0f, TransitionState.STARTED),
+ step(0f),
+ step(.3f),
+ step(.5f),
+ step(1f),
+ step(1f, TransitionState.FINISHED),
+ ),
+ testScope = testScope,
+ )
+
+ // immediately 0f
+ values.forEach { assertThat(it).isEqualTo(0f) }
+ }
+
+ @Test
+ fun deviceEntryParentViewAlpha_shadeNotExpanded() =
+ testComponent.runTest {
+ val actual by collectLastValue(underTest.deviceEntryParentViewAlpha)
+ shadeExpanded(false)
+ runCurrent()
+
+ // fade out
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(actual).isEqualTo(1f)
+
+ repository.sendTransitionStep(step(.1f))
+ assertThat(actual).isIn(Range.open(.1f, .9f))
+
+ // alpha is 1f before the full transition starts ending
+ repository.sendTransitionStep(step(0.8f))
+ assertThat(actual).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(actual).isEqualTo(0f)
}
private fun step(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt
new file mode 100644
index 0000000..1494c92
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt
@@ -0,0 +1,84 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class LockscreenToGoneTransitionViewModelTest : SysuiTestCase() {
+ private lateinit var underTest: LockscreenToGoneTransitionViewModel
+ private lateinit var repository: FakeKeyguardTransitionRepository
+
+ @Before
+ fun setUp() {
+ repository = FakeKeyguardTransitionRepository()
+ val interactor =
+ KeyguardTransitionInteractorFactory.create(
+ scope = TestScope().backgroundScope,
+ repository = repository,
+ )
+ .keyguardTransitionInteractor
+ underTest =
+ LockscreenToGoneTransitionViewModel(
+ interactor,
+ )
+ }
+
+ @Test
+ fun deviceEntryParentViewHides() = runTest {
+ val deviceEntryParentViewAlpha by collectValues(underTest.deviceEntryParentViewAlpha)
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.1f))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.4f))
+ repository.sendTransitionStep(step(0.5f))
+ repository.sendTransitionStep(step(0.6f))
+ repository.sendTransitionStep(step(0.8f))
+ repository.sendTransitionStep(step(1f))
+ deviceEntryParentViewAlpha.forEach { assertThat(it).isEqualTo(0f) }
+ }
+
+ private fun step(
+ value: Float,
+ state: TransitionState = TransitionState.RUNNING
+ ): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ value = value,
+ transitionState = state,
+ ownerName = "LockscreenToGoneTransitionViewModelTest"
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
index 41f8856..4cbefa3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
@@ -18,109 +18,185 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
+import com.android.SysUITestModule
+import com.android.TestMocksModule
+import com.android.collectLastValue
+import com.android.collectValues
+import com.android.runCurrent
+import com.android.runTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FakeFeatureFlagsClassicModule
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.shade.data.repository.FakeShadeRepository
+import com.android.systemui.user.domain.UserDomainLayerModule
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
+import dagger.BindsInstance
+import dagger.Component
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() {
- private lateinit var underTest: LockscreenToOccludedTransitionViewModel
- private lateinit var repository: FakeKeyguardTransitionRepository
+ @SysUISingleton
+ @Component(
+ modules =
+ [
+ SysUITestModule::class,
+ UserDomainLayerModule::class,
+ ]
+ )
+ interface TestComponent : SysUITestComponent<LockscreenToOccludedTransitionViewModel> {
+ val repository: FakeKeyguardTransitionRepository
+ val keyguardRepository: FakeKeyguardRepository
+ val shadeRepository: FakeShadeRepository
- @Before
- fun setUp() {
- repository = FakeKeyguardTransitionRepository()
- val interactor =
- KeyguardTransitionInteractorFactory.create(
- scope = TestScope().backgroundScope,
- repository = repository,
- )
- .keyguardTransitionInteractor
- underTest = LockscreenToOccludedTransitionViewModel(interactor)
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance test: SysuiTestCase,
+ featureFlags: FakeFeatureFlagsClassicModule,
+ mocks: TestMocksModule,
+ ): TestComponent
+ }
+
+ fun shadeExpanded(expanded: Boolean) {
+ if (expanded) {
+ shadeRepository.setQsExpansion(1f)
+ } else {
+ keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
+ shadeRepository.setQsExpansion(0f)
+ shadeRepository.setLockscreenShadeExpansion(0f)
+ }
+ }
}
+ private val testComponent: TestComponent =
+ DaggerLockscreenToOccludedTransitionViewModelTest_TestComponent.factory()
+ .create(
+ test = this,
+ featureFlags =
+ FakeFeatureFlagsClassicModule {
+ set(Flags.FACE_AUTH_REFACTOR, true)
+ set(Flags.FULL_SCREEN_USER_SWITCHER, true)
+ },
+ mocks = TestMocksModule(),
+ )
+
@Test
fun lockscreenFadeOut() =
- runTest(UnconfinedTestDispatcher()) {
- val values = mutableListOf<Float>()
-
- val job = underTest.lockscreenAlpha.onEach { values.add(it) }.launchIn(this)
-
- // Should start running here...
- repository.sendTransitionStep(step(0f, TransitionState.STARTED))
- repository.sendTransitionStep(step(0f))
- repository.sendTransitionStep(step(0.1f))
- repository.sendTransitionStep(step(0.4f))
- repository.sendTransitionStep(step(0.7f))
- // ...up to here
- repository.sendTransitionStep(step(1f))
-
+ testComponent.runTest {
+ val values by collectValues(underTest.lockscreenAlpha)
+ repository.sendTransitionSteps(
+ steps =
+ listOf(
+ step(0f, TransitionState.STARTED), // Should start running here...
+ step(0f),
+ step(.1f),
+ step(.4f),
+ step(.7f), // ...up to here
+ step(1f),
+ ),
+ testScope = testScope,
+ )
// Only 3 values should be present, since the dream overlay runs for a small fraction
// of the overall animation time
assertThat(values.size).isEqualTo(5)
values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
-
- job.cancel()
}
@Test
fun lockscreenTranslationY() =
- runTest(UnconfinedTestDispatcher()) {
- val values = mutableListOf<Float>()
-
+ testComponent.runTest {
val pixels = 100
- val job =
- underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
-
- // Should start running here...
- repository.sendTransitionStep(step(0f, TransitionState.STARTED))
- repository.sendTransitionStep(step(0f))
- repository.sendTransitionStep(step(0.3f))
- repository.sendTransitionStep(step(0.5f))
- repository.sendTransitionStep(step(1f))
- // ...up to here
-
+ val values by collectValues(underTest.lockscreenTranslationY(pixels))
+ repository.sendTransitionSteps(
+ steps =
+ listOf(
+ step(0f, TransitionState.STARTED), // Should start running here...
+ step(0f),
+ step(.3f),
+ step(.5f),
+ step(1f), // ...up to here
+ ),
+ testScope = testScope,
+ )
assertThat(values.size).isEqualTo(5)
values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) }
-
- job.cancel()
}
@Test
fun lockscreenTranslationYIsCanceled() =
- runTest(UnconfinedTestDispatcher()) {
- val values = mutableListOf<Float>()
-
+ testComponent.runTest {
val pixels = 100
- val job =
- underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
-
- repository.sendTransitionStep(step(0f, TransitionState.STARTED))
- repository.sendTransitionStep(step(0f))
- repository.sendTransitionStep(step(0.3f))
- repository.sendTransitionStep(step(0.3f, TransitionState.CANCELED))
-
+ val values by collectValues(underTest.lockscreenTranslationY(pixels))
+ repository.sendTransitionSteps(
+ steps =
+ listOf(
+ step(0f, TransitionState.STARTED),
+ step(0f),
+ step(.3f),
+ step(0.3f, TransitionState.CANCELED),
+ ),
+ testScope = testScope,
+ )
assertThat(values.size).isEqualTo(4)
values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) }
// Cancel will reset the translation
assertThat(values[3]).isEqualTo(0)
+ }
- job.cancel()
+ @Test
+ fun deviceEntryParentViewAlpha_shadeExpanded() =
+ testComponent.runTest {
+ val values by collectValues(underTest.deviceEntryParentViewAlpha)
+ shadeExpanded(true)
+ runCurrent()
+
+ // immediately 0f
+ repository.sendTransitionSteps(
+ steps =
+ listOf(
+ step(0f, TransitionState.STARTED),
+ step(.5f),
+ step(1f, TransitionState.FINISHED)
+ ),
+ testScope = testScope,
+ )
+
+ values.forEach { assertThat(it).isEqualTo(0f) }
+ }
+
+ @Test
+ fun deviceEntryParentViewAlpha_shadeNotExpanded() =
+ testComponent.runTest {
+ val actual by collectLastValue(underTest.deviceEntryParentViewAlpha)
+ shadeExpanded(false)
+ runCurrent()
+
+ // fade out
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(actual).isEqualTo(1f)
+
+ repository.sendTransitionStep(step(.2f))
+ assertThat(actual).isIn(Range.open(.1f, .9f))
+
+ // alpha is 1f before the full transition starts ending
+ repository.sendTransitionStep(step(0.8f))
+ assertThat(actual).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(actual).isEqualTo(0f)
}
private fun step(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt
new file mode 100644
index 0000000..4f56435
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt
@@ -0,0 +1,159 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
+import com.android.SysUITestModule
+import com.android.TestMocksModule
+import com.android.collectLastValue
+import com.android.runCurrent
+import com.android.runTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FakeFeatureFlagsClassicModule
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.shade.data.repository.FakeShadeRepository
+import com.android.systemui.user.domain.UserDomainLayerModule
+import com.google.common.collect.Range
+import com.google.common.truth.Truth
+import dagger.BindsInstance
+import dagger.Component
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class LockscreenToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() {
+ @SysUISingleton
+ @Component(
+ modules =
+ [
+ SysUITestModule::class,
+ UserDomainLayerModule::class,
+ ]
+ )
+ interface TestComponent : SysUITestComponent<LockscreenToPrimaryBouncerTransitionViewModel> {
+ val repository: FakeKeyguardTransitionRepository
+ val keyguardRepository: FakeKeyguardRepository
+ val shadeRepository: FakeShadeRepository
+
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance test: SysuiTestCase,
+ featureFlags: FakeFeatureFlagsClassicModule,
+ mocks: TestMocksModule,
+ ): TestComponent
+ }
+
+ fun shadeExpanded(expanded: Boolean) {
+ if (expanded) {
+ shadeRepository.setQsExpansion(1f)
+ } else {
+ keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
+ shadeRepository.setQsExpansion(0f)
+ shadeRepository.setLockscreenShadeExpansion(0f)
+ }
+ }
+ }
+
+ private val testComponent: TestComponent =
+ DaggerLockscreenToPrimaryBouncerTransitionViewModelTest_TestComponent.factory()
+ .create(
+ test = this,
+ featureFlags =
+ FakeFeatureFlagsClassicModule {
+ set(Flags.FACE_AUTH_REFACTOR, true)
+ set(Flags.FULL_SCREEN_USER_SWITCHER, true)
+ },
+ mocks = TestMocksModule(),
+ )
+
+ @Test
+ fun deviceEntryParentViewAlpha_shadeExpanded() =
+ testComponent.runTest {
+ val actual by collectLastValue(underTest.deviceEntryParentViewAlpha)
+ shadeExpanded(true)
+ runCurrent()
+
+ // immediately 0f
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ runCurrent()
+ Truth.assertThat(actual).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(.2f))
+ runCurrent()
+ Truth.assertThat(actual).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(0.8f))
+ runCurrent()
+ Truth.assertThat(actual).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ runCurrent()
+ Truth.assertThat(actual).isEqualTo(0f)
+ }
+
+ @Test
+ fun deviceEntryParentViewAlpha_shadeNotExpanded() =
+ testComponent.runTest {
+ val actual by collectLastValue(underTest.deviceEntryParentViewAlpha)
+ shadeExpanded(false)
+ runCurrent()
+
+ // fade out
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ runCurrent()
+ Truth.assertThat(actual).isEqualTo(1f)
+
+ repository.sendTransitionStep(step(.1f))
+ runCurrent()
+ Truth.assertThat(actual).isIn(Range.open(.1f, .9f))
+
+ // alpha is 1f before the full transition starts ending
+ repository.sendTransitionStep(step(0.8f))
+ runCurrent()
+ Truth.assertThat(actual).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ runCurrent()
+ Truth.assertThat(actual).isEqualTo(0f)
+ }
+
+ private fun step(
+ value: Float,
+ state: TransitionState = TransitionState.RUNNING,
+ ): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ value = value,
+ transitionState = state,
+ ownerName = "LockscreenToPrimaryBouncerTransitionViewModelTest"
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt
new file mode 100644
index 0000000..0eb8ff6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt
@@ -0,0 +1,170 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class OccludedToAodTransitionViewModelTest : SysuiTestCase() {
+ private lateinit var underTest: OccludedToAodTransitionViewModel
+ private lateinit var repository: FakeKeyguardTransitionRepository
+ private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+ private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
+
+ @Before
+ fun setUp() {
+ repository = FakeKeyguardTransitionRepository()
+ fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
+ biometricSettingsRepository = FakeBiometricSettingsRepository()
+
+ underTest =
+ OccludedToAodTransitionViewModel(
+ KeyguardTransitionInteractorFactory.create(
+ scope = TestScope().backgroundScope,
+ repository = repository,
+ )
+ .keyguardTransitionInteractor,
+ DeviceEntryUdfpsInteractor(
+ fingerprintPropertyRepository = fingerprintPropertyRepository,
+ fingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository(),
+ biometricSettingsRepository = biometricSettingsRepository,
+ ),
+ )
+ }
+
+ @Test
+ fun deviceEntryBackgroundViewAlpha() = runTest {
+ val deviceEntryBackgroundViewAlpha by
+ collectLastValue(underTest.deviceEntryBackgroundViewAlpha)
+
+ // immediately 0f
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(0.4f))
+ assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(.85f))
+ assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(1f))
+ assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f)
+ }
+
+ @Test
+ fun deviceEntryParentViewAlpha_udfpsEnrolled() = runTest {
+ fingerprintPropertyRepository.supportsUdfps()
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha)
+
+ // immediately 1f
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(deviceEntryParentViewAlpha).isEqualTo(1f)
+
+ repository.sendTransitionStep(step(0.5f))
+ assertThat(deviceEntryParentViewAlpha).isEqualTo(1f)
+
+ repository.sendTransitionStep(step(.95f))
+ assertThat(deviceEntryParentViewAlpha).isEqualTo(1f)
+
+ repository.sendTransitionStep(step(1f))
+ assertThat(deviceEntryParentViewAlpha).isEqualTo(1f)
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(deviceEntryParentViewAlpha).isEqualTo(1f)
+ }
+
+ @Test
+ fun deviceEntryParentViewAlpha_rearFpEnrolled_noUpdates() = runTest {
+ fingerprintPropertyRepository.supportsRearFps()
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha)
+
+ // no updates
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(0.5f))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(.95f))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(1f))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+ }
+
+ @Test
+ fun deviceEntryParentViewAlpha_udfpsNotEnrolled_noUpdates() = runTest {
+ fingerprintPropertyRepository.supportsUdfps()
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+ val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha)
+
+ // no updates
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(0.5f))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(.95f))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(1f))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+ }
+
+ private fun step(
+ value: Float,
+ state: TransitionState = TransitionState.RUNNING
+ ): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.OCCLUDED,
+ to = KeyguardState.AOD,
+ value = value,
+ transitionState = state,
+ ownerName = "OccludedToAodTransitionViewModelTest"
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
index ec95cb8..d077227 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
@@ -19,6 +19,10 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -26,6 +30,7 @@
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
@@ -35,22 +40,35 @@
import org.junit.Test
import org.junit.runner.RunWith
+@ExperimentalCoroutinesApi
@SmallTest
@RunWith(AndroidJUnit4::class)
class OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() {
private lateinit var underTest: OccludedToLockscreenTransitionViewModel
private lateinit var repository: FakeKeyguardTransitionRepository
+ private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+ private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
@Before
fun setUp() {
repository = FakeKeyguardTransitionRepository()
- val interactor =
- KeyguardTransitionInteractorFactory.create(
- scope = TestScope().backgroundScope,
- repository = repository,
- )
- .keyguardTransitionInteractor
- underTest = OccludedToLockscreenTransitionViewModel(interactor)
+ fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
+ biometricSettingsRepository = FakeBiometricSettingsRepository()
+ underTest =
+ OccludedToLockscreenTransitionViewModel(
+ interactor =
+ KeyguardTransitionInteractorFactory.create(
+ scope = TestScope().backgroundScope,
+ repository = repository,
+ )
+ .keyguardTransitionInteractor,
+ deviceEntryUdfpsInteractor =
+ DeviceEntryUdfpsInteractor(
+ fingerprintPropertyRepository = fingerprintPropertyRepository,
+ fingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository(),
+ biometricSettingsRepository = biometricSettingsRepository,
+ ),
+ )
}
@Test
@@ -113,6 +131,78 @@
job.cancel()
}
+ @Test
+ fun deviceEntryParentViewFadeIn() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Float>()
+
+ val job = underTest.deviceEntryParentViewAlpha.onEach { values.add(it) }.launchIn(this)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.1f))
+ // Should start running here...
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.4f))
+ repository.sendTransitionStep(step(0.5f))
+ repository.sendTransitionStep(step(0.6f))
+ // ...up to here
+ repository.sendTransitionStep(step(0.8f))
+ repository.sendTransitionStep(step(1f))
+
+ assertThat(values.size).isEqualTo(5)
+ values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
+
+ job.cancel()
+ }
+
+ @Test
+ fun deviceEntryBackgroundViewShows() =
+ runTest(UnconfinedTestDispatcher()) {
+ fingerprintPropertyRepository.supportsUdfps()
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ val values = mutableListOf<Float>()
+
+ val job =
+ underTest.deviceEntryBackgroundViewAlpha.onEach { values.add(it) }.launchIn(this)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.1f))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.4f))
+ repository.sendTransitionStep(step(0.5f))
+ repository.sendTransitionStep(step(0.6f))
+ repository.sendTransitionStep(step(0.8f))
+ repository.sendTransitionStep(step(1f))
+
+ values.forEach { assertThat(it).isEqualTo(1f) }
+
+ job.cancel()
+ }
+
+ @Test
+ fun deviceEntryBackgroundView_noUdfpsEnrolled_noUpdates() =
+ runTest(UnconfinedTestDispatcher()) {
+ fingerprintPropertyRepository.supportsRearFps()
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ val values = mutableListOf<Float>()
+
+ val job =
+ underTest.deviceEntryBackgroundViewAlpha.onEach { values.add(it) }.launchIn(this)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.1f))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.4f))
+ repository.sendTransitionStep(step(0.5f))
+ repository.sendTransitionStep(step(0.6f))
+ repository.sendTransitionStep(step(0.8f))
+ repository.sendTransitionStep(step(1f))
+
+ assertThat(values).isEmpty() // no updates
+
+ job.cancel()
+ }
+
private fun step(
value: Float,
state: TransitionState = TransitionState.RUNNING
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt
new file mode 100644
index 0000000..350b310
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt
@@ -0,0 +1,164 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class PrimaryBouncerToAodTransitionViewModelTest : SysuiTestCase() {
+ private lateinit var underTest: PrimaryBouncerToAodTransitionViewModel
+ private lateinit var repository: FakeKeyguardTransitionRepository
+ private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+ private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
+
+ @Before
+ fun setUp() {
+ repository = FakeKeyguardTransitionRepository()
+ fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
+ biometricSettingsRepository = FakeBiometricSettingsRepository()
+ val interactor =
+ KeyguardTransitionInteractorFactory.create(
+ scope = TestScope().backgroundScope,
+ repository = repository,
+ )
+ .keyguardTransitionInteractor
+ underTest =
+ PrimaryBouncerToAodTransitionViewModel(
+ interactor,
+ DeviceEntryUdfpsInteractor(
+ fingerprintPropertyRepository = fingerprintPropertyRepository,
+ fingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository(),
+ biometricSettingsRepository = biometricSettingsRepository,
+ ),
+ )
+ }
+
+ @Test
+ fun deviceEntryBackgroundViewAlpha() = runTest {
+ fingerprintPropertyRepository.supportsUdfps()
+ val deviceEntryBackgroundViewAlpha by
+ collectLastValue(underTest.deviceEntryBackgroundViewAlpha)
+
+ // immediately 0f
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(0.4f))
+ assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(.85f))
+ assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f)
+
+ repository.sendTransitionStep(step(1f))
+ assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f)
+ }
+
+ @Test
+ fun deviceEntryParentViewAlpha_udfpsEnrolled_fadeIn() = runTest {
+ fingerprintPropertyRepository.supportsUdfps()
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+
+ repository.sendTransitionStep(step(0.5f))
+ repository.sendTransitionStep(step(.75f))
+ repository.sendTransitionStep(step(1f))
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(deviceEntryParentViewAlpha).isEqualTo(1f)
+ }
+
+ @Test
+ fun deviceEntryParentViewAlpha_rearFpEnrolled_noUpdates() = runTest {
+ fingerprintPropertyRepository.supportsRearFps()
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha)
+
+ // animation doesn't start until the end
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(0.5f))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(.95f))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(1f))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+ }
+
+ @Test
+ fun deviceEntryParentViewAlpha_udfpsNotEnrolled_noUpdates() = runTest {
+ fingerprintPropertyRepository.supportsUdfps()
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+ val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(0.5f))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(.75f))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(1f))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(deviceEntryParentViewAlpha).isNull()
+ }
+
+ private fun step(
+ value: Float,
+ state: TransitionState = TransitionState.RUNNING
+ ): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = KeyguardState.AOD,
+ value = value,
+ transitionState = state,
+ ownerName = "PrimaryBouncerToAodTransitionViewModelTest"
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt
new file mode 100644
index 0000000..24e4920
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt
@@ -0,0 +1,142 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class PrimaryBouncerToLockscreenTransitionViewModelTest : SysuiTestCase() {
+ private lateinit var underTest: PrimaryBouncerToLockscreenTransitionViewModel
+ private lateinit var repository: FakeKeyguardTransitionRepository
+ private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+ private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
+
+ @Before
+ fun setUp() {
+ repository = FakeKeyguardTransitionRepository()
+ fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
+ biometricSettingsRepository = FakeBiometricSettingsRepository()
+
+ underTest =
+ PrimaryBouncerToLockscreenTransitionViewModel(
+ KeyguardTransitionInteractorFactory.create(
+ scope = TestScope().backgroundScope,
+ repository = repository,
+ )
+ .keyguardTransitionInteractor,
+ DeviceEntryUdfpsInteractor(
+ fingerprintPropertyRepository = fingerprintPropertyRepository,
+ fingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository(),
+ biometricSettingsRepository = biometricSettingsRepository,
+ ),
+ )
+ }
+
+ @Test
+ fun deviceEntryParentViewAlpha() = runTest {
+ val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha)
+
+ // immediately 1f
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(deviceEntryParentViewAlpha).isEqualTo(1f)
+
+ repository.sendTransitionStep(step(0.4f))
+ assertThat(deviceEntryParentViewAlpha).isEqualTo(1f)
+
+ repository.sendTransitionStep(step(.85f))
+ assertThat(deviceEntryParentViewAlpha).isEqualTo(1f)
+
+ repository.sendTransitionStep(step(1f))
+ assertThat(deviceEntryParentViewAlpha).isEqualTo(1f)
+ }
+
+ @Test
+ fun deviceEntryBackgroundViewAlpha_udfpsEnrolled_show() = runTest {
+ fingerprintPropertyRepository.supportsUdfps()
+ val bgViewAlpha by collectLastValue(underTest.deviceEntryBackgroundViewAlpha)
+
+ // immediately 1f
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(bgViewAlpha).isEqualTo(1f)
+
+ repository.sendTransitionStep(step(0.1f))
+ assertThat(bgViewAlpha).isEqualTo(1f)
+
+ repository.sendTransitionStep(step(.3f))
+ assertThat(bgViewAlpha).isEqualTo(1f)
+
+ repository.sendTransitionStep(step(.5f))
+ assertThat(bgViewAlpha).isEqualTo(1f)
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(bgViewAlpha).isEqualTo(1f)
+ }
+
+ @Test
+ fun deviceEntryBackgroundViewAlpha_rearFpEnrolled_noUpdates() = runTest {
+ fingerprintPropertyRepository.supportsRearFps()
+ val bgViewAlpha by collectLastValue(underTest.deviceEntryBackgroundViewAlpha)
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(bgViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(0.5f))
+ assertThat(bgViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(.75f))
+ assertThat(bgViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(1f))
+ assertThat(bgViewAlpha).isNull()
+
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(bgViewAlpha).isNull()
+ }
+
+ private fun step(
+ value: Float,
+ state: TransitionState = TransitionState.RUNNING
+ ): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = KeyguardState.LOCKSCREEN,
+ value = value,
+ transitionState = state,
+ ownerName = "PrimaryBouncerToLockscreenTransitionViewModelTest"
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
index 0c5e438..005cac4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
@@ -19,10 +19,15 @@
import android.hardware.biometrics.SensorLocationInternal
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
-class FakeFingerprintPropertyRepository : FingerprintPropertyRepository {
+@SysUISingleton
+class FakeFingerprintPropertyRepository @Inject constructor() : FingerprintPropertyRepository {
private val _sensorId: MutableStateFlow<Int> = MutableStateFlow(-1)
override val sensorId = _sensorId.asStateFlow()
@@ -50,4 +55,29 @@
_sensorType.value = sensorType
_sensorLocations.value = sensorLocations
}
+
+ /** setProperties as if the device supports UDFPS_OPTICAL. */
+ fun supportsUdfps() {
+ setProperties(
+ sensorId = 0,
+ strength = SensorStrength.STRONG,
+ sensorType = FingerprintSensorType.UDFPS_OPTICAL,
+ sensorLocations = emptyMap(),
+ )
+ }
+
+ /** setProperties as if the device supports the rear fingerprint sensor. */
+ fun supportsRearFps() {
+ setProperties(
+ sensorId = 0,
+ strength = SensorStrength.STRONG,
+ sensorType = FingerprintSensorType.REAR,
+ sensorLocations = emptyMap(),
+ )
+ }
+}
+
+@Module
+interface FakeFingerprintPropertyRepositoryModule {
+ @Binds fun bindFake(fake: FakeFingerprintPropertyRepository): FingerprintPropertyRepository
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt
index 44286b7..8ff04a63 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt
@@ -15,17 +15,23 @@
package com.android.systemui.deviceentry.data
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepositoryModule
import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepositoryModule
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepositoryModule
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepositoryModule
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepositoryModule
import com.android.systemui.keyguard.data.repository.FakeTrustRepositoryModule
import dagger.Module
@Module(
includes =
[
+ FakeBiometricSettingsRepositoryModule::class,
FakeDeviceEntryRepositoryModule::class,
- FakeTrustRepositoryModule::class,
FakeDeviceEntryFaceAuthRepositoryModule::class,
+ FakeDeviceEntryFingerprintAuthRepositoryModule::class,
+ FakeFingerprintPropertyRepositoryModule::class,
+ FakeTrustRepositoryModule::class,
]
)
object FakeDeviceEntryDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt
index 85261123..df31a12 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt
@@ -18,13 +18,18 @@
package com.android.systemui.keyguard.data.repository
import com.android.internal.widget.LockPatternUtils
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.AuthenticationFlags
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
-class FakeBiometricSettingsRepository : BiometricSettingsRepository {
+@SysUISingleton
+class FakeBiometricSettingsRepository @Inject constructor() : BiometricSettingsRepository {
private val _isFingerprintEnrolledAndEnabled = MutableStateFlow(false)
override val isFingerprintEnrolledAndEnabled: StateFlow<Boolean>
get() = _isFingerprintEnrolledAndEnabled
@@ -97,3 +102,8 @@
}
}
}
+
+@Module
+interface FakeBiometricSettingsRepositoryModule {
+ @Binds fun bindFake(fake: FakeBiometricSettingsRepository): BiometricSettingsRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
index 38791ca..c9160ef 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
@@ -17,14 +17,20 @@
package com.android.systemui.keyguard.data.repository
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.FingerprintAuthenticationStatus
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.filterNotNull
-class FakeDeviceEntryFingerprintAuthRepository : DeviceEntryFingerprintAuthRepository {
+@SysUISingleton
+class FakeDeviceEntryFingerprintAuthRepository @Inject constructor() :
+ DeviceEntryFingerprintAuthRepository {
private val _isLockedOut = MutableStateFlow(false)
override val isLockedOut: StateFlow<Boolean> = _isLockedOut.asStateFlow()
fun setLockedOut(lockedOut: Boolean) {
@@ -52,3 +58,11 @@
_authenticationStatus.value = status
}
}
+
+@Module
+interface FakeDeviceEntryFingerprintAuthRepositoryModule {
+ @Binds
+ fun bindFake(
+ fake: FakeDeviceEntryFingerprintAuthRepository
+ ): DeviceEntryFingerprintAuthRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
index b90ad8c..3674244 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
@@ -151,6 +151,17 @@
_transitions.emit(step)
}
+ suspend fun sendTransitionSteps(
+ steps: List<TransitionStep>,
+ testScope: TestScope,
+ validateStep: Boolean = true
+ ) {
+ steps.forEach {
+ sendTransitionStep(it, validateStep = validateStep)
+ testScope.testScheduler.runCurrent()
+ }
+ }
+
override fun startTransition(info: TransitionInfo): UUID? {
return if (info.animator == null) UUID.randomUUID() else null
}