• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.communal.ui.viewmodel
18 
19 import android.graphics.Color
20 import com.android.systemui.communal.domain.interactor.CommunalInteractor
21 import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
22 import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
23 import com.android.systemui.communal.shared.model.CommunalScenes
24 import com.android.systemui.communal.util.CommunalColors
25 import com.android.systemui.dagger.SysUISingleton
26 import com.android.systemui.dagger.qualifiers.Application
27 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
28 import com.android.systemui.keyguard.shared.model.Edge
29 import com.android.systemui.keyguard.shared.model.KeyguardState
30 import com.android.systemui.keyguard.shared.model.TransitionState
31 import com.android.systemui.keyguard.ui.viewmodel.DreamingToGlanceableHubTransitionViewModel
32 import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransitionViewModel
33 import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToLockscreenTransitionViewModel
34 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGlanceableHubTransitionViewModel
35 import com.android.systemui.scene.shared.flag.SceneContainerFlag
36 import com.android.systemui.scene.shared.model.Scenes
37 import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
38 import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
39 import javax.inject.Inject
40 import kotlinx.coroutines.CoroutineScope
41 import kotlinx.coroutines.flow.Flow
42 import kotlinx.coroutines.flow.SharingStarted
43 import kotlinx.coroutines.flow.combine
44 import kotlinx.coroutines.flow.distinctUntilChanged
45 import kotlinx.coroutines.flow.filter
46 import kotlinx.coroutines.flow.flowOf
47 import kotlinx.coroutines.flow.map
48 import kotlinx.coroutines.flow.merge
49 import kotlinx.coroutines.flow.onStart
50 import kotlinx.coroutines.flow.stateIn
51 
52 /** View model for transitions related to the communal hub. */
53 @SysUISingleton
54 class CommunalTransitionViewModel
55 @Inject
56 constructor(
57     @Application applicationScope: CoroutineScope,
58     communalColors: CommunalColors,
59     glanceableHubToLockscreenTransitionViewModel: GlanceableHubToLockscreenTransitionViewModel,
60     lockscreenToGlanceableHubTransitionViewModel: LockscreenToGlanceableHubTransitionViewModel,
61     dreamToGlanceableHubTransitionViewModel: DreamingToGlanceableHubTransitionViewModel,
62     glanceableHubToDreamTransitionViewModel: GlanceableHubToDreamingTransitionViewModel,
63     communalInteractor: CommunalInteractor,
64     private val communalSceneInteractor: CommunalSceneInteractor,
65     communalSettingsInteractor: CommunalSettingsInteractor,
66     keyguardTransitionInteractor: KeyguardTransitionInteractor,
67 ) {
68     /**
69      * Snaps to [CommunalScenes.Communal], showing the glanceable hub immediately without any
70      * transition.
71      */
72     fun snapToCommunal() {
73         communalSceneInteractor.snapToScene(
74             newScene = CommunalScenes.Communal,
75             loggingReason = "transition view model",
76         )
77     }
78 
79     // Show UMO on glanceable hub immediately on transition into glanceable hub
80     private val showUmoFromOccludedToGlanceableHub: Flow<Boolean> =
81         keyguardTransitionInteractor
82             .transition(
83                 Edge.create(from = KeyguardState.OCCLUDED, to = KeyguardState.GLANCEABLE_HUB)
84             )
85             .filter {
86                 (it.transitionState == TransitionState.STARTED ||
87                     it.transitionState == TransitionState.CANCELED)
88             }
89             .map { it.transitionState == TransitionState.STARTED }
90 
91     private val showUmoFromGlanceableHubToOccluded: Flow<Boolean> =
92         keyguardTransitionInteractor
93             .transition(
94                 edge = Edge.create(from = Scenes.Communal),
95                 edgeWithoutSceneContainer = Edge.create(from = KeyguardState.GLANCEABLE_HUB),
96             )
97             .filter {
98                 it.to == KeyguardState.OCCLUDED &&
99                     (it.transitionState == TransitionState.FINISHED ||
100                         it.transitionState == TransitionState.CANCELED)
101             }
102             .map { it.transitionState != TransitionState.FINISHED }
103 
104     /**
105      * Whether UMO location should be on communal. This flow is responsive to transitions so that a
106      * new value is emitted at the right step of a transition to/from communal hub that the location
107      * of UMO should be updated.
108      */
109     val isUmoOnCommunal: Flow<Boolean> =
110         anyOf(
111                 communalSceneInteractor.isIdleOnCommunal,
112                 allOf(
113                     // Only show UMO on the hub if the hub is at least partially visible. This
114                     // prevents
115                     // the UMO from being missing on the lock screen when going from the hub to lock
116                     // screen in some way other than through a direct transition, such as unlocking
117                     // from
118                     // the hub, then pressing power twice to go back to the lock screen.
119                     communalSceneInteractor.isCommunalVisible,
120                     // TODO(b/378942852): polish UMO transitions when scene container is enabled
121                     if (SceneContainerFlag.isEnabled) flowOf(true)
122                     else
123                         merge(
124                                 lockscreenToGlanceableHubTransitionViewModel.showUmo,
125                                 glanceableHubToLockscreenTransitionViewModel.showUmo,
126                                 dreamToGlanceableHubTransitionViewModel.showUmo,
127                                 glanceableHubToDreamTransitionViewModel.showUmo,
128                                 showUmoFromOccludedToGlanceableHub,
129                                 showUmoFromGlanceableHubToOccluded,
130                             )
131                             .onStart { emit(false) },
132                 ),
133             )
134             .stateIn(
135                 scope = applicationScope,
136                 started = SharingStarted.WhileSubscribed(),
137                 initialValue = false,
138             )
139 
140     /** Whether to show communal when exiting the occluded state. */
141     val showCommunalFromOccluded: Flow<Boolean> = communalInteractor.showCommunalFromOccluded
142 
143     val transitionFromOccludedEnded =
144         keyguardTransitionInteractor
145             .transition(Edge.create(from = KeyguardState.OCCLUDED))
146             .filter { step ->
147                 step.transitionState == TransitionState.FINISHED ||
148                     step.transitionState == TransitionState.CANCELED
149             }
150 
151     val recentsBackgroundColor: Flow<Color?> =
152         combine(
153                 showCommunalFromOccluded,
154                 communalColors.backgroundColor,
155                 communalSettingsInteractor.communalBackground,
156             ) { showCommunalFromOccluded, backgroundColor, backgroundType ->
157                 if (showCommunalFromOccluded && backgroundType.opaque) {
158                     backgroundColor
159                 } else {
160                     null
161                 }
162             }
163             .distinctUntilChanged()
164 }
165