diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt index e04cbfd88bb331899dd0482cebad31ffc74c204a..503fd34ce2c228594062775311dd0a561e824171 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt @@ -39,6 +39,7 @@ 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.android.systemui.kosmos.testScope +import com.android.systemui.shade.data.repository.fakeShadeRepository import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor import com.android.systemui.statusbar.phone.dozeParameters import com.android.systemui.statusbar.phone.screenOffAnimationController @@ -72,6 +73,7 @@ class KeyguardRootViewModelTest : SysuiTestCase() { private val deviceEntryRepository = kosmos.fakeDeviceEntryRepository private val notificationsKeyguardInteractor = kosmos.notificationsKeyguardInteractor private val dozeParameters = kosmos.dozeParameters + private val shadeRepository = kosmos.fakeShadeRepository private val underTest by lazy { kosmos.keyguardRootViewModel } private val viewState = ViewStateAccessor() @@ -308,4 +310,22 @@ class KeyguardRootViewModelTest : SysuiTestCase() { assertThat(alpha).isEqualTo(1.0f) } + + @Test + fun alpha_emitsOnShadeExpansion() = + testScope.runTest { + val alpha by collectLastValue(underTest.alpha(viewState)) + + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.AOD, + to = KeyguardState.LOCKSCREEN, + testScope, + ) + + shadeRepository.setQsExpansion(0f) + assertThat(alpha).isEqualTo(1f) + + shadeRepository.setQsExpansion(0.5f) + assertThat(alpha).isEqualTo(0f) + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt index 35119338fb32a49cdc51f708ff064b80e50f3ef4..921eb66cd3ccdacf84934baeaef7445713f4f115 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.ui.viewmodel import android.graphics.Point +import android.util.MathUtils import android.view.View.VISIBLE import com.android.systemui.Flags.newAodTransition import com.android.systemui.common.shared.model.NotificationContainerBounds @@ -33,6 +34,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING import com.android.systemui.keyguard.shared.model.TransitionState.STARTED import com.android.systemui.keyguard.ui.StateToValue +import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor import com.android.systemui.statusbar.phone.DozeParameters import com.android.systemui.statusbar.phone.ScreenOffAnimationController @@ -43,6 +45,7 @@ import com.android.systemui.util.ui.AnimatedValue import com.android.systemui.util.ui.toAnimatedValueFlow import com.android.systemui.util.ui.zip import javax.inject.Inject +import kotlin.math.max import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow @@ -63,7 +66,7 @@ constructor( private val dozeParameters: DozeParameters, private val keyguardInteractor: KeyguardInteractor, private val communalInteractor: CommunalInteractor, - keyguardTransitionInteractor: KeyguardTransitionInteractor, + private val keyguardTransitionInteractor: KeyguardTransitionInteractor, private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor, private val alternateBouncerToGoneTransitionViewModel: AlternateBouncerToGoneTransitionViewModel, @@ -87,6 +90,7 @@ constructor( private val screenOffAnimationController: ScreenOffAnimationController, private val aodBurnInViewModel: AodBurnInViewModel, private val aodAlphaViewModel: AodAlphaViewModel, + private val shadeInteractor: ShadeInteractor, ) { val burnInLayerVisibility: Flow<Int> = @@ -102,6 +106,16 @@ constructor( .onStart { emit(false) } .distinctUntilChanged() + private val alphaOnShadeExpansion: Flow<Float> = + combine( + shadeInteractor.qsExpansion, + shadeInteractor.shadeExpansion, + ) { qsExpansion, shadeExpansion -> + // Fade out quickly as the shade expands + 1f - MathUtils.constrainedMap(0f, 1f, 0f, 0.2f, max(qsExpansion, shadeExpansion)) + } + .distinctUntilChanged() + /** Last point that the root view was tapped */ val lastRootViewTapPosition: Flow<Point?> = keyguardInteractor.lastRootViewTapPosition @@ -119,10 +133,12 @@ constructor( fun alpha(viewState: ViewStateAccessor): Flow<Float> { return combine( communalInteractor.isIdleOnCommunal, + keyguardTransitionInteractor.transitionValue(GONE).onStart { emit(0f) }, // The transitions are mutually exclusive, so they are safe to merge to get the last // value emitted by any of them. Do not add flows that cannot make this guarantee. merge( aodAlphaViewModel.alpha, + alphaOnShadeExpansion, keyguardInteractor.dismissAlpha.filterNotNull(), alternateBouncerToGoneTransitionViewModel.lockscreenAlpha, aodToLockscreenTransitionViewModel.lockscreenAlpha(viewState), @@ -140,11 +156,12 @@ constructor( primaryBouncerToLockscreenTransitionViewModel.lockscreenAlpha, ) .onStart { emit(1f) } - ) { isIdleOnCommunal, alpha -> - if (isIdleOnCommunal) { + ) { isIdleOnCommunal, goneValue, alpha -> + if (isIdleOnCommunal || goneValue == 1f) { // Keyguard should not show while the communal hub is fully visible. This check // is added since at the moment, closing the notification shade will cause the - // keyguard alpha to be set back to 1. + // keyguard alpha to be set back to 1. Also ensure keyguard is never visible + // when GONE. 0f } else { alpha diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt index 4939237bbafefd78eb1c9ed9b20ce2293ef2f794..ecf66a297f0dbf9ce03b6b389ff19a9c3aef119e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt @@ -24,6 +24,7 @@ import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor import com.android.systemui.statusbar.phone.dozeParameters import com.android.systemui.statusbar.phone.screenOffAnimationController @@ -56,5 +57,6 @@ val Kosmos.keyguardRootViewModel by Fixture { screenOffAnimationController = screenOffAnimationController, aodBurnInViewModel = aodBurnInViewModel, aodAlphaViewModel = aodAlphaViewModel, + shadeInteractor = shadeInteractor, ) }