Loading mechanics/src/com/android/mechanics/impl/Computations.kt +16 −14 Original line number Diff line number Diff line Loading @@ -495,7 +495,8 @@ internal abstract class Computations : CurrentFrameInput, LastFrameState, Static val delta = afterBreakpoint - beforeBreakpoint val deltaIsFinite = delta.fastIsFinite() if (deltaIsFinite && delta != 0f) { if (deltaIsFinite) { if (delta != 0f) { // There is a discontinuity on this breakpoint, that needs to be // animated. The delta is pushed to the spring, to consume the // discontinuity over time. Loading @@ -505,11 +506,12 @@ internal abstract class Computations : CurrentFrameInput, LastFrameState, Static velocityDelta = initialSpringVelocity, ) // When *first* crossing a discontinuity in a given frame, the static // mapped velocity observed during previous frame is added as initial // velocity to the spring. This is done ot most once per frame, and only // if there is an actual discontinuity. // When *first* crossing a discontinuity in a given frame, the // static mapped velocity observed during previous frame is added as // initial velocity to the spring. This is done ot most once per // frame, and only if there is an actual discontinuity. initialSpringVelocity = 0f } } else { // The before and / or after mapping produced an non-finite number, // which is not allowed. This intentionally crashes eng-builds, since Loading mechanics/tests/goldens/segmentChange_inMaxDirection_zeroDelta.json 0 → 100644 +82 −0 Original line number Diff line number Diff line { "frame_ids": [ 0, 16, 32, 48 ], "features": [ { "name": "input", "type": "float", "data_points": [ 0, 0.5, 1, 1 ] }, { "name": "gestureDirection", "type": "string", "data_points": [ "Max", "Max", "Max", "Max" ] }, { "name": "output", "type": "float", "data_points": [ 0, 0, 0, 0 ] }, { "name": "outputTarget", "type": "float", "data_points": [ 0, 0, 0, 0 ] }, { "name": "outputSpring", "type": "springParameters", "data_points": [ { "stiffness": 100000, "dampingRatio": 1 }, { "stiffness": 700, "dampingRatio": 0.9 }, { "stiffness": 700, "dampingRatio": 0.9 }, { "stiffness": 700, "dampingRatio": 0.9 } ] }, { "name": "isStable", "type": "boolean", "data_points": [ true, true, true, true ] } ] } No newline at end of file mechanics/tests/src/com/android/mechanics/MotionValueTest.kt +29 −10 Original line number Diff line number Diff line Loading @@ -14,8 +14,6 @@ * limitations under the License. */ @file:OptIn(ExperimentalCoroutinesApi::class) package com.android.mechanics import android.util.Log Loading Loading @@ -52,7 +50,6 @@ import com.android.mechanics.testing.input import com.android.mechanics.testing.isStable import com.android.mechanics.testing.output import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch import org.junit.Rule import org.junit.Test Loading Loading @@ -114,6 +111,13 @@ class MotionValueTest : MotionBuilderContext by FakeMotionSpecBuilderContext.Def awaitStable() } @Test fun segmentChange_inMaxDirection_zeroDelta() = motion.goldenTest(spec = specBuilder(Mapping.Zero) { fixedValueFromCurrent(0.5f) }) { animateValueTo(1f, changePerFrame = 0.5f) awaitStable() } @Test fun segmentChange_inMinDirection_animatedWhenReachingBreakpoint() = motion.goldenTest( Loading Loading @@ -519,7 +523,7 @@ class MotionValueTest : MotionBuilderContext by FakeMotionSpecBuilderContext.Def animatedInputSequence(0f, 1f, 1f, 0f, 0f) } assertThat(wtfLog.loggedFailures).isEmpty() assertThat(wtfLog.hasLoggedFailures()).isFalse() } @Test Loading @@ -546,8 +550,9 @@ class MotionValueTest : MotionBuilderContext by FakeMotionSpecBuilderContext.Def animatedInputSequence(0f, 0f) } assertThat(wtfLog.loggedFailures).hasSize(1) assertThat(wtfLog.loggedFailures.first()).startsWith("Delta between mappings is undefined") val loggedFailures = wtfLog.removeLoggedFailures() assertThat(loggedFailures).hasSize(1) assertThat(loggedFailures.first()).startsWith("Delta between mappings is undefined") } @Test Loading @@ -569,9 +574,9 @@ class MotionValueTest : MotionBuilderContext by FakeMotionSpecBuilderContext.Def ) { animatedInputSequence(0f, 0.5f, 1f, 1.5f, 2f, 3f) } assertThat(wtfLog.loggedFailures).hasSize(1) assertThat(wtfLog.loggedFailures.first()) .startsWith("Delta between breakpoints is undefined") val loggedFailures = wtfLog.removeLoggedFailures() assertThat(loggedFailures).hasSize(1) assertThat(loggedFailures.first()).startsWith("Delta between breakpoints is undefined") } @Test Loading Loading @@ -610,7 +615,7 @@ class MotionValueTest : MotionBuilderContext by FakeMotionSpecBuilderContext.Def } class WtfLogRule : ExternalResource() { val loggedFailures = mutableListOf<String>() private val loggedFailures = mutableListOf<String>() private lateinit var oldHandler: TerribleFailureHandler Loading @@ -625,6 +630,20 @@ class MotionValueTest : MotionBuilderContext by FakeMotionSpecBuilderContext.Def override fun after() { Log.setWtfHandler(oldHandler) // In eng-builds, some misconfiguration in a MotionValue would cause a crash. However, // in tests (and in production), we want animations to proceed even with such errors. // When a test ends, we should check loggedFailures, if they were expected. assertThat(loggedFailures).isEmpty() } fun hasLoggedFailures() = loggedFailures.isNotEmpty() fun removeLoggedFailures(): List<String> { if (loggedFailures.isEmpty()) error("loggedFailures is empty") val list = loggedFailures.toList() loggedFailures.clear() return list } } Loading Loading
mechanics/src/com/android/mechanics/impl/Computations.kt +16 −14 Original line number Diff line number Diff line Loading @@ -495,7 +495,8 @@ internal abstract class Computations : CurrentFrameInput, LastFrameState, Static val delta = afterBreakpoint - beforeBreakpoint val deltaIsFinite = delta.fastIsFinite() if (deltaIsFinite && delta != 0f) { if (deltaIsFinite) { if (delta != 0f) { // There is a discontinuity on this breakpoint, that needs to be // animated. The delta is pushed to the spring, to consume the // discontinuity over time. Loading @@ -505,11 +506,12 @@ internal abstract class Computations : CurrentFrameInput, LastFrameState, Static velocityDelta = initialSpringVelocity, ) // When *first* crossing a discontinuity in a given frame, the static // mapped velocity observed during previous frame is added as initial // velocity to the spring. This is done ot most once per frame, and only // if there is an actual discontinuity. // When *first* crossing a discontinuity in a given frame, the // static mapped velocity observed during previous frame is added as // initial velocity to the spring. This is done ot most once per // frame, and only if there is an actual discontinuity. initialSpringVelocity = 0f } } else { // The before and / or after mapping produced an non-finite number, // which is not allowed. This intentionally crashes eng-builds, since Loading
mechanics/tests/goldens/segmentChange_inMaxDirection_zeroDelta.json 0 → 100644 +82 −0 Original line number Diff line number Diff line { "frame_ids": [ 0, 16, 32, 48 ], "features": [ { "name": "input", "type": "float", "data_points": [ 0, 0.5, 1, 1 ] }, { "name": "gestureDirection", "type": "string", "data_points": [ "Max", "Max", "Max", "Max" ] }, { "name": "output", "type": "float", "data_points": [ 0, 0, 0, 0 ] }, { "name": "outputTarget", "type": "float", "data_points": [ 0, 0, 0, 0 ] }, { "name": "outputSpring", "type": "springParameters", "data_points": [ { "stiffness": 100000, "dampingRatio": 1 }, { "stiffness": 700, "dampingRatio": 0.9 }, { "stiffness": 700, "dampingRatio": 0.9 }, { "stiffness": 700, "dampingRatio": 0.9 } ] }, { "name": "isStable", "type": "boolean", "data_points": [ true, true, true, true ] } ] } No newline at end of file
mechanics/tests/src/com/android/mechanics/MotionValueTest.kt +29 −10 Original line number Diff line number Diff line Loading @@ -14,8 +14,6 @@ * limitations under the License. */ @file:OptIn(ExperimentalCoroutinesApi::class) package com.android.mechanics import android.util.Log Loading Loading @@ -52,7 +50,6 @@ import com.android.mechanics.testing.input import com.android.mechanics.testing.isStable import com.android.mechanics.testing.output import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch import org.junit.Rule import org.junit.Test Loading Loading @@ -114,6 +111,13 @@ class MotionValueTest : MotionBuilderContext by FakeMotionSpecBuilderContext.Def awaitStable() } @Test fun segmentChange_inMaxDirection_zeroDelta() = motion.goldenTest(spec = specBuilder(Mapping.Zero) { fixedValueFromCurrent(0.5f) }) { animateValueTo(1f, changePerFrame = 0.5f) awaitStable() } @Test fun segmentChange_inMinDirection_animatedWhenReachingBreakpoint() = motion.goldenTest( Loading Loading @@ -519,7 +523,7 @@ class MotionValueTest : MotionBuilderContext by FakeMotionSpecBuilderContext.Def animatedInputSequence(0f, 1f, 1f, 0f, 0f) } assertThat(wtfLog.loggedFailures).isEmpty() assertThat(wtfLog.hasLoggedFailures()).isFalse() } @Test Loading @@ -546,8 +550,9 @@ class MotionValueTest : MotionBuilderContext by FakeMotionSpecBuilderContext.Def animatedInputSequence(0f, 0f) } assertThat(wtfLog.loggedFailures).hasSize(1) assertThat(wtfLog.loggedFailures.first()).startsWith("Delta between mappings is undefined") val loggedFailures = wtfLog.removeLoggedFailures() assertThat(loggedFailures).hasSize(1) assertThat(loggedFailures.first()).startsWith("Delta between mappings is undefined") } @Test Loading @@ -569,9 +574,9 @@ class MotionValueTest : MotionBuilderContext by FakeMotionSpecBuilderContext.Def ) { animatedInputSequence(0f, 0.5f, 1f, 1.5f, 2f, 3f) } assertThat(wtfLog.loggedFailures).hasSize(1) assertThat(wtfLog.loggedFailures.first()) .startsWith("Delta between breakpoints is undefined") val loggedFailures = wtfLog.removeLoggedFailures() assertThat(loggedFailures).hasSize(1) assertThat(loggedFailures.first()).startsWith("Delta between breakpoints is undefined") } @Test Loading Loading @@ -610,7 +615,7 @@ class MotionValueTest : MotionBuilderContext by FakeMotionSpecBuilderContext.Def } class WtfLogRule : ExternalResource() { val loggedFailures = mutableListOf<String>() private val loggedFailures = mutableListOf<String>() private lateinit var oldHandler: TerribleFailureHandler Loading @@ -625,6 +630,20 @@ class MotionValueTest : MotionBuilderContext by FakeMotionSpecBuilderContext.Def override fun after() { Log.setWtfHandler(oldHandler) // In eng-builds, some misconfiguration in a MotionValue would cause a crash. However, // in tests (and in production), we want animations to proceed even with such errors. // When a test ends, we should check loggedFailures, if they were expected. assertThat(loggedFailures).isEmpty() } fun hasLoggedFailures() = loggedFailures.isNotEmpty() fun removeLoggedFailures(): List<String> { if (loggedFailures.isEmpty()) error("loggedFailures is empty") val list = loggedFailures.toList() loggedFailures.clear() return list } } Loading