1 package com.android.systemui.navigationbar.gestural
2 
3 import android.content.res.Resources
4 import android.util.TypedValue
5 import androidx.core.animation.Interpolator
6 import androidx.core.animation.PathInterpolator
7 import androidx.dynamicanimation.animation.SpringForce
8 import com.android.systemui.R
9 
10 data class EdgePanelParams(private var resources: Resources) {
11 
12     data class ArrowDimens(
13             val length: Float? = 0f,
14             val height: Float? = 0f,
15             val alpha: Float = 0f,
16             val heightSpring: SpringForce? = null,
17             val lengthSpring: SpringForce? = null,
18             var alphaSpring: Step<SpringForce>? = null,
19             var alphaInterpolator: Step<Float>? = null
20     )
21 
22     data class BackgroundDimens(
23             val width: Float? = 0f,
24             val height: Float = 0f,
25             val edgeCornerRadius: Float = 0f,
26             val farCornerRadius: Float = 0f,
27             val alpha: Float = 0f,
28             val widthSpring: SpringForce? = null,
29             val heightSpring: SpringForce? = null,
30             val farCornerRadiusSpring: SpringForce? = null,
31             val edgeCornerRadiusSpring: SpringForce? = null,
32             val alphaSpring: SpringForce? = null,
33     )
34 
35     data class BackIndicatorDimens(
36             val horizontalTranslation: Float? = 0f,
37             val scale: Float = 0f,
38             val scalePivotX: Float? = null,
39             val arrowDimens: ArrowDimens,
40             val backgroundDimens: BackgroundDimens,
41             val verticalTranslationSpring: SpringForce? = null,
42             val horizontalTranslationSpring: SpringForce? = null,
43             val scaleSpring: SpringForce? = null,
44     )
45 
46     lateinit var entryIndicator: BackIndicatorDimens
47         private set
48     lateinit var activeIndicator: BackIndicatorDimens
49         private set
50     lateinit var cancelledIndicator: BackIndicatorDimens
51         private set
52     lateinit var flungIndicator: BackIndicatorDimens
53         private set
54     lateinit var committedIndicator: BackIndicatorDimens
55         private set
56     lateinit var preThresholdIndicator: BackIndicatorDimens
57         private set
58     lateinit var fullyStretchedIndicator: BackIndicatorDimens
59         private set
60 
61     // navigation bar edge constants
62     var arrowPaddingEnd: Int = 0
63         private set
64     var arrowThickness: Float = 0f
65         private set
66     // The closest to y
67     var minArrowYPosition: Int = 0
68         private set
69     var fingerOffset: Int = 0
70         private set
71     var staticTriggerThreshold: Float = 0f
72         private set
73     var reactivationTriggerThreshold: Float = 0f
74         private set
75     var deactivationTriggerThreshold: Float = 0f
76         get() = -field
77         private set
78     lateinit var dynamicTriggerThresholdRange: ClosedRange<Float>
79         private set
80     var swipeProgressThreshold: Float = 0f
81         private set
82 
83     lateinit var entryWidthInterpolator: Interpolator
84         private set
85     lateinit var entryWidthTowardsEdgeInterpolator: Interpolator
86         private set
87     lateinit var activeWidthInterpolator: Interpolator
88         private set
89     lateinit var arrowAngleInterpolator: Interpolator
90         private set
91     lateinit var horizontalTranslationInterpolator: Interpolator
92         private set
93     lateinit var verticalTranslationInterpolator: Interpolator
94         private set
95     lateinit var farCornerInterpolator: Interpolator
96         private set
97     lateinit var edgeCornerInterpolator: Interpolator
98         private set
99     lateinit var heightInterpolator: Interpolator
100         private set
101 
102     init {
103         update(resources)
104     }
105 
106     private fun getDimen(id: Int): Float {
107         return resources.getDimension(id)
108     }
109 
110     private fun getDimenFloat(id: Int): Float {
111         return TypedValue().run { resources.getValue(id, this, true); float }
112     }
113 
114     private fun getPx(id: Int): Int {
115         return resources.getDimensionPixelSize(id)
116     }
117 
118     fun update(resources: Resources) {
119         this.resources = resources
120         arrowThickness = getDimen(R.dimen.navigation_edge_arrow_thickness)
121         arrowPaddingEnd = getPx(R.dimen.navigation_edge_panel_padding)
122         minArrowYPosition = getPx(R.dimen.navigation_edge_arrow_min_y)
123         fingerOffset = getPx(R.dimen.navigation_edge_finger_offset)
124         staticTriggerThreshold = getDimen(R.dimen.navigation_edge_action_drag_threshold)
125         reactivationTriggerThreshold =
126                 getDimen(R.dimen.navigation_edge_action_reactivation_drag_threshold)
127         deactivationTriggerThreshold =
128                 getDimen(R.dimen.navigation_edge_action_deactivation_drag_threshold)
129         dynamicTriggerThresholdRange =
130                 reactivationTriggerThreshold..deactivationTriggerThreshold
131         swipeProgressThreshold = getDimen(R.dimen.navigation_edge_action_progress_threshold)
132 
133         entryWidthInterpolator = PathInterpolator(.19f, 1.27f, .71f, .86f)
134         entryWidthTowardsEdgeInterpolator = PathInterpolator(1f, -3f, 1f, 1.2f)
135         activeWidthInterpolator = PathInterpolator(.7f, -0.24f, .48f, 1.21f)
136         arrowAngleInterpolator = entryWidthInterpolator
137         horizontalTranslationInterpolator = PathInterpolator(0.2f, 1.0f, 1.0f, 1.0f)
138         verticalTranslationInterpolator = PathInterpolator(.5f, 1.15f, .41f, .94f)
139         farCornerInterpolator = PathInterpolator(.03f, .19f, .14f, 1.09f)
140         edgeCornerInterpolator = PathInterpolator(0f, 1.11f, .85f, .84f)
141         heightInterpolator = PathInterpolator(1f, .05f, .9f, -0.29f)
142 
143         val activeCommittedArrowLengthSpring = createSpring(1500f, 0.29f)
144         val activeCommittedArrowHeightSpring = createSpring(1500f, 0.29f)
145         val flungCommittedEdgeCornerSpring = createSpring(10000f, 1f)
146         val flungCommittedFarCornerSpring = createSpring(10000f, 1f)
147         val flungCommittedWidthSpring = createSpring(10000f, 1f)
148         val flungCommittedHeightSpring = createSpring(10000f, 1f)
149 
150         val commonArrowDimensAlphaThreshold = .165f
151         val commonArrowDimensAlphaFactor = 1.05f
152         val commonArrowDimensAlphaSpring = Step(
153             threshold = commonArrowDimensAlphaThreshold,
154             factor = commonArrowDimensAlphaFactor,
155             postThreshold = createSpring(180f, 0.9f),
156             preThreshold = createSpring(2000f, 0.6f)
157         )
158         val commonArrowDimensAlphaSpringInterpolator = Step(
159             threshold = commonArrowDimensAlphaThreshold,
160             factor = commonArrowDimensAlphaFactor,
161             postThreshold = 1f,
162             preThreshold = 0f
163         )
164 
165         entryIndicator = BackIndicatorDimens(
166                 horizontalTranslation = getDimen(R.dimen.navigation_edge_entry_margin),
167                 scale = getDimenFloat(R.dimen.navigation_edge_entry_scale),
168                 scalePivotX = getDimen(R.dimen.navigation_edge_pre_threshold_background_width),
169                 horizontalTranslationSpring = createSpring(800f, 0.76f),
170                 verticalTranslationSpring = createSpring(30000f, 1f),
171                 scaleSpring = createSpring(120f, 0.8f),
172                 arrowDimens = ArrowDimens(
173                         length = getDimen(R.dimen.navigation_edge_entry_arrow_length),
174                         height = getDimen(R.dimen.navigation_edge_entry_arrow_height),
175                         alpha = 0f,
176                         lengthSpring = createSpring(600f, 0.4f),
177                         heightSpring = createSpring(600f, 0.4f),
178                         alphaSpring = commonArrowDimensAlphaSpring,
179                         alphaInterpolator = commonArrowDimensAlphaSpringInterpolator
180                 ),
181                 backgroundDimens = BackgroundDimens(
182                         alpha = 1f,
183                         width = getDimen(R.dimen.navigation_edge_entry_background_width),
184                         height = getDimen(R.dimen.navigation_edge_entry_background_height),
185                         edgeCornerRadius = getDimen(R.dimen.navigation_edge_entry_edge_corners),
186                         farCornerRadius = getDimen(R.dimen.navigation_edge_entry_far_corners),
187                         widthSpring = createSpring(450f, 0.65f),
188                         heightSpring = createSpring(1500f, 0.45f),
189                         farCornerRadiusSpring = createSpring(300f, 0.5f),
190                         edgeCornerRadiusSpring = createSpring(150f, 0.5f),
191                 )
192         )
193 
194         activeIndicator = BackIndicatorDimens(
195                 horizontalTranslation = getDimen(R.dimen.navigation_edge_active_margin),
196                 scale = getDimenFloat(R.dimen.navigation_edge_active_scale),
197                 horizontalTranslationSpring = createSpring(1000f, 0.8f),
198                 scaleSpring = createSpring(325f, 0.55f),
199                 scalePivotX = getDimen(R.dimen.navigation_edge_active_background_width),
200                 arrowDimens = ArrowDimens(
201                         length = getDimen(R.dimen.navigation_edge_active_arrow_length),
202                         height = getDimen(R.dimen.navigation_edge_active_arrow_height),
203                         alpha = 1f,
204                         lengthSpring = activeCommittedArrowLengthSpring,
205                         heightSpring = activeCommittedArrowHeightSpring,
206                         alphaSpring = commonArrowDimensAlphaSpring,
207                         alphaInterpolator = commonArrowDimensAlphaSpringInterpolator
208                 ),
209                 backgroundDimens = BackgroundDimens(
210                         alpha = 1f,
211                         width = getDimen(R.dimen.navigation_edge_active_background_width),
212                         height = getDimen(R.dimen.navigation_edge_active_background_height),
213                         edgeCornerRadius = getDimen(R.dimen.navigation_edge_active_edge_corners),
214                         farCornerRadius = getDimen(R.dimen.navigation_edge_active_far_corners),
215                         widthSpring = createSpring(850f, 0.75f),
216                         heightSpring = createSpring(10000f, 1f),
217                         edgeCornerRadiusSpring = createSpring(2600f, 0.855f),
218                         farCornerRadiusSpring = createSpring(1200f, 0.30f),
219                 )
220         )
221 
222         preThresholdIndicator = BackIndicatorDimens(
223                 horizontalTranslation = getDimen(R.dimen.navigation_edge_pre_threshold_margin),
224                 scale = getDimenFloat(R.dimen.navigation_edge_pre_threshold_scale),
225                 scalePivotX = getDimen(R.dimen.navigation_edge_pre_threshold_background_width),
226                 scaleSpring = createSpring(120f, 0.8f),
227                 horizontalTranslationSpring = createSpring(6000f, 1f),
228                 arrowDimens = ArrowDimens(
229                         length = getDimen(R.dimen.navigation_edge_pre_threshold_arrow_length),
230                         height = getDimen(R.dimen.navigation_edge_pre_threshold_arrow_height),
231                         alpha = 1f,
232                         lengthSpring = createSpring(100f, 0.6f),
233                         heightSpring = createSpring(100f, 0.6f),
234                         alphaSpring = commonArrowDimensAlphaSpring,
235                         alphaInterpolator = commonArrowDimensAlphaSpringInterpolator
236                 ),
237                 backgroundDimens = BackgroundDimens(
238                         alpha = 1f,
239                         width = getDimen(R.dimen.navigation_edge_pre_threshold_background_width),
240                         height = getDimen(R.dimen.navigation_edge_pre_threshold_background_height),
241                         edgeCornerRadius =
242                                 getDimen(R.dimen.navigation_edge_pre_threshold_edge_corners),
243                         farCornerRadius =
244                                 getDimen(R.dimen.navigation_edge_pre_threshold_far_corners),
245                         widthSpring = createSpring(650f, 1f),
246                         heightSpring = createSpring(1500f, 0.45f),
247                         farCornerRadiusSpring = createSpring(300f, 1f),
248                         edgeCornerRadiusSpring = createSpring(250f, 0.5f),
249                 )
250         )
251 
252         committedIndicator = activeIndicator.copy(
253                 horizontalTranslation = null,
254                 scalePivotX = null,
255                 arrowDimens = activeIndicator.arrowDimens.copy(
256                         lengthSpring = activeCommittedArrowLengthSpring,
257                         heightSpring = activeCommittedArrowHeightSpring,
258                         length = null,
259                         height = null,
260                 ),
261                 backgroundDimens = activeIndicator.backgroundDimens.copy(
262                         alpha = 0f,
263                         // explicitly set to null to preserve previous width upon state change
264                         width = null,
265                         widthSpring = flungCommittedWidthSpring,
266                         heightSpring = flungCommittedHeightSpring,
267                         edgeCornerRadiusSpring = flungCommittedEdgeCornerSpring,
268                         farCornerRadiusSpring = flungCommittedFarCornerSpring,
269                         alphaSpring = createSpring(1400f, 1f),
270                 ),
271                 scale = 0.86f,
272                 scaleSpring = createSpring(5700f, 1f),
273         )
274 
275         flungIndicator = committedIndicator.copy(
276                 arrowDimens = committedIndicator.arrowDimens.copy(
277                         lengthSpring = createSpring(850f, 0.46f),
278                         heightSpring = createSpring(850f, 0.46f),
279                         length = activeIndicator.arrowDimens.length,
280                         height = activeIndicator.arrowDimens.height
281                 ),
282                 backgroundDimens = committedIndicator.backgroundDimens.copy(
283                         widthSpring = flungCommittedWidthSpring,
284                         heightSpring = flungCommittedHeightSpring,
285                         edgeCornerRadiusSpring = flungCommittedEdgeCornerSpring,
286                         farCornerRadiusSpring = flungCommittedFarCornerSpring,
287                 )
288         )
289 
290         cancelledIndicator = entryIndicator.copy(
291                 backgroundDimens = entryIndicator.backgroundDimens.copy(
292                         width = 0f,
293                         alpha = 0f,
294                         alphaSpring = createSpring(450f, 1f)
295                 )
296         )
297 
298         fullyStretchedIndicator = BackIndicatorDimens(
299                 horizontalTranslation = getDimen(R.dimen.navigation_edge_stretch_margin),
300                 scale = getDimenFloat(R.dimen.navigation_edge_stretch_scale),
301                 horizontalTranslationSpring = null,
302                 verticalTranslationSpring = null,
303                 scaleSpring = null,
304                 arrowDimens = ArrowDimens(
305                         length = getDimen(R.dimen.navigation_edge_stretched_arrow_length),
306                         height = getDimen(R.dimen.navigation_edge_stretched_arrow_height),
307                         alpha = 1f,
308                         alphaSpring = null,
309                         heightSpring = null,
310                         lengthSpring = null,
311                 ),
312                 backgroundDimens = BackgroundDimens(
313                         alpha = 1f,
314                         width = getDimen(R.dimen.navigation_edge_stretch_background_width),
315                         height = getDimen(R.dimen.navigation_edge_stretch_background_height),
316                         edgeCornerRadius = getDimen(R.dimen.navigation_edge_stretch_edge_corners),
317                         farCornerRadius = getDimen(R.dimen.navigation_edge_stretch_far_corners),
318                         alphaSpring = null,
319                         widthSpring = null,
320                         heightSpring = null,
321                         edgeCornerRadiusSpring = null,
322                         farCornerRadiusSpring = null,
323                 )
324         )
325     }
326 }
327 
328 fun createSpring(stiffness: Float, dampingRatio: Float): SpringForce {
329     return SpringForce().setStiffness(stiffness).setDampingRatio(dampingRatio)
330 }