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