Merge "Fix RippleFinished being called on first draw." into tm-qpr-dev

This commit is contained in:
Yein Jo
2022-12-12 21:04:23 +00:00
committed by Android (Google) Code Review
5 changed files with 67 additions and 73 deletions

View File

@@ -21,9 +21,20 @@ import androidx.annotation.VisibleForTesting
/** Controller that handles playing [RippleAnimation]. */
class MultiRippleController(private val multipleRippleView: MultiRippleView) {
private val ripplesFinishedListeners = ArrayList<RipplesFinishedListener>()
companion object {
/** Max number of ripple animations at a time. */
@VisibleForTesting const val MAX_RIPPLE_NUMBER = 10
interface RipplesFinishedListener {
/** Triggered when all the ripples finish running. */
fun onRipplesFinish()
}
}
fun addRipplesFinishedListener(listener: RipplesFinishedListener) {
ripplesFinishedListeners.add(listener)
}
/** Updates all the ripple colors during the animation. */
@@ -38,8 +49,13 @@ class MultiRippleController(private val multipleRippleView: MultiRippleView) {
multipleRippleView.ripples.add(rippleAnimation)
// Remove ripple once the animation is done
rippleAnimation.play { multipleRippleView.ripples.remove(rippleAnimation) }
rippleAnimation.play {
// Remove ripple once the animation is done
multipleRippleView.ripples.remove(rippleAnimation)
if (multipleRippleView.ripples.isEmpty()) {
ripplesFinishedListeners.forEach { listener -> listener.onRipplesFinish() }
}
}
// Trigger drawing
multipleRippleView.invalidate()

View File

@@ -33,21 +33,11 @@ class MultiRippleView(context: Context?, attrs: AttributeSet?) : View(context, a
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
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?) {
@@ -76,8 +66,6 @@ class MultiRippleView(context: Context?, attrs: AttributeSet?) : View(context, a
if (shouldInvalidate) {
invalidate()
} else { // Nothing is playing.
listeners.forEach { listener -> listener.onRipplesFinish() }
}
}
}

View File

@@ -404,7 +404,7 @@ public class MediaControlPanel {
MultiRippleView multiRippleView = vh.getMultiRippleView();
mMultiRippleController = new MultiRippleController(multiRippleView);
mTurbulenceNoiseController = new TurbulenceNoiseController(vh.getTurbulenceNoiseView());
multiRippleView.addRipplesFinishedListener(
mMultiRippleController.addRipplesFinishedListener(
() -> {
if (mTurbulenceNoiseAnimationConfig == null) {
mTurbulenceNoiseAnimationConfig = createLingeringNoiseAnimation();

View File

@@ -101,4 +101,52 @@ class MultiRippleControllerTest : SysuiTestCase() {
assertThat(multiRippleView.ripples.size).isEqualTo(0)
}
}
@Test
fun play_onFinishesAllRipples_triggersRipplesFinished() {
var isTriggered = false
val listener =
object : MultiRippleController.Companion.RipplesFinishedListener {
override fun onRipplesFinish() {
isTriggered = true
}
}
multiRippleController.addRipplesFinishedListener(listener)
fakeExecutor.execute {
multiRippleController.play(RippleAnimation(RippleAnimationConfig(duration = 1000)))
multiRippleController.play(RippleAnimation(RippleAnimationConfig(duration = 2000)))
assertThat(multiRippleView.ripples.size).isEqualTo(2)
fakeSystemClock.advanceTime(2000L)
assertThat(multiRippleView.ripples.size).isEqualTo(0)
assertThat(isTriggered).isTrue()
}
}
@Test
fun play_notAllRipplesFinished_doesNotTriggerRipplesFinished() {
var isTriggered = false
val listener =
object : MultiRippleController.Companion.RipplesFinishedListener {
override fun onRipplesFinish() {
isTriggered = true
}
}
multiRippleController.addRipplesFinishedListener(listener)
fakeExecutor.execute {
multiRippleController.play(RippleAnimation(RippleAnimationConfig(duration = 1000)))
multiRippleController.play(RippleAnimation(RippleAnimationConfig(duration = 2000)))
assertThat(multiRippleView.ripples.size).isEqualTo(2)
fakeSystemClock.advanceTime(1000L)
assertThat(multiRippleView.ripples.size).isEqualTo(1)
assertThat(isTriggered).isFalse()
}
}
}

View File

@@ -1,58 +0,0 @@
/*
* 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()
}
}
}