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