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