Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2020 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.animation.Animator |
| 20 | import android.animation.AnimatorListenerAdapter |
| 21 | import android.animation.ValueAnimator |
Lucas Dupin | 13f4b8a | 2020-02-19 13:41:52 -0800 | [diff] [blame] | 22 | import android.app.WallpaperManager |
Lucas Dupin | 7ee64cc | 2020-03-31 14:48:43 -0700 | [diff] [blame] | 23 | import android.util.Log |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 24 | import android.view.Choreographer |
| 25 | import android.view.View |
Lucas Dupin | b7685c5 | 2020-03-14 17:41:19 -0700 | [diff] [blame] | 26 | import androidx.annotation.VisibleForTesting |
Lucas Dupin | 15a7514 | 2020-03-05 18:11:26 -0800 | [diff] [blame] | 27 | import androidx.dynamicanimation.animation.FloatPropertyCompat |
| 28 | import androidx.dynamicanimation.animation.SpringAnimation |
| 29 | import androidx.dynamicanimation.animation.SpringForce |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 30 | import com.android.internal.util.IndentingPrintWriter |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 31 | import com.android.systemui.Dumpable |
| 32 | import com.android.systemui.Interpolators |
Ned Burns | aaeb44b | 2020-02-12 23:48:26 -0500 | [diff] [blame] | 33 | import com.android.systemui.dump.DumpManager |
Lucas Dupin | b7685c5 | 2020-03-14 17:41:19 -0700 | [diff] [blame] | 34 | import com.android.systemui.plugins.statusbar.StatusBarStateController |
Lucas Dupin | b16c49a | 2020-04-01 21:46:18 -0700 | [diff] [blame] | 35 | import com.android.systemui.statusbar.notification.ActivityLaunchAnimator |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 36 | import com.android.systemui.statusbar.phone.BiometricUnlockController |
| 37 | import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK |
Lucas Dupin | 1bd84d3 | 2020-03-13 17:28:18 -0700 | [diff] [blame] | 38 | import com.android.systemui.statusbar.phone.NotificationShadeWindowController |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 39 | import com.android.systemui.statusbar.phone.PanelExpansionListener |
Ahan Wu | 765f178 | 2020-04-02 23:08:15 +0800 | [diff] [blame] | 40 | import com.android.systemui.statusbar.phone.ScrimController |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 41 | import com.android.systemui.statusbar.policy.KeyguardStateController |
| 42 | import java.io.FileDescriptor |
| 43 | import java.io.PrintWriter |
| 44 | import javax.inject.Inject |
| 45 | import javax.inject.Singleton |
| 46 | import kotlin.math.max |
| 47 | |
| 48 | /** |
| 49 | * Controller responsible for statusbar window blur. |
| 50 | */ |
| 51 | @Singleton |
Lucas Dupin | 13f4b8a | 2020-02-19 13:41:52 -0800 | [diff] [blame] | 52 | class NotificationShadeDepthController @Inject constructor( |
Lucas Dupin | b7685c5 | 2020-03-14 17:41:19 -0700 | [diff] [blame] | 53 | private val statusBarStateController: StatusBarStateController, |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 54 | private val blurUtils: BlurUtils, |
| 55 | private val biometricUnlockController: BiometricUnlockController, |
| 56 | private val keyguardStateController: KeyguardStateController, |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 57 | private val choreographer: Choreographer, |
Lucas Dupin | 13f4b8a | 2020-02-19 13:41:52 -0800 | [diff] [blame] | 58 | private val wallpaperManager: WallpaperManager, |
Lucas Dupin | 1bd84d3 | 2020-03-13 17:28:18 -0700 | [diff] [blame] | 59 | private val notificationShadeWindowController: NotificationShadeWindowController, |
Ned Burns | aaeb44b | 2020-02-12 23:48:26 -0500 | [diff] [blame] | 60 | dumpManager: DumpManager |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 61 | ) : PanelExpansionListener, Dumpable { |
| 62 | companion object { |
| 63 | private const val WAKE_UP_ANIMATION_ENABLED = true |
Lucas Dupin | 7ee64cc | 2020-03-31 14:48:43 -0700 | [diff] [blame] | 64 | private const val TAG = "DepthController" |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 65 | } |
| 66 | |
| 67 | lateinit var root: View |
Santiago Etchebehere | 68eb53e | 2020-02-25 14:25:34 -0800 | [diff] [blame] | 68 | private var blurRoot: View? = null |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 69 | private var keyguardAnimator: Animator? = null |
| 70 | private var notificationAnimator: Animator? = null |
| 71 | private var updateScheduled: Boolean = false |
Lucas Dupin | b7685c5 | 2020-03-14 17:41:19 -0700 | [diff] [blame] | 72 | private var shadeExpansion = 0f |
Lucas Dupin | b16c49a | 2020-04-01 21:46:18 -0700 | [diff] [blame] | 73 | private var ignoreShadeBlurUntilHidden: Boolean = false |
Lucas Dupin | b7685c5 | 2020-03-14 17:41:19 -0700 | [diff] [blame] | 74 | @VisibleForTesting |
Lucas Dupin | b079daa | 2020-03-24 15:56:23 -0700 | [diff] [blame] | 75 | var shadeSpring = DepthAnimation() |
| 76 | @VisibleForTesting |
| 77 | var globalActionsSpring = DepthAnimation() |
Lucas Dupin | 3a8531e | 2020-04-06 17:18:09 -0700 | [diff] [blame] | 78 | var showingHomeControls: Boolean = false |
Lucas Dupin | b7685c5 | 2020-03-14 17:41:19 -0700 | [diff] [blame] | 79 | |
Lucas Dupin | ee92cc2 | 2020-03-31 20:45:42 -0700 | [diff] [blame] | 80 | @VisibleForTesting |
| 81 | var brightnessMirrorSpring = DepthAnimation() |
| 82 | var brightnessMirrorVisible: Boolean = false |
| 83 | set(value) { |
| 84 | field = value |
| 85 | brightnessMirrorSpring.animateTo(if (value) blurUtils.blurRadiusOfRatio(1f) |
| 86 | else 0) |
| 87 | } |
| 88 | |
Lucas Dupin | b7685c5 | 2020-03-14 17:41:19 -0700 | [diff] [blame] | 89 | /** |
Lucas Dupin | b16c49a | 2020-04-01 21:46:18 -0700 | [diff] [blame] | 90 | * When launching an app from the shade, the animations progress should affect how blurry the |
| 91 | * shade is, overriding the expansion amount. |
| 92 | */ |
| 93 | var notificationLaunchAnimationParams: ActivityLaunchAnimator.ExpandAnimationParameters? = null |
| 94 | set(value) { |
| 95 | field = value |
| 96 | if (value != null) { |
| 97 | scheduleUpdate() |
| 98 | return |
| 99 | } |
| 100 | |
| 101 | if (shadeSpring.radius == 0) { |
| 102 | return |
| 103 | } |
| 104 | ignoreShadeBlurUntilHidden = true |
| 105 | shadeSpring.animateTo(0) |
| 106 | shadeSpring.finishIfRunning() |
| 107 | } |
| 108 | |
| 109 | /** |
Ahan Wu | 765f178 | 2020-04-02 23:08:15 +0800 | [diff] [blame] | 110 | * Force stop blur effect when necessary. |
| 111 | */ |
| 112 | private var scrimsVisible: Boolean = false |
| 113 | set(value) { |
| 114 | if (field == value) return |
| 115 | field = value |
| 116 | scheduleUpdate() |
| 117 | } |
| 118 | |
| 119 | /** |
Lucas Dupin | b7685c5 | 2020-03-14 17:41:19 -0700 | [diff] [blame] | 120 | * Blur radius of the wake-up animation on this frame. |
| 121 | */ |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 122 | private var wakeAndUnlockBlurRadius = 0 |
| 123 | set(value) { |
| 124 | if (field == value) return |
| 125 | field = value |
| 126 | scheduleUpdate() |
| 127 | } |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 128 | |
| 129 | /** |
| 130 | * Callback that updates the window blur value and is called only once per frame. |
| 131 | */ |
Lucas Dupin | 7ee64cc | 2020-03-31 14:48:43 -0700 | [diff] [blame] | 132 | @VisibleForTesting |
| 133 | val updateBlurCallback = Choreographer.FrameCallback { |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 134 | updateScheduled = false |
| 135 | |
Lucas Dupin | b16c49a | 2020-04-01 21:46:18 -0700 | [diff] [blame] | 136 | var shadeRadius = max(shadeSpring.radius, wakeAndUnlockBlurRadius).toFloat() |
| 137 | shadeRadius *= 1f - brightnessMirrorSpring.ratio |
| 138 | val launchProgress = notificationLaunchAnimationParams?.linearProgress ?: 0f |
| 139 | shadeRadius *= (1f - launchProgress) * (1f - launchProgress) |
| 140 | |
| 141 | if (ignoreShadeBlurUntilHidden) { |
| 142 | if (shadeRadius == 0f) { |
| 143 | ignoreShadeBlurUntilHidden = false |
| 144 | } else { |
| 145 | shadeRadius = 0f |
| 146 | } |
| 147 | } |
Lucas Dupin | 3a8531e | 2020-04-06 17:18:09 -0700 | [diff] [blame] | 148 | |
| 149 | // Home controls have black background, this means that we should not have blur when they |
| 150 | // are fully visible, otherwise we'll enter Client Composition unnecessarily. |
| 151 | var globalActionsRadius = globalActionsSpring.radius |
| 152 | if (showingHomeControls) { |
| 153 | globalActionsRadius = 0 |
| 154 | } |
Ahan Wu | 765f178 | 2020-04-02 23:08:15 +0800 | [diff] [blame] | 155 | var blur = max(shadeRadius.toInt(), globalActionsRadius) |
| 156 | |
| 157 | // Make blur be 0 if it is necessary to stop blur effect. |
| 158 | if (scrimsVisible) { |
| 159 | blur = 0 |
| 160 | } |
| 161 | |
Santiago Etchebehere | 68eb53e | 2020-02-25 14:25:34 -0800 | [diff] [blame] | 162 | blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur) |
Lucas Dupin | 7ee64cc | 2020-03-31 14:48:43 -0700 | [diff] [blame] | 163 | try { |
| 164 | wallpaperManager.setWallpaperZoomOut(root.windowToken, |
| 165 | blurUtils.ratioOfBlurRadius(blur)) |
| 166 | } catch (e: IllegalArgumentException) { |
| 167 | Log.w(TAG, "Can't set zoom. Window is gone: ${root.windowToken}", e) |
| 168 | } |
Lucas Dupin | 1bd84d3 | 2020-03-13 17:28:18 -0700 | [diff] [blame] | 169 | notificationShadeWindowController.setBackgroundBlurRadius(blur) |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 170 | } |
| 171 | |
| 172 | /** |
| 173 | * Animate blurs when unlocking. |
| 174 | */ |
| 175 | private val keyguardStateCallback = object : KeyguardStateController.Callback { |
| 176 | override fun onKeyguardFadingAwayChanged() { |
| 177 | if (!keyguardStateController.isKeyguardFadingAway || |
| 178 | biometricUnlockController.mode != MODE_WAKE_AND_UNLOCK) { |
| 179 | return |
| 180 | } |
| 181 | |
| 182 | keyguardAnimator?.cancel() |
| 183 | keyguardAnimator = ValueAnimator.ofFloat(1f, 0f).apply { |
| 184 | duration = keyguardStateController.keyguardFadingAwayDuration |
| 185 | startDelay = keyguardStateController.keyguardFadingAwayDelay |
| 186 | interpolator = Interpolators.DECELERATE_QUINT |
| 187 | addUpdateListener { animation: ValueAnimator -> |
| 188 | wakeAndUnlockBlurRadius = |
Lucas Dupin | 13f4b8a | 2020-02-19 13:41:52 -0800 | [diff] [blame] | 189 | blurUtils.blurRadiusOfRatio(animation.animatedValue as Float) |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 190 | } |
| 191 | addListener(object : AnimatorListenerAdapter() { |
| 192 | override fun onAnimationEnd(animation: Animator?) { |
| 193 | keyguardAnimator = null |
| 194 | scheduleUpdate() |
| 195 | } |
| 196 | }) |
| 197 | start() |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | override fun onKeyguardShowingChanged() { |
| 202 | if (keyguardStateController.isShowing) { |
| 203 | keyguardAnimator?.cancel() |
| 204 | notificationAnimator?.cancel() |
| 205 | } |
| 206 | } |
| 207 | } |
| 208 | |
Lucas Dupin | b7685c5 | 2020-03-14 17:41:19 -0700 | [diff] [blame] | 209 | private val statusBarStateCallback = object : StatusBarStateController.StateListener { |
| 210 | override fun onStateChanged(newState: Int) { |
| 211 | updateShadeBlur() |
| 212 | } |
| 213 | |
| 214 | override fun onDozingChanged(isDozing: Boolean) { |
Lucas Dupin | b079daa | 2020-03-24 15:56:23 -0700 | [diff] [blame] | 215 | if (isDozing) { |
| 216 | shadeSpring.finishIfRunning() |
| 217 | globalActionsSpring.finishIfRunning() |
Lucas Dupin | ee92cc2 | 2020-03-31 20:45:42 -0700 | [diff] [blame] | 218 | brightnessMirrorSpring.finishIfRunning() |
Lucas Dupin | b7685c5 | 2020-03-14 17:41:19 -0700 | [diff] [blame] | 219 | } |
| 220 | } |
Ahan Wu | 765f178 | 2020-04-02 23:08:15 +0800 | [diff] [blame] | 221 | |
| 222 | override fun onDozeAmountChanged(linear: Float, eased: Float) { |
| 223 | wakeAndUnlockBlurRadius = blurUtils.blurRadiusOfRatio(eased) |
| 224 | } |
Lucas Dupin | b7685c5 | 2020-03-14 17:41:19 -0700 | [diff] [blame] | 225 | } |
| 226 | |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 227 | init { |
Ned Burns | aaeb44b | 2020-02-12 23:48:26 -0500 | [diff] [blame] | 228 | dumpManager.registerDumpable(javaClass.name, this) |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 229 | if (WAKE_UP_ANIMATION_ENABLED) { |
| 230 | keyguardStateController.addCallback(keyguardStateCallback) |
| 231 | } |
Lucas Dupin | b7685c5 | 2020-03-14 17:41:19 -0700 | [diff] [blame] | 232 | statusBarStateController.addCallback(statusBarStateCallback) |
Ahan Wu | 765f178 | 2020-04-02 23:08:15 +0800 | [diff] [blame] | 233 | notificationShadeWindowController.setScrimsVisibilityListener { |
| 234 | // Stop blur effect when scrims is opaque to avoid unnecessary GPU composition. |
| 235 | visibility -> scrimsVisible = visibility == ScrimController.OPAQUE |
| 236 | } |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 237 | } |
| 238 | |
| 239 | /** |
| 240 | * Update blurs when pulling down the shade |
| 241 | */ |
| 242 | override fun onPanelExpansionChanged(expansion: Float, tracking: Boolean) { |
Lucas Dupin | b7685c5 | 2020-03-14 17:41:19 -0700 | [diff] [blame] | 243 | if (expansion == shadeExpansion) { |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 244 | return |
| 245 | } |
Lucas Dupin | b7685c5 | 2020-03-14 17:41:19 -0700 | [diff] [blame] | 246 | shadeExpansion = expansion |
| 247 | updateShadeBlur() |
| 248 | } |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 249 | |
Lucas Dupin | b7685c5 | 2020-03-14 17:41:19 -0700 | [diff] [blame] | 250 | private fun updateShadeBlur() { |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 251 | var newBlur = 0 |
Ahan Wu | 765f178 | 2020-04-02 23:08:15 +0800 | [diff] [blame] | 252 | val state = statusBarStateController.state |
Lucas Dupin | b0b7a04 | 2020-04-15 12:23:26 -0700 | [diff] [blame] | 253 | if ((state == StatusBarState.SHADE || state == StatusBarState.SHADE_LOCKED) && |
| 254 | !keyguardStateController.isKeyguardFadingAway) { |
Lucas Dupin | 029cc6a | 2020-04-13 17:11:15 +0000 | [diff] [blame] | 255 | newBlur = blurUtils.blurRadiusOfRatio(shadeExpansion) |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 256 | } |
Lucas Dupin | b079daa | 2020-03-24 15:56:23 -0700 | [diff] [blame] | 257 | shadeSpring.animateTo(newBlur) |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 258 | } |
| 259 | |
Santiago Etchebehere | 68eb53e | 2020-02-25 14:25:34 -0800 | [diff] [blame] | 260 | private fun scheduleUpdate(viewToBlur: View? = null) { |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 261 | if (updateScheduled) { |
| 262 | return |
| 263 | } |
| 264 | updateScheduled = true |
Santiago Etchebehere | 68eb53e | 2020-02-25 14:25:34 -0800 | [diff] [blame] | 265 | blurRoot = viewToBlur |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 266 | choreographer.postFrameCallback(updateBlurCallback) |
| 267 | } |
| 268 | |
Lucas Dupin | 7719856 | 2020-03-31 14:16:16 -0700 | [diff] [blame] | 269 | fun updateGlobalDialogVisibility(visibility: Float, dialogView: View?) { |
Lucas Dupin | b079daa | 2020-03-24 15:56:23 -0700 | [diff] [blame] | 270 | globalActionsSpring.animateTo(blurUtils.blurRadiusOfRatio(visibility), dialogView) |
Santiago Etchebehere | 68eb53e | 2020-02-25 14:25:34 -0800 | [diff] [blame] | 271 | } |
| 272 | |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 273 | override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { |
Lucas Dupin | 13f4b8a | 2020-02-19 13:41:52 -0800 | [diff] [blame] | 274 | IndentingPrintWriter(pw, " ").let { |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 275 | it.println("StatusBarWindowBlurController:") |
| 276 | it.increaseIndent() |
Lucas Dupin | b079daa | 2020-03-24 15:56:23 -0700 | [diff] [blame] | 277 | it.println("shadeRadius: ${shadeSpring.radius}") |
| 278 | it.println("globalActionsRadius: ${globalActionsSpring.radius}") |
Lucas Dupin | ee92cc2 | 2020-03-31 20:45:42 -0700 | [diff] [blame] | 279 | it.println("brightnessMirrorRadius: ${brightnessMirrorSpring.radius}") |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 280 | it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius") |
Lucas Dupin | b16c49a | 2020-04-01 21:46:18 -0700 | [diff] [blame] | 281 | it.println("notificationLaunchAnimationProgress: " + |
| 282 | "${notificationLaunchAnimationParams?.linearProgress}") |
| 283 | it.println("ignoreShadeBlurUntilHidden: $ignoreShadeBlurUntilHidden") |
Lucas Dupin | 43d0124 | 2020-02-03 11:58:33 -0800 | [diff] [blame] | 284 | } |
| 285 | } |
Lucas Dupin | b079daa | 2020-03-24 15:56:23 -0700 | [diff] [blame] | 286 | |
| 287 | /** |
| 288 | * Animation helper that smoothly animates the depth using a spring and deals with frame |
| 289 | * invalidation. |
| 290 | */ |
| 291 | inner class DepthAnimation() { |
| 292 | /** |
| 293 | * Blur radius visible on the UI, in pixels. |
| 294 | */ |
| 295 | var radius = 0 |
Lucas Dupin | ee92cc2 | 2020-03-31 20:45:42 -0700 | [diff] [blame] | 296 | |
| 297 | /** |
| 298 | * Depth ratio of the current blur radius. |
| 299 | */ |
| 300 | val ratio |
| 301 | get() = blurUtils.ratioOfBlurRadius(radius) |
Lucas Dupin | b079daa | 2020-03-24 15:56:23 -0700 | [diff] [blame] | 302 | |
| 303 | /** |
| 304 | * Radius that we're animating to. |
| 305 | */ |
| 306 | private var pendingRadius = -1 |
| 307 | |
| 308 | /** |
| 309 | * View on {@link Surface} that wants depth. |
| 310 | */ |
| 311 | private var view: View? = null |
| 312 | |
| 313 | private var springAnimation = SpringAnimation(this, object : |
| 314 | FloatPropertyCompat<DepthAnimation>("blurRadius") { |
| 315 | override fun setValue(rect: DepthAnimation?, value: Float) { |
| 316 | radius = value.toInt() |
| 317 | scheduleUpdate(view) |
| 318 | } |
| 319 | |
| 320 | override fun getValue(rect: DepthAnimation?): Float { |
| 321 | return radius.toFloat() |
| 322 | } |
| 323 | }) |
| 324 | |
| 325 | init { |
| 326 | springAnimation.spring = SpringForce(0.0f) |
| 327 | springAnimation.spring.dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY |
Lucas Dupin | 19e7e55 | 2020-04-01 13:16:58 -0700 | [diff] [blame] | 328 | springAnimation.spring.stiffness = SpringForce.STIFFNESS_HIGH |
Lucas Dupin | b079daa | 2020-03-24 15:56:23 -0700 | [diff] [blame] | 329 | springAnimation.addEndListener { _, _, _, _ -> pendingRadius = -1 } |
| 330 | } |
| 331 | |
| 332 | fun animateTo(newRadius: Int, viewToBlur: View? = null) { |
| 333 | if (pendingRadius == newRadius && view == viewToBlur) { |
| 334 | return |
| 335 | } |
| 336 | view = viewToBlur |
| 337 | pendingRadius = newRadius |
| 338 | springAnimation.animateToFinalPosition(newRadius.toFloat()) |
| 339 | } |
| 340 | |
| 341 | fun finishIfRunning() { |
| 342 | if (springAnimation.isRunning) { |
| 343 | springAnimation.skipToEnd() |
| 344 | } |
| 345 | } |
| 346 | } |
Lucas Dupin | 13f4b8a | 2020-02-19 13:41:52 -0800 | [diff] [blame] | 347 | } |