Add turbulence noise effects after ripple in UMO.
There will be a follow up CL to polish the turbulence noise. This is a first pass. Please find the recording in the bug. Bug: 249536060 Test: TurbulenceNoiseControllerTest, MultiRippleControllerTest, MediaControlPanelTest, ColorSchemeTransitionTest Change-Id: Iab2e9725e2b9fc6ec2eaa9f7721054458731fd0b
This commit is contained in:
@@ -53,6 +53,15 @@
|
||||
app:layout_constraintTop_toTopOf="@id/album_art"
|
||||
app:layout_constraintBottom_toBottomOf="@id/album_art" />
|
||||
|
||||
<com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseView
|
||||
android:id="@+id/turbulence_noise_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/qs_media_session_height_expanded"
|
||||
app:layout_constraintStart_toStartOf="@id/album_art"
|
||||
app:layout_constraintEnd_toEndOf="@id/album_art"
|
||||
app:layout_constraintTop_toTopOf="@id/album_art"
|
||||
app:layout_constraintBottom_toBottomOf="@id/album_art" />
|
||||
|
||||
<!-- Guideline for output switcher -->
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/center_vertical_guideline"
|
||||
|
||||
@@ -44,6 +44,16 @@
|
||||
app:layout_constraintTop_toTopOf="@+id/album_art"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/album_art" />
|
||||
|
||||
<!-- Turbulence noise must have the same constraint as the album art. -->
|
||||
<Constraint
|
||||
android:id="@+id/turbulence_noise_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/qs_media_session_height_collapsed"
|
||||
app:layout_constraintStart_toStartOf="@+id/album_art"
|
||||
app:layout_constraintEnd_toEndOf="@+id/album_art"
|
||||
app:layout_constraintTop_toTopOf="@+id/album_art"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/album_art" />
|
||||
|
||||
<Constraint
|
||||
android:id="@+id/header_title"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -37,6 +37,16 @@
|
||||
app:layout_constraintTop_toTopOf="@+id/album_art"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/album_art" />
|
||||
|
||||
<!-- Turbulence noise must have the same constraint as the album art. -->
|
||||
<Constraint
|
||||
android:id="@+id/turbulence_noise_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/qs_media_session_height_expanded"
|
||||
app:layout_constraintStart_toStartOf="@+id/album_art"
|
||||
app:layout_constraintEnd_toEndOf="@+id/album_art"
|
||||
app:layout_constraintTop_toTopOf="@+id/album_art"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/album_art" />
|
||||
|
||||
<Constraint
|
||||
android:id="@+id/header_title"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -27,6 +27,7 @@ import androidx.constraintlayout.widget.Barrier
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.media.controls.models.GutsViewHolder
|
||||
import com.android.systemui.surfaceeffects.ripple.MultiRippleView
|
||||
import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseView
|
||||
import com.android.systemui.util.animation.TransitionLayout
|
||||
|
||||
private const val TAG = "MediaViewHolder"
|
||||
@@ -38,6 +39,8 @@ class MediaViewHolder constructor(itemView: View) {
|
||||
// Player information
|
||||
val albumView = itemView.requireViewById<ImageView>(R.id.album_art)
|
||||
val multiRippleView = itemView.requireViewById<MultiRippleView>(R.id.touch_ripple_view)
|
||||
val turbulenceNoiseView =
|
||||
itemView.requireViewById<TurbulenceNoiseView>(R.id.turbulence_noise_view)
|
||||
val appIcon = itemView.requireViewById<ImageView>(R.id.icon)
|
||||
val titleText = itemView.requireViewById<TextView>(R.id.header_title)
|
||||
val artistText = itemView.requireViewById<TextView>(R.id.header_artist)
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.android.settingslib.Utils
|
||||
import com.android.systemui.media.controls.models.player.MediaViewHolder
|
||||
import com.android.systemui.monet.ColorScheme
|
||||
import com.android.systemui.surfaceeffects.ripple.MultiRippleController
|
||||
import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseController
|
||||
|
||||
/**
|
||||
* A [ColorTransition] is an object that updates the colors of views each time [updateColorScheme]
|
||||
@@ -102,13 +103,21 @@ internal constructor(
|
||||
private val context: Context,
|
||||
private val mediaViewHolder: MediaViewHolder,
|
||||
private val multiRippleController: MultiRippleController,
|
||||
private val turbulenceNoiseController: TurbulenceNoiseController,
|
||||
animatingColorTransitionFactory: AnimatingColorTransitionFactory
|
||||
) {
|
||||
constructor(
|
||||
context: Context,
|
||||
mediaViewHolder: MediaViewHolder,
|
||||
multiRippleController: MultiRippleController,
|
||||
) : this(context, mediaViewHolder, multiRippleController, ::AnimatingColorTransition)
|
||||
turbulenceNoiseController: TurbulenceNoiseController
|
||||
) : this(
|
||||
context,
|
||||
mediaViewHolder,
|
||||
multiRippleController,
|
||||
turbulenceNoiseController,
|
||||
::AnimatingColorTransition
|
||||
)
|
||||
|
||||
val bgColor = context.getColor(com.android.systemui.R.color.material_dynamic_secondary95)
|
||||
val surfaceColor =
|
||||
@@ -129,6 +138,7 @@ internal constructor(
|
||||
mediaViewHolder.actionPlayPause.backgroundTintList = accentColorList
|
||||
mediaViewHolder.gutsViewHolder.setAccentPrimaryColor(accentPrimary)
|
||||
multiRippleController.updateColor(accentPrimary)
|
||||
turbulenceNoiseController.updateNoiseColor(accentPrimary)
|
||||
}
|
||||
|
||||
val accentSecondary =
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.BlendMode;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorMatrix;
|
||||
import android.graphics.ColorMatrixColorFilter;
|
||||
@@ -64,6 +65,7 @@ import androidx.annotation.UiThread;
|
||||
import androidx.constraintlayout.widget.ConstraintSet;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.graphics.ColorUtils;
|
||||
import com.android.internal.jank.InteractionJankMonitor;
|
||||
import com.android.internal.logging.InstanceId;
|
||||
import com.android.settingslib.widget.AdaptiveIcon;
|
||||
@@ -101,9 +103,12 @@ import com.android.systemui.shared.system.SysUiStatsLog;
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.surfaceeffects.ripple.MultiRippleController;
|
||||
import com.android.systemui.surfaceeffects.ripple.MultiRippleView;
|
||||
import com.android.systemui.surfaceeffects.ripple.RippleAnimation;
|
||||
import com.android.systemui.surfaceeffects.ripple.RippleAnimationConfig;
|
||||
import com.android.systemui.surfaceeffects.ripple.RippleShader;
|
||||
import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseAnimationConfig;
|
||||
import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseController;
|
||||
import com.android.systemui.util.ColorUtilKt;
|
||||
import com.android.systemui.util.animation.TransitionLayout;
|
||||
import com.android.systemui.util.time.SystemClock;
|
||||
@@ -216,7 +221,9 @@ public class MediaControlPanel {
|
||||
private boolean mShowBroadcastDialogButton = false;
|
||||
private String mSwitchBroadcastApp;
|
||||
private MultiRippleController mMultiRippleController;
|
||||
private TurbulenceNoiseController mTurbulenceNoiseController;
|
||||
private FeatureFlags mFeatureFlags;
|
||||
private TurbulenceNoiseAnimationConfig mTurbulenceNoiseAnimationConfig = null;
|
||||
|
||||
/**
|
||||
* Initialize a new control panel
|
||||
@@ -393,9 +400,20 @@ public class MediaControlPanel {
|
||||
AnimatorSet exit = loadAnimator(R.anim.media_metadata_exit,
|
||||
Interpolators.EMPHASIZED_ACCELERATE, titleText, artistText);
|
||||
|
||||
mMultiRippleController = new MultiRippleController(vh.getMultiRippleView());
|
||||
MultiRippleView multiRippleView = vh.getMultiRippleView();
|
||||
mMultiRippleController = new MultiRippleController(multiRippleView);
|
||||
mTurbulenceNoiseController = new TurbulenceNoiseController(vh.getTurbulenceNoiseView());
|
||||
multiRippleView.addRipplesFinishedListener(
|
||||
() -> {
|
||||
if (mTurbulenceNoiseAnimationConfig == null) {
|
||||
mTurbulenceNoiseAnimationConfig = createLingeringNoiseAnimation();
|
||||
}
|
||||
// Color will be correctly updated in ColorSchemeTransition.
|
||||
mTurbulenceNoiseController.play(mTurbulenceNoiseAnimationConfig);
|
||||
}
|
||||
);
|
||||
mColorSchemeTransition = new ColorSchemeTransition(
|
||||
mContext, mMediaViewHolder, mMultiRippleController);
|
||||
mContext, mMediaViewHolder, mMultiRippleController, mTurbulenceNoiseController);
|
||||
mMetadataAnimationHandler = new MetadataAnimationHandler(exit, enter);
|
||||
}
|
||||
|
||||
@@ -1025,7 +1043,7 @@ public class MediaControlPanel {
|
||||
/* maxWidth= */ maxSize,
|
||||
/* maxHeight= */ maxSize,
|
||||
/* pixelDensity= */ getContext().getResources().getDisplayMetrics().density,
|
||||
mColorSchemeTransition.getAccentPrimary().getTargetColor(),
|
||||
mColorSchemeTransition.getAccentPrimary().getCurrentColor(),
|
||||
/* opacity= */ 100,
|
||||
/* shouldFillRipple= */ false,
|
||||
/* sparkleStrength= */ 0f,
|
||||
@@ -1034,6 +1052,26 @@ public class MediaControlPanel {
|
||||
);
|
||||
}
|
||||
|
||||
private TurbulenceNoiseAnimationConfig createLingeringNoiseAnimation() {
|
||||
return new TurbulenceNoiseAnimationConfig(
|
||||
TurbulenceNoiseAnimationConfig.DEFAULT_NOISE_GRID_COUNT,
|
||||
TurbulenceNoiseAnimationConfig.DEFAULT_LUMINOSITY_MULTIPLIER,
|
||||
/* noiseMoveSpeedX= */ 0f,
|
||||
/* noiseMoveSpeedY= */ 0f,
|
||||
TurbulenceNoiseAnimationConfig.DEFAULT_NOISE_SPEED_Z,
|
||||
/* color= */ mColorSchemeTransition.getAccentPrimary().getCurrentColor(),
|
||||
// We want to add (BlendMode.PLUS) the turbulence noise on top of the album art.
|
||||
// Thus, set the background color with alpha 0.
|
||||
/* backgroundColor= */ ColorUtils.setAlphaComponent(Color.BLACK, 0),
|
||||
TurbulenceNoiseAnimationConfig.DEFAULT_OPACITY,
|
||||
/* width= */ mMediaViewHolder.getMultiRippleView().getWidth(),
|
||||
/* height= */ mMediaViewHolder.getMultiRippleView().getHeight(),
|
||||
TurbulenceNoiseAnimationConfig.DEFAULT_NOISE_DURATION_IN_MILLIS,
|
||||
this.getContext().getResources().getDisplayMetrics().density,
|
||||
BlendMode.PLUS,
|
||||
/* onAnimationEnd= */ null
|
||||
);
|
||||
}
|
||||
private void clearButton(final ImageButton button) {
|
||||
button.setImageDrawable(null);
|
||||
button.setContentDescription(null);
|
||||
|
||||
@@ -31,11 +31,21 @@ import android.view.View
|
||||
class MultiRippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
|
||||
|
||||
internal val ripples = ArrayList<RippleAnimation>()
|
||||
private val listeners = ArrayList<RipplesFinishedListener>()
|
||||
private val ripplePaint = Paint()
|
||||
private var isWarningLogged = false
|
||||
|
||||
companion object {
|
||||
private const val TAG = "MultiRippleView"
|
||||
|
||||
interface RipplesFinishedListener {
|
||||
/** Triggered when all the ripples finish running. */
|
||||
fun onRipplesFinish()
|
||||
}
|
||||
}
|
||||
|
||||
fun addRipplesFinishedListener(listener: RipplesFinishedListener) {
|
||||
listeners.add(listener)
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas?) {
|
||||
@@ -62,6 +72,10 @@ class MultiRippleView(context: Context?, attrs: AttributeSet?) : View(context, a
|
||||
shouldInvalidate = shouldInvalidate || anim.isPlaying()
|
||||
}
|
||||
|
||||
if (shouldInvalidate) invalidate()
|
||||
if (shouldInvalidate) {
|
||||
invalidate()
|
||||
} else { // Nothing is playing.
|
||||
listeners.forEach { listener -> listener.onRipplesFinish() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ data class TurbulenceNoiseAnimationConfig(
|
||||
val noiseMoveSpeedZ: Float = DEFAULT_NOISE_SPEED_Z,
|
||||
|
||||
/** Color of the effect. */
|
||||
val color: Int = DEFAULT_COLOR,
|
||||
var color: Int = DEFAULT_COLOR,
|
||||
/** Background color of the effect. */
|
||||
val backgroundColor: Int = DEFAULT_BACKGROUND_COLOR,
|
||||
val opacity: Int = DEFAULT_OPACITY,
|
||||
|
||||
@@ -17,6 +17,11 @@ package com.android.systemui.surfaceeffects.turbulencenoise
|
||||
|
||||
/** A controller that plays [TurbulenceNoiseView]. */
|
||||
class TurbulenceNoiseController(private val turbulenceNoiseView: TurbulenceNoiseView) {
|
||||
/** Updates the color of the noise. */
|
||||
fun updateNoiseColor(color: Int) {
|
||||
turbulenceNoiseView.updateColor(color)
|
||||
}
|
||||
|
||||
// TODO: add cancel and/ or pause once design requirements become clear.
|
||||
/** Plays [TurbulenceNoiseView] with the given config. */
|
||||
fun play(turbulenceNoiseAnimationConfig: TurbulenceNoiseAnimationConfig) {
|
||||
|
||||
@@ -104,8 +104,8 @@ class TurbulenceNoiseShader : RuntimeShader(TURBULENCE_NOISE_SHADER) {
|
||||
*
|
||||
* Expected value range is [1, 0].
|
||||
*/
|
||||
fun setOpacity(fadeOut: Float) {
|
||||
setFloatUniform("in_opacity", fadeOut)
|
||||
fun setOpacity(opacity: Float) {
|
||||
setFloatUniform("in_opacity", opacity)
|
||||
}
|
||||
|
||||
/** Sets the size of the shader. */
|
||||
|
||||
@@ -40,6 +40,7 @@ class TurbulenceNoiseView(context: Context?, attrs: AttributeSet?) : View(contex
|
||||
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
|
||||
@@ -49,6 +50,14 @@ class TurbulenceNoiseView(context: Context?, attrs: AttributeSet?) : View(contex
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas?) {
|
||||
if (canvas == null || !canvas.isHardwareAccelerated) {
|
||||
// Drawing with the turbulence noise shader requires hardware acceleration, so skip
|
||||
@@ -101,6 +110,7 @@ class TurbulenceNoiseView(context: Context?, attrs: AttributeSet?) : View(contex
|
||||
}
|
||||
|
||||
private fun applyConfig(config: TurbulenceNoiseAnimationConfig) {
|
||||
this.config = config
|
||||
with(turbulenceNoiseShader) {
|
||||
setGridCount(config.gridCount)
|
||||
setColor(ColorUtils.setAlphaComponent(config.color, config.opacity))
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.android.systemui.media.controls.models.GutsViewHolder
|
||||
import com.android.systemui.media.controls.models.player.MediaViewHolder
|
||||
import com.android.systemui.monet.ColorScheme
|
||||
import com.android.systemui.surfaceeffects.ripple.MultiRippleController
|
||||
import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseController
|
||||
import junit.framework.Assert.assertEquals
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
@@ -62,6 +63,7 @@ class ColorSchemeTransitionTest : SysuiTestCase() {
|
||||
@Mock private lateinit var mediaViewHolder: MediaViewHolder
|
||||
@Mock private lateinit var gutsViewHolder: GutsViewHolder
|
||||
@Mock private lateinit var multiRippleController: MultiRippleController
|
||||
@Mock private lateinit var turbulenceNoiseController: TurbulenceNoiseController
|
||||
|
||||
@JvmField @Rule val mockitoRule = MockitoJUnit.rule()
|
||||
|
||||
@@ -76,6 +78,7 @@ class ColorSchemeTransitionTest : SysuiTestCase() {
|
||||
context,
|
||||
mediaViewHolder,
|
||||
multiRippleController,
|
||||
turbulenceNoiseController,
|
||||
animatingColorTransitionFactory
|
||||
)
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ import com.android.systemui.plugins.FalsingManager
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||
import com.android.systemui.surfaceeffects.ripple.MultiRippleView
|
||||
import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseView
|
||||
import com.android.systemui.util.animation.TransitionLayout
|
||||
import com.android.systemui.util.concurrency.FakeExecutor
|
||||
import com.android.systemui.util.mockito.KotlinArgumentCaptor
|
||||
@@ -178,6 +179,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
|
||||
private lateinit var dismiss: FrameLayout
|
||||
private lateinit var dismissText: TextView
|
||||
private lateinit var multiRippleView: MultiRippleView
|
||||
private lateinit var turbulenceNoiseView: TurbulenceNoiseView
|
||||
|
||||
private lateinit var session: MediaSession
|
||||
private lateinit var device: MediaDeviceData
|
||||
@@ -382,6 +384,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
multiRippleView = MultiRippleView(context, null)
|
||||
turbulenceNoiseView = TurbulenceNoiseView(context, null)
|
||||
|
||||
whenever(viewHolder.player).thenReturn(view)
|
||||
whenever(viewHolder.appIcon).thenReturn(appIcon)
|
||||
@@ -425,6 +428,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
|
||||
whenever(viewHolder.actionsTopBarrier).thenReturn(actionsTopBarrier)
|
||||
|
||||
whenever(viewHolder.multiRippleView).thenReturn(multiRippleView)
|
||||
whenever(viewHolder.turbulenceNoiseView).thenReturn(turbulenceNoiseView)
|
||||
}
|
||||
|
||||
/** Initialize elements for the recommendation view holder */
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.systemui.surfaceeffects.ripple
|
||||
|
||||
import android.testing.AndroidTestingRunner
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.util.concurrency.FakeExecutor
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
class MultiRippleViewTest : SysuiTestCase() {
|
||||
private val fakeSystemClock = FakeSystemClock()
|
||||
// FakeExecutor is needed to run animator.
|
||||
private val fakeExecutor = FakeExecutor(fakeSystemClock)
|
||||
|
||||
@Test
|
||||
fun onRippleFinishes_triggersRippleFinished() {
|
||||
val multiRippleView = MultiRippleView(context, null)
|
||||
val multiRippleController = MultiRippleController(multiRippleView)
|
||||
val rippleAnimationConfig = RippleAnimationConfig(duration = 1000L)
|
||||
|
||||
var isTriggered = false
|
||||
val listener =
|
||||
object : MultiRippleView.Companion.RipplesFinishedListener {
|
||||
override fun onRipplesFinish() {
|
||||
isTriggered = true
|
||||
}
|
||||
}
|
||||
multiRippleView.addRipplesFinishedListener(listener)
|
||||
|
||||
fakeExecutor.execute {
|
||||
val rippleAnimation = RippleAnimation(rippleAnimationConfig)
|
||||
multiRippleController.play(rippleAnimation)
|
||||
|
||||
fakeSystemClock.advanceTime(rippleAnimationConfig.duration)
|
||||
|
||||
assertThat(isTriggered).isTrue()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.android.systemui.surfaceeffects.turbulencenoise
|
||||
|
||||
import android.graphics.Color
|
||||
import android.testing.AndroidTestingRunner
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
@@ -48,4 +49,23 @@ class TurbulenceNoiseControllerTest : SysuiTestCase() {
|
||||
assertThat(turbulenceNoiseView.isPlaying).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateColor_updatesCorrectColor() {
|
||||
val config = TurbulenceNoiseAnimationConfig(duration = 1000f, color = Color.WHITE)
|
||||
val turbulenceNoiseView = TurbulenceNoiseView(context, null)
|
||||
val expectedColor = Color.RED
|
||||
|
||||
val turbulenceNoiseController = TurbulenceNoiseController(turbulenceNoiseView)
|
||||
|
||||
fakeExecutor.execute {
|
||||
turbulenceNoiseController.play(config)
|
||||
|
||||
turbulenceNoiseView.updateColor(expectedColor)
|
||||
|
||||
fakeSystemClock.advanceTime(config.duration.toLong())
|
||||
|
||||
assertThat(config.color).isEqualTo(expectedColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user