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

Commit 5ba08af4 authored by Mike Schneider's avatar Mike Schneider Committed by Android (Google) Code Review
Browse files

Merge "Immediately activate / deactivate managed motion values on creation" into main

parents c7f37e3c 022308a7
Loading
Loading
Loading
Loading
+17 −28
Original line number Diff line number Diff line
@@ -70,7 +70,12 @@ class MotionValueCollection(
     * [MotionValueCollection] is kept active.
     */
    fun create(spec: () -> MotionSpec, label: String? = null): ManagedMotionValue {
        return ManagedMotionComputation(this, spec, label).also { managedComputations.add(it) }
        return ManagedMotionComputation(this, spec, label).also {
            if (isActive) {
                it.onActivate()
            }
            managedComputations.add(it)
        }
    }

    /**
@@ -96,12 +101,7 @@ class MotionValueCollection(
            var capturedGestureDragOffset = currentGestureDragOffset
            var capturedDirection = currentDirection

            val activeComputations = mutableSetOf<ManagedMotionComputation>()
            managedComputations.forEach {
                it.onActivate()
                activeComputations.add(it)
            }
            activeComputationCount = activeComputations.size
            managedComputations.forEach { it.onActivate() }

            try {
                isAnimating = true
@@ -115,17 +115,6 @@ class MotionValueCollection(
                while (true) {

                    withFrameNanos { frameTimeNanos ->
                        val addedComputations = managedComputations - activeComputations
                        val removedComputations = activeComputations - managedComputations
                        addedComputations.forEach {
                            it.onActivate()
                            activeComputations.add(it)
                        }
                        removedComputations.forEach {
                            it.onDeactivate()
                            activeComputations.remove(it)
                        }
                        activeComputationCount = activeComputations.size
                        frameCount++

                        currentAnimationTimeNanos = frameTimeNanos
@@ -137,7 +126,7 @@ class MotionValueCollection(
                        currentDirection = gestureContext.direction
                        currentGestureDragOffset = gestureContext.dragOffset

                        activeComputations.forEach { it.onFrameStart() }
                        managedComputations.forEach { it.onFrameStart() }
                    }

                    // At this point, the complete frame is done (including layout, drawing and
@@ -152,7 +141,7 @@ class MotionValueCollection(
                    // re-computation if the current state is being read before the next frame).

                    var scheduleNextFrame = false
                    activeComputations.forEach {
                    managedComputations.forEach {
                        if (it.onFrameEnd(isAnimatingUninterrupted)) {
                            scheduleNextFrame = true
                        }
@@ -181,7 +170,9 @@ class MotionValueCollection(
                    }

                    isAnimating = false
                    activeComputations.forEach { it.debugInspector?.isAnimating = false }
                    managedComputations.forEach { it.debugInspector?.isAnimating = false }
                    val activeComputations = managedComputations.toSet()

                    snapshotFlow {
                            val hasComputations =
                                activeComputations.isNotEmpty() || managedComputations.isNotEmpty()
@@ -197,12 +188,11 @@ class MotionValueCollection(
                        }
                        .first { it }
                    isAnimating = true
                    activeComputations.forEach { it.debugInspector?.isAnimating = true }
                    managedComputations.forEach { it.debugInspector?.isAnimating = true }
                }
            } finally {
                isActive = false
                activeComputations.forEach { it.onDeactivate() }
                activeComputationCount = 0
                managedComputations.forEach { it.onDeactivate() }
            }
        }
    }
@@ -241,10 +231,6 @@ class MotionValueCollection(
    var frameCount = 0
        private set

    @VisibleForTesting
    var activeComputationCount = 0
        private set

    @VisibleForTesting
    // Note - this is public so that its accessible by the mechanics:testing library
    val managedMotionValues: Set<ManagedMotionValue>
@@ -252,6 +238,7 @@ class MotionValueCollection(

    internal fun onDispose(toDispose: ManagedMotionComputation) {
        managedComputations.remove(toDispose)
        toDispose.onDeactivate()
    }
}

@@ -399,6 +386,8 @@ internal class ManagedMotionComputation(
        capturedAnimation = currentComputedValues.animation
        capturedSpringState = currentSpringState

        onFrameStart()

        debugInspector?.isAnimating = true
        debugInspector?.isActive = true
    }
+48 −31
Original line number Diff line number Diff line
@@ -69,18 +69,52 @@ class MotionValueCollectionLifecycleTest :
    }

    @Test
    fun keepRunning_activatesExisting() = runTest {
    fun create_withoutKeepRunning_remainsInactive() = runTest {
        val input = mutableFloatStateOf(1f)
        val underTest = MotionValueCollection(input::value, FakeGestureContext)

        rule.setContent {}

        assertThat(underTest.isActive).isFalse()

        val motionValue = underTest.create({ MotionSpec.Identity })
        assertThat(motionValue.output).isNaN()
        val inspector = motionValue.debugInspector()
        assertThat(inspector.isActive).isFalse()
    }

    @Test
    fun create_whileKeepRunning_isActivatedImmediately() = runTest {
        val input = mutableFloatStateOf(1f)
        val underTest = MotionValueCollection(input::value, FakeGestureContext)

        rule.setContent { LaunchedEffect(Unit) { underTest.keepRunning() } }
        rule.awaitIdle()

        assertThat(underTest.isActive).isTrue()
        assertThat(underTest.managedMotionValues.size).isEqualTo(0)

        val motionValue = underTest.create({ MotionSpec.Identity })
        assertThat(motionValue.output).isEqualTo(1f)
        val inspector = motionValue.debugInspector()
        assertThat(inspector.isActive).isTrue()
    }

    @Test
    fun keepRunning_activatesAlreadyCreated() = runTest {
        val input = mutableFloatStateOf(0f)
        val underTest = MotionValueCollection(input::value, FakeGestureContext)

        val inspector = underTest.create({ MotionSpec.Identity }).debugInspector()
        val motionValue = underTest.create({ MotionSpec.Identity })
        val inspector = motionValue.debugInspector()

        assertThat(underTest.frameCount).isEqualTo(0)
        assertThat(underTest.isActive).isFalse()
        assertThat(underTest.isAnimating).isFalse()
        assertThat(underTest.activeComputationCount).isEqualTo(0)
        assertThat(underTest.managedMotionValues.size).isEqualTo(1)
        assertThat(inspector.isActive).isFalse()
        assertThat(inspector.isAnimating).isFalse()
        assertThat(motionValue.output).isNaN()

        rule.setContent { LaunchedEffect(Unit) { underTest.keepRunning() } }

@@ -89,9 +123,10 @@ class MotionValueCollectionLifecycleTest :
        assertThat(underTest.frameCount).isEqualTo(1)
        assertThat(underTest.isActive).isTrue()
        assertThat(underTest.isAnimating).isFalse()
        assertThat(underTest.activeComputationCount).isEqualTo(1)
        assertThat(underTest.managedMotionValues.size).isEqualTo(1)
        assertThat(inspector.isActive).isTrue()
        assertThat(inspector.isAnimating).isFalse()
        assertThat(motionValue.output).isFinite()
    }

    @Test
@@ -109,7 +144,7 @@ class MotionValueCollectionLifecycleTest :
        assertThat(underTest.frameCount).isEqualTo(1)
        assertThat(underTest.isActive).isTrue()
        assertThat(underTest.isAnimating).isFalse()
        assertThat(underTest.activeComputationCount).isEqualTo(1)
        assertThat(underTest.managedMotionValues.size).isEqualTo(1)
        assertThat(inspector.isActive).isTrue()
        assertThat(inspector.isAnimating).isFalse()

@@ -119,7 +154,7 @@ class MotionValueCollectionLifecycleTest :
        assertThat(underTest.frameCount).isEqualTo(2)
        assertThat(underTest.isActive).isTrue()
        assertThat(underTest.isAnimating).isFalse()
        assertThat(underTest.activeComputationCount).isEqualTo(0)
        assertThat(underTest.managedMotionValues.size).isEqualTo(0)
        assertThat(inspector.isActive).isFalse()
        assertThat(inspector.isAnimating).isFalse()
    }
@@ -138,32 +173,14 @@ class MotionValueCollectionLifecycleTest :

        assertThat(underTest.isActive).isFalse()
        assertThat(inspector.isActive).isFalse()
        assertThat(underTest.activeComputationCount).isEqualTo(0)
        assertThat(underTest.managedMotionValues.size).isEqualTo(1)

        motionValue.dispose()
        rule.awaitIdle()

        assertThat(underTest.isActive).isFalse()
        assertThat(inspector.isActive).isFalse()
        assertThat(underTest.activeComputationCount).isEqualTo(0)
    }

    @Test
    fun keepRunning_activatesNew() = runTest {
        val input = mutableFloatStateOf(0f)
        val underTest = MotionValueCollection(input::value, FakeGestureContext)

        rule.setContent { LaunchedEffect(Unit) { underTest.keepRunning() } }
        rule.awaitIdle()

        assertThat(underTest.isActive).isTrue()
        assertThat(underTest.activeComputationCount).isEqualTo(0)

        val inspector = underTest.create({ MotionSpec.Identity }).debugInspector()
        rule.awaitIdle()

        assertThat(underTest.activeComputationCount).isEqualTo(1)
        assertThat(inspector.isActive).isTrue()
        assertThat(underTest.managedMotionValues.size).isEqualTo(0)
    }

    @Test
@@ -180,21 +197,21 @@ class MotionValueCollectionLifecycleTest :
        rule.awaitIdle()

        assertThat(underTest.isActive).isTrue()
        assertThat(underTest.activeComputationCount).isEqualTo(2)
        assertThat(underTest.managedMotionValues.size).isEqualTo(2)
        assertThat(inspector1.isActive).isTrue()
        assertThat(inspector2.isActive).isTrue()

        mv1.dispose()
        rule.awaitIdle()

        assertThat(underTest.activeComputationCount).isEqualTo(1)
        assertThat(underTest.managedMotionValues.size).isEqualTo(1)
        assertThat(inspector1.isActive).isFalse()
        assertThat(inspector2.isActive).isTrue()

        mv2.dispose()
        rule.awaitIdle()

        assertThat(underTest.activeComputationCount).isEqualTo(0)
        assertThat(underTest.managedMotionValues.size).isEqualTo(0)
        assertThat(inspector1.isActive).isFalse()
        assertThat(inspector2.isActive).isFalse()
    }
@@ -215,14 +232,14 @@ class MotionValueCollectionLifecycleTest :

        assertThat(underTest.isActive).isTrue()
        assertThat(inspector.isActive).isTrue()
        assertThat(underTest.activeComputationCount).isEqualTo(1)
        assertThat(underTest.managedMotionValues.size).isEqualTo(1)

        keepRunning.value = false
        rule.awaitIdle()

        assertThat(underTest.isActive).isFalse()
        assertThat(inspector.isActive).isFalse()
        assertThat(underTest.activeComputationCount).isEqualTo(0)
        assertThat(underTest.managedMotionValues.size).isEqualTo(1)
    }

    @Test