Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 959ac760 authored by Joshua Tsuji's avatar Joshua Tsuji
Browse files

Modifies PhysicsAnimator's cancellation methods to support tests.

Test: atest SystemUITests
Change-Id: I97ae15d827958b2fdcf7a9f9df6e1254406fd0c8
parent a76b7135
Loading
Loading
Loading
Loading
+31 −6
Original line number Diff line number Diff line
@@ -125,6 +125,13 @@ class PhysicsAnimator<T> private constructor (val target: T) {
     */
    internal var startAction: () -> Unit = ::startInternal

    /**
     * Action to run when [cancel] is called. This can be changed by
     * [PhysicsAnimatorTestUtils.prepareForTest] to cancel animations from the main thread, which
     * is required.
     */
    internal var cancelAction: (Set<FloatPropertyCompat<in T>>) -> Unit = ::cancelInternal

    /**
     * Springs a property to the given value, using the provided configuration settings.
     *
@@ -429,10 +436,13 @@ class PhysicsAnimator<T> private constructor (val target: T) {
                        max = max(currentValue, this.max)
                    }

                    // Apply the configuration and start the animation. Since flings can't be
                    // redirected while in motion, cancel it first.
                    // Flings can't be updated to a new position while maintaining velocity, because
                    // we're using the explicitly provided start velocity. Cancel any flings (or
                    // springs) on this property before flinging.
                    cancel(animatedProperty)

                    // Apply the configuration and start the animation.
                    getFlingAnimation(animatedProperty)
                            .also { it.cancel() }
                            .also { flingConfig.applyToAnimation(it) }
                            .start()
                }
@@ -707,11 +717,26 @@ class PhysicsAnimator<T> private constructor (val target: T) {
        return springConfigs.keys.union(flingConfigs.keys)
    }

    /**
     * Cancels the given properties. This is typically called immediately by [cancel], unless this
     * animator is under test.
     */
    internal fun cancelInternal(properties: Set<FloatPropertyCompat<in T>>) {
        for (property in properties) {
            flingAnimations[property]?.cancel()
            springAnimations[property]?.cancel()
        }
    }

    /** Cancels all in progress animations on all properties. */
    fun cancel() {
        for (dynamicAnim in flingAnimations.values.union(springAnimations.values)) {
            dynamicAnim.cancel()
        cancelAction(flingAnimations.keys)
        cancelAction(springAnimations.keys)
    }

    /** Cancels in progress animations on the provided properties only. */
    fun cancel(vararg properties: FloatPropertyCompat<in T>) {
        cancelAction(properties.toSet())
    }

    /**
+26 −0
Original line number Diff line number Diff line
@@ -363,8 +363,12 @@ object PhysicsAnimatorTestUtils {
        private val testEndListeners = ArrayList<PhysicsAnimator.EndListener<T>>()
        private val testUpdateListeners = ArrayList<PhysicsAnimator.UpdateListener<T>>()

        /** Whether we're currently in the middle of executing startInternal(). */
        private var currentlyRunningStartInternal = false

        init {
            animator.startAction = ::startForTest
            animator.cancelAction = ::cancelForTest
        }

        internal fun addTestEndListener(listener: PhysicsAnimator.EndListener<T>) {
@@ -437,7 +441,29 @@ object PhysicsAnimatorTestUtils {
                    }
                })

                currentlyRunningStartInternal = true
                animator.startInternal()
                currentlyRunningStartInternal = false
                unblockLatch.countDown()
            }

            unblockLatch.await(timeoutMs, TimeUnit.MILLISECONDS)
        }

        private fun cancelForTest(properties: Set<FloatPropertyCompat<in T>>) {
            // If this was called from startInternal, we are already on the animation thread, and
            // should just call cancelInternal rather than posting it. If we post it, the
            // cancellation will occur after the rest of startInternal() and we'll immediately
            // cancel the animation we worked so hard to start!
            if (currentlyRunningStartInternal) {
                animator.cancelInternal(properties)
                return
            }

            val unblockLatch = CountDownLatch(1)

            animationThreadHandler.post {
                animator.cancelInternal(properties)
                unblockLatch.countDown()
            }