• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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