diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 73539f9380e6a..6514ca44cf98e 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -1849,7 +1849,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, .alpha(1) .translationX(0) .translationY(0) - .setDuration(300) + .setDuration(450) .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .setUpdateListener(animation -> { float animatedValue = animation.getAnimatedFraction(); @@ -1878,7 +1878,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, .alpha(0) .translationX(mGlobalActionsLayout.getAnimationOffsetX()) .translationY(mGlobalActionsLayout.getAnimationOffsetY()) - .setDuration(300) + .setDuration(550) .withEndAction(this::completeDismiss) .setInterpolator(new LogAccelerateInterpolator()) .setUpdateListener(animation -> { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt index 8945f360f7b82..a3faa80485d0d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt @@ -67,32 +67,9 @@ class NotificationShadeDepthController @Inject constructor( private var updateScheduled: Boolean = false private var shadeExpansion = 0f @VisibleForTesting - var shadeSpring = SpringAnimation(this, object : - FloatPropertyCompat("shadeBlurRadius") { - override fun setValue(rect: NotificationShadeDepthController?, value: Float) { - shadeBlurRadius = value.toInt() - } - - override fun getValue(rect: NotificationShadeDepthController?): Float { - return shadeBlurRadius.toFloat() - } - }) - private val zoomInterpolator = Interpolators.ACCELERATE_DECELERATE - - /** - * Radius that we're animating to. - */ - private var pendingShadeBlurRadius = -1 - - /** - * Shade blur radius on the current frame. - */ - private var shadeBlurRadius = 0 - set(value) { - if (field == value) return - field = value - scheduleUpdate() - } + var shadeSpring = DepthAnimation() + @VisibleForTesting + var globalActionsSpring = DepthAnimation() /** * Blur radius of the wake-up animation on this frame. @@ -103,7 +80,6 @@ class NotificationShadeDepthController @Inject constructor( field = value scheduleUpdate() } - private var globalDialogVisibility = 0f /** * Callback that updates the window blur value and is called only once per frame. @@ -111,12 +87,9 @@ class NotificationShadeDepthController @Inject constructor( private val updateBlurCallback = Choreographer.FrameCallback { updateScheduled = false - val blur = max(shadeBlurRadius, - max(wakeAndUnlockBlurRadius, blurUtils.blurRadiusOfRatio(globalDialogVisibility))) + val blur = max(max(shadeSpring.radius, wakeAndUnlockBlurRadius), globalActionsSpring.radius) blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur) - val rawZoom = max(blurUtils.ratioOfBlurRadius(blur), globalDialogVisibility) - wallpaperManager.setWallpaperZoomOut(root.windowToken, - zoomInterpolator.getInterpolation(rawZoom)) + wallpaperManager.setWallpaperZoomOut(root.windowToken, blurUtils.ratioOfBlurRadius(blur)) notificationShadeWindowController.setBackgroundBlurRadius(blur) } @@ -163,8 +136,9 @@ class NotificationShadeDepthController @Inject constructor( } override fun onDozingChanged(isDozing: Boolean) { - if (isDozing && shadeSpring.isRunning) { - shadeSpring.skipToEnd() + if (isDozing) { + shadeSpring.finishIfRunning() + globalActionsSpring.finishIfRunning() } } } @@ -174,10 +148,6 @@ class NotificationShadeDepthController @Inject constructor( if (WAKE_UP_ANIMATION_ENABLED) { keyguardStateController.addCallback(keyguardStateCallback) } - shadeSpring.spring = SpringForce(0.0f) - shadeSpring.spring.dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY - shadeSpring.spring.stiffness = SpringForce.STIFFNESS_LOW - shadeSpring.addEndListener { _, _, _, _ -> pendingShadeBlurRadius = -1 } statusBarStateController.addCallback(statusBarStateCallback) } @@ -198,11 +168,7 @@ class NotificationShadeDepthController @Inject constructor( newBlur = blurUtils.blurRadiusOfRatio(shadeExpansion) } - if (pendingShadeBlurRadius == newBlur) { - return - } - pendingShadeBlurRadius = newBlur - shadeSpring.animateToFinalPosition(newBlur.toFloat()) + shadeSpring.animateTo(newBlur) } private fun scheduleUpdate(viewToBlur: View? = null) { @@ -215,19 +181,72 @@ class NotificationShadeDepthController @Inject constructor( } fun updateGlobalDialogVisibility(visibility: Float, dialogView: View) { - if (visibility == globalDialogVisibility) { - return - } - globalDialogVisibility = visibility - scheduleUpdate(dialogView) + globalActionsSpring.animateTo(blurUtils.blurRadiusOfRatio(visibility), dialogView) } override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array) { IndentingPrintWriter(pw, " ").let { it.println("StatusBarWindowBlurController:") it.increaseIndent() - it.println("shadeBlurRadius: $shadeBlurRadius") + it.println("shadeRadius: ${shadeSpring.radius}") + it.println("globalActionsRadius: ${globalActionsSpring.radius}") it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius") } } + + /** + * Animation helper that smoothly animates the depth using a spring and deals with frame + * invalidation. + */ + inner class DepthAnimation() { + /** + * Blur radius visible on the UI, in pixels. + */ + var radius = 0 + private set + + /** + * Radius that we're animating to. + */ + private var pendingRadius = -1 + + /** + * View on {@link Surface} that wants depth. + */ + private var view: View? = null + + private var springAnimation = SpringAnimation(this, object : + FloatPropertyCompat("blurRadius") { + override fun setValue(rect: DepthAnimation?, value: Float) { + radius = value.toInt() + scheduleUpdate(view) + } + + override fun getValue(rect: DepthAnimation?): Float { + return radius.toFloat() + } + }) + + init { + springAnimation.spring = SpringForce(0.0f) + springAnimation.spring.dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY + springAnimation.spring.stiffness = SpringForce.STIFFNESS_MEDIUM + springAnimation.addEndListener { _, _, _, _ -> pendingRadius = -1 } + } + + fun animateTo(newRadius: Int, viewToBlur: View? = null) { + if (pendingRadius == newRadius && view == viewToBlur) { + return + } + view = viewToBlur + pendingRadius = newRadius + springAnimation.animateToFinalPosition(newRadius.toFloat()) + } + + fun finishIfRunning() { + if (springAnimation.isRunning) { + springAnimation.skipToEnd() + } + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt index f061f34072d04..f4583f99f2d6a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt @@ -22,7 +22,6 @@ import android.testing.TestableLooper.RunWithLooper import android.view.Choreographer import android.view.View import android.view.ViewRootImpl -import androidx.dynamicanimation.animation.SpringAnimation import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager @@ -35,10 +34,14 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor -import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.eq import org.mockito.Mock -import org.mockito.Mockito.* +import org.mockito.Mockito.`when` +import org.mockito.Mockito.any +import org.mockito.Mockito.anyFloat +import org.mockito.Mockito.anyString +import org.mockito.Mockito.clearInvocations +import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit @RunWith(AndroidTestingRunner::class) @@ -56,7 +59,8 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() { @Mock private lateinit var dumpManager: DumpManager @Mock private lateinit var root: View @Mock private lateinit var viewRootImpl: ViewRootImpl - @Mock private lateinit var shadeSpring: SpringAnimation + @Mock private lateinit var shadeSpring: NotificationShadeDepthController.DepthAnimation + @Mock private lateinit var globalActionsSpring: NotificationShadeDepthController.DepthAnimation @JvmField @Rule val mockitoRule = MockitoJUnit.rule() private lateinit var statusBarStateListener: StatusBarStateController.StateListener @@ -76,6 +80,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() { keyguardStateController, choreographer, wallpaperManager, notificationShadeWindowController, dumpManager) notificationShadeDepthController.shadeSpring = shadeSpring + notificationShadeDepthController.globalActionsSpring = globalActionsSpring notificationShadeDepthController.root = root val captor = ArgumentCaptor.forClass(StatusBarStateController.StateListener::class.java) @@ -92,7 +97,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() { fun onPanelExpansionChanged_apliesBlur_ifShade() { notificationShadeDepthController.onPanelExpansionChanged(1f /* expansion */, false /* tracking */) - verify(shadeSpring).animateToFinalPosition(eq(maxBlur.toFloat())) + verify(shadeSpring).animateTo(eq(maxBlur), any()) } @Test @@ -102,13 +107,13 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() { statusBarState = StatusBarState.KEYGUARD statusBarStateListener.onStateChanged(statusBarState) - verify(shadeSpring).animateToFinalPosition(eq(0f)) + verify(shadeSpring).animateTo(eq(0), any()) } @Test - fun updateGlobalDialogVisibility_schedulesUpdate() { + fun updateGlobalDialogVisibility_appliesBlur() { notificationShadeDepthController.updateGlobalDialogVisibility(0.5f, root) - verify(choreographer).postFrameCallback(any()) + verify(globalActionsSpring).animateTo(eq(maxBlur / 2), safeEq(root)) } private fun safeEq(value: T): T {