Fade out UDFPS on shadeExpand & dialogProgress

When the UDFPS view refactor is enabled,
fade out UDFPS views when the shade expands to full
shade and to QS. Also, don't show the UDFPS view when
a dialog shows.

Test: atest UdfpsKeyguardInteractorTest UdfpsLockscreenViewModelTest
Test: manually enable udfps view refactor and pull down notification
shade (from the middle of LS and from the top). Launch dialogs such
as the power menu. See UDFPS lockscreen view hides + shows as expected
Bug: 278719514

Change-Id: I5cbcb217b7bd5df7a7f19cb118b843c3de0db744
This commit is contained in:
Beverly
2023-07-12 21:07:26 +00:00
parent 2427c53a28
commit 15f2355116
7 changed files with 454 additions and 60 deletions

View File

@@ -21,10 +21,16 @@ import android.animation.FloatEvaluator
import android.animation.IntEvaluator
import com.android.systemui.common.ui.data.repository.ConfigurationRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.statusbar.phone.hideAffordancesRequest
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.onStart
/** Encapsulates business logic for transitions between UDFPS states on the keyguard. */
@ExperimentalCoroutinesApi
@@ -35,6 +41,8 @@ constructor(
configRepo: ConfigurationRepository,
burnInInteractor: BurnInInteractor,
keyguardInteractor: KeyguardInteractor,
shadeRepository: ShadeRepository,
dialogManager: SystemUIDialogManager,
) {
private val intEvaluator = IntEvaluator()
private val floatEvaluator = FloatEvaluator()
@@ -56,6 +64,26 @@ constructor(
floatEvaluator.evaluate(dozeAmount, 0, fullyDozingBurnInProgress),
)
}
val dialogHideAffordancesRequest: Flow<Boolean> = dialogManager.hideAffordancesRequest
val qsProgress: Flow<Float> =
shadeRepository.qsExpansion // swipe from top of LS
.map { (it * 2).coerceIn(0f, 1f) }
.onStart { emit(0f) }
val shadeExpansion: Flow<Float> =
combine(
shadeRepository.udfpsTransitionToFullShadeProgress, // swipe from middle of LS
keyguardInteractor.statusBarState, // quick swipe from middle of LS
) { shadeProgress, statusBarState ->
if (statusBarState == StatusBarState.SHADE_LOCKED) {
1f
} else {
shadeProgress
}
}
.onStart { emit(0f) }
}
data class BurnInOffsets(

View File

@@ -21,13 +21,17 @@ import androidx.annotation.ColorInt
import com.android.settingslib.Utils.getColorAttrDefaultColor
import com.android.systemui.R
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.UdfpsKeyguardInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.StatusBarState
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.flatMapLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
@@ -38,6 +42,8 @@ open class UdfpsLockscreenViewModel(
lockscreenColorResId: Int,
alternateBouncerColorResId: Int,
transitionInteractor: KeyguardTransitionInteractor,
udfpsKeyguardInteractor: UdfpsKeyguardInteractor,
keyguardInteractor: KeyguardInteractor,
) {
private val toLockscreen: Flow<TransitionViewModel> =
transitionInteractor.anyStateToLockscreenTransition.map {
@@ -54,46 +60,53 @@ open class UdfpsLockscreenViewModel(
}
private val toAlternateBouncer: Flow<TransitionViewModel> =
transitionInteractor.anyStateToAlternateBouncerTransition.map {
TransitionViewModel(
alpha = 1f,
scale =
if (visibleInKeyguardState(it.from)) {
1f
} else {
it.value
},
color = getColorAttrDefaultColor(context, alternateBouncerColorResId),
)
keyguardInteractor.statusBarState.flatMapLatest { statusBarState ->
transitionInteractor.anyStateToAlternateBouncerTransition.map {
TransitionViewModel(
alpha = 1f,
scale =
if (visibleInKeyguardState(it.from, statusBarState)) {
1f
} else {
it.value
},
color = getColorAttrDefaultColor(context, alternateBouncerColorResId),
)
}
}
private val fadeOut: Flow<TransitionViewModel> =
merge(
transitionInteractor.anyStateToGoneTransition,
transitionInteractor.anyStateToAodTransition,
transitionInteractor.anyStateToOccludedTransition,
transitionInteractor.anyStateToPrimaryBouncerTransition,
transitionInteractor.anyStateToDreamingTransition,
)
.map {
TransitionViewModel(
alpha =
if (visibleInKeyguardState(it.from)) {
1f - it.value
} else {
0f
},
scale = 1f,
color =
if (it.from == KeyguardState.ALTERNATE_BOUNCER) {
getColorAttrDefaultColor(context, alternateBouncerColorResId)
} else {
getColorAttrDefaultColor(context, lockscreenColorResId)
},
keyguardInteractor.statusBarState.flatMapLatest { statusBarState ->
merge(
transitionInteractor.anyStateToGoneTransition,
transitionInteractor.anyStateToAodTransition,
transitionInteractor.anyStateToOccludedTransition,
transitionInteractor.anyStateToPrimaryBouncerTransition,
transitionInteractor.anyStateToDreamingTransition,
)
}
.map {
TransitionViewModel(
alpha =
if (visibleInKeyguardState(it.from, statusBarState)) {
1f - it.value
} else {
0f
},
scale = 1f,
color =
if (it.from == KeyguardState.ALTERNATE_BOUNCER) {
getColorAttrDefaultColor(context, alternateBouncerColorResId)
} else {
getColorAttrDefaultColor(context, lockscreenColorResId)
},
)
}
}
private fun visibleInKeyguardState(state: KeyguardState): Boolean {
private fun visibleInKeyguardState(
state: KeyguardState,
statusBarState: StatusBarState
): Boolean {
return when (state) {
KeyguardState.OFF,
KeyguardState.DOZING,
@@ -102,17 +115,53 @@ open class UdfpsLockscreenViewModel(
KeyguardState.PRIMARY_BOUNCER,
KeyguardState.GONE,
KeyguardState.OCCLUDED -> false
KeyguardState.LOCKSCREEN,
KeyguardState.LOCKSCREEN -> statusBarState == StatusBarState.KEYGUARD
KeyguardState.ALTERNATE_BOUNCER -> true
}
}
val transition: Flow<TransitionViewModel> =
private val keyguardStateTransition =
merge(
toAlternateBouncer,
toLockscreen,
fadeOut,
)
private val dialogHideAffordancesAlphaMultiplier: Flow<Float> =
udfpsKeyguardInteractor.dialogHideAffordancesRequest.map { hideAffordances ->
if (hideAffordances) {
0f
} else {
1f
}
}
private val alphaMultiplier: Flow<Float> =
combine(
transitionInteractor.startedKeyguardState,
dialogHideAffordancesAlphaMultiplier,
udfpsKeyguardInteractor.shadeExpansion,
udfpsKeyguardInteractor.qsProgress,
) { startedKeyguardState, dialogHideAffordancesAlphaMultiplier, shadeExpansion, qsProgress
->
if (startedKeyguardState == KeyguardState.ALTERNATE_BOUNCER) {
1f
} else {
dialogHideAffordancesAlphaMultiplier * (1f - shadeExpansion) * (1f - qsProgress)
}
}
val transition: Flow<TransitionViewModel> =
combine(
alphaMultiplier,
keyguardStateTransition,
) { alphaMultiplier, keyguardStateTransition ->
TransitionViewModel(
alpha = keyguardStateTransition.alpha * alphaMultiplier,
scale = keyguardStateTransition.scale,
color = keyguardStateTransition.color,
)
}
val visible: Flow<Boolean> = transition.map { it.alpha != 0f }
}
@@ -123,12 +172,15 @@ constructor(
val context: Context,
transitionInteractor: KeyguardTransitionInteractor,
interactor: UdfpsKeyguardInteractor,
keyguardInteractor: KeyguardInteractor,
) :
UdfpsLockscreenViewModel(
context,
android.R.attr.textColorPrimary,
com.android.internal.R.attr.materialColorOnPrimaryFixed,
transitionInteractor,
interactor,
keyguardInteractor,
) {
val dozeAmount: Flow<Float> = interactor.dozeAmount
val burnInOffsets: Flow<BurnInOffsets> = interactor.burnInOffsets
@@ -147,12 +199,16 @@ class BackgroundViewModel
constructor(
val context: Context,
transitionInteractor: KeyguardTransitionInteractor,
interactor: UdfpsKeyguardInteractor,
keyguardInteractor: KeyguardInteractor,
) :
UdfpsLockscreenViewModel(
context,
com.android.internal.R.attr.colorSurface,
com.android.internal.R.attr.materialColorPrimaryFixed,
transitionInteractor,
interactor,
keyguardInteractor,
)
data class TransitionViewModel(

View File

@@ -0,0 +1,34 @@
/*
* 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.statusbar.phone
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
/** Whether dialogs are requesting for affordances to be hidden or not. */
val SystemUIDialogManager.hideAffordancesRequest: Flow<Boolean>
get() = conflatedCallbackFlow {
val callback =
SystemUIDialogManager.Listener { hideAffordance ->
trySendWithFailureLogging(hideAffordance, "dialogHideAffordancesRequest")
}
registerListener(callback)
trySendWithFailureLogging(shouldHideAffordance(), "dialogHideAffordancesRequestInitial")
awaitClose { unregisterListener(callback) }
}

View File

@@ -33,6 +33,9 @@ import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.WakeSleepReason
import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
@@ -46,6 +49,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@ExperimentalCoroutinesApi
@@ -63,19 +67,21 @@ class UdfpsKeyguardInteractorTest : SysuiTestCase() {
private lateinit var fakeCommandQueue: FakeCommandQueue
private lateinit var featureFlags: FakeFeatureFlags
private lateinit var burnInInteractor: BurnInInteractor
private lateinit var shadeRepository: FakeShadeRepository
@Mock private lateinit var burnInHelper: BurnInHelperWrapper
@Mock private lateinit var dialogManager: SystemUIDialogManager
private lateinit var underTest: UdfpsKeyguardInteractor
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
testScope = TestScope()
configRepository = FakeConfigurationRepository()
keyguardRepository = FakeKeyguardRepository()
bouncerRepository = FakeKeyguardBouncerRepository()
shadeRepository = FakeShadeRepository()
fakeCommandQueue = FakeCommandQueue()
featureFlags =
FakeFeatureFlags().apply {
@@ -102,6 +108,8 @@ class UdfpsKeyguardInteractorTest : SysuiTestCase() {
bouncerRepository,
configRepository,
),
shadeRepository,
dialogManager,
)
}
@@ -142,6 +150,61 @@ class UdfpsKeyguardInteractorTest : SysuiTestCase() {
assertThat(burnInOffsets?.burnInXOffset).isEqualTo(burnInXOffset)
}
@Test
fun dialogHideAffordances() =
testScope.runTest {
val dialogHideAffordancesRequest by
collectLastValue(underTest.dialogHideAffordancesRequest)
runCurrent()
val captor = argumentCaptor<SystemUIDialogManager.Listener>()
verify(dialogManager).registerListener(captor.capture())
captor.value.shouldHideAffordances(false)
assertThat(dialogHideAffordancesRequest).isEqualTo(false)
captor.value.shouldHideAffordances(true)
assertThat(dialogHideAffordancesRequest).isEqualTo(true)
captor.value.shouldHideAffordances(false)
assertThat(dialogHideAffordancesRequest).isEqualTo(false)
}
@Test
fun shadeExpansion_updates() =
testScope.runTest {
keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
val shadeExpansion by collectLastValue(underTest.shadeExpansion)
assertThat(shadeExpansion).isEqualTo(0f)
shadeRepository.setUdfpsTransitionToFullShadeProgress(.5f)
assertThat(shadeExpansion).isEqualTo(.5f)
shadeRepository.setUdfpsTransitionToFullShadeProgress(.7f)
assertThat(shadeExpansion).isEqualTo(.7f)
shadeRepository.setUdfpsTransitionToFullShadeProgress(.22f)
assertThat(shadeExpansion).isEqualTo(.22f)
keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
assertThat(shadeExpansion).isEqualTo(1f)
}
@Test
fun qsProgress_updates() =
testScope.runTest {
val qsProgress by collectLastValue(underTest.qsProgress)
assertThat(qsProgress).isEqualTo(0f)
shadeRepository.setQsExpansion(.22f)
assertThat(qsProgress).isEqualTo(.44f)
shadeRepository.setQsExpansion(.5f)
assertThat(qsProgress).isEqualTo(1f)
shadeRepository.setQsExpansion(.7f)
assertThat(qsProgress).isEqualTo(1f)
}
private fun initializeBurnInOffsets() {
whenever(burnInHelper.burnInProgressOffset()).thenReturn(burnInProgress)
whenever(burnInHelper.burnInOffset(anyInt(), /* xAxis */ eq(true)))

View File

@@ -32,6 +32,8 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.UdfpsKeyguardInteractor
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -58,7 +60,9 @@ class UdfpsAodViewModelTest : SysuiTestCase() {
private lateinit var keyguardRepository: FakeKeyguardRepository
private lateinit var fakeCommandQueue: FakeCommandQueue
private lateinit var featureFlags: FakeFeatureFlags
private lateinit var shadeRepository: FakeShadeRepository
@Mock private lateinit var dialogManager: SystemUIDialogManager
@Mock private lateinit var burnInHelper: BurnInHelperWrapper
@Before
@@ -70,6 +74,7 @@ class UdfpsAodViewModelTest : SysuiTestCase() {
keyguardRepository = FakeKeyguardRepository()
bouncerRepository = FakeKeyguardBouncerRepository()
fakeCommandQueue = FakeCommandQueue()
shadeRepository = FakeShadeRepository()
featureFlags =
FakeFeatureFlags().apply {
set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, true)
@@ -93,6 +98,8 @@ class UdfpsAodViewModelTest : SysuiTestCase() {
bouncerRepository,
configRepository,
),
shadeRepository,
dialogManager,
)
underTest =

View File

@@ -33,6 +33,8 @@ 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.domain.interactor.UdfpsKeyguardInteractor
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -60,8 +62,10 @@ class UdfpsFingerprintViewModelTest : SysuiTestCase() {
private lateinit var fakeCommandQueue: FakeCommandQueue
private lateinit var featureFlags: FakeFeatureFlags
private lateinit var transitionRepository: FakeKeyguardTransitionRepository
private lateinit var shadeRepository: FakeShadeRepository
@Mock private lateinit var burnInHelper: BurnInHelperWrapper
@Mock private lateinit var dialogManager: SystemUIDialogManager
@Before
fun setUp() {
@@ -79,35 +83,39 @@ class UdfpsFingerprintViewModelTest : SysuiTestCase() {
}
bouncerRepository = FakeKeyguardBouncerRepository()
transitionRepository = FakeKeyguardTransitionRepository()
shadeRepository = FakeShadeRepository()
val transitionInteractor =
KeyguardTransitionInteractor(
transitionRepository,
testScope.backgroundScope,
)
val udfpsKeyguardInteractor =
UdfpsKeyguardInteractor(
val keyguardInteractor =
KeyguardInteractor(
keyguardRepository,
fakeCommandQueue,
featureFlags,
bouncerRepository,
configRepository,
BurnInInteractor(
context,
burnInHelper,
testScope.backgroundScope,
configRepository,
FakeSystemClock(),
),
KeyguardInteractor(
keyguardRepository,
fakeCommandQueue,
featureFlags,
bouncerRepository,
configRepository,
),
)
underTest =
FingerprintViewModel(
context,
transitionInteractor,
udfpsKeyguardInteractor,
UdfpsKeyguardInteractor(
configRepository,
BurnInInteractor(
context,
burnInHelper,
testScope.backgroundScope,
configRepository,
FakeSystemClock(),
),
keyguardInteractor,
shadeRepository,
dialogManager,
),
keyguardInteractor,
)
}

View File

@@ -20,12 +20,26 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.Utils
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FakeFeatureFlags
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.BurnInInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.UdfpsKeyguardInteractor
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.statusbar.phone.SystemUIDialogManager
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -35,6 +49,8 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
/** Tests UDFPS lockscreen view model transitions. */
@@ -48,26 +64,63 @@ class UdfpsLockscreenViewModelTest : SysuiTestCase() {
private val alternateBouncerColor =
Utils.getColorAttrDefaultColor(context, alternateBouncerResId)
@Mock private lateinit var dialogManager: SystemUIDialogManager
private lateinit var underTest: UdfpsLockscreenViewModel
private lateinit var testScope: TestScope
private lateinit var transitionRepository: FakeKeyguardTransitionRepository
private lateinit var configRepository: FakeConfigurationRepository
private lateinit var keyguardRepository: FakeKeyguardRepository
private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
private lateinit var shadeRepository: FakeShadeRepository
private lateinit var featureFlags: FakeFeatureFlags
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
testScope = TestScope()
transitionRepository = FakeKeyguardTransitionRepository()
val transitionInteractor =
KeyguardTransitionInteractor(
transitionRepository,
testScope.backgroundScope,
configRepository = FakeConfigurationRepository()
keyguardRepository = FakeKeyguardRepository()
bouncerRepository = FakeKeyguardBouncerRepository()
shadeRepository = FakeShadeRepository()
featureFlags =
FakeFeatureFlags().apply {
set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, true)
set(Flags.FACE_AUTH_REFACTOR, false)
}
val keyguardInteractor =
KeyguardInteractor(
keyguardRepository,
commandQueue = mock(),
featureFlags,
bouncerRepository,
configRepository,
)
underTest =
UdfpsLockscreenViewModel(
context,
lockscreenColorResId,
alternateBouncerResId,
transitionInteractor,
KeyguardTransitionInteractor(
transitionRepository,
testScope.backgroundScope,
),
UdfpsKeyguardInteractor(
configRepository,
BurnInInteractor(
context,
burnInHelperWrapper = mock(),
testScope.backgroundScope,
configRepository,
FakeSystemClock(),
),
keyguardInteractor,
shadeRepository,
dialogManager,
),
keyguardInteractor,
)
}
@@ -125,6 +178,7 @@ class UdfpsLockscreenViewModelTest : SysuiTestCase() {
testScope.runTest {
val transition by collectLastValue(underTest.transition)
val visible by collectLastValue(underTest.visible)
keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
// TransitionState.STARTED: lockscreen -> AOD
transitionRepository.sendTransitionStep(
@@ -175,6 +229,56 @@ class UdfpsLockscreenViewModelTest : SysuiTestCase() {
assertThat(visible).isFalse()
}
@Test
fun lockscreenShadeLockedToAod() =
testScope.runTest {
val transition by collectLastValue(underTest.transition)
val visible by collectLastValue(underTest.visible)
keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
// TransitionState.STARTED: lockscreen -> AOD
transitionRepository.sendTransitionStep(
TransitionStep(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.AOD,
value = 0f,
transitionState = TransitionState.STARTED,
ownerName = "lockscreenToAod",
)
)
runCurrent()
assertThat(transition?.alpha).isEqualTo(0f)
assertThat(visible).isFalse()
// TransitionState.RUNNING: lockscreen -> AOD
transitionRepository.sendTransitionStep(
TransitionStep(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.AOD,
value = .6f,
transitionState = TransitionState.RUNNING,
ownerName = "lockscreenToAod",
)
)
runCurrent()
assertThat(transition?.alpha).isEqualTo(0f)
assertThat(visible).isFalse()
// TransitionState.FINISHED: lockscreen -> AOD
transitionRepository.sendTransitionStep(
TransitionStep(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.AOD,
value = 1f,
transitionState = TransitionState.FINISHED,
ownerName = "lockscreenToAod",
)
)
runCurrent()
assertThat(transition?.alpha).isEqualTo(0f)
assertThat(visible).isFalse()
}
@Test
fun aodToLockscreen() =
testScope.runTest {
@@ -235,6 +339,7 @@ class UdfpsLockscreenViewModelTest : SysuiTestCase() {
testScope.runTest {
val transition by collectLastValue(underTest.transition)
val visible by collectLastValue(underTest.visible)
keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
// TransitionState.STARTED: lockscreen -> alternate bouncer
transitionRepository.sendTransitionStep(
@@ -398,6 +503,7 @@ class UdfpsLockscreenViewModelTest : SysuiTestCase() {
testScope.runTest {
val transition by collectLastValue(underTest.transition)
val visible by collectLastValue(underTest.visible)
keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
// TransitionState.STARTED: lockscreen -> occluded
transitionRepository.sendTransitionStep(
@@ -502,4 +608,96 @@ class UdfpsLockscreenViewModelTest : SysuiTestCase() {
assertThat(transition?.color).isEqualTo(lockscreenColor)
assertThat(visible).isTrue()
}
@Test
fun qsProgressChange() =
testScope.runTest {
val transition by collectLastValue(underTest.transition)
val visible by collectLastValue(underTest.visible)
givenTransitionToLockscreenFinished()
// qsExpansion = 0f
shadeRepository.setQsExpansion(0f)
runCurrent()
assertThat(transition?.alpha).isEqualTo(1f)
assertThat(visible).isEqualTo(true)
// qsExpansion = .25
shadeRepository.setQsExpansion(.2f)
runCurrent()
assertThat(transition?.alpha).isEqualTo(.6f)
assertThat(visible).isEqualTo(true)
// qsExpansion = .5
shadeRepository.setQsExpansion(.5f)
runCurrent()
assertThat(transition?.alpha).isEqualTo(0f)
assertThat(visible).isEqualTo(false)
// qsExpansion = 1
shadeRepository.setQsExpansion(1f)
runCurrent()
assertThat(transition?.alpha).isEqualTo(0f)
assertThat(visible).isEqualTo(false)
}
@Test
fun shadeExpansionChanged() =
testScope.runTest {
val transition by collectLastValue(underTest.transition)
val visible by collectLastValue(underTest.visible)
givenTransitionToLockscreenFinished()
// shadeExpansion = 0f
shadeRepository.setUdfpsTransitionToFullShadeProgress(0f)
runCurrent()
assertThat(transition?.alpha).isEqualTo(1f)
assertThat(visible).isEqualTo(true)
// shadeExpansion = .2
shadeRepository.setUdfpsTransitionToFullShadeProgress(.2f)
runCurrent()
assertThat(transition?.alpha).isEqualTo(.8f)
assertThat(visible).isEqualTo(true)
// shadeExpansion = .5
shadeRepository.setUdfpsTransitionToFullShadeProgress(.5f)
runCurrent()
assertThat(transition?.alpha).isEqualTo(.5f)
assertThat(visible).isEqualTo(true)
// shadeExpansion = 1
shadeRepository.setUdfpsTransitionToFullShadeProgress(1f)
runCurrent()
assertThat(transition?.alpha).isEqualTo(0f)
assertThat(visible).isEqualTo(false)
}
@Test
fun dialogHideAffordancesRequestChanged() =
testScope.runTest {
val transition by collectLastValue(underTest.transition)
givenTransitionToLockscreenFinished()
runCurrent()
val captor = argumentCaptor<SystemUIDialogManager.Listener>()
Mockito.verify(dialogManager).registerListener(captor.capture())
captor.value.shouldHideAffordances(true)
assertThat(transition?.alpha).isEqualTo(0f)
captor.value.shouldHideAffordances(false)
assertThat(transition?.alpha).isEqualTo(1f)
}
private suspend fun givenTransitionToLockscreenFinished() {
transitionRepository.sendTransitionStep(
TransitionStep(
from = KeyguardState.AOD,
to = KeyguardState.LOCKSCREEN,
value = 1f,
transitionState = TransitionState.FINISHED,
ownerName = "givenTransitionToLockscreenFinished",
)
)
}
}