Merge "Make power menu animaiton smoother" into rvc-dev am: 4a0651a6d7

Change-Id: Ibcb65de00eea299ba0affe82f57314e62a081ae4
This commit is contained in:
Lucas Dupin
2020-03-25 01:30:25 +00:00
committed by Automerger Merge Worker
3 changed files with 83 additions and 59 deletions

View File

@@ -1849,7 +1849,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
.alpha(1) .alpha(1)
.translationX(0) .translationX(0)
.translationY(0) .translationY(0)
.setDuration(300) .setDuration(450)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.setUpdateListener(animation -> { .setUpdateListener(animation -> {
float animatedValue = animation.getAnimatedFraction(); float animatedValue = animation.getAnimatedFraction();
@@ -1878,7 +1878,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
.alpha(0) .alpha(0)
.translationX(mGlobalActionsLayout.getAnimationOffsetX()) .translationX(mGlobalActionsLayout.getAnimationOffsetX())
.translationY(mGlobalActionsLayout.getAnimationOffsetY()) .translationY(mGlobalActionsLayout.getAnimationOffsetY())
.setDuration(300) .setDuration(550)
.withEndAction(this::completeDismiss) .withEndAction(this::completeDismiss)
.setInterpolator(new LogAccelerateInterpolator()) .setInterpolator(new LogAccelerateInterpolator())
.setUpdateListener(animation -> { .setUpdateListener(animation -> {

View File

@@ -67,32 +67,9 @@ class NotificationShadeDepthController @Inject constructor(
private var updateScheduled: Boolean = false private var updateScheduled: Boolean = false
private var shadeExpansion = 0f private var shadeExpansion = 0f
@VisibleForTesting @VisibleForTesting
var shadeSpring = SpringAnimation(this, object : var shadeSpring = DepthAnimation()
FloatPropertyCompat<NotificationShadeDepthController>("shadeBlurRadius") { @VisibleForTesting
override fun setValue(rect: NotificationShadeDepthController?, value: Float) { var globalActionsSpring = DepthAnimation()
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()
}
/** /**
* Blur radius of the wake-up animation on this frame. * Blur radius of the wake-up animation on this frame.
@@ -103,7 +80,6 @@ class NotificationShadeDepthController @Inject constructor(
field = value field = value
scheduleUpdate() scheduleUpdate()
} }
private var globalDialogVisibility = 0f
/** /**
* Callback that updates the window blur value and is called only once per frame. * 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 { private val updateBlurCallback = Choreographer.FrameCallback {
updateScheduled = false updateScheduled = false
val blur = max(shadeBlurRadius, val blur = max(max(shadeSpring.radius, wakeAndUnlockBlurRadius), globalActionsSpring.radius)
max(wakeAndUnlockBlurRadius, blurUtils.blurRadiusOfRatio(globalDialogVisibility)))
blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur) blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur)
val rawZoom = max(blurUtils.ratioOfBlurRadius(blur), globalDialogVisibility) wallpaperManager.setWallpaperZoomOut(root.windowToken, blurUtils.ratioOfBlurRadius(blur))
wallpaperManager.setWallpaperZoomOut(root.windowToken,
zoomInterpolator.getInterpolation(rawZoom))
notificationShadeWindowController.setBackgroundBlurRadius(blur) notificationShadeWindowController.setBackgroundBlurRadius(blur)
} }
@@ -163,8 +136,9 @@ class NotificationShadeDepthController @Inject constructor(
} }
override fun onDozingChanged(isDozing: Boolean) { override fun onDozingChanged(isDozing: Boolean) {
if (isDozing && shadeSpring.isRunning) { if (isDozing) {
shadeSpring.skipToEnd() shadeSpring.finishIfRunning()
globalActionsSpring.finishIfRunning()
} }
} }
} }
@@ -174,10 +148,6 @@ class NotificationShadeDepthController @Inject constructor(
if (WAKE_UP_ANIMATION_ENABLED) { if (WAKE_UP_ANIMATION_ENABLED) {
keyguardStateController.addCallback(keyguardStateCallback) 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) statusBarStateController.addCallback(statusBarStateCallback)
} }
@@ -198,11 +168,7 @@ class NotificationShadeDepthController @Inject constructor(
newBlur = blurUtils.blurRadiusOfRatio(shadeExpansion) newBlur = blurUtils.blurRadiusOfRatio(shadeExpansion)
} }
if (pendingShadeBlurRadius == newBlur) { shadeSpring.animateTo(newBlur)
return
}
pendingShadeBlurRadius = newBlur
shadeSpring.animateToFinalPosition(newBlur.toFloat())
} }
private fun scheduleUpdate(viewToBlur: View? = null) { private fun scheduleUpdate(viewToBlur: View? = null) {
@@ -215,19 +181,72 @@ class NotificationShadeDepthController @Inject constructor(
} }
fun updateGlobalDialogVisibility(visibility: Float, dialogView: View) { fun updateGlobalDialogVisibility(visibility: Float, dialogView: View) {
if (visibility == globalDialogVisibility) { globalActionsSpring.animateTo(blurUtils.blurRadiusOfRatio(visibility), dialogView)
return
}
globalDialogVisibility = visibility
scheduleUpdate(dialogView)
} }
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
IndentingPrintWriter(pw, " ").let { IndentingPrintWriter(pw, " ").let {
it.println("StatusBarWindowBlurController:") it.println("StatusBarWindowBlurController:")
it.increaseIndent() it.increaseIndent()
it.println("shadeBlurRadius: $shadeBlurRadius") it.println("shadeRadius: ${shadeSpring.radius}")
it.println("globalActionsRadius: ${globalActionsSpring.radius}")
it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius") 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<DepthAnimation>("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()
}
}
}
} }

View File

@@ -22,7 +22,6 @@ import android.testing.TestableLooper.RunWithLooper
import android.view.Choreographer import android.view.Choreographer
import android.view.View import android.view.View
import android.view.ViewRootImpl import android.view.ViewRootImpl
import androidx.dynamicanimation.animation.SpringAnimation
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager import com.android.systemui.dump.DumpManager
@@ -35,10 +34,14 @@ import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.eq import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock 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 import org.mockito.junit.MockitoJUnit
@RunWith(AndroidTestingRunner::class) @RunWith(AndroidTestingRunner::class)
@@ -56,7 +59,8 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
@Mock private lateinit var dumpManager: DumpManager @Mock private lateinit var dumpManager: DumpManager
@Mock private lateinit var root: View @Mock private lateinit var root: View
@Mock private lateinit var viewRootImpl: ViewRootImpl @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() @JvmField @Rule val mockitoRule = MockitoJUnit.rule()
private lateinit var statusBarStateListener: StatusBarStateController.StateListener private lateinit var statusBarStateListener: StatusBarStateController.StateListener
@@ -76,6 +80,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
keyguardStateController, choreographer, wallpaperManager, keyguardStateController, choreographer, wallpaperManager,
notificationShadeWindowController, dumpManager) notificationShadeWindowController, dumpManager)
notificationShadeDepthController.shadeSpring = shadeSpring notificationShadeDepthController.shadeSpring = shadeSpring
notificationShadeDepthController.globalActionsSpring = globalActionsSpring
notificationShadeDepthController.root = root notificationShadeDepthController.root = root
val captor = ArgumentCaptor.forClass(StatusBarStateController.StateListener::class.java) val captor = ArgumentCaptor.forClass(StatusBarStateController.StateListener::class.java)
@@ -92,7 +97,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
fun onPanelExpansionChanged_apliesBlur_ifShade() { fun onPanelExpansionChanged_apliesBlur_ifShade() {
notificationShadeDepthController.onPanelExpansionChanged(1f /* expansion */, notificationShadeDepthController.onPanelExpansionChanged(1f /* expansion */,
false /* tracking */) false /* tracking */)
verify(shadeSpring).animateToFinalPosition(eq(maxBlur.toFloat())) verify(shadeSpring).animateTo(eq(maxBlur), any())
} }
@Test @Test
@@ -102,13 +107,13 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
statusBarState = StatusBarState.KEYGUARD statusBarState = StatusBarState.KEYGUARD
statusBarStateListener.onStateChanged(statusBarState) statusBarStateListener.onStateChanged(statusBarState)
verify(shadeSpring).animateToFinalPosition(eq(0f)) verify(shadeSpring).animateTo(eq(0), any())
} }
@Test @Test
fun updateGlobalDialogVisibility_schedulesUpdate() { fun updateGlobalDialogVisibility_appliesBlur() {
notificationShadeDepthController.updateGlobalDialogVisibility(0.5f, root) notificationShadeDepthController.updateGlobalDialogVisibility(0.5f, root)
verify(choreographer).postFrameCallback(any()) verify(globalActionsSpring).animateTo(eq(maxBlur / 2), safeEq(root))
} }
private fun <T : Any> safeEq(value: T): T { private fun <T : Any> safeEq(value: T): T {