Merge "Fix RippleFinished being called on first draw." into tm-qpr-dev
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleController.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleController.kt
index 93e78ac..8cd8bf6 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleController.kt
@@ -21,9 +21,20 @@
/** 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 @@
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()
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt
index b8dc223..550d2c6 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt
@@ -33,21 +33,11 @@
@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 @@
if (shouldInvalidate) {
invalidate()
- } else { // Nothing is playing.
- listeners.forEach { listener -> listener.onRipplesFinish() }
}
}
}
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 df8fb91..c2442d6 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
@@ -404,7 +404,7 @@
MultiRippleView multiRippleView = vh.getMultiRippleView();
mMultiRippleController = new MultiRippleController(multiRippleView);
mTurbulenceNoiseController = new TurbulenceNoiseController(vh.getTurbulenceNoiseView());
- multiRippleView.addRipplesFinishedListener(
+ mMultiRippleController.addRipplesFinishedListener(
() -> {
if (mTurbulenceNoiseAnimationConfig == null) {
mTurbulenceNoiseAnimationConfig = createLingeringNoiseAnimation();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt
index 0d19ab1..056e386 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt
@@ -101,4 +101,52 @@
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()
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleViewTest.kt
deleted file mode 100644
index 2024d53..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleViewTest.kt
+++ /dev/null
@@ -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()
- }
- }
-}