Merge changes I2928567e,I81171f04 into main
* changes:
Add transition for glanceble hub -> dream
Handle dream->glanceable_hub transitions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
index d86b35d..92396e0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
@@ -93,25 +93,6 @@
}
@Test
- fun deviceDreaming_forceBlankScene() =
- with(kosmos) {
- testScope.runTest {
- val scene by collectLastValue(communalInteractor.desiredScene)
-
- communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
- assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
-
- fakeKeyguardTransitionRepository.sendTransitionSteps(
- from = KeyguardState.GLANCEABLE_HUB,
- to = KeyguardState.DREAMING,
- testScope = this
- )
-
- assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
- }
- }
-
- @Test
fun deviceDocked_forceCommunalScene() =
with(kosmos) {
testScope.runTest {
@@ -125,13 +106,6 @@
testScope = this
)
assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
-
- fakeKeyguardTransitionRepository.sendTransitionSteps(
- from = KeyguardState.GLANCEABLE_HUB,
- to = KeyguardState.DREAMING,
- testScope = this
- )
- assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
index a6715df..c670506 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
@@ -11,7 +11,6 @@
import com.android.systemui.dreams.ui.viewmodel.DreamOverlayViewModel
import com.android.systemui.log.core.FakeLogBuffer
import com.android.systemui.statusbar.BlurUtils
-import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
@@ -46,7 +45,6 @@
@Mock private lateinit var hostViewController: ComplicationHostViewController
@Mock private lateinit var statusBarViewController: DreamOverlayStatusBarViewController
@Mock private lateinit var stateController: DreamOverlayStateController
- @Mock private lateinit var configController: ConfigurationController
@Mock private lateinit var transitionViewModel: DreamOverlayViewModel
private val logBuffer = FakeLogBuffer.Factory.create()
private lateinit var controller: DreamOverlayAnimationsController
@@ -62,7 +60,6 @@
stateController,
DREAM_BLUR_RADIUS,
transitionViewModel,
- configController,
DREAM_IN_BLUR_ANIMATION_DURATION,
DREAM_IN_COMPLICATIONS_ANIMATION_DURATION,
DREAM_IN_TRANSLATION_Y_DISTANCE,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt
index 4defe8a..aba21c9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt
@@ -19,12 +19,14 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectValues
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.res.R
import com.android.systemui.testKosmos
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
@@ -38,6 +40,7 @@
val kosmos = testKosmos()
val testScope = kosmos.testScope
+ val configurationRepository by lazy { kosmos.fakeConfigurationRepository }
val underTest by lazy { kosmos.dreamingToGlanceableHubTransitionViewModel }
@Test
@@ -66,7 +69,12 @@
@Test
fun dreamOverlayTranslationX() =
testScope.runTest {
- val values by collectValues(underTest.dreamOverlayTranslationX(100))
+ configurationRepository.setDimensionPixelSize(
+ R.dimen.dreaming_to_hub_transition_dream_overlay_translation_x,
+ -100
+ )
+
+ val values by collectValues(underTest.dreamOverlayTranslationX)
assertThat(values).isEmpty()
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelTest.kt
new file mode 100644
index 0000000..11890c7
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelTest.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2024 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.common.ui.data.repository.fakeConfigurationRepository
+import com.android.systemui.coroutines.collectValues
+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.res.R
+import com.android.systemui.testKosmos
+import com.google.common.collect.Range
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class GlanceableHubToDreamingTransitionViewModelTest : SysuiTestCase() {
+ val kosmos = testKosmos()
+ val testScope = kosmos.testScope
+
+ val configurationRepository by lazy { kosmos.fakeConfigurationRepository }
+ val underTest by lazy { kosmos.glanceableHubToDreamingTransitionViewModel }
+
+ @Test
+ fun dreamOverlayAlpha() =
+ testScope.runTest {
+ val values by collectValues(underTest.dreamOverlayAlpha)
+ assertThat(values).isEmpty()
+
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+ listOf(
+ step(0f, TransitionState.STARTED),
+ step(0f),
+ // Should start running here...
+ step(0.1f),
+ step(0.5f),
+ // Up to here...
+ step(1f),
+ ),
+ testScope,
+ )
+
+ assertThat(values).hasSize(2)
+ values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
+ }
+
+ @Test
+ fun dreamOverlayTranslationX() =
+ testScope.runTest {
+ configurationRepository.setDimensionPixelSize(
+ R.dimen.hub_to_dreaming_transition_dream_overlay_translation_x,
+ 100
+ )
+
+ val values by collectValues(underTest.dreamOverlayTranslationX)
+ assertThat(values).isEmpty()
+
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+ listOf(
+ step(0f, TransitionState.STARTED),
+ step(0.3f),
+ step(0.6f),
+ ),
+ testScope,
+ )
+
+ assertThat(values).hasSize(3)
+ values.forEach { assertThat(it).isIn(Range.closed(-100f, 0f)) }
+ }
+
+ private fun step(
+ value: Float,
+ state: TransitionState = TransitionState.RUNNING
+ ): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.GLANCEABLE_HUB,
+ to = KeyguardState.DREAMING,
+ value = value,
+ transitionState = state,
+ ownerName = GlanceableHubToDreamingTransitionViewModelTest::class.java.simpleName
+ )
+ }
+}
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5436642..4be1deb 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1518,6 +1518,12 @@
<!-- GLANCEABLE_HUB -> LOCKSCREEN transition: Amount to shift lockscreen content on entering -->
<dimen name="hub_to_lockscreen_transition_lockscreen_translation_x">824dp</dimen>
+ <!-- DREAMING -> GLANCEABLE_HUB transition: Amount to shift dream overlay on entering -->
+ <dimen name="dreaming_to_hub_transition_dream_overlay_translation_x">-824dp</dimen>
+
+ <!-- GLANCEABLE_HUB -> DREAMING transition: Amount to shift dream overlay on entering -->
+ <dimen name="hub_to_dreaming_transition_dream_overlay_translation_x">824dp</dimen>
+
<!-- Distance that the full shade transition takes in order for media to fully transition to
the shade -->
<dimen name="lockscreen_shade_media_transition_distance">120dp</dimen>
@@ -1861,7 +1867,6 @@
<dimen name="dream_overlay_y_offset">80dp</dimen>
<dimen name="dream_overlay_entry_y_offset">40dp</dimen>
<dimen name="dream_overlay_exit_y_offset">40dp</dimen>
- <dimen name="dream_overlay_exit_x_offset">824dp</dimen>
<dimen name="status_view_margin_horizontal">0dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index f7ba5a4..8397372 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -88,7 +88,6 @@
val docked = dockManager.isDocked
return when {
- to == KeyguardState.DREAMING -> CommunalSceneKey.Blank
docked && to == KeyguardState.LOCKSCREEN && from != KeyguardState.GLANCEABLE_HUB -> {
CommunalSceneKey.Communal
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index 9000da3..b97bace 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -40,7 +40,6 @@
import com.android.systemui.log.dagger.DreamLog
import com.android.systemui.statusbar.BlurUtils
import com.android.systemui.statusbar.CrossFadeHelper
-import com.android.systemui.statusbar.policy.ConfigurationController
import javax.inject.Inject
import javax.inject.Named
import kotlinx.coroutines.launch
@@ -55,7 +54,6 @@
private val mOverlayStateController: DreamOverlayStateController,
@Named(DreamOverlayModule.DREAM_BLUR_RADIUS) private val mDreamBlurRadius: Int,
private val dreamOverlayViewModel: DreamOverlayViewModel,
- private val configController: ConfigurationController,
@Named(DreamOverlayModule.DREAM_IN_BLUR_ANIMATION_DURATION)
private val mDreamInBlurAnimDurationMs: Long,
@Named(DreamOverlayModule.DREAM_IN_COMPLICATIONS_ANIMATION_DURATION)
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamOverlayViewModel.kt b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamOverlayViewModel.kt
index dd67a4c..bd99f4b 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamOverlayViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamOverlayViewModel.kt
@@ -20,6 +20,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.ui.viewmodel.DreamingToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransitionViewModel
import com.android.systemui.res.R
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -33,16 +34,16 @@
@Inject
constructor(
configurationInteractor: ConfigurationInteractor,
- private val toGlanceableHubTransitionViewModel: DreamingToGlanceableHubTransitionViewModel,
+ toGlanceableHubTransitionViewModel: DreamingToGlanceableHubTransitionViewModel,
+ fromGlanceableHubTransitionInteractor: GlanceableHubToDreamingTransitionViewModel,
private val toLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel,
) {
val dreamOverlayTranslationX: Flow<Float> =
- configurationInteractor
- .dimensionPixelSize(R.dimen.dream_overlay_exit_x_offset)
- .flatMapLatest { px: Int ->
- toGlanceableHubTransitionViewModel.dreamOverlayTranslationX(px)
- }
+ merge(
+ toGlanceableHubTransitionViewModel.dreamOverlayTranslationX,
+ fromGlanceableHubTransitionInteractor.dreamOverlayTranslationX,
+ )
val dreamOverlayTranslationY: Flow<Float> =
configurationInteractor
@@ -55,6 +56,7 @@
merge(
toLockscreenTransitionViewModel.dreamOverlayAlpha,
toGlanceableHubTransitionViewModel.dreamOverlayAlpha,
+ fromGlanceableHubTransitionInteractor.dreamOverlayAlpha,
)
val transitionEnded = toLockscreenTransitionViewModel.transitionEnded
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index c6594ef..acfa107 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -18,6 +18,7 @@
import android.animation.ValueAnimator
import com.android.app.animation.Interpolators
+import com.android.app.tracing.coroutines.launch
import com.android.systemui.Flags.communalHub
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
@@ -64,12 +65,13 @@
private fun listenForDreamingToGlanceableHub() {
if (!communalHub()) return
- glanceableHubTransitions.listenForGlanceableHubTransition(
- transitionName = "listenForDreamingToGlanceableHub",
- transitionOwnerName = TAG,
- fromState = KeyguardState.DREAMING,
- toState = KeyguardState.GLANCEABLE_HUB,
- )
+ scope.launch("$TAG#listenForDreamingToGlanceableHub", mainDispatcher) {
+ glanceableHubTransitions.listenForGlanceableHubTransition(
+ transitionOwnerName = TAG,
+ fromState = KeyguardState.DREAMING,
+ toState = KeyguardState.GLANCEABLE_HUB,
+ )
+ }
}
fun startToLockscreenTransition() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
index fbf195e..786c3c6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
@@ -27,13 +27,16 @@
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.power.domain.interactor.PowerInteractor
-import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleMultiple
+import com.android.systemui.util.kotlin.BooleanFlowOperators.and
+import com.android.systemui.util.kotlin.BooleanFlowOperators.not
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
@SysUISingleton
class FromGlanceableHubTransitionInteractor
@@ -58,13 +61,12 @@
if (!Flags.communalHub()) {
return
}
- listenForHubToLockscreen()
+ listenForHubToLockscreenOrDreaming()
listenForHubToDozing()
listenForHubToPrimaryBouncer()
listenForHubToAlternateBouncer()
listenForHubToOccluded()
listenForHubToGone()
- listenForHubToDreaming()
}
override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
@@ -82,13 +84,24 @@
* Listens for the glanceable hub transition to lock screen and directly drives the keyguard
* transition.
*/
- private fun listenForHubToLockscreen() {
- glanceableHubTransitions.listenForGlanceableHubTransition(
- transitionName = "listenForHubToLockscreen",
- transitionOwnerName = TAG,
- fromState = KeyguardState.GLANCEABLE_HUB,
- toState = KeyguardState.LOCKSCREEN,
- )
+ private fun listenForHubToLockscreenOrDreaming() {
+ scope.launch("$TAG#listenForGlanceableHubToLockscreenOrDream") {
+ keyguardInteractor.isDreaming.collectLatest { dreaming ->
+ withContext(mainDispatcher) {
+ val toState =
+ if (dreaming) {
+ KeyguardState.DREAMING
+ } else {
+ KeyguardState.LOCKSCREEN
+ }
+ glanceableHubTransitions.listenForGlanceableHubTransition(
+ transitionOwnerName = TAG,
+ fromState = KeyguardState.GLANCEABLE_HUB,
+ toState = toState,
+ )
+ }
+ }
+ }
}
private fun listenForHubToPrimaryBouncer() {
@@ -137,31 +150,15 @@
}
}
- private fun listenForHubToDreaming() {
- val invalidFromStates = setOf(KeyguardState.AOD, KeyguardState.DOZING)
- scope.launch("$TAG#listenForHubToDreaming") {
- keyguardInteractor.isAbleToDream
- .sampleMultiple(startedKeyguardTransitionStep, finishedKeyguardState)
- .collect { (isAbleToDream, lastStartedTransition, finishedKeyguardState) ->
- val isOnHub = finishedKeyguardState == KeyguardState.GLANCEABLE_HUB
- val isTransitionInterruptible =
- lastStartedTransition.to == KeyguardState.GLANCEABLE_HUB &&
- !invalidFromStates.contains(lastStartedTransition.from)
- if (isAbleToDream && (isOnHub || isTransitionInterruptible)) {
- startTransitionTo(KeyguardState.DREAMING)
- }
- }
- }
- }
-
private fun listenForHubToOccluded() {
scope.launch {
- keyguardInteractor.isKeyguardOccluded.sample(startedKeyguardState, ::Pair).collect {
- (isOccluded, keyguardState) ->
- if (isOccluded && keyguardState == fromState) {
- startTransitionTo(KeyguardState.OCCLUDED)
+ and(keyguardInteractor.isKeyguardOccluded, not(keyguardInteractor.isDreaming))
+ .sample(startedKeyguardState, ::Pair)
+ .collect { (isOccludedAndNotDreaming, keyguardState) ->
+ if (isOccludedAndNotDreaming && keyguardState == fromState) {
+ startTransitionTo(KeyguardState.OCCLUDED)
+ }
}
- }
}
}
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 40b2c63..7263ae9 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
@@ -360,13 +360,13 @@
if (!com.android.systemui.Flags.communalHub()) {
return
}
-
- glanceableHubTransitions.listenForGlanceableHubTransition(
- transitionName = "listenForLockscreenToGlanceableHub",
- transitionOwnerName = TAG,
- fromState = KeyguardState.LOCKSCREEN,
- toState = KeyguardState.GLANCEABLE_HUB,
- )
+ scope.launch(mainDispatcher) {
+ glanceableHubTransitions.listenForGlanceableHubTransition(
+ transitionOwnerName = TAG,
+ fromState = KeyguardState.LOCKSCREEN,
+ toState = KeyguardState.GLANCEABLE_HUB,
+ )
+ }
}
override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt
index 809c0aee..6cb1eb4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt
@@ -18,11 +18,9 @@
import android.animation.ValueAnimator
import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.launch
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalTransitionProgress
import com.android.systemui.communal.shared.model.CommunalSceneKey
-import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -32,13 +30,11 @@
import java.util.UUID
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.flowOn
class GlanceableHubTransitions
@Inject
constructor(
- @Application private val scope: CoroutineScope,
@Background private val bgDispatcher: CoroutineDispatcher,
private val transitionInteractor: KeyguardTransitionInteractor,
private val transitionRepository: KeyguardTransitionRepository,
@@ -52,105 +48,101 @@
* externally. The progress is used for both transitions caused by user touch input or by
* programmatic changes.
*/
- fun listenForGlanceableHubTransition(
- transitionName: String,
+ suspend fun listenForGlanceableHubTransition(
transitionOwnerName: String,
fromState: KeyguardState,
toState: KeyguardState,
) {
val toScene =
- if (toState == KeyguardState.GLANCEABLE_HUB) {
- CommunalSceneKey.Communal
- } else {
+ if (fromState == KeyguardState.GLANCEABLE_HUB) {
CommunalSceneKey.Blank
+ } else {
+ CommunalSceneKey.Communal
}
var transitionId: UUID? = null
- scope.launch("$transitionOwnerName#$transitionName") {
- communalInteractor
- .transitionProgressToScene(toScene)
- .sample(
- transitionInteractor.startedKeyguardTransitionStep.flowOn(bgDispatcher),
- ::Pair
- )
- .collect { pair ->
- val (transitionProgress, lastStartedStep) = pair
- val id = transitionId
- if (id == null) {
- // No transition started.
- if (
- transitionProgress is CommunalTransitionProgress.Transition &&
- lastStartedStep.to == fromState
- ) {
- transitionId =
- transitionRepository.startTransition(
- TransitionInfo(
- ownerName = transitionOwnerName,
- from = fromState,
- to = toState,
- animator = null, // transition will be manually controlled
- )
+ communalInteractor
+ .transitionProgressToScene(toScene)
+ .sample(
+ transitionInteractor.startedKeyguardTransitionStep.flowOn(bgDispatcher),
+ ::Pair,
+ )
+ .collect { (transitionProgress, lastStartedStep) ->
+ val id = transitionId
+ if (id == null) {
+ // No transition started.
+ if (
+ transitionProgress is CommunalTransitionProgress.Transition &&
+ lastStartedStep.to == fromState
+ ) {
+ transitionId =
+ transitionRepository.startTransition(
+ TransitionInfo(
+ ownerName = transitionOwnerName,
+ from = fromState,
+ to = toState,
+ animator = null, // transition will be manually controlled
)
- }
- } else {
- if (lastStartedStep.to != toState) {
- return@collect
- }
- // An existing `id` means a transition is started, and calls to
- // `updateTransition` will control it until FINISHED or CANCELED
- val nextState: TransitionState
- val progressFraction: Float
- when (transitionProgress) {
- is CommunalTransitionProgress.Idle -> {
- if (transitionProgress.scene == toScene) {
- nextState = TransitionState.FINISHED
- progressFraction = 1f
- } else {
- nextState = TransitionState.CANCELED
- progressFraction = 0f
- }
- }
- is CommunalTransitionProgress.Transition -> {
- nextState = TransitionState.RUNNING
- progressFraction = transitionProgress.progress
- }
- is CommunalTransitionProgress.OtherTransition -> {
- // Shouldn't happen but if another transition starts during the
- // current one, mark the current one as canceled.
+ )
+ }
+ } else {
+ if (lastStartedStep.to != toState) {
+ return@collect
+ }
+ // An existing `id` means a transition is started, and calls to
+ // `updateTransition` will control it until FINISHED or CANCELED
+ val nextState: TransitionState
+ val progressFraction: Float
+ when (transitionProgress) {
+ is CommunalTransitionProgress.Idle -> {
+ if (transitionProgress.scene == toScene) {
+ nextState = TransitionState.FINISHED
+ progressFraction = 1f
+ } else {
nextState = TransitionState.CANCELED
progressFraction = 0f
}
}
- transitionRepository.updateTransition(
- id,
- progressFraction,
- nextState,
- )
-
- if (
- nextState == TransitionState.CANCELED ||
- nextState == TransitionState.FINISHED
- ) {
- transitionId = null
+ is CommunalTransitionProgress.Transition -> {
+ nextState = TransitionState.RUNNING
+ progressFraction = transitionProgress.progress
}
-
- // If canceled, just put the state back.
- if (nextState == TransitionState.CANCELED) {
- transitionRepository.startTransition(
- TransitionInfo(
- ownerName = transitionOwnerName,
- from = toState,
- to = fromState,
- animator =
- ValueAnimator().apply {
- interpolator = Interpolators.LINEAR
- duration = 0
- }
- )
- )
+ is CommunalTransitionProgress.OtherTransition -> {
+ // Shouldn't happen but if another transition starts during the
+ // current one, mark the current one as canceled.
+ nextState = TransitionState.CANCELED
+ progressFraction = 0f
}
}
+ transitionRepository.updateTransition(
+ id,
+ progressFraction,
+ nextState,
+ )
+
+ if (
+ nextState == TransitionState.CANCELED ||
+ nextState == TransitionState.FINISHED
+ ) {
+ transitionId = null
+ }
+
+ // If canceled, just put the state back.
+ if (nextState == TransitionState.CANCELED) {
+ transitionRepository.startTransition(
+ TransitionInfo(
+ ownerName = transitionOwnerName,
+ from = toState,
+ to = fromState,
+ animator =
+ ValueAnimator().apply {
+ interpolator = Interpolators.LINEAR
+ duration = 0
+ }
+ )
+ )
+ }
}
- }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
index 374a932..c64f277 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
@@ -17,18 +17,26 @@
package com.android.systemui.keyguard.ui.viewmodel
import com.android.app.animation.Interpolators.EMPHASIZED
+import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.res.R
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class DreamingToGlanceableHubTransitionViewModel
@Inject
-constructor(animationFlow: KeyguardTransitionAnimationFlow) {
+constructor(
+ animationFlow: KeyguardTransitionAnimationFlow,
+ configurationInteractor: ConfigurationInteractor,
+) {
private val transitionAnimation =
animationFlow.setup(
@@ -37,14 +45,18 @@
to = KeyguardState.GLANCEABLE_HUB,
)
- fun dreamOverlayTranslationX(translatePx: Int): Flow<Float> {
- return transitionAnimation.sharedFlow(
- duration = TO_GLANCEABLE_HUB_DURATION,
- onStep = { it * -translatePx },
- interpolator = EMPHASIZED,
- name = "DREAMING->GLANCEABLE_HUB: overlayTranslationX",
- )
- }
+ val dreamOverlayTranslationX: Flow<Float> =
+ configurationInteractor
+ .dimensionPixelSize(R.dimen.dreaming_to_hub_transition_dream_overlay_translation_x)
+ .flatMapLatest { translatePx ->
+ transitionAnimation.sharedFlow(
+ duration = TO_GLANCEABLE_HUB_DURATION,
+ onStep = { value -> value * translatePx },
+ interpolator = EMPHASIZED,
+ onCancel = { 0f },
+ name = "DREAMING->GLANCEABLE_HUB: overlayTranslationX",
+ )
+ }
val dreamOverlayAlpha: Flow<Float> =
transitionAnimation.sharedFlow(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt
new file mode 100644
index 0000000..478c4faa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 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.app.animation.Interpolators
+import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.res.R
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class GlanceableHubToDreamingTransitionViewModel
+@Inject
+constructor(
+ animationFlow: KeyguardTransitionAnimationFlow,
+ configurationInteractor: ConfigurationInteractor,
+) {
+
+ private val transitionAnimation =
+ animationFlow.setup(
+ duration = FROM_GLANCEABLE_HUB_DURATION,
+ from = KeyguardState.GLANCEABLE_HUB,
+ to = KeyguardState.DREAMING,
+ )
+
+ val dreamOverlayAlpha: Flow<Float> =
+ transitionAnimation.sharedFlow(
+ duration = 167.milliseconds,
+ startTime = 167.milliseconds,
+ onStep = { it },
+ name = "GLANCEABLE_HUB->DREAMING: dreamOverlayAlpha",
+ )
+
+ val dreamOverlayTranslationX: Flow<Float> =
+ configurationInteractor
+ .dimensionPixelSize(R.dimen.hub_to_dreaming_transition_dream_overlay_translation_x)
+ .flatMapLatest { translatePx: Int ->
+ transitionAnimation.sharedFlow(
+ duration = FROM_GLANCEABLE_HUB_DURATION,
+ onStep = { value -> -translatePx + value * translatePx },
+ interpolator = Interpolators.EMPHASIZED,
+ onCancel = { -translatePx.toFloat() },
+ name = "GLANCEABLE_HUB->LOCKSCREEN: dreamOverlayTranslationX"
+ )
+ }
+
+ private companion object {
+ val FROM_GLANCEABLE_HUB_DURATION = 1.seconds
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index abd4238..69cd173 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -129,7 +129,6 @@
val glanceableHubTransitions =
GlanceableHubTransitions(
- scope = testScope,
bgDispatcher = kosmos.testDispatcher,
transitionInteractor = transitionInteractor,
transitionRepository = transitionRepository,
@@ -1812,26 +1811,40 @@
@Test
fun glanceableHubToDreaming() =
testScope.runTest {
- // GIVEN a device that is not dreaming or dozing
- keyguardRepository.setDreamingWithOverlay(false)
+ // GIVEN that we are dreaming and not dozing
+ keyguardRepository.setDreaming(true)
keyguardRepository.setDozeTransitionModel(
DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
)
runCurrent()
// GIVEN a prior transition has run to GLANCEABLE_HUB
- runTransitionAndSetWakefulness(KeyguardState.LOCKSCREEN, KeyguardState.GLANCEABLE_HUB)
+ runTransitionAndSetWakefulness(KeyguardState.DREAMING, KeyguardState.GLANCEABLE_HUB)
+ runCurrent()
- // WHEN the device begins to dream
- keyguardRepository.setDreamingWithOverlay(true)
- advanceTimeBy(100L)
+ // WHEN a transition away from glanceable hub starts
+ val currentScene = CommunalSceneKey.Communal
+ val targetScene = CommunalSceneKey.Blank
+
+ val transitionState =
+ MutableStateFlow<ObservableCommunalTransitionState>(
+ ObservableCommunalTransitionState.Transition(
+ fromScene = currentScene,
+ toScene = targetScene,
+ progress = flowOf(0f, 0.1f),
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
+ )
+ )
+ communalInteractor.setTransitionState(transitionState)
+ runCurrent()
assertThat(transitionRepository)
.startedTransition(
ownerName = FromGlanceableHubTransitionInteractor::class.simpleName,
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.DREAMING,
- animatorAssertion = { it.isNotNull() },
+ animatorAssertion = { it.isNull() }, // transition should be manually animated
)
coroutineContext.cancelChildren()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt
index 55885bf..5dd5073 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt
@@ -19,13 +19,11 @@
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
val Kosmos.glanceableHubTransitions by
Kosmos.Fixture {
GlanceableHubTransitions(
- scope = applicationCoroutineScope,
bgDispatcher = testDispatcher,
transitionRepository = keyguardTransitionRepository,
transitionInteractor = keyguardTransitionInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelKosmos.kt
similarity index 87%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelKosmos.kt
index b370859..00741eb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelKosmos.kt
@@ -16,12 +16,14 @@
package com.android.systemui.keyguard.ui.viewmodel
+import com.android.systemui.common.ui.domain.interactor.configurationInteractor
import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
import com.android.systemui.kosmos.Kosmos
val Kosmos.dreamingToGlanceableHubTransitionViewModel by
Kosmos.Fixture {
DreamingToGlanceableHubTransitionViewModel(
+ configurationInteractor = configurationInteractor,
animationFlow = keyguardTransitionAnimationFlow,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelKosmos.kt
similarity index 77%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelKosmos.kt
index b370859..1302f15 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelKosmos.kt
@@ -16,12 +16,14 @@
package com.android.systemui.keyguard.ui.viewmodel
+import com.android.systemui.common.ui.domain.interactor.configurationInteractor
import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
import com.android.systemui.kosmos.Kosmos
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
+val Kosmos.glanceableHubToDreamingTransitionViewModel by
Kosmos.Fixture {
- DreamingToGlanceableHubTransitionViewModel(
+ GlanceableHubToDreamingTransitionViewModel(
+ configurationInteractor = configurationInteractor,
animationFlow = keyguardTransitionAnimationFlow,
)
}