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.Flags.centralizedStatusBarHeightFix 22 import com.android.systemui.common.ui.data.repository.ConfigurationRepository 23 import com.android.systemui.dagger.SysUISingleton 24 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor 25 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor 26 import com.android.systemui.res.R 27 import com.android.systemui.shade.LargeScreenHeaderHelper 28 import com.android.systemui.statusbar.policy.SplitShadeStateController 29 import dagger.Lazy 30 import javax.inject.Inject 31 import kotlinx.coroutines.flow.Flow 32 import kotlinx.coroutines.flow.MutableStateFlow 33 import kotlinx.coroutines.flow.asStateFlow 34 import kotlinx.coroutines.flow.combine 35 import kotlinx.coroutines.flow.debounce 36 import kotlinx.coroutines.flow.distinctUntilChanged 37 import kotlinx.coroutines.flow.map 38 import kotlinx.coroutines.flow.onStart 39 40 /** Encapsulates business-logic specifically related to the shared notification stack container. */ 41 @SysUISingleton 42 class SharedNotificationContainerInteractor 43 @Inject 44 constructor( 45 configurationRepository: ConfigurationRepository, 46 private val context: Context, 47 private val splitShadeStateController: SplitShadeStateController, 48 keyguardInteractor: KeyguardInteractor, 49 deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, 50 largeScreenHeaderHelperLazy: Lazy<LargeScreenHeaderHelper>, 51 ) { 52 53 private val _topPosition = MutableStateFlow(0f) 54 val topPosition = _topPosition.asStateFlow() 55 56 private val _notificationStackChanged = MutableStateFlow(0L) 57 /** An internal modification was made to notifications */ 58 val notificationStackChanged = _notificationStackChanged.debounce(20L) 59 60 val configurationBasedDimensions: Flow<ConfigurationBasedDimensions> = 61 configurationRepository.onAnyConfigurationChange 62 .onStart { emit(Unit) } 63 .map { _ -> 64 with(context.resources) { 65 ConfigurationBasedDimensions( 66 useSplitShade = 67 splitShadeStateController.shouldUseSplitNotificationShade( 68 context.resources 69 ), 70 useLargeScreenHeader = 71 getBoolean(R.bool.config_use_large_screen_shade_header), 72 marginHorizontal = 73 getDimensionPixelSize(R.dimen.notification_panel_margin_horizontal), 74 marginBottom = 75 getDimensionPixelSize(R.dimen.notification_panel_margin_bottom), 76 marginTop = getDimensionPixelSize(R.dimen.notification_panel_margin_top), 77 marginTopLargeScreen = 78 if (centralizedStatusBarHeightFix()) { 79 largeScreenHeaderHelperLazy.get().getLargeScreenHeaderHeight() 80 } else { 81 getDimensionPixelSize(R.dimen.large_screen_shade_header_height) 82 }, 83 keyguardSplitShadeTopMargin = 84 getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin), 85 ) 86 } 87 } 88 .distinctUntilChanged() 89 90 /** 91 * The notification shelf can extend over the lock icon area if: 92 * * UDFPS supported. Ambient indication will always appear below 93 * * UDFPS not supported and ambient indication not visible, which will appear above lock icon 94 */ 95 val useExtraShelfSpace: Flow<Boolean> = 96 combine( 97 keyguardInteractor.ambientIndicationVisible, 98 deviceEntryUdfpsInteractor.isUdfpsSupported, 99 ) { ambientIndicationVisible, isUdfpsSupported -> 100 isUdfpsSupported || !ambientIndicationVisible 101 } 102 103 val isSplitShadeEnabled: Flow<Boolean> = 104 configurationBasedDimensions 105 .map { dimens: ConfigurationBasedDimensions -> dimens.useSplitShade } 106 .distinctUntilChanged() 107 108 /** Top position (without translation) of the shared container. */ 109 fun setTopPosition(top: Float) { 110 _topPosition.value = top 111 } 112 113 /** An internal modification was made to notifications */ 114 fun notificationStackChanged() { 115 _notificationStackChanged.value = _notificationStackChanged.value + 1 116 } 117 118 data class ConfigurationBasedDimensions( 119 val useSplitShade: Boolean, 120 val useLargeScreenHeader: Boolean, 121 val marginHorizontal: Int, 122 val marginBottom: Int, 123 val marginTop: Int, 124 val marginTopLargeScreen: Int, 125 val keyguardSplitShadeTopMargin: Int, 126 ) 127 } 128