• 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 package com.android.systemui.shade.domain.interactor
18 
19 import com.android.compose.animation.scene.TransitionKey
20 import kotlinx.coroutines.CoroutineScope
21 import kotlinx.coroutines.flow.Flow
22 import kotlinx.coroutines.flow.SharingStarted
23 import kotlinx.coroutines.flow.StateFlow
24 import kotlinx.coroutines.flow.combine
25 import kotlinx.coroutines.flow.stateIn
26 
27 /** Business logic for shade interactions. */
28 interface ShadeInteractor : BaseShadeInteractor {
29     /** Emits true if the Notifications shade is currently allowed and false otherwise. */
30     val isShadeEnabled: StateFlow<Boolean>
31 
32     /** Emits true if QS shade is currently allowed and false otherwise. */
33     val isQsEnabled: StateFlow<Boolean>
34 
35     /** Whether either the Notifications shade or QS shade is fully expanded. */
36     val isAnyFullyExpanded: StateFlow<Boolean>
37 
38     /** Whether the Notifications Shade is fully expanded. */
39     val isShadeFullyExpanded: Flow<Boolean>
40 
41     /** Whether Notifications Shade is expanded a non-zero amount. */
42     val isShadeAnyExpanded: StateFlow<Boolean>
43 
44     /** Whether the Notifications Shade is fully collapsed. */
45     val isShadeFullyCollapsed: Flow<Boolean>
46 
47     /**
48      * Whether the user is expanding or collapsing either the shade or quick settings with user
49      * input (i.e. dragging a pointer). This will be true even if the user's input gesture had ended
50      * but a transition they initiated is still animating.
51      */
52     val isUserInteracting: StateFlow<Boolean>
53 
54     /** Are touches allowed on the notification panel? */
55     val isShadeTouchable: Flow<Boolean>
56 
57     /** Whether the shade can be expanded from QQS to QS. */
58     val isExpandToQsEnabled: Flow<Boolean>
59 }
60 
61 /** ShadeInteractor methods with implementations that differ between non-empty impls. */
62 interface BaseShadeInteractor {
63     /** The amount [0-1] either QS or the shade has been opened. */
64     val anyExpansion: StateFlow<Float>
65 
66     /**
67      * Whether either the shade or QS is partially or fully expanded, i.e. not fully collapsed. At
68      * this time, this is not simply a matter of checking if either value in shadeExpansion and
69      * qsExpansion is greater than zero, because it includes the legacy concept of whether input
70      * transfer is about to occur. If the scene container flag is enabled, it just checks whether
71      * either expansion value is positive.
72      *
73      * TODO(b/300258424) remove all but the first sentence of this comment
74      */
75     val isAnyExpanded: StateFlow<Boolean>
76 
77     /** The amount [0-1] that the Notifications Shade has been opened. */
78     val shadeExpansion: StateFlow<Float>
79 
80     /**
81      * The amount [0-1] QS has been opened. Normal shade with notifications (QQS) visible will
82      * report 0f. If split shade is enabled, value matches shadeExpansion.
83      */
84     val qsExpansion: StateFlow<Float>
85 
86     /** Whether Quick Settings Shade is expanded a non-zero amount. */
87     val isQsExpanded: StateFlow<Boolean>
88 
89     /**
90      * Emits true whenever Quick Settings is being expanded without first expanding the Shade or if
91      * if Quick Settings is being collapsed without first collapsing to shade, i.e. expanding with
92      * 2-finger swipe or collapsing by flinging from the bottom of the screen. This concept was
93      * previously called "expand immediate" in the legacy codebase.
94      */
95     val isQsBypassingShade: Flow<Boolean>
96 
97     /**
98      * Emits true when QS is displayed over the entire screen of the device. Currently, this only
99      * happens on phones that are not unfolded when QS expansion is equal to 1.
100      */
101     val isQsFullscreen: Flow<Boolean>
102 
103     /**
104      * Whether the user is expanding or collapsing the shade with user input. This will be true even
105      * if the user's input gesture has ended but a transition they initiated is animating.
106      */
107     val isUserInteractingWithShade: Flow<Boolean>
108 
109     /**
110      * Whether the user is expanding or collapsing quick settings with user input. This will be true
111      * even if the user's input gesture has ended but a transition they initiated is still
112      * animating.
113      */
114     val isUserInteractingWithQs: Flow<Boolean>
115 
116     /**
117      * Triggers the expansion (opening) of the notifications shade. If it is already expanded, this
118      * has no effect.
119      */
expandNotificationsShadenull120     fun expandNotificationsShade(loggingReason: String, transitionKey: TransitionKey? = null)
121 
122     /**
123      * Triggers the expansion (opening) of the quick settings shade. If it is already expanded, this
124      * has no effect.
125      */
126     fun expandQuickSettingsShade(loggingReason: String, transitionKey: TransitionKey? = null)
127 
128     /**
129      * Triggers the collapse (closing) of the notifications shade. If it is already collapsed, this
130      * has no effect.
131      */
132     fun collapseNotificationsShade(loggingReason: String, transitionKey: TransitionKey? = null)
133 
134     /**
135      * Triggers the collapse (closing) of the quick settings shade. If it is already collapsed, this
136      * has no effect.
137      */
138     fun collapseQuickSettingsShade(
139         loggingReason: String,
140         transitionKey: TransitionKey? = null,
141         bypassNotificationsShade: Boolean = false,
142     )
143 
144     /**
145      * Triggers the collapse (closing) of the notifications shade or quick settings shade, whichever
146      * is open. If both are already collapsed, this has no effect.
147      */
148     fun collapseEitherShade(loggingReason: String, transitionKey: TransitionKey? = null)
149 }
150 
151 fun createAnyExpansionFlow(
152     scope: CoroutineScope,
153     shadeExpansion: Flow<Float>,
154     qsExpansion: Flow<Float>,
155 ): StateFlow<Float> {
156     return combine(shadeExpansion, qsExpansion) { shadeExp, qsExp -> maxOf(shadeExp, qsExp) }
157         .stateIn(scope, SharingStarted.Eagerly, 0f)
158 }
159