• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2023 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.scene.data.repository
18 
19 import com.android.compose.animation.scene.ContentKey
20 import com.android.compose.animation.scene.ObservableTransitionState
21 import com.android.compose.animation.scene.OverlayKey
22 import com.android.compose.animation.scene.SceneKey
23 import com.android.compose.animation.scene.TransitionKey
24 import com.android.systemui.dagger.SysUISingleton
25 import com.android.systemui.dagger.qualifiers.Application
26 import com.android.systemui.scene.shared.model.SceneContainerConfig
27 import com.android.systemui.scene.shared.model.SceneDataSource
28 import javax.inject.Inject
29 import kotlinx.coroutines.CoroutineScope
30 import kotlinx.coroutines.flow.Flow
31 import kotlinx.coroutines.flow.MutableStateFlow
32 import kotlinx.coroutines.flow.SharingStarted
33 import kotlinx.coroutines.flow.StateFlow
34 import kotlinx.coroutines.flow.asStateFlow
35 import kotlinx.coroutines.flow.flatMapLatest
36 import kotlinx.coroutines.flow.flowOf
37 import kotlinx.coroutines.flow.stateIn
38 
39 @SysUISingleton
40 /** Source of truth for scene framework application state. */
41 class SceneContainerRepository
42 @Inject
43 constructor(
44     @Application applicationScope: CoroutineScope,
45     config: SceneContainerConfig,
46     private val dataSource: SceneDataSource,
47 ) {
48     /**
49      * The keys of all scenes and overlays in the container.
50      *
51      * They will be sorted in z-order such that the last one is the one that should be rendered on
52      * top of all previous ones.
53      */
54     val allContentKeys: List<ContentKey> = config.sceneKeys + config.overlayKeys
55 
56     val currentScene: StateFlow<SceneKey> = dataSource.currentScene
57 
58     /**
59      * The current set of overlays to be shown (may be empty).
60      *
61      * Note that during a transition between overlays, a different set of overlays may be rendered -
62      * but only the ones in this set are considered the current overlays.
63      */
64     val currentOverlays: StateFlow<Set<OverlayKey>> = dataSource.currentOverlays
65 
66     private val _isVisible = MutableStateFlow(true)
67     val isVisible: StateFlow<Boolean> = _isVisible.asStateFlow()
68 
69     /**
70      * Whether there's an ongoing remotely-initiated user interaction.
71      *
72      * For more information see the logic in `SceneInteractor` that mutates this.
73      */
74     val isRemoteUserInputOngoing = MutableStateFlow(false)
75 
76     /** Whether there's ongoing user input on the scene container Composable hierarchy */
77     val isSceneContainerUserInputOngoing = MutableStateFlow(false)
78 
79     private val defaultTransitionState = ObservableTransitionState.Idle(config.initialSceneKey)
80     private val _transitionState = MutableStateFlow<Flow<ObservableTransitionState>?>(null)
81     val transitionState: StateFlow<ObservableTransitionState> =
82         _transitionState
83             .flatMapLatest { innerFlowOrNull -> innerFlowOrNull ?: flowOf(defaultTransitionState) }
84             .stateIn(
85                 scope = applicationScope,
86                 started = SharingStarted.Eagerly,
87                 initialValue = defaultTransitionState,
88             )
89 
90     /** Number of currently active transition animations. */
91     val activeTransitionAnimationCount = MutableStateFlow(0)
92 
93     fun changeScene(toScene: SceneKey, transitionKey: TransitionKey? = null) {
94         dataSource.changeScene(toScene = toScene, transitionKey = transitionKey)
95     }
96 
97     fun snapToScene(toScene: SceneKey) {
98         dataSource.snapToScene(toScene = toScene)
99     }
100 
101     /**
102      * Request to show [overlay] so that it animates in from [currentScene] and ends up being
103      * visible on screen.
104      *
105      * After this returns, this overlay will be included in [currentOverlays]. This does nothing if
106      * [overlay] is already shown.
107      */
108     fun showOverlay(overlay: OverlayKey, transitionKey: TransitionKey? = null) {
109         dataSource.showOverlay(overlay = overlay, transitionKey = transitionKey)
110     }
111 
112     /**
113      * Request to hide [overlay] so that it animates out to [currentScene] and ends up *not* being
114      * visible on screen.
115      *
116      * After this returns, this overlay will not be included in [currentOverlays]. This does nothing
117      * if [overlay] is already hidden.
118      */
119     fun hideOverlay(overlay: OverlayKey, transitionKey: TransitionKey? = null) {
120         dataSource.hideOverlay(overlay = overlay, transitionKey = transitionKey)
121     }
122 
123     /**
124      * Replace [from] by [to] so that [from] ends up not being visible on screen and [to] ends up
125      * being visible.
126      *
127      * This throws if [from] is not currently shown or if [to] is already shown.
128      */
129     fun replaceOverlay(from: OverlayKey, to: OverlayKey, transitionKey: TransitionKey? = null) {
130         dataSource.replaceOverlay(from = from, to = to, transitionKey = transitionKey)
131     }
132 
133     /**
134      * Instantly shows [overlay].
135      *
136      * The change is instantaneous and not animated; it will be observable in the next frame and
137      * there will be no transition animation.
138      */
139     fun instantlyShowOverlay(overlay: OverlayKey) {
140         dataSource.instantlyShowOverlay(overlay)
141     }
142 
143     /**
144      * Instantly hides [overlay].
145      *
146      * The change is instantaneous and not animated; it will be observable in the next frame and
147      * there will be no transition animation.
148      */
149     fun instantlyHideOverlay(overlay: OverlayKey) {
150         dataSource.instantlyHideOverlay(overlay)
151     }
152 
153     /** Sets whether the container is visible. */
154     fun setVisible(isVisible: Boolean) {
155         _isVisible.value = isVisible
156     }
157 
158     /**
159      * Binds the given flow so the system remembers it.
160      *
161      * Note that you must call is with `null` when the UI is done or risk a memory leak.
162      */
163     fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) {
164         _transitionState.value = transitionState
165     }
166 
167     /**
168      * If currently in a transition between contents, cancel that transition and go back to the
169      * pre-transition state.
170      */
171     fun freezeAndAnimateToCurrentState() {
172         dataSource.freezeAndAnimateToCurrentState()
173     }
174 }
175