summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Andreas Miko <amiko@google.com> 2024-05-03 04:30:52 +0200
committer Andreas Miko <amiko@google.com> 2024-05-16 13:12:45 +0200
commit7e404fb2847e93ff1f935a13e3f76c8e9c85e948 (patch)
tree7e6e933c5093b93a7da2e2b3c99d0ef9052a7663
parent19db0f80344a0997661c0c2bdffd6cf62879fdaa (diff)
Enable and auto-convert old KTF transitions to scene container
When a collector of a transition with old KTF states listened to e.g. AOD -> GONE in the past, the KTF state GONE won't exist in the future. This now requires two things to happen to be able to listen to the same transition: 1. GONE needs to be converted to UNDEFINED (AOD -> UNDEFINED) 2. Because AOD -> UNDEFINED is not conclusive (it could be also a AOD -> Bouncer transition) you need to additionally listen/filter to scene container and make sure Lockscreen -> Gone is in progress. The auto-convert aspect is a convenience function to make todays viewmodels work easily while migrating to scene container. Test: KeyguardTransitionInteractorTest Bug: b/330311871 Flag: ACONFIG com.android.systemui.scene_container DEVELOPMENT Change-Id: If6032d6cb3eec498a124c204317bb96971ac74c2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt195
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt5
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt38
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt28
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt75
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt37
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt2
8 files changed, 372 insertions, 17 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
index bf0939c6c46f..52fb2bbf312f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
@@ -19,9 +19,13 @@ 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.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.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
@@ -29,31 +33,67 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.OFF
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
+import com.android.systemui.keyguard.shared.model.KeyguardState.UNDEFINED
import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED
import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
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.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertEquals
import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertThrows
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
@kotlinx.coroutines.ExperimentalCoroutinesApi
-@android.platform.test.annotations.EnabledOnRavenwood
class KeyguardTransitionInteractorTest : SysuiTestCase() {
val kosmos = testKosmos()
val underTest = kosmos.keyguardTransitionInteractor
val repository = kosmos.fakeKeyguardTransitionRepository
val testScope = kosmos.testScope
+ private val sceneTransitions =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(Scenes.Lockscreen)
+ )
+
+ private val lsToGone =
+ ObservableTransitionState.Transition(
+ Scenes.Lockscreen,
+ Scenes.Gone,
+ flowOf(Scenes.Lockscreen),
+ flowOf(0f),
+ false,
+ flowOf(false)
+ )
+
+ private val goneToLs =
+ ObservableTransitionState.Transition(
+ Scenes.Gone,
+ Scenes.Lockscreen,
+ flowOf(Scenes.Lockscreen),
+ flowOf(0f),
+ false,
+ flowOf(false)
+ )
+
+ @Before
+ fun setUp() {
+ kosmos.sceneContainerRepository.setTransitionState(sceneTransitions)
+ }
+
@Test
fun transitionCollectorsReceivesOnlyAppropriateEvents() =
testScope.runTest {
@@ -482,6 +522,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
}
@Test
+ @DisableSceneContainer
fun isInTransitionToState() =
testScope.runTest {
val results by collectValues(underTest.isInTransitionToState(GONE))
@@ -586,7 +627,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
)
sendSteps(
- TransitionStep(DOZING, GONE, 0f, STARTED),
+ TransitionStep(DOZING, LOCKSCREEN, 0f, STARTED),
)
assertThat(results)
@@ -598,7 +639,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
)
sendSteps(
- TransitionStep(DOZING, GONE, 0f, RUNNING),
+ TransitionStep(DOZING, LOCKSCREEN, 0f, RUNNING),
)
assertThat(results)
@@ -610,7 +651,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
)
sendSteps(
- TransitionStep(DOZING, GONE, 0f, FINISHED),
+ TransitionStep(DOZING, LOCKSCREEN, 0f, FINISHED),
)
assertThat(results)
@@ -623,9 +664,9 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
)
sendSteps(
- TransitionStep(GONE, DOZING, 0f, STARTED),
- TransitionStep(GONE, DOZING, 0f, RUNNING),
- TransitionStep(GONE, DOZING, 1f, FINISHED),
+ TransitionStep(LOCKSCREEN, DOZING, 0f, STARTED),
+ TransitionStep(LOCKSCREEN, DOZING, 0f, RUNNING),
+ TransitionStep(LOCKSCREEN, DOZING, 1f, FINISHED),
)
assertThat(results)
@@ -638,8 +679,8 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
)
sendSteps(
- TransitionStep(DOZING, GONE, 0f, STARTED),
- TransitionStep(DOZING, GONE, 0f, RUNNING),
+ TransitionStep(DOZING, LOCKSCREEN, 0f, STARTED),
+ TransitionStep(DOZING, LOCKSCREEN, 0f, RUNNING),
)
assertThat(results)
@@ -1404,6 +1445,142 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
)
}
+ @Test
+ @DisableSceneContainer
+ fun getOrCreateFlow_no_conversion_with_flag_off() =
+ testScope.runTest {
+ val currentStates by
+ collectValues(underTest.getOrCreateFlow(Edge(PRIMARY_BOUNCER, GONE)))
+
+ val sendStep1 = TransitionStep(PRIMARY_BOUNCER, GONE, 0f, STARTED)
+ sendSteps(sendStep1)
+
+ assertEquals(listOf(sendStep1), currentStates)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun getOrCreateFlow_conversion_with_flag_on() =
+ testScope.runTest {
+ val currentStates by
+ collectValues(underTest.getOrCreateFlow(Edge(PRIMARY_BOUNCER, GONE)))
+
+ val sendStep1 = TransitionStep(PRIMARY_BOUNCER, GONE, 0f, STARTED)
+ sendSteps(sendStep1)
+
+ assertEquals(listOf<TransitionStep>(), currentStates)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun getOrCreateFlow_conversion_emits_values_with_sceneContainer_in_correct_state() =
+ testScope.runTest {
+ val currentStates by collectValues(underTest.getOrCreateFlow(Edge(LOCKSCREEN, GONE)))
+ val currentStatesConverted by
+ collectValues(underTest.getOrCreateFlow(Edge(LOCKSCREEN, UNDEFINED)))
+
+ sceneTransitions.value = lsToGone
+ val sendStep1 = TransitionStep(LOCKSCREEN, UNDEFINED, 0f, STARTED)
+ val sendStep2 = TransitionStep(LOCKSCREEN, UNDEFINED, 1f, FINISHED)
+ val sendStep3 = TransitionStep(LOCKSCREEN, AOD, 0f, STARTED)
+ sendSteps(sendStep1, sendStep2, sendStep3)
+
+ assertEquals(listOf(sendStep1, sendStep2), currentStates)
+ assertEquals(listOf(sendStep1, sendStep2), currentStatesConverted)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun getOrCreateFlow_conversion_emits_nothing_with_sceneContainer_in_wrong_state() =
+ testScope.runTest {
+ val currentStates by collectValues(underTest.getOrCreateFlow(Edge(LOCKSCREEN, GONE)))
+
+ sceneTransitions.value = goneToLs
+ val sendStep1 = TransitionStep(LOCKSCREEN, UNDEFINED, 0f, STARTED)
+ val sendStep2 = TransitionStep(LOCKSCREEN, UNDEFINED, 1f, FINISHED)
+ val sendStep3 = TransitionStep(LOCKSCREEN, AOD, 0f, STARTED)
+ sendSteps(sendStep1, sendStep2, sendStep3)
+
+ assertEquals(listOf<TransitionStep>(), currentStates)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun getOrCreateFlow_conversion_emits_values_when_edge_within_lockscreen_scene() =
+ testScope.runTest {
+ val currentStates by collectValues(underTest.getOrCreateFlow(Edge(LOCKSCREEN, DOZING)))
+
+ sceneTransitions.value = goneToLs
+ val sendStep1 = TransitionStep(LOCKSCREEN, DOZING, 0f, STARTED)
+ val sendStep2 = TransitionStep(LOCKSCREEN, DOZING, 1f, FINISHED)
+ val sendStep3 = TransitionStep(LOCKSCREEN, AOD, 0f, STARTED)
+ sendSteps(sendStep1, sendStep2, sendStep3)
+
+ assertEquals(listOf(sendStep1, sendStep2), currentStates)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun getOrCreateFlow_conversion_emits_values_with_null_edge_within_lockscreen_scene() =
+ testScope.runTest {
+ val currentStates by collectValues(underTest.getOrCreateFlow(Edge(LOCKSCREEN, null)))
+ val currentStatesReversed by
+ collectValues(underTest.getOrCreateFlow(Edge(null, LOCKSCREEN)))
+
+ sceneTransitions.value = goneToLs
+ val sendStep1 = TransitionStep(LOCKSCREEN, DOZING, 0f, STARTED)
+ val sendStep2 = TransitionStep(LOCKSCREEN, DOZING, 1f, FINISHED)
+ val sendStep3 = TransitionStep(LOCKSCREEN, AOD, 0f, STARTED)
+ val sendStep4 = TransitionStep(AOD, LOCKSCREEN, 0f, STARTED)
+ sendSteps(sendStep1, sendStep2, sendStep3, sendStep4)
+
+ assertEquals(listOf(sendStep1, sendStep2, sendStep3), currentStates)
+ assertEquals(listOf(sendStep4), currentStatesReversed)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun getOrCreateFlow_conversion_emits_values_with_null_edge_out_of_lockscreen_scene() =
+ testScope.runTest {
+ val currentStates by collectValues(underTest.getOrCreateFlow(Edge(null, UNDEFINED)))
+ val currentStatesMapped by collectValues(underTest.getOrCreateFlow(Edge(null, GONE)))
+
+ sceneTransitions.value = lsToGone
+ val sendStep1 = TransitionStep(LOCKSCREEN, UNDEFINED, 0f, STARTED)
+ val sendStep2 = TransitionStep(LOCKSCREEN, UNDEFINED, 1f, FINISHED)
+ val sendStep3 = TransitionStep(UNDEFINED, AOD, 0f, STARTED)
+ val sendStep4 = TransitionStep(AOD, LOCKSCREEN, 0f, STARTED)
+ sendSteps(sendStep1, sendStep2, sendStep3, sendStep4)
+
+ assertEquals(listOf(sendStep1, sendStep2), currentStates)
+ assertEquals(listOf(sendStep1, sendStep2), currentStatesMapped)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun getOrCreateFlow_conversion_does_not_emit_with_null_edge_with_wrong_stl_state() =
+ testScope.runTest {
+ val currentStatesMapped by collectValues(underTest.getOrCreateFlow(Edge(null, GONE)))
+
+ sceneTransitions.value = goneToLs
+ val sendStep1 = TransitionStep(LOCKSCREEN, UNDEFINED, 0f, STARTED)
+ val sendStep2 = TransitionStep(LOCKSCREEN, UNDEFINED, 1f, FINISHED)
+ val sendStep3 = TransitionStep(UNDEFINED, AOD, 0f, STARTED)
+ val sendStep4 = TransitionStep(AOD, LOCKSCREEN, 0f, STARTED)
+ sendSteps(sendStep1, sendStep2, sendStep3, sendStep4)
+
+ assertEquals(listOf<TransitionStep>(), currentStatesMapped)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun getOrCreateFlow_null_edges_throw() =
+ testScope.runTest {
+ assertThrows(IllegalStateException::class.java) {
+ underTest.getOrCreateFlow(Edge(null, null))
+ }
+ }
+
private suspend fun sendSteps(vararg steps: TransitionStep) {
steps.forEach {
repository.sendTransitionStep(it)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
index d63293675034..7a9bd924afa4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
@@ -87,6 +87,7 @@ class BouncerToGoneFlowsTest(flags: FlagsParameterization) : SysuiTestCase() {
}
@Test
+ @BrokenWithSceneContainer(339465026)
fun scrimAlpha_runDimissFromKeyguard_shadeExpanded() =
testScope.runTest {
val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER))
@@ -137,6 +138,7 @@ class BouncerToGoneFlowsTest(flags: FlagsParameterization) : SysuiTestCase() {
}
@Test
+ @BrokenWithSceneContainer(339465026)
fun scrimBehindAlpha_leaveShadeOpen() =
testScope.runTest {
val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER))
@@ -161,6 +163,7 @@ class BouncerToGoneFlowsTest(flags: FlagsParameterization) : SysuiTestCase() {
}
@Test
+ @BrokenWithSceneContainer(339465026)
fun showAllNotifications_isTrue_whenLeaveShadeOpen() =
testScope.runTest {
val showAllNotifications by
@@ -177,6 +180,7 @@ class BouncerToGoneFlowsTest(flags: FlagsParameterization) : SysuiTestCase() {
}
@Test
+ @BrokenWithSceneContainer(339465026)
fun showAllNotifications_isFalse_whenLeaveShadeIsNotOpen() =
testScope.runTest {
val showAllNotifications by
@@ -193,6 +197,7 @@ class BouncerToGoneFlowsTest(flags: FlagsParameterization) : SysuiTestCase() {
}
@Test
+ @BrokenWithSceneContainer(330311871)
fun scrimBehindAlpha_doNotLeaveShadeOpen() =
testScope.runTest {
val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER))
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 838b2a79adff..20ffa3312fa6 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
@@ -30,6 +30,8 @@ import com.android.systemui.communal.data.repository.communalRepository
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
+import com.android.systemui.flags.DisableSceneContainer
+import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.parameterizeSceneContainerFlag
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
@@ -37,7 +39,9 @@ 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.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor
import com.android.systemui.statusbar.phone.dozeParameters
@@ -49,6 +53,8 @@ import com.android.systemui.util.ui.stopAnimating
import com.android.systemui.util.ui.value
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -75,6 +81,11 @@ class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase()
private val viewState = ViewStateAccessor()
+ private val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(Scenes.Lockscreen)
+ )
+
companion object {
@JvmStatic
@Parameters(name = "{0}")
@@ -96,6 +107,7 @@ class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase()
AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT,
)
}
+ kosmos.sceneContainerRepository.setTransitionState(transitionState)
}
@Test
@@ -309,6 +321,32 @@ class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase()
}
@Test
+ @EnableSceneContainer
+ fun alpha_transitionToHub_isZero_scene_container() =
+ testScope.runTest {
+ val alpha by collectLastValue(underTest.alpha(viewState))
+
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.Lockscreen,
+ toScene = Scenes.Communal,
+ emptyFlow(),
+ emptyFlow(),
+ false,
+ emptyFlow()
+ )
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.UNDEFINED,
+ testScope,
+ )
+
+ assertThat(alpha).isEqualTo(0f)
+ }
+
+ @Test
+ @DisableSceneContainer
fun alpha_transitionToHub_isZero() =
testScope.runTest {
val alpha by collectLastValue(underTest.alpha(viewState))
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt
index 58c6817c4270..1c1fcc450d73 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt
@@ -18,8 +18,10 @@ package com.android.systemui.keyguard.ui.viewmodel
import android.platform.test.flag.junit.FlagsParameterization
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.flags.BrokenWithSceneContainer
import com.android.systemui.flags.Flags
import com.android.systemui.flags.andSceneContainer
import com.android.systemui.flags.fakeFeatureFlagsClassic
@@ -30,11 +32,16 @@ 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.kosmos.testScope
+import com.android.systemui.scene.data.repository.sceneContainerRepository
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.testKosmos
import com.google.common.collect.Range
import com.google.common.truth.Truth
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -58,6 +65,11 @@ class LockscreenToPrimaryBouncerTransitionViewModelTest(flags: FlagsParameteriza
private val keyguardRepository = kosmos.fakeKeyguardRepository
private lateinit var underTest: LockscreenToPrimaryBouncerTransitionViewModel
+ private val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(Scenes.Lockscreen)
+ )
+
companion object {
@JvmStatic
@Parameters(name = "{0}")
@@ -76,6 +88,7 @@ class LockscreenToPrimaryBouncerTransitionViewModelTest(flags: FlagsParameteriza
}
@Test
+ @BrokenWithSceneContainer(330311871)
fun deviceEntryParentViewAlpha_shadeExpanded() =
testScope.runTest {
val actual by collectLastValue(underTest.deviceEntryParentViewAlpha)
@@ -107,6 +120,17 @@ class LockscreenToPrimaryBouncerTransitionViewModelTest(flags: FlagsParameteriza
shadeExpanded(false)
runCurrent()
+ kosmos.sceneContainerRepository.setTransitionState(transitionState)
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.Lockscreen,
+ toScene = Scenes.Bouncer,
+ emptyFlow(),
+ emptyFlow(),
+ false,
+ emptyFlow()
+ )
+ runCurrent()
// fade out
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
runCurrent()
@@ -132,7 +156,9 @@ class LockscreenToPrimaryBouncerTransitionViewModelTest(flags: FlagsParameteriza
): TransitionStep {
return TransitionStep(
from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.PRIMARY_BOUNCER,
+ to =
+ if (SceneContainerFlag.isEnabled) KeyguardState.UNDEFINED
+ else KeyguardState.PRIMARY_BOUNCER,
value = value,
transitionState = state,
ownerName = "LockscreenToPrimaryBouncerTransitionViewModelTest"
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index da17366a8416..82e2bb719818 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -30,6 +30,7 @@ import com.android.systemui.common.shared.model.NotificationContainerBounds
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
+import com.android.systemui.flags.BrokenWithSceneContainer
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.Flags
@@ -107,18 +108,25 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S
val testScope = kosmos.testScope
val configurationRepository
get() = kosmos.fakeConfigurationRepository
+
val keyguardRepository
get() = kosmos.fakeKeyguardRepository
+
val keyguardInteractor
get() = kosmos.keyguardInteractor
+
val keyguardRootViewModel
get() = kosmos.keyguardRootViewModel
+
val keyguardTransitionRepository
get() = kosmos.fakeKeyguardTransitionRepository
+
val shadeTestUtil
get() = kosmos.shadeTestUtil
+
val sharedNotificationContainerInteractor
get() = kosmos.sharedNotificationContainerInteractor
+
val largeScreenHeaderHelper
get() = kosmos.mockLargeScreenHeaderHelper
@@ -814,6 +822,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S
}
@Test
+ @BrokenWithSceneContainer(330311871)
fun alphaDoesNotUpdateWhileGoneTransitionIsRunning() =
testScope.runTest {
val viewState = ViewStateAccessor()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index aad1ec5f0031..9e863a38a8ee 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -20,6 +20,7 @@ package com.android.systemui.keyguard.domain.interactor
import android.annotation.FloatRange
import android.annotation.SuppressLint
import android.util.Log
+import com.android.compose.animation.scene.SceneKey
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardRepository
@@ -31,10 +32,13 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
+import com.android.systemui.keyguard.shared.model.KeyguardState.UNDEFINED
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
+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.util.kotlin.pairwise
import java.util.UUID
import javax.inject.Inject
@@ -71,6 +75,7 @@ constructor(
private val fromAlternateBouncerTransitionInteractor:
dagger.Lazy<FromAlternateBouncerTransitionInteractor>,
private val fromDozingTransitionInteractor: dagger.Lazy<FromDozingTransitionInteractor>,
+ private val sceneInteractor: dagger.Lazy<SceneInteractor>,
) {
private val transitionMap = mutableMapOf<Edge, MutableSharedFlow<TransitionStep>>()
@@ -152,17 +157,73 @@ constructor(
}
}
- /** Given an [edge], return a SharedFlow to collect only relevant [TransitionStep]. */
+ /** Given an [edge], return a Flow to collect only relevant [TransitionStep]s. */
@SuppressLint("SharedFlowCreation")
- fun getOrCreateFlow(edge: Edge): MutableSharedFlow<TransitionStep> {
- return transitionMap.getOrPut(edge) {
- MutableSharedFlow(
- extraBufferCapacity = 10,
- onBufferOverflow = BufferOverflow.DROP_OLDEST
+ fun getOrCreateFlow(edge: Edge): Flow<TransitionStep> {
+ check(!(edge.from == null && edge.to == null)) { "to and from can't both be null" }
+ val mappedEdge = getMappedEdge(edge)
+
+ val flow: Flow<TransitionStep> =
+ transitionMap.getOrPut(mappedEdge) {
+ MutableSharedFlow(
+ extraBufferCapacity = 10,
+ onBufferOverflow = BufferOverflow.DROP_OLDEST
+ )
+ }
+
+ return if (SceneContainerFlag.isEnabled) {
+ flow.filter {
+ val fromScene = edge.from?.mapToSceneContainerScene()
+ val toScene = edge.to?.mapToSceneContainerScene()
+
+ fun SceneKey?.isLockscreenOrNull() = this == Scenes.Lockscreen || this == null
+
+ return@filter (fromScene.isLockscreenOrNull() && toScene.isLockscreenOrNull()) ||
+ sceneInteractor.get().transitionState.value.isTransitioning(fromScene, toScene)
+ }
+ } else {
+ flow
+ }
+ }
+
+ /**
+ * Converts old KTF states to UNDEFINED when [SceneContainerFlag] is enabled.
+ *
+ * Does nothing otherwise.
+ *
+ * This method should eventually be removed when new code is only written for scene container.
+ * Even when all edges are ported today, there is still development on going in production that
+ * might utilize old states.
+ */
+ private fun getMappedEdge(edge: Edge): Edge {
+ if (!SceneContainerFlag.isEnabled) return edge
+
+ val newEdge =
+ Edge(
+ from = edge.from?.mapToSceneContainerState(),
+ to = edge.to?.mapToSceneContainerState()
+ )
+ if (newEdge.from == UNDEFINED && newEdge.to == UNDEFINED) {
+ Log.e(
+ TAG,
+ "The edge ${edge.from?.name} => ${edge.to?.name} was automatically " +
+ "converted to ${newEdge.from.name} => ${newEdge.to.name} but does not " +
+ "exist anymore in KTF. Please remove or port this edge to scene " +
+ "container."
+ )
+ } else if (newEdge.from != edge.from || newEdge.to != edge.to) {
+ Log.w(
+ TAG,
+ "The edge ${edge.from?.name} => ${edge.to?.name} was automatically " +
+ "converted to ${newEdge.from?.name} => ${newEdge.to?.name} (+ Scene " +
+ "filter). This should work but should eventually be ported to " +
+ "define the correct transition explicitly."
)
}
+ return newEdge
}
+
/**
* Receive all [TransitionStep] matching a filter of [from]->[to]. Allow nulls in order to match
* any transition, for instance (any)->GONE.
@@ -536,6 +597,6 @@ constructor(
) = repository.updateTransition(transitionId, value, state)
companion object {
- private const val TAG = "KeyguardTransitionInteractor"
+ private val TAG = KeyguardTransitionInteractor::class.simpleName
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
index 6d96db34e23a..6a2bb5f51c5d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
@@ -15,6 +15,9 @@
*/
package com.android.systemui.keyguard.shared.model
+import com.android.compose.animation.scene.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
+
/** List of all possible states to transition to/from */
enum class KeyguardState {
/**
@@ -84,6 +87,40 @@ enum class KeyguardState {
/** An activity is displaying over the keyguard. */
OCCLUDED;
+ fun mapToSceneContainerState(): KeyguardState {
+ return when (this) {
+ OFF,
+ DOZING,
+ DREAMING,
+ DREAMING_LOCKSCREEN_HOSTED,
+ AOD,
+ ALTERNATE_BOUNCER,
+ OCCLUDED,
+ LOCKSCREEN -> this
+ GLANCEABLE_HUB,
+ PRIMARY_BOUNCER,
+ GONE,
+ UNDEFINED -> UNDEFINED
+ }
+ }
+
+ fun mapToSceneContainerScene(): SceneKey? {
+ return when (this) {
+ OFF,
+ DOZING,
+ DREAMING,
+ DREAMING_LOCKSCREEN_HOSTED,
+ AOD,
+ ALTERNATE_BOUNCER,
+ OCCLUDED,
+ LOCKSCREEN -> Scenes.Lockscreen
+ GLANCEABLE_HUB -> Scenes.Communal
+ PRIMARY_BOUNCER -> Scenes.Bouncer
+ GONE -> Scenes.Gone
+ UNDEFINED -> null
+ }
+ }
+
companion object {
/** Whether the lockscreen is visible when we're FINISHED in the given state. */
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt
index 6cc1e8eba73d..c90642d93939 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt
@@ -20,6 +20,7 @@ import com.android.systemui.keyguard.data.repository.keyguardRepository
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.scene.domain.interactor.sceneInteractor
val Kosmos.keyguardTransitionInteractor: KeyguardTransitionInteractor by
Kosmos.Fixture {
@@ -32,5 +33,6 @@ val Kosmos.keyguardTransitionInteractor: KeyguardTransitionInteractor by
fromAodTransitionInteractor = { fromAodTransitionInteractor },
fromAlternateBouncerTransitionInteractor = { fromAlternateBouncerTransitionInteractor },
fromDozingTransitionInteractor = { fromDozingTransitionInteractor },
+ sceneInteractor = { sceneInteractor }
)
}