1 /*
2  * Copyright (C) 2022 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.statusbar
18 
19 import android.content.Context
20 import android.util.IndentingPrintWriter
21 import android.util.MathUtils
22 import androidx.annotation.FloatRange
23 import androidx.annotation.Px
24 import com.android.systemui.dump.DumpManager
25 import com.android.systemui.plugins.qs.QS
26 import com.android.systemui.res.R
27 import com.android.systemui.statusbar.policy.ConfigurationController
28 import com.android.systemui.statusbar.policy.SplitShadeStateController
29 import dagger.assisted.Assisted
30 import dagger.assisted.AssistedFactory
31 import dagger.assisted.AssistedInject
32 import kotlin.math.max
33 
34 /** Responsible for the QS components during the lockscreen shade transition. */
35 class LockscreenShadeQsTransitionController
36 @AssistedInject
37 constructor(
38     context: Context,
39     configurationController: ConfigurationController,
40     dumpManager: DumpManager,
41     @Assisted private val qsProvider: () -> QS?,
42     splitShadeStateController: SplitShadeStateController
43 ) :
44     AbstractLockscreenShadeTransitionController(
45         context,
46         configurationController,
47         dumpManager,
48         splitShadeStateController
49     ) {
50 
51     private val qs: QS?
52         get() = qsProvider()
53 
54     /**
55      * The progress fraction of the QS transition during lockscreen shade expansion.
56      *
57      * Note that this value might be 0 for some time when the expansion is already in progress,
58      * since there is a transition start delay for QS on some device configurations. For this
59      * reason, don't use this value to check whether the shade expansion is in progress.
60      */
61     @FloatRange(from = 0.0, to = 1.0)
62     var qsTransitionFraction = 0f
63         private set
64 
65     /**
66      * The fraction of the QS "squish" transition progress during lockscreen shade expansion.
67      *
68      * Note that in some device configurations (large screens) this value can start at a value
69      * greater than 0. For this reason don't use this value to check whether the QS transition has
70      * started or not.
71      */
72     @FloatRange(from = 0.0, to = 1.0)
73     var qsSquishTransitionFraction = 0f
74         private set
75 
76     /**
77      * The drag down amount, in pixels __for the QS transition__, also taking into account the
78      * [qsTransitionStartDelay].
79      *
80      * Since it takes into account the start delay, it is __not__ the same as the raw drag down
81      * amount from the shade expansion.
82      */
83     @Px private var qsDragDownAmount = 0f
84 
85     /**
86      * Distance it takes for the QS transition to complete during the lockscreen shade expansion.
87      */
88     @Px private var qsTransitionDistance = 0
89 
90     /** Distance delay for the QS transition to start during the lockscreen shade expansion. */
91     @Px private var qsTransitionStartDelay = 0
92 
93     /**
94      * Distance that it takes to complete the QS "squish" transition during the lockscreen shade
95      * expansion.
96      */
97     @Px private var qsSquishTransitionDistance = 0
98 
99     /**
100      * Whether the transition to full shade is in progress. Might be `true` even though
101      * [qsTransitionFraction] is still 0, due to [qsTransitionStartDelay].
102      */
103     private var isTransitioningToFullShade = false
104 
105     /**
106      * The fraction at which the QS "squish" transition should start during the lockscreen shade
107      * expansion.
108      *
109      * 0 is fully collapsed, 1 is fully expanded.
110      */
111     @FloatRange(from = 0.0, to = 1.0) private var qsSquishStartFraction = 0f
112 
updateResourcesnull113     override fun updateResources() {
114         qsTransitionDistance =
115             context.resources.getDimensionPixelSize(R.dimen.lockscreen_shade_qs_transition_distance)
116         qsTransitionStartDelay =
117             context.resources.getDimensionPixelSize(R.dimen.lockscreen_shade_qs_transition_delay)
118         qsSquishTransitionDistance =
119             context.resources.getDimensionPixelSize(
120                 R.dimen.lockscreen_shade_qs_squish_transition_distance
121             )
122         qsSquishStartFraction =
123             context.resources.getFloat(R.dimen.lockscreen_shade_qs_squish_start_fraction)
124 
125         qsSquishTransitionFraction = max(qsSquishTransitionFraction, qsSquishStartFraction)
126     }
127 
onDragDownAmountChangednull128     override fun onDragDownAmountChanged(dragDownAmount: Float) {
129         qsDragDownAmount = dragDownAmount - qsTransitionStartDelay
130         qsTransitionFraction = MathUtils.saturate(qsDragDownAmount / qsTransitionDistance)
131         qsSquishTransitionFraction =
132             MathUtils.lerp(
133                 /* start= */ qsSquishStartFraction,
134                 /* stop= */ 1f,
135                 /* amount= */ MathUtils.saturate(qsDragDownAmount / qsSquishTransitionDistance)
136             )
137         isTransitioningToFullShade = dragDownAmount > 0.0f
138         qs?.setTransitionToFullShadeProgress(
139             isTransitioningToFullShade,
140             qsTransitionFraction,
141             qsSquishTransitionFraction
142         )
143     }
144 
dumpnull145     override fun dump(pw: IndentingPrintWriter) {
146         pw.println(
147             """
148             Resources:
149               qsTransitionDistance: $qsTransitionDistance
150               qsTransitionStartDelay: $qsTransitionStartDelay
151               qsSquishTransitionDistance: $qsSquishTransitionDistance
152               qsSquishStartFraction: $qsSquishStartFraction
153             State:
154               dragDownAmount: $dragDownAmount
155               qsDragDownAmount: $qsDragDownAmount
156               qsDragFraction: $qsTransitionFraction
157               qsSquishFraction: $qsSquishTransitionFraction
158               isTransitioningToFullShade: $isTransitioningToFullShade
159         """
160                 .trimIndent()
161         )
162     }
163 
164     @AssistedFactory
interfacenull165     fun interface Factory {
166         fun create(qsProvider: () -> QS?): LockscreenShadeQsTransitionController
167     }
168 }
169