diff options
| author | 2023-01-06 02:18:49 +0000 | |
|---|---|---|
| committer | 2023-01-06 02:18:49 +0000 | |
| commit | ee663e2cd0a4e0f63a98131b2bcbeb42e666782a (patch) | |
| tree | 1c54a0c55a9c55281995e188e780c37272483c18 | |
| parent | ba1ee78ab77aa04db2a97f870826a13f613e48c2 (diff) | |
| parent | 1887b976699123fe433f7b1216e728aaf31866ef (diff) | |
Merge "Refactor Turbulence noise" into tm-qpr-dev
7 files changed, 408 insertions, 88 deletions
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 5ac3aad749fc..67159512a701 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 @@ data class TurbulenceNoiseAnimationConfig( 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 4c7e5f4c7093..b8f4b276dd6a 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 19c114d2693c..7456c4334f0f 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 @@ class TurbulenceNoiseShader : RuntimeShader(TURBULENCE_NOISE_SHADER) { 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 68712c6cd1de..e1e515d14771 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,75 +25,162 @@ import android.util.AttributeSet 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 + @VisibleForTesting var noiseConfig: TurbulenceNoiseAnimationConfig? = null + @VisibleForTesting var currentAnimator: ValueAnimator? = null - val isPlaying: Boolean - get() = animator.isRunning + override fun onDraw(canvas: Canvas?) { + if (canvas == null || !canvas.isHardwareAccelerated) { + // Drawing with the turbulence noise shader requires hardware acceleration, so skip + // if it's unsupported. + return + } - init { - // Only visible during the animation. - visibility = INVISIBLE + canvas.drawPaint(paint) } /** 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) + internal fun updateColor(color: Int) { + noiseConfig?.let { + turbulenceNoiseShader.setColor(ColorUtils.setAlphaComponent(color, it.opacity)) } } - override fun onDraw(canvas: Canvas?) { - if (canvas == null || !canvas.isHardwareAccelerated) { - // Drawing with the turbulence noise shader requires hardware acceleration, so skip - // if it's unsupported. + /** Plays the turbulence noise with no easing. */ + @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) + fun play(onAnimationEnd: Runnable? = null) { + if (noiseConfig == null) { return } + val config = noiseConfig!! - canvas.drawPaint(paint) + 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 + turbulenceNoiseShader.setNoiseMove( + initialX + timeInSec * config.noiseMoveSpeedX, + initialY + timeInSec * config.noiseMoveSpeedY, + initialZ + timeInSec * config.noiseMoveSpeedZ + ) + + turbulenceNoiseShader.setOpacity(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-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 } - fun play(config: TurbulenceNoiseAnimationConfig) { - if (isPlaying) { - return // Ignore if the animation is playing. + /** Plays the turbulence noise with linear ease-out. */ + @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) + fun playEaseOut(onAnimationEnd: Runnable? = null) { + if (noiseConfig == null) { + return } - visibility = VISIBLE - applyConfig(config) + val config = noiseConfig!! + + val animator = ValueAnimator.ofFloat(0f, 1f) + animator.duration = config.easeOutDuration.toLong() - // Add random offset to avoid same patterned noise. - val offsetX = random.nextFloat() - val offsetY = random.nextFloat() + // Animation should start from the initial position to avoid abrupt transition. + val initialX = turbulenceNoiseShader.noiseOffsetX + val initialY = turbulenceNoiseShader.noiseOffsetY + val initialZ = turbulenceNoiseShader.noiseOffsetZ - animator.duration = config.duration.toLong() 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 + val progress = 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) + // TODO: Replace it with a better curve. + turbulenceNoiseShader.setOpacity((1f - progress) * config.luminosityMultiplier) invalidate() } @@ -101,16 +188,31 @@ class TurbulenceNoiseView(context: Context?, attrs: AttributeSet?) : View(contex animator.addListener( object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { - visibility = INVISIBLE - config.onAnimationEnd?.run() + 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() } - private fun applyConfig(config: TurbulenceNoiseAnimationConfig) { - this.config = config + /** 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 @@ class TurbulenceNoiseView(context: Context?, attrs: AttributeSet?) : View(contex } 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 db7a145e2ade..15c34430f455 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 @@ public class MediaControlPanel { 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 d25c8c1a5899..614261d476c6 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 @@ package com.android.systemui.surfaceeffects.turbulencenoise 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 @@ class TurbulenceNoiseControllerTest : SysuiTestCase() { 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(turbulenceNoiseController.state).isEqualTo(EASE_IN) + + fakeSystemClock.advanceTime(config.easeInDuration.toLong()) + + 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(turbulenceNoiseView.isPlaying).isTrue() + assertThat(turbulenceNoiseController.state).isEqualTo(EASE_IN) + assertThat(turbulenceNoiseView.visibility).isEqualTo(VISIBLE) + assertThat(turbulenceNoiseView.noiseConfig).isEqualTo(config) - fakeSystemClock.advanceTime(config.duration.toLong()) + // Play all the animations. + fakeSystemClock.advanceTime( + config.easeInDuration.toLong() + + config.maxDuration.toLong() + + config.easeOutDuration.toLong() + ) - assertThat(turbulenceNoiseView.isPlaying).isFalse() + 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 @@ class TurbulenceNoiseControllerTest : SysuiTestCase() { 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 633aac076502..ce7f2f4eb6ea 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 @@ class TurbulenceNoiseViewTest : SysuiTestCase() { 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) + fun play_playsAnimation() { + 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 }) + + fakeSystemClock.advanceTime(config.maxDuration.toLong()) - assertThat(turbulenceNoiseView.visibility).isEqualTo(View.VISIBLE) + assertThat(onAnimationEndCalled).isTrue() + } + } - fakeSystemClock.advanceTime(config.duration.toLong()) + @Test + fun playEaseIn_playsEaseInAnimation() { + val config = TurbulenceNoiseAnimationConfig() + val turbulenceNoiseView = TurbulenceNoiseView(context, null).also { it.applyConfig(config) } + var onAnimationEndCalled = false - assertThat(turbulenceNoiseView.visibility).isEqualTo(View.INVISIBLE) + fakeExecutor.execute { + turbulenceNoiseView.playEaseIn(onAnimationEnd = { onAnimationEndCalled = true }) + + fakeSystemClock.advanceTime(config.easeInDuration.toLong()) + + assertThat(onAnimationEndCalled).isTrue() } } @Test - fun play_playsAnimation() { - val config = TurbulenceNoiseAnimationConfig(duration = 1000f) - val turbulenceNoiseView = TurbulenceNoiseView(context, null) + fun playEaseOut_playsEaseOutAnimation() { + val config = TurbulenceNoiseAnimationConfig() + val turbulenceNoiseView = TurbulenceNoiseView(context, null).also { it.applyConfig(config) } + var onAnimationEndCalled = false fakeExecutor.execute { - turbulenceNoiseView.play(config) + turbulenceNoiseView.playEaseOut(onAnimationEnd = { onAnimationEndCalled = true }) + + fakeSystemClock.advanceTime(config.easeOutDuration.toLong()) - assertThat(turbulenceNoiseView.isPlaying).isTrue() + 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 finish_animationPlaying_finishesAnimation() { + 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() + assertThat(turbulenceNoiseView.currentAnimator).isNotNull() - fakeSystemClock.advanceTime(config.duration.toLong()) + turbulenceNoiseView.finish() - assertThat(animationEnd).isTrue() + assertThat(onAnimationEndCalled).isTrue() + assertThat(turbulenceNoiseView.currentAnimator).isNull() } } } |