summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt113
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt145
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java1
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt2
5 files changed, 226 insertions, 45 deletions
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
index d924d88d1e59..92d5c26148e4 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
@@ -74,6 +74,16 @@ sealed interface ObservableTransitionState {
*/
val isUserInputOngoing: Flow<Boolean>,
) : ObservableTransitionState
+
+ fun isIdle(scene: SceneKey?): Boolean {
+ return this is Idle && (scene == null || this.currentScene == scene)
+ }
+
+ fun isTransitioning(from: SceneKey? = null, to: SceneKey? = null): Boolean {
+ return this is Transition &&
+ (from == null || this.fromScene == from) &&
+ (to == null || this.toScene == to)
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
index bb2eeb77969d..dc35e4311d25 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
@@ -16,11 +16,16 @@
package com.android.systemui.keyguard.domain.interactor
+import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.BiometricUnlockMode
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
+import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -42,6 +47,7 @@ constructor(
fromBouncerInteractor: FromPrimaryBouncerTransitionInteractor,
fromAlternateBouncerInteractor: FromAlternateBouncerTransitionInteractor,
notificationLaunchAnimationInteractor: NotificationLaunchAnimationInteractor,
+ sceneInteractor: SceneInteractor,
) {
private val defaultSurfaceBehindVisibility =
transitionInteractor.finishedKeyguardState.map(::isSurfaceVisible)
@@ -103,21 +109,42 @@ constructor(
* animation. This is used to keep the RemoteAnimationTarget alive until we're done using it.
*/
val usingKeyguardGoingAwayAnimation: Flow<Boolean> =
- combine(
- transitionInteractor.isInTransitionToState(KeyguardState.GONE),
- transitionInteractor.finishedKeyguardState,
- surfaceBehindInteractor.isAnimatingSurface,
- notificationLaunchAnimationInteractor.isLaunchAnimationRunning,
- ) { isInTransitionToGone, finishedState, isAnimatingSurface, notifLaunchRunning ->
- // Using the animation if we're animating it directly, or if the
- // ActivityLaunchAnimator is in the process of animating it.
- val animationsRunning = isAnimatingSurface || notifLaunchRunning
- // We may still be animating the surface after the keyguard is fully GONE, since
- // some animations (like the translation spring) are not tied directly to the
- // transition step amount.
- isInTransitionToGone || (finishedState == KeyguardState.GONE && animationsRunning)
- }
- .distinctUntilChanged()
+ if (SceneContainerFlag.isEnabled) {
+ combine(
+ sceneInteractor.transitionState,
+ surfaceBehindInteractor.isAnimatingSurface,
+ notificationLaunchAnimationInteractor.isLaunchAnimationRunning,
+ ) { transition, isAnimatingSurface, isLaunchAnimationRunning ->
+ // Using the animation if we're animating it directly, or if the
+ // ActivityLaunchAnimator is in the process of animating it.
+ val isAnyAnimationRunning = isAnimatingSurface || isLaunchAnimationRunning
+ // We may still be animating the surface after the keyguard is fully GONE, since
+ // some animations (like the translation spring) are not tied directly to the
+ // transition step amount.
+ transition.isTransitioning(to = Scenes.Gone) ||
+ (isAnyAnimationRunning &&
+ (transition.isIdle(Scenes.Gone) ||
+ transition.isTransitioning(from = Scenes.Gone)))
+ }
+ .distinctUntilChanged()
+ } else {
+ combine(
+ transitionInteractor.isInTransitionToState(KeyguardState.GONE),
+ transitionInteractor.finishedKeyguardState,
+ surfaceBehindInteractor.isAnimatingSurface,
+ notificationLaunchAnimationInteractor.isLaunchAnimationRunning,
+ ) { isInTransitionToGone, finishedState, isAnimatingSurface, notifLaunchRunning ->
+ // Using the animation if we're animating it directly, or if the
+ // ActivityLaunchAnimator is in the process of animating it.
+ val animationsRunning = isAnimatingSurface || notifLaunchRunning
+ // We may still be animating the surface after the keyguard is fully GONE, since
+ // some animations (like the translation spring) are not tied directly to the
+ // transition step amount.
+ isInTransitionToGone ||
+ (finishedState == KeyguardState.GONE && animationsRunning)
+ }
+ .distinctUntilChanged()
+ }
/**
* Whether the lockscreen is visible, from the Window Manager (WM) perspective.
@@ -127,28 +154,44 @@ constructor(
* want to know if the AOD/clock/notifs/etc. are visible.
*/
val lockscreenVisibility: Flow<Boolean> =
- transitionInteractor.currentKeyguardState
- .sample(transitionInteractor.startedStepWithPrecedingStep, ::Pair)
- .map { (currentState, startedWithPrev) ->
- val startedFromStep = startedWithPrev?.previousValue
- val startedStep = startedWithPrev?.newValue
- val returningToGoneAfterCancellation =
- startedStep?.to == KeyguardState.GONE &&
- startedFromStep?.transitionState == TransitionState.CANCELED &&
- startedFromStep.from == KeyguardState.GONE
+ if (SceneContainerFlag.isEnabled) {
+ sceneInteractor.transitionState
+ .pairwise(ObservableTransitionState.Idle(Scenes.Lockscreen))
+ .map { (prevTransitionState, transitionState) ->
+ val isReturningToGoneAfterCancellation =
+ prevTransitionState.isTransitioning(from = Scenes.Gone) &&
+ transitionState.isTransitioning(to = Scenes.Gone)
+ val isNotOnGone =
+ !transitionState.isTransitioning(from = Scenes.Gone) &&
+ !transitionState.isIdle(Scenes.Gone)
- if (!returningToGoneAfterCancellation) {
- // By default, apply the lockscreen visibility of the current state.
- KeyguardState.lockscreenVisibleInState(currentState)
- } else {
- // If we're transitioning to GONE after a prior canceled transition from GONE,
- // then this is the camera launch transition from an asleep state back to GONE.
- // We don't want to show the lockscreen since we're aborting the lock and going
- // back to GONE.
- KeyguardState.lockscreenVisibleInState(KeyguardState.GONE)
+ isNotOnGone && !isReturningToGoneAfterCancellation
}
- }
- .distinctUntilChanged()
+ .distinctUntilChanged()
+ } else {
+ transitionInteractor.currentKeyguardState
+ .sample(transitionInteractor.startedStepWithPrecedingStep, ::Pair)
+ .map { (currentState, startedWithPrev) ->
+ val startedFromStep = startedWithPrev?.previousValue
+ val startedStep = startedWithPrev?.newValue
+ val returningToGoneAfterCancellation =
+ startedStep?.to == KeyguardState.GONE &&
+ startedFromStep?.transitionState == TransitionState.CANCELED &&
+ startedFromStep.from == KeyguardState.GONE
+
+ if (!returningToGoneAfterCancellation) {
+ // By default, apply the lockscreen visibility of the current state.
+ KeyguardState.lockscreenVisibleInState(currentState)
+ } else {
+ // If we're transitioning to GONE after a prior canceled transition from
+ // GONE, then this is the camera launch transition from an asleep state back
+ // to GONE. We don't want to show the lockscreen since we're aborting the
+ // lock and going back to GONE.
+ KeyguardState.lockscreenVisibleInState(KeyguardState.GONE)
+ }
+ }
+ .distinctUntilChanged()
+ }
/**
* Whether always-on-display (AOD) is visible when the lockscreen is visible, from window
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
index b1a8dd1d3fdc..a77169e74de5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
@@ -18,20 +18,29 @@ package com.android.systemui.keyguard.domain.interactor
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
+import com.android.systemui.flags.DisableSceneContainer
+import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
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.scene.data.repository.sceneContainerRepository
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertEquals
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -57,14 +66,22 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
.thenReturn(surfaceBehindIsAnimatingFlow)
}
- private val underTest = kosmos.windowManagerLockscreenVisibilityInteractor
+ private val underTest = lazy { kosmos.windowManagerLockscreenVisibilityInteractor }
private val testScope = kosmos.testScope
private val transitionRepository = kosmos.fakeKeyguardTransitionRepository
+ @Before
+ fun setUp() {
+ // lazy value needs to be called here otherwise flow collection misbehaves
+ underTest.value
+ kosmos.sceneContainerRepository.setTransitionState(sceneTransitions)
+ }
+
@Test
+ @DisableSceneContainer
fun surfaceBehindVisibility_switchesToCorrectFlow() =
testScope.runTest {
- val values by collectValues(underTest.surfaceBehindVisibility)
+ val values by collectValues(underTest.value.surfaceBehindVisibility)
// Start on LOCKSCREEN.
transitionRepository.sendTransitionStep(
@@ -170,9 +187,10 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
}
@Test
+ @DisableSceneContainer
fun testUsingGoingAwayAnimation_duringTransitionToGone() =
testScope.runTest {
- val values by collectValues(underTest.usingKeyguardGoingAwayAnimation)
+ val values by collectValues(underTest.value.usingKeyguardGoingAwayAnimation)
// Start on LOCKSCREEN.
transitionRepository.sendTransitionStep(
@@ -230,9 +248,10 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
}
@Test
+ @DisableSceneContainer
fun testNotUsingGoingAwayAnimation_evenWhenAnimating_ifStateIsNotGone() =
testScope.runTest {
- val values by collectValues(underTest.usingKeyguardGoingAwayAnimation)
+ val values by collectValues(underTest.value.usingKeyguardGoingAwayAnimation)
// Start on LOCKSCREEN.
transitionRepository.sendTransitionStep(
@@ -319,9 +338,10 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
}
@Test
+ @DisableSceneContainer
fun lockscreenVisibility_visibleWhenGone() =
testScope.runTest {
- val values by collectValues(underTest.lockscreenVisibility)
+ val values by collectValues(underTest.value.lockscreenVisibility)
// Start on LOCKSCREEN.
transitionRepository.sendTransitionStep(
@@ -385,9 +405,10 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
}
@Test
+ @DisableSceneContainer
fun testLockscreenVisibility_usesFromState_ifCanceled() =
testScope.runTest {
- val values by collectValues(underTest.lockscreenVisibility)
+ val values by collectValues(underTest.value.lockscreenVisibility)
transitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
@@ -486,9 +507,10 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
* state during the AOD/isAsleep -> GONE transition is AOD (where lockscreen visibility = true).
*/
@Test
+ @DisableSceneContainer
fun testLockscreenVisibility_falseDuringTransitionToGone_fromCanceledGone() =
testScope.runTest {
- val values by collectValues(underTest.lockscreenVisibility)
+ val values by collectValues(underTest.value.lockscreenVisibility)
transitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
@@ -587,11 +609,11 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
)
}
- /** */
@Test
+ @DisableSceneContainer
fun testLockscreenVisibility_trueDuringTransitionToGone_fromNotCanceledGone() =
testScope.runTest {
- val values by collectValues(underTest.lockscreenVisibility)
+ val values by collectValues(underTest.value.lockscreenVisibility)
transitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
@@ -702,4 +724,109 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
values
)
}
+
+ @Test
+ @EnableSceneContainer
+ fun sceneContainer_lockscreenVisibility_visibleWhenNotGone() =
+ testScope.runTest {
+ val lockscreenVisibility by collectLastValue(underTest.value.lockscreenVisibility)
+
+ sceneTransitions.value = lsToGone
+ assertThat(lockscreenVisibility).isTrue()
+
+ sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
+ assertThat(lockscreenVisibility).isFalse()
+
+ sceneTransitions.value = goneToLs
+ assertThat(lockscreenVisibility).isFalse()
+
+ sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
+ assertThat(lockscreenVisibility).isTrue()
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun sceneContainer_lockscreenVisibility_notVisibleWhenReturningToGone() =
+ testScope.runTest {
+ val lockscreenVisibility by collectLastValue(underTest.value.lockscreenVisibility)
+
+ sceneTransitions.value = goneToLs
+ assertThat(lockscreenVisibility).isFalse()
+
+ sceneTransitions.value = lsToGone
+ assertThat(lockscreenVisibility).isFalse()
+
+ sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
+ assertThat(lockscreenVisibility).isFalse()
+
+ sceneTransitions.value = goneToLs
+ assertThat(lockscreenVisibility).isFalse()
+
+ sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
+ assertThat(lockscreenVisibility).isTrue()
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun sceneContainer_usingGoingAwayAnimation_duringTransitionToGone() =
+ testScope.runTest {
+ val usingKeyguardGoingAwayAnimation by
+ collectLastValue(underTest.value.usingKeyguardGoingAwayAnimation)
+
+ sceneTransitions.value = lsToGone
+ assertThat(usingKeyguardGoingAwayAnimation).isTrue()
+
+ sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
+ assertThat(usingKeyguardGoingAwayAnimation).isFalse()
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun sceneContainer_usingGoingAwayAnimation_surfaceBehindIsAnimating() =
+ testScope.runTest {
+ val usingKeyguardGoingAwayAnimation by
+ collectLastValue(underTest.value.usingKeyguardGoingAwayAnimation)
+
+ sceneTransitions.value = lsToGone
+ surfaceBehindIsAnimatingFlow.emit(true)
+ assertThat(usingKeyguardGoingAwayAnimation).isTrue()
+
+ sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
+ assertThat(usingKeyguardGoingAwayAnimation).isTrue()
+
+ sceneTransitions.value = goneToLs
+ assertThat(usingKeyguardGoingAwayAnimation).isTrue()
+
+ surfaceBehindIsAnimatingFlow.emit(false)
+ assertThat(usingKeyguardGoingAwayAnimation).isFalse()
+ }
+
+ companion object {
+ private val progress = MutableStateFlow(0f)
+
+ private val sceneTransitions =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(Scenes.Lockscreen)
+ )
+
+ private val lsToGone =
+ ObservableTransitionState.Transition(
+ Scenes.Lockscreen,
+ Scenes.Gone,
+ flowOf(Scenes.Lockscreen),
+ progress,
+ false,
+ flowOf(false)
+ )
+
+ private val goneToLs =
+ ObservableTransitionState.Transition(
+ Scenes.Gone,
+ Scenes.Lockscreen,
+ flowOf(Scenes.Lockscreen),
+ progress,
+ false,
+ flowOf(false)
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 56e5e293c799..aac36405e9b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -138,7 +138,6 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt
index 29167d64d1f1..b38acc8a46dc 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.statusbar.notification.domain.interactor.notificationLaunchAnimationInteractor
val Kosmos.windowManagerLockscreenVisibilityInteractor by
@@ -29,5 +30,6 @@ val Kosmos.windowManagerLockscreenVisibilityInteractor by
fromBouncerInteractor = fromPrimaryBouncerTransitionInteractor,
fromAlternateBouncerInteractor = fromAlternateBouncerTransitionInteractor,
notificationLaunchAnimationInteractor = notificationLaunchAnimationInteractor,
+ sceneInteractor = sceneInteractor,
)
}