Merge "Fix RippleFinished being called on first draw." into tm-qpr-dev am: 801a4b98a3 am: 3f7a9f81c0
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20665370 Change-Id: Ic01e80f6c0409861c55ecae4d27b9144ba2e4c7e Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user