• 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.model
18 
19 import com.android.compose.animation.scene.ObservableTransitionState
20 import com.android.compose.animation.scene.OverlayKey
21 import com.android.compose.animation.scene.SceneKey
22 import com.android.systemui.dagger.SysUISingleton
23 import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
24 import com.android.systemui.scene.domain.interactor.SceneInteractor
25 import com.android.systemui.scene.shared.flag.SceneContainerFlag
26 import com.android.systemui.scene.shared.model.Overlays
27 import com.android.systemui.scene.shared.model.Scenes
28 import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
29 import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
30 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING
31 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_COMMUNAL_HUB_SHOWING
32 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
33 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE
34 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED
35 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
36 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
37 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags
38 import dagger.Lazy
39 import javax.inject.Inject
40 import kotlinx.coroutines.flow.StateFlow
41 
42 /**
43  * A plugin for [SysUiState] that provides overrides for certain state flags that must be pulled
44  * from the scene framework when that framework is enabled.
45  */
46 @SysUISingleton
47 class SceneContainerPlugin
48 @Inject
49 constructor(
50     private val sceneInteractor: Lazy<SceneInteractor>,
51     private val occlusionInteractor: Lazy<SceneContainerOcclusionInteractor>,
52     private val shadeDisplaysRepository: Lazy<ShadeDisplaysRepository>,
53 ) {
54 
55     private val shadeDisplayId: StateFlow<Int> by lazy { shadeDisplaysRepository.get().displayId }
56 
57     /**
58      * Returns an override value for the given [flag] or `null` if the scene framework isn't enabled
59      * or if the flag value doesn't need to be overridden.
60      */
61     fun flagValueOverride(@SystemUiStateFlags flag: Long, displayId: Int): Boolean? {
62         if (!SceneContainerFlag.isEnabled) {
63             return null
64         }
65 
66         if (ShadeWindowGoesAround.isEnabled && shadeDisplayId.value != displayId) {
67             // The shade is in another display. All flags related to the shade container will map to
68             // false on other displays now.
69             //
70             // Note that this assumes there is only one SceneContainer and it is only on the shade
71             // window display. If there will be more, this will need to be revisited
72             return false
73         }
74         val transitionState = sceneInteractor.get().transitionState.value
75         val idleTransitionStateOrNull = transitionState as? ObservableTransitionState.Idle
76         val invisibleDueToOcclusion = occlusionInteractor.get().invisibleDueToOcclusion.value
77         return idleTransitionStateOrNull?.let { idleState ->
78             EvaluatorByFlag[flag]?.invoke(
79                 SceneContainerPluginState(
80                     scene = idleState.currentScene,
81                     overlays = idleState.currentOverlays,
82                     isVisible = sceneInteractor.get().isVisible.value,
83                     invisibleDueToOcclusion = invisibleDueToOcclusion,
84                 )
85             )
86         }
87     }
88 
89     companion object {
90 
91         /**
92          * Value evaluator function by state flag ID.
93          *
94          * The value evaluator function can be invoked, passing in the current [SceneKey] to know
95          * the override value of the flag ID.
96          *
97          * If the map doesn't contain an entry for a certain flag ID, it means that it doesn't need
98          * to be overridden by the scene framework.
99          */
100         val EvaluatorByFlag =
101             mapOf<Long, (SceneContainerPluginState) -> Boolean>(
102                 SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE to
103                     {
104                         when {
105                             !it.isVisible -> false
106                             it.scene != Scenes.Gone -> true
107                             it.overlays.isNotEmpty() -> true
108                             else -> false
109                         }
110                     },
111                 SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED to
112                     {
113                         when {
114                             !it.isVisible -> false
115                             it.scene == Scenes.Lockscreen -> true
116                             it.scene == Scenes.Shade -> true
117                             Overlays.NotificationsShade in it.overlays -> true
118                             else -> false
119                         }
120                     },
121                 SYSUI_STATE_QUICK_SETTINGS_EXPANDED to
122                     {
123                         when {
124                             !it.isVisible -> false
125                             it.scene == Scenes.QuickSettings -> true
126                             Overlays.QuickSettingsShade in it.overlays -> true
127                             else -> false
128                         }
129                     },
130                 SYSUI_STATE_BOUNCER_SHOWING to { it.isVisible && Overlays.Bouncer in it.overlays },
131                 SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING to
132                     {
133                         it.isVisible && it.scene == Scenes.Lockscreen
134                     },
135                 SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED to
136                     {
137                         it.scene == Scenes.Lockscreen && it.invisibleDueToOcclusion
138                     },
139                 SYSUI_STATE_COMMUNAL_HUB_SHOWING to { it.isVisible && it.scene == Scenes.Communal },
140             )
141     }
142 
143     data class SceneContainerPluginState(
144         val scene: SceneKey,
145         val overlays: Set<OverlayKey>,
146         val invisibleDueToOcclusion: Boolean,
147         val isVisible: Boolean,
148     )
149 }
150