Merge "Refactor Turbulence noise" into tm-qpr-dev
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt
index 5ac3aad7..6715951 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt
@@ -49,13 +49,16 @@
val opacity: Int = DEFAULT_OPACITY,
val width: Float = 0f,
val height: Float = 0f,
- val duration: Float = DEFAULT_NOISE_DURATION_IN_MILLIS,
+ val maxDuration: Float = DEFAULT_MAX_DURATION_IN_MILLIS,
+ val easeInDuration: Float = DEFAULT_EASING_DURATION_IN_MILLIS,
+ val easeOutDuration: Float = DEFAULT_EASING_DURATION_IN_MILLIS,
val pixelDensity: Float = 1f,
val blendMode: BlendMode = DEFAULT_BLEND_MODE,
val onAnimationEnd: Runnable? = null
) {
companion object {
- const val DEFAULT_NOISE_DURATION_IN_MILLIS = 7500F
+ const val DEFAULT_MAX_DURATION_IN_MILLIS = 7500f
+ const val DEFAULT_EASING_DURATION_IN_MILLIS = 750f
const val DEFAULT_LUMINOSITY_MULTIPLIER = 1f
const val DEFAULT_NOISE_GRID_COUNT = 1.2f
const val DEFAULT_NOISE_SPEED_Z = 0.3f
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseController.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseController.kt
index 4c7e5f4..b8f4b27 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseController.kt
@@ -15,16 +15,106 @@
*/
package com.android.systemui.surfaceeffects.turbulencenoise
-/** A controller that plays [TurbulenceNoiseView]. */
+import android.view.View
+import androidx.annotation.VisibleForTesting
+import java.util.Random
+
+/** Plays [TurbulenceNoiseView] in ease-in, main (no easing), and ease-out order. */
class TurbulenceNoiseController(private val turbulenceNoiseView: TurbulenceNoiseView) {
+
+ companion object {
+ /**
+ * States of the turbulence noise animation.
+ *
+ * <p>The state is designed to be follow the order below: [AnimationState.EASE_IN],
+ * [AnimationState.MAIN], [AnimationState.EASE_OUT].
+ */
+ enum class AnimationState {
+ EASE_IN,
+ MAIN,
+ EASE_OUT,
+ NOT_PLAYING
+ }
+ }
+
+ private val random = Random()
+
+ /** Current state of the animation. */
+ @VisibleForTesting
+ var state: AnimationState = AnimationState.NOT_PLAYING
+ set(value) {
+ field = value
+ if (state == AnimationState.NOT_PLAYING) {
+ turbulenceNoiseView.visibility = View.INVISIBLE
+ turbulenceNoiseView.clearConfig()
+ } else {
+ turbulenceNoiseView.visibility = View.VISIBLE
+ }
+ }
+
+ init {
+ turbulenceNoiseView.visibility = View.INVISIBLE
+ }
+
/** Updates the color of the noise. */
fun updateNoiseColor(color: Int) {
+ if (state == AnimationState.NOT_PLAYING) {
+ return
+ }
turbulenceNoiseView.updateColor(color)
}
- // TODO: add cancel and/ or pause once design requirements become clear.
- /** Plays [TurbulenceNoiseView] with the given config. */
- fun play(turbulenceNoiseAnimationConfig: TurbulenceNoiseAnimationConfig) {
- turbulenceNoiseView.play(turbulenceNoiseAnimationConfig)
+ /**
+ * Plays [TurbulenceNoiseView] with the given config.
+ *
+ * <p>It plays ease-in, main, and ease-out animations in sequence.
+ */
+ fun play(config: TurbulenceNoiseAnimationConfig) {
+ if (state != AnimationState.NOT_PLAYING) {
+ return // Ignore if any of the animation is playing.
+ }
+
+ turbulenceNoiseView.applyConfig(config)
+ playEaseInAnimation()
+ }
+
+ // TODO(b/237282226): Support force finish.
+ /** Finishes the main animation, which triggers the ease-out animation. */
+ fun finish() {
+ if (state == AnimationState.MAIN) {
+ turbulenceNoiseView.finish(nextAnimation = this::playEaseOutAnimation)
+ }
+ }
+
+ private fun playEaseInAnimation() {
+ if (state != AnimationState.NOT_PLAYING) {
+ return
+ }
+ state = AnimationState.EASE_IN
+
+ // Add offset to avoid repetitive noise.
+ turbulenceNoiseView.playEaseIn(
+ offsetX = random.nextFloat(),
+ offsetY = random.nextFloat(),
+ this::playMainAnimation
+ )
+ }
+
+ private fun playMainAnimation() {
+ if (state != AnimationState.EASE_IN) {
+ return
+ }
+ state = AnimationState.MAIN
+
+ turbulenceNoiseView.play(this::playEaseOutAnimation)
+ }
+
+ private fun playEaseOutAnimation() {
+ if (state != AnimationState.MAIN) {
+ return
+ }
+ state = AnimationState.EASE_OUT
+
+ turbulenceNoiseView.playEaseOut(onAnimationEnd = { state = AnimationState.NOT_PLAYING })
}
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShader.kt
index 19c114d..7456c43 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShader.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShader.kt
@@ -114,8 +114,19 @@
setFloatUniform("in_aspectRatio", width / max(height, 0.001f))
}
- /** Sets noise move speed in x, y, and z direction. */
+ /** Current noise movements in x, y, and z axes. */
+ var noiseOffsetX: Float = 0f
+ private set
+ var noiseOffsetY: Float = 0f
+ private set
+ var noiseOffsetZ: Float = 0f
+ private set
+
+ /** Sets noise move offset in x, y, and z direction. */
fun setNoiseMove(x: Float, y: Float, z: Float) {
- setFloatUniform("in_noiseMove", x, y, z)
+ noiseOffsetX = x
+ noiseOffsetY = y
+ noiseOffsetZ = z
+ setFloatUniform("in_noiseMove", noiseOffsetX, noiseOffsetY, noiseOffsetZ)
}
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseView.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseView.kt
index 68712c6..e1e515d 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseView.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseView.kt
@@ -25,38 +25,29 @@
import android.view.View
import androidx.annotation.VisibleForTesting
import androidx.core.graphics.ColorUtils
-import java.util.Random
-import kotlin.math.sin
-/** View that renders turbulence noise effect. */
+/**
+ * View that renders turbulence noise effect.
+ *
+ * <p>Use [TurbulenceNoiseController] to control the turbulence animation. If you want to make some
+ * other turbulence noise effects, either add functionality to [TurbulenceNoiseController] or create
+ * another controller instead of extend or modify the [TurbulenceNoiseView].
+ *
+ * <p>Please keep the [TurbulenceNoiseView] (or View in general) not aware of the state.
+ *
+ * <p>Please avoid inheriting the View if possible. Instead, reconsider adding a controller for a
+ * new case.
+ */
class TurbulenceNoiseView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
companion object {
private const val MS_TO_SEC = 0.001f
- private const val TWO_PI = Math.PI.toFloat() * 2f
}
- @VisibleForTesting val turbulenceNoiseShader = TurbulenceNoiseShader()
+ private val turbulenceNoiseShader = TurbulenceNoiseShader()
private val paint = Paint().apply { this.shader = turbulenceNoiseShader }
- private val random = Random()
- private val animator: ValueAnimator = ValueAnimator.ofFloat(0f, 1f)
- private var config: TurbulenceNoiseAnimationConfig? = null
-
- val isPlaying: Boolean
- get() = animator.isRunning
-
- init {
- // Only visible during the animation.
- visibility = INVISIBLE
- }
-
- /** Updates the color during the animation. No-op if there's no animation playing. */
- fun updateColor(color: Int) {
- config?.let {
- it.color = color
- applyConfig(it)
- }
- }
+ @VisibleForTesting var noiseConfig: TurbulenceNoiseAnimationConfig? = null
+ @VisibleForTesting var currentAnimator: ValueAnimator? = null
override fun onDraw(canvas: Canvas?) {
if (canvas == null || !canvas.isHardwareAccelerated) {
@@ -68,32 +59,38 @@
canvas.drawPaint(paint)
}
- fun play(config: TurbulenceNoiseAnimationConfig) {
- if (isPlaying) {
- return // Ignore if the animation is playing.
+ /** Updates the color during the animation. No-op if there's no animation playing. */
+ internal fun updateColor(color: Int) {
+ noiseConfig?.let {
+ turbulenceNoiseShader.setColor(ColorUtils.setAlphaComponent(color, it.opacity))
}
- visibility = VISIBLE
- applyConfig(config)
+ }
- // Add random offset to avoid same patterned noise.
- val offsetX = random.nextFloat()
- val offsetY = random.nextFloat()
+ /** Plays the turbulence noise with no easing. */
+ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+ fun play(onAnimationEnd: Runnable? = null) {
+ if (noiseConfig == null) {
+ return
+ }
+ val config = noiseConfig!!
- animator.duration = config.duration.toLong()
+ val animator = ValueAnimator.ofFloat(0f, 1f)
+ animator.duration = config.maxDuration.toLong()
+
+ // Animation should start from the initial position to avoid abrupt transition.
+ val initialX = turbulenceNoiseShader.noiseOffsetX
+ val initialY = turbulenceNoiseShader.noiseOffsetY
+ val initialZ = turbulenceNoiseShader.noiseOffsetZ
+
animator.addUpdateListener { updateListener ->
val timeInSec = updateListener.currentPlayTime * MS_TO_SEC
- // Remap [0,1] to [0, 2*PI]
- val progress = TWO_PI * updateListener.animatedValue as Float
-
turbulenceNoiseShader.setNoiseMove(
- offsetX + timeInSec * config.noiseMoveSpeedX,
- offsetY + timeInSec * config.noiseMoveSpeedY,
- timeInSec * config.noiseMoveSpeedZ
+ initialX + timeInSec * config.noiseMoveSpeedX,
+ initialY + timeInSec * config.noiseMoveSpeedY,
+ initialZ + timeInSec * config.noiseMoveSpeedZ
)
- // Fade in and out the noise as the animation progress.
- // TODO: replace it with a better curve
- turbulenceNoiseShader.setOpacity(sin(TWO_PI - progress) * config.luminosityMultiplier)
+ turbulenceNoiseShader.setOpacity(config.luminosityMultiplier)
invalidate()
}
@@ -101,16 +98,121 @@
animator.addListener(
object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
- visibility = INVISIBLE
- config.onAnimationEnd?.run()
+ currentAnimator = null
+ onAnimationEnd?.run()
}
}
)
+
animator.start()
+ currentAnimator = animator
}
- private fun applyConfig(config: TurbulenceNoiseAnimationConfig) {
- this.config = config
+ /** Plays the turbulence noise with linear ease-in. */
+ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+ fun playEaseIn(offsetX: Float = 0f, offsetY: Float = 0f, onAnimationEnd: Runnable? = null) {
+ if (noiseConfig == null) {
+ return
+ }
+ val config = noiseConfig!!
+
+ val animator = ValueAnimator.ofFloat(0f, 1f)
+ animator.duration = config.easeInDuration.toLong()
+
+ // Animation should start from the initial position to avoid abrupt transition.
+ val initialX = turbulenceNoiseShader.noiseOffsetX
+ val initialY = turbulenceNoiseShader.noiseOffsetY
+ val initialZ = turbulenceNoiseShader.noiseOffsetZ
+
+ animator.addUpdateListener { updateListener ->
+ val timeInSec = updateListener.currentPlayTime * MS_TO_SEC
+ val progress = updateListener.animatedValue as Float
+
+ turbulenceNoiseShader.setNoiseMove(
+ offsetX + initialX + timeInSec * config.noiseMoveSpeedX,
+ offsetY + initialY + timeInSec * config.noiseMoveSpeedY,
+ initialZ + timeInSec * config.noiseMoveSpeedZ
+ )
+
+ // TODO: Replace it with a better curve.
+ turbulenceNoiseShader.setOpacity(progress * config.luminosityMultiplier)
+
+ invalidate()
+ }
+
+ animator.addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ currentAnimator = null
+ onAnimationEnd?.run()
+ }
+ }
+ )
+
+ animator.start()
+ currentAnimator = animator
+ }
+
+ /** Plays the turbulence noise with linear ease-out. */
+ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+ fun playEaseOut(onAnimationEnd: Runnable? = null) {
+ if (noiseConfig == null) {
+ return
+ }
+ val config = noiseConfig!!
+
+ val animator = ValueAnimator.ofFloat(0f, 1f)
+ animator.duration = config.easeOutDuration.toLong()
+
+ // Animation should start from the initial position to avoid abrupt transition.
+ val initialX = turbulenceNoiseShader.noiseOffsetX
+ val initialY = turbulenceNoiseShader.noiseOffsetY
+ val initialZ = turbulenceNoiseShader.noiseOffsetZ
+
+ animator.addUpdateListener { updateListener ->
+ val timeInSec = updateListener.currentPlayTime * MS_TO_SEC
+ val progress = updateListener.animatedValue as Float
+
+ turbulenceNoiseShader.setNoiseMove(
+ initialX + timeInSec * config.noiseMoveSpeedX,
+ initialY + timeInSec * config.noiseMoveSpeedY,
+ initialZ + timeInSec * config.noiseMoveSpeedZ
+ )
+
+ // TODO: Replace it with a better curve.
+ turbulenceNoiseShader.setOpacity((1f - progress) * config.luminosityMultiplier)
+
+ invalidate()
+ }
+
+ animator.addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ currentAnimator = null
+ onAnimationEnd?.run()
+ }
+ }
+ )
+
+ animator.start()
+ currentAnimator = animator
+ }
+
+ /** Finishes the current animation if playing and plays the next animation if given. */
+ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+ fun finish(nextAnimation: Runnable? = null) {
+ // Calling Animator#end sets the animation state back to the initial state. Using pause to
+ // avoid visual artifacts.
+ currentAnimator?.pause()
+ currentAnimator = null
+
+ nextAnimation?.run()
+ }
+
+ /** Applies shader uniforms. Must be called before playing animation. */
+ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+ fun applyConfig(config: TurbulenceNoiseAnimationConfig) {
+ noiseConfig = config
with(turbulenceNoiseShader) {
setGridCount(config.gridCount)
setColor(ColorUtils.setAlphaComponent(config.color, config.opacity))
@@ -120,4 +222,8 @@
}
paint.blendMode = config.blendMode
}
+
+ internal fun clearConfig() {
+ noiseConfig = null
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index db7a145..15c3443 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -1070,7 +1070,9 @@
TurbulenceNoiseAnimationConfig.DEFAULT_OPACITY,
/* width= */ mMediaViewHolder.getMultiRippleView().getWidth(),
/* height= */ mMediaViewHolder.getMultiRippleView().getHeight(),
- TurbulenceNoiseAnimationConfig.DEFAULT_NOISE_DURATION_IN_MILLIS,
+ TurbulenceNoiseAnimationConfig.DEFAULT_MAX_DURATION_IN_MILLIS,
+ TurbulenceNoiseAnimationConfig.DEFAULT_EASING_DURATION_IN_MILLIS,
+ TurbulenceNoiseAnimationConfig.DEFAULT_EASING_DURATION_IN_MILLIS,
this.getContext().getResources().getDisplayMetrics().density,
BlendMode.PLUS,
/* onAnimationEnd= */ null
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt
index d25c8c1..614261d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt
@@ -17,8 +17,14 @@
import android.graphics.Color
import android.testing.AndroidTestingRunner
+import android.view.View.INVISIBLE
+import android.view.View.VISIBLE
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseController.Companion.AnimationState.EASE_IN
+import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseController.Companion.AnimationState.EASE_OUT
+import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseController.Companion.AnimationState.MAIN
+import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseController.Companion.AnimationState.NOT_PLAYING
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -33,26 +39,117 @@
private val fakeExecutor = FakeExecutor(fakeSystemClock)
@Test
- fun play_playsTurbulenceNoise() {
- val config = TurbulenceNoiseAnimationConfig(duration = 1000f)
+ fun play_playsTurbulenceNoiseInOrder() {
+ val config = TurbulenceNoiseAnimationConfig(maxDuration = 1000f)
val turbulenceNoiseView = TurbulenceNoiseView(context, null)
-
val turbulenceNoiseController = TurbulenceNoiseController(turbulenceNoiseView)
+ assertThat(turbulenceNoiseController.state).isEqualTo(NOT_PLAYING)
+
fakeExecutor.execute {
turbulenceNoiseController.play(config)
- assertThat(turbulenceNoiseView.isPlaying).isTrue()
+ assertThat(turbulenceNoiseController.state).isEqualTo(EASE_IN)
- fakeSystemClock.advanceTime(config.duration.toLong())
+ fakeSystemClock.advanceTime(config.easeInDuration.toLong())
- assertThat(turbulenceNoiseView.isPlaying).isFalse()
+ assertThat(turbulenceNoiseController.state).isEqualTo(MAIN)
+
+ fakeSystemClock.advanceTime(config.maxDuration.toLong())
+
+ assertThat(turbulenceNoiseController.state).isEqualTo(EASE_OUT)
+
+ fakeSystemClock.advanceTime(config.easeOutDuration.toLong())
+
+ assertThat(turbulenceNoiseController.state).isEqualTo(NOT_PLAYING)
+ }
+ }
+
+ @Test
+ fun play_alreadyPlaying_ignoresNewAnimationRequest() {
+ val config = TurbulenceNoiseAnimationConfig(maxDuration = 1000f)
+ val turbulenceNoiseView = TurbulenceNoiseView(context, null)
+ // Currently playing the main animation.
+ val turbulenceNoiseController =
+ TurbulenceNoiseController(turbulenceNoiseView).also { it.state = MAIN }
+
+ fakeExecutor.execute {
+ // Request another animation
+ turbulenceNoiseController.play(config)
+
+ assertThat(turbulenceNoiseController.state).isEqualTo(MAIN)
+ }
+ }
+
+ @Test
+ fun finish_mainAnimationPlaying_playsEaseOutAnimation() {
+ val config = TurbulenceNoiseAnimationConfig(maxDuration = 1000f)
+ val turbulenceNoiseView = TurbulenceNoiseView(context, null)
+ val turbulenceNoiseController =
+ TurbulenceNoiseController(turbulenceNoiseView).also { it.state = MAIN }
+
+ fakeExecutor.execute {
+ turbulenceNoiseController.play(config)
+
+ fakeSystemClock.advanceTime(config.maxDuration.toLong() / 2)
+
+ turbulenceNoiseController.finish()
+
+ assertThat(turbulenceNoiseController.state).isEqualTo(EASE_OUT)
+ }
+ }
+
+ @Test
+ fun finish_nonMainAnimationPlaying_doesNotFinishAnimation() {
+ val config = TurbulenceNoiseAnimationConfig(maxDuration = 1000f)
+ val turbulenceNoiseView = TurbulenceNoiseView(context, null)
+ val turbulenceNoiseController =
+ TurbulenceNoiseController(turbulenceNoiseView).also { it.state = EASE_IN }
+
+ fakeExecutor.execute {
+ turbulenceNoiseController.play(config)
+
+ fakeSystemClock.advanceTime(config.maxDuration.toLong() / 2)
+
+ turbulenceNoiseController.finish()
+
+ assertThat(turbulenceNoiseController.state).isEqualTo(EASE_IN)
+ }
+ }
+
+ @Test
+ fun onAnimationFinished_resetsStateCorrectly() {
+ val config = TurbulenceNoiseAnimationConfig(maxDuration = 1000f)
+ val turbulenceNoiseView = TurbulenceNoiseView(context, null)
+ val turbulenceNoiseController = TurbulenceNoiseController(turbulenceNoiseView)
+
+ assertThat(turbulenceNoiseController.state).isEqualTo(NOT_PLAYING)
+ assertThat(turbulenceNoiseView.visibility).isEqualTo(INVISIBLE)
+ assertThat(turbulenceNoiseView.noiseConfig).isNull()
+
+ fakeExecutor.execute {
+ turbulenceNoiseController.play(config)
+
+ assertThat(turbulenceNoiseController.state).isEqualTo(EASE_IN)
+ assertThat(turbulenceNoiseView.visibility).isEqualTo(VISIBLE)
+ assertThat(turbulenceNoiseView.noiseConfig).isEqualTo(config)
+
+ // Play all the animations.
+ fakeSystemClock.advanceTime(
+ config.easeInDuration.toLong() +
+ config.maxDuration.toLong() +
+ config.easeOutDuration.toLong()
+ )
+
+ assertThat(turbulenceNoiseController.state).isEqualTo(NOT_PLAYING)
+ assertThat(turbulenceNoiseView.visibility).isEqualTo(INVISIBLE)
+ assertThat(turbulenceNoiseView.noiseConfig).isNull()
}
}
@Test
fun updateColor_updatesCorrectColor() {
- val config = TurbulenceNoiseAnimationConfig(duration = 1000f, color = Color.WHITE)
+ val config = TurbulenceNoiseAnimationConfig(maxDuration = 1000f, color = Color.WHITE)
val turbulenceNoiseView = TurbulenceNoiseView(context, null)
val expectedColor = Color.RED
@@ -61,9 +158,9 @@
fakeExecutor.execute {
turbulenceNoiseController.play(config)
- turbulenceNoiseView.updateColor(expectedColor)
+ turbulenceNoiseController.updateNoiseColor(expectedColor)
- fakeSystemClock.advanceTime(config.duration.toLong())
+ fakeSystemClock.advanceTime(config.maxDuration.toLong())
assertThat(config.color).isEqualTo(expectedColor)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseViewTest.kt
index 633aac0..ce7f2f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseViewTest.kt
@@ -16,7 +16,6 @@
package com.android.systemui.surfaceeffects.turbulencenoise
import android.testing.AndroidTestingRunner
-import android.view.View
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.concurrency.FakeExecutor
@@ -34,53 +33,65 @@
private val fakeExecutor = FakeExecutor(fakeSystemClock)
@Test
- fun play_viewHasCorrectVisibility() {
- val config = TurbulenceNoiseAnimationConfig(duration = 1000f)
- val turbulenceNoiseView = TurbulenceNoiseView(context, null)
-
- assertThat(turbulenceNoiseView.visibility).isEqualTo(View.INVISIBLE)
-
- fakeExecutor.execute {
- turbulenceNoiseView.play(config)
-
- assertThat(turbulenceNoiseView.visibility).isEqualTo(View.VISIBLE)
-
- fakeSystemClock.advanceTime(config.duration.toLong())
-
- assertThat(turbulenceNoiseView.visibility).isEqualTo(View.INVISIBLE)
- }
- }
-
- @Test
fun play_playsAnimation() {
- val config = TurbulenceNoiseAnimationConfig(duration = 1000f)
- val turbulenceNoiseView = TurbulenceNoiseView(context, null)
+ val config = TurbulenceNoiseAnimationConfig()
+ val turbulenceNoiseView = TurbulenceNoiseView(context, null).also { it.applyConfig(config) }
+ var onAnimationEndCalled = false
fakeExecutor.execute {
- turbulenceNoiseView.play(config)
+ turbulenceNoiseView.play(onAnimationEnd = { onAnimationEndCalled = true })
- assertThat(turbulenceNoiseView.isPlaying).isTrue()
+ fakeSystemClock.advanceTime(config.maxDuration.toLong())
+
+ assertThat(onAnimationEndCalled).isTrue()
}
}
@Test
- fun play_onEnd_triggersOnAnimationEnd() {
- var animationEnd = false
- val config =
- TurbulenceNoiseAnimationConfig(
- duration = 1000f,
- onAnimationEnd = { animationEnd = true }
- )
- val turbulenceNoiseView = TurbulenceNoiseView(context, null)
+ fun playEaseIn_playsEaseInAnimation() {
+ val config = TurbulenceNoiseAnimationConfig()
+ val turbulenceNoiseView = TurbulenceNoiseView(context, null).also { it.applyConfig(config) }
+ var onAnimationEndCalled = false
fakeExecutor.execute {
- turbulenceNoiseView.play(config)
+ turbulenceNoiseView.playEaseIn(onAnimationEnd = { onAnimationEndCalled = true })
- assertThat(turbulenceNoiseView.isPlaying).isTrue()
+ fakeSystemClock.advanceTime(config.easeInDuration.toLong())
- fakeSystemClock.advanceTime(config.duration.toLong())
+ assertThat(onAnimationEndCalled).isTrue()
+ }
+ }
- assertThat(animationEnd).isTrue()
+ @Test
+ fun playEaseOut_playsEaseOutAnimation() {
+ val config = TurbulenceNoiseAnimationConfig()
+ val turbulenceNoiseView = TurbulenceNoiseView(context, null).also { it.applyConfig(config) }
+ var onAnimationEndCalled = false
+
+ fakeExecutor.execute {
+ turbulenceNoiseView.playEaseOut(onAnimationEnd = { onAnimationEndCalled = true })
+
+ fakeSystemClock.advanceTime(config.easeOutDuration.toLong())
+
+ assertThat(onAnimationEndCalled).isTrue()
+ }
+ }
+
+ @Test
+ fun finish_animationPlaying_finishesAnimation() {
+ val config = TurbulenceNoiseAnimationConfig()
+ val turbulenceNoiseView = TurbulenceNoiseView(context, null).also { it.applyConfig(config) }
+ var onAnimationEndCalled = false
+
+ fakeExecutor.execute {
+ turbulenceNoiseView.play(onAnimationEnd = { onAnimationEndCalled = true })
+
+ assertThat(turbulenceNoiseView.currentAnimator).isNotNull()
+
+ turbulenceNoiseView.finish()
+
+ assertThat(onAnimationEndCalled).isTrue()
+ assertThat(turbulenceNoiseView.currentAnimator).isNull()
}
}
}