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 18 package com.android.systemui.statusbar.notification.stack.domain.interactor 19 20 import android.content.Context 21 import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor 22 import com.android.systemui.dagger.SysUISingleton 23 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor 24 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor 25 import com.android.systemui.res.R 26 import com.android.systemui.scene.shared.flag.SceneContainerFlag 27 import com.android.systemui.shade.LargeScreenHeaderHelper 28 import com.android.systemui.shade.ShadeDisplayAware 29 import com.android.systemui.statusbar.policy.SplitShadeStateController 30 import dagger.Lazy 31 import javax.inject.Inject 32 import kotlinx.coroutines.FlowPreview 33 import kotlinx.coroutines.flow.Flow 34 import kotlinx.coroutines.flow.MutableStateFlow 35 import kotlinx.coroutines.flow.asStateFlow 36 import kotlinx.coroutines.flow.combine 37 import kotlinx.coroutines.flow.debounce 38 import kotlinx.coroutines.flow.distinctUntilChanged 39 import kotlinx.coroutines.flow.map 40 41 /** Encapsulates business-logic specifically related to the shared notification stack container. */ 42 @OptIn(FlowPreview::class) 43 @SysUISingleton 44 class SharedNotificationContainerInteractor 45 @Inject 46 constructor( 47 @ShadeDisplayAware private val context: Context, 48 private val splitShadeStateController: Lazy<SplitShadeStateController>, 49 @ShadeDisplayAware configurationInteractor: ConfigurationInteractor, 50 keyguardInteractor: KeyguardInteractor, 51 deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, 52 largeScreenHeaderHelperLazy: Lazy<LargeScreenHeaderHelper>, 53 ) { 54 55 private val _topPosition = MutableStateFlow(0f) 56 val topPosition = _topPosition.asStateFlow() 57 58 private val _notificationStackChanged = MutableStateFlow(0L) 59 /** An internal modification was made to notifications */ 60 val notificationStackChanged = _notificationStackChanged.debounce(20L) 61 62 /* Warning: Even though the value it emits only contains the split shade status, this flow must 63 * emit a value whenever the configuration *or* the split shade status changes. Adding a 64 * distinctUntilChanged() to this would cause configurationBasedDimensions to miss configuration 65 * updates that affect other resources, like margins or the large screen header flag. 66 */ 67 @Deprecated("Use SharedNotificationContainerViewModel.ConfigurationBasedDimensions instead") 68 val configurationBasedDimensions: Flow<ConfigurationBasedDimensions> = 69 configurationInteractor.onAnyConfigurationChange 70 .map { 71 val shouldUseSplitShade = 72 splitShadeStateController 73 .get() 74 .shouldUseSplitNotificationShade(context.resources) 75 with(context.resources) { 76 ConfigurationBasedDimensions( 77 useSplitShade = shouldUseSplitShade, 78 useLargeScreenHeader = 79 getBoolean(R.bool.config_use_large_screen_shade_header), 80 marginHorizontal = 81 getDimensionPixelSize(R.dimen.notification_panel_margin_horizontal), 82 marginBottom = 83 getDimensionPixelSize(R.dimen.notification_panel_margin_bottom), 84 marginTop = getDimensionPixelSize(R.dimen.notification_panel_margin_top), 85 marginTopLargeScreen = 86 largeScreenHeaderHelperLazy.get().getLargeScreenHeaderHeight(), 87 keyguardSplitShadeTopMargin = 88 getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin), 89 ) 90 } 91 } 92 .distinctUntilChanged() 93 get() { 94 SceneContainerFlag.assertInLegacyMode() 95 return field 96 } 97 98 /** 99 * The notification shelf can extend over the lock icon area if: 100 * * UDFPS supported. Ambient indication will always appear below 101 * * UDFPS not supported and ambient indication not visible, which will appear above lock icon 102 */ 103 val useExtraShelfSpace: Flow<Boolean> = 104 combine( 105 keyguardInteractor.ambientIndicationVisible, 106 deviceEntryUdfpsInteractor.isUdfpsSupported, 107 ) { ambientIndicationVisible, isUdfpsSupported -> 108 isUdfpsSupported || !ambientIndicationVisible 109 } 110 111 /** Top position (without translation) of the shared container. */ 112 fun setTopPosition(top: Float) { 113 _topPosition.value = top 114 } 115 116 /** An internal modification was made to notifications */ 117 fun notificationStackChanged() { 118 _notificationStackChanged.value = _notificationStackChanged.value + 1 119 } 120 121 @Deprecated("Use SharedNotificationContainerViewModel.ConfigurationBasedDimensions instead") 122 data class ConfigurationBasedDimensions( 123 val useSplitShade: Boolean, 124 val useLargeScreenHeader: Boolean, 125 val marginHorizontal: Int, 126 val marginBottom: Int, 127 val marginTop: Int, 128 val marginTopLargeScreen: Int, 129 val keyguardSplitShadeTopMargin: Int, 130 ) 131 } 132