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.communal.data.repository
18 
19 import com.android.compose.animation.scene.ObservableTransitionState
20 import com.android.compose.animation.scene.SceneKey
21 import com.android.compose.animation.scene.TransitionKey
22 import com.android.systemui.communal.dagger.Communal
23 import com.android.systemui.communal.shared.model.CommunalScenes
24 import com.android.systemui.dagger.SysUISingleton
25 import com.android.systemui.dagger.qualifiers.Application
26 import com.android.systemui.dagger.qualifiers.Background
27 import com.android.systemui.scene.shared.model.SceneDataSource
28 import javax.inject.Inject
29 import kotlinx.coroutines.CoroutineScope
30 import kotlinx.coroutines.ExperimentalCoroutinesApi
31 import kotlinx.coroutines.delay
32 import kotlinx.coroutines.flow.Flow
33 import kotlinx.coroutines.flow.MutableStateFlow
34 import kotlinx.coroutines.flow.SharingStarted
35 import kotlinx.coroutines.flow.StateFlow
36 import kotlinx.coroutines.flow.flatMapLatest
37 import kotlinx.coroutines.flow.flowOf
38 import kotlinx.coroutines.flow.stateIn
39 import kotlinx.coroutines.launch
40 
41 /** Encapsulates the state of communal mode. */
42 interface CommunalSceneRepository {
43     /**
44      * Target scene as requested by the underlying [SceneTransitionLayout] or through [changeScene].
45      */
46     val currentScene: StateFlow<SceneKey>
47 
48     /** Exposes the transition state of the communal [SceneTransitionLayout]. */
49     val transitionState: StateFlow<ObservableTransitionState>
50 
51     /** Updates the requested scene. */
52     fun changeScene(toScene: SceneKey, transitionKey: TransitionKey? = null)
53 
54     /** Immediately snaps to the desired scene. */
55     fun snapToScene(toScene: SceneKey, delayMillis: Long = 0)
56 
57     /**
58      * Updates the transition state of the hub [SceneTransitionLayout].
59      *
60      * Note that you must call is with `null` when the UI is done or risk a memory leak.
61      */
62     fun setTransitionState(transitionState: Flow<ObservableTransitionState>?)
63 }
64 
65 @OptIn(ExperimentalCoroutinesApi::class)
66 @SysUISingleton
67 class CommunalSceneRepositoryImpl
68 @Inject
69 constructor(
70     @Application private val applicationScope: CoroutineScope,
71     @Background backgroundScope: CoroutineScope,
72     @Communal private val sceneDataSource: SceneDataSource,
73 ) : CommunalSceneRepository {
74 
75     override val currentScene: StateFlow<SceneKey> = sceneDataSource.currentScene
76 
77     private val defaultTransitionState = ObservableTransitionState.Idle(CommunalScenes.Default)
78     private val _transitionState = MutableStateFlow<Flow<ObservableTransitionState>?>(null)
79     override val transitionState: StateFlow<ObservableTransitionState> =
80         _transitionState
innerFlowOrNullnull81             .flatMapLatest { innerFlowOrNull -> innerFlowOrNull ?: flowOf(defaultTransitionState) }
82             .stateIn(
83                 scope = backgroundScope,
84                 started = SharingStarted.Lazily,
85                 initialValue = defaultTransitionState,
86             )
87 
changeScenenull88     override fun changeScene(toScene: SceneKey, transitionKey: TransitionKey?) {
89         applicationScope.launch {
90             // SceneTransitionLayout state updates must be triggered on the thread the STL was
91             // created on.
92             sceneDataSource.changeScene(toScene, transitionKey)
93         }
94     }
95 
snapToScenenull96     override fun snapToScene(toScene: SceneKey, delayMillis: Long) {
97         applicationScope.launch {
98             // SceneTransitionLayout state updates must be triggered on the thread the STL was
99             // created on.
100             delay(delayMillis)
101             sceneDataSource.snapToScene(toScene)
102         }
103     }
104 
105     /**
106      * Updates the transition state of the hub [SceneTransitionLayout].
107      *
108      * Note that you must call is with `null` when the UI is done or risk a memory leak.
109      */
setTransitionStatenull110     override fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) {
111         _transitionState.value = transitionState
112     }
113 }
114