[go: nahoru, domu]

Add Animation Clock support to AnimatedValue

This CL updates AnimatedValue to use an AnimationClockObservable for
ticking, and thus removing the dependency on Choreographer.

Test: Unit tests added in commit
Bug: 144878730
Change-Id: I2cd43380a1c69ee49ace6fd6eaf1c8ab44ef94d0
diff --git a/ui/ui-animation-core/api/0.1.0-dev04.txt b/ui/ui-animation-core/api/0.1.0-dev04.txt
index e1b1920..61912a7 100644
--- a/ui/ui-animation-core/api/0.1.0-dev04.txt
+++ b/ui/ui-animation-core/api/0.1.0-dev04.txt
@@ -2,9 +2,10 @@
 package androidx.animation {
 
   public final class AnimatedFloat extends androidx.animation.BaseAnimatedValue<java.lang.Float,androidx.animation.AnimationVector1D> {
-    ctor public AnimatedFloat(androidx.animation.ValueHolder<java.lang.Float> valueHolder);
-    ctor public AnimatedFloat(float initVal);
-    method public void doAnimationFrame$lintWithKotlin(long time);
+    ctor public AnimatedFloat(androidx.animation.ValueHolder<java.lang.Float> valueHolder, androidx.animation.AnimationClockObservable clock);
+    ctor public AnimatedFloat(float initVal, androidx.animation.AnimationClockObservable clock);
+    ctor @Deprecated public AnimatedFloat(androidx.animation.ValueHolder<java.lang.Float> valueHolder);
+    method public void doAnimationFrame$lintWithKotlin(long timeMillis);
     method public float getVelocity();
     method public void setBounds(float min = Float.NEGATIVE_INFINITY, float max = Float.POSITIVE_INFINITY);
     method public void snapTo(float targetValue);
@@ -12,7 +13,7 @@
   }
 
   public final class AnimatedValue<T, V extends androidx.animation.AnimationVector> extends androidx.animation.BaseAnimatedValue<T,V> {
-    ctor public AnimatedValue(androidx.animation.ValueHolder<T> valueHolder, androidx.animation.TwoWayConverter<T,V> typeConverter);
+    ctor public AnimatedValue(androidx.animation.ValueHolder<T> valueHolder, androidx.animation.TwoWayConverter<T,V> typeConverter, androidx.animation.AnimationClockObservable clock);
     method public V getVelocity();
     property public final V velocity;
   }
@@ -23,8 +24,8 @@
   }
 
   public final class AnimatedVectorValue<V extends androidx.animation.AnimationVector> extends androidx.animation.BaseAnimatedValue<V,V> {
-    ctor public AnimatedVectorValue(androidx.animation.ValueHolder<V> valueHolder);
-    ctor public AnimatedVectorValue(V initVal);
+    ctor public AnimatedVectorValue(androidx.animation.ValueHolder<V> valueHolder, androidx.animation.AnimationClockObservable clock);
+    ctor public AnimatedVectorValue(V initVal, androidx.animation.AnimationClockObservable clock);
   }
 
   public abstract class AnimationBuilder<T> {
diff --git a/ui/ui-animation-core/api/current.txt b/ui/ui-animation-core/api/current.txt
index e1b1920..61912a7 100644
--- a/ui/ui-animation-core/api/current.txt
+++ b/ui/ui-animation-core/api/current.txt
@@ -2,9 +2,10 @@
 package androidx.animation {
 
   public final class AnimatedFloat extends androidx.animation.BaseAnimatedValue<java.lang.Float,androidx.animation.AnimationVector1D> {
-    ctor public AnimatedFloat(androidx.animation.ValueHolder<java.lang.Float> valueHolder);
-    ctor public AnimatedFloat(float initVal);
-    method public void doAnimationFrame$lintWithKotlin(long time);
+    ctor public AnimatedFloat(androidx.animation.ValueHolder<java.lang.Float> valueHolder, androidx.animation.AnimationClockObservable clock);
+    ctor public AnimatedFloat(float initVal, androidx.animation.AnimationClockObservable clock);
+    ctor @Deprecated public AnimatedFloat(androidx.animation.ValueHolder<java.lang.Float> valueHolder);
+    method public void doAnimationFrame$lintWithKotlin(long timeMillis);
     method public float getVelocity();
     method public void setBounds(float min = Float.NEGATIVE_INFINITY, float max = Float.POSITIVE_INFINITY);
     method public void snapTo(float targetValue);
@@ -12,7 +13,7 @@
   }
 
   public final class AnimatedValue<T, V extends androidx.animation.AnimationVector> extends androidx.animation.BaseAnimatedValue<T,V> {
-    ctor public AnimatedValue(androidx.animation.ValueHolder<T> valueHolder, androidx.animation.TwoWayConverter<T,V> typeConverter);
+    ctor public AnimatedValue(androidx.animation.ValueHolder<T> valueHolder, androidx.animation.TwoWayConverter<T,V> typeConverter, androidx.animation.AnimationClockObservable clock);
     method public V getVelocity();
     property public final V velocity;
   }
@@ -23,8 +24,8 @@
   }
 
   public final class AnimatedVectorValue<V extends androidx.animation.AnimationVector> extends androidx.animation.BaseAnimatedValue<V,V> {
-    ctor public AnimatedVectorValue(androidx.animation.ValueHolder<V> valueHolder);
-    ctor public AnimatedVectorValue(V initVal);
+    ctor public AnimatedVectorValue(androidx.animation.ValueHolder<V> valueHolder, androidx.animation.AnimationClockObservable clock);
+    ctor public AnimatedVectorValue(V initVal, androidx.animation.AnimationClockObservable clock);
   }
 
   public abstract class AnimationBuilder<T> {
diff --git a/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev04.txt b/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev04.txt
index e1b1920..61912a7 100644
--- a/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev04.txt
+++ b/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev04.txt
@@ -2,9 +2,10 @@
 package androidx.animation {
 
   public final class AnimatedFloat extends androidx.animation.BaseAnimatedValue<java.lang.Float,androidx.animation.AnimationVector1D> {
-    ctor public AnimatedFloat(androidx.animation.ValueHolder<java.lang.Float> valueHolder);
-    ctor public AnimatedFloat(float initVal);
-    method public void doAnimationFrame$lintWithKotlin(long time);
+    ctor public AnimatedFloat(androidx.animation.ValueHolder<java.lang.Float> valueHolder, androidx.animation.AnimationClockObservable clock);
+    ctor public AnimatedFloat(float initVal, androidx.animation.AnimationClockObservable clock);
+    ctor @Deprecated public AnimatedFloat(androidx.animation.ValueHolder<java.lang.Float> valueHolder);
+    method public void doAnimationFrame$lintWithKotlin(long timeMillis);
     method public float getVelocity();
     method public void setBounds(float min = Float.NEGATIVE_INFINITY, float max = Float.POSITIVE_INFINITY);
     method public void snapTo(float targetValue);
@@ -12,7 +13,7 @@
   }
 
   public final class AnimatedValue<T, V extends androidx.animation.AnimationVector> extends androidx.animation.BaseAnimatedValue<T,V> {
-    ctor public AnimatedValue(androidx.animation.ValueHolder<T> valueHolder, androidx.animation.TwoWayConverter<T,V> typeConverter);
+    ctor public AnimatedValue(androidx.animation.ValueHolder<T> valueHolder, androidx.animation.TwoWayConverter<T,V> typeConverter, androidx.animation.AnimationClockObservable clock);
     method public V getVelocity();
     property public final V velocity;
   }
@@ -23,8 +24,8 @@
   }
 
   public final class AnimatedVectorValue<V extends androidx.animation.AnimationVector> extends androidx.animation.BaseAnimatedValue<V,V> {
-    ctor public AnimatedVectorValue(androidx.animation.ValueHolder<V> valueHolder);
-    ctor public AnimatedVectorValue(V initVal);
+    ctor public AnimatedVectorValue(androidx.animation.ValueHolder<V> valueHolder, androidx.animation.AnimationClockObservable clock);
+    ctor public AnimatedVectorValue(V initVal, androidx.animation.AnimationClockObservable clock);
   }
 
   public abstract class AnimationBuilder<T> {
diff --git a/ui/ui-animation-core/api/public_plus_experimental_current.txt b/ui/ui-animation-core/api/public_plus_experimental_current.txt
index e1b1920..61912a7 100644
--- a/ui/ui-animation-core/api/public_plus_experimental_current.txt
+++ b/ui/ui-animation-core/api/public_plus_experimental_current.txt
@@ -2,9 +2,10 @@
 package androidx.animation {
 
   public final class AnimatedFloat extends androidx.animation.BaseAnimatedValue<java.lang.Float,androidx.animation.AnimationVector1D> {
-    ctor public AnimatedFloat(androidx.animation.ValueHolder<java.lang.Float> valueHolder);
-    ctor public AnimatedFloat(float initVal);
-    method public void doAnimationFrame$lintWithKotlin(long time);
+    ctor public AnimatedFloat(androidx.animation.ValueHolder<java.lang.Float> valueHolder, androidx.animation.AnimationClockObservable clock);
+    ctor public AnimatedFloat(float initVal, androidx.animation.AnimationClockObservable clock);
+    ctor @Deprecated public AnimatedFloat(androidx.animation.ValueHolder<java.lang.Float> valueHolder);
+    method public void doAnimationFrame$lintWithKotlin(long timeMillis);
     method public float getVelocity();
     method public void setBounds(float min = Float.NEGATIVE_INFINITY, float max = Float.POSITIVE_INFINITY);
     method public void snapTo(float targetValue);
@@ -12,7 +13,7 @@
   }
 
   public final class AnimatedValue<T, V extends androidx.animation.AnimationVector> extends androidx.animation.BaseAnimatedValue<T,V> {
-    ctor public AnimatedValue(androidx.animation.ValueHolder<T> valueHolder, androidx.animation.TwoWayConverter<T,V> typeConverter);
+    ctor public AnimatedValue(androidx.animation.ValueHolder<T> valueHolder, androidx.animation.TwoWayConverter<T,V> typeConverter, androidx.animation.AnimationClockObservable clock);
     method public V getVelocity();
     property public final V velocity;
   }
@@ -23,8 +24,8 @@
   }
 
   public final class AnimatedVectorValue<V extends androidx.animation.AnimationVector> extends androidx.animation.BaseAnimatedValue<V,V> {
-    ctor public AnimatedVectorValue(androidx.animation.ValueHolder<V> valueHolder);
-    ctor public AnimatedVectorValue(V initVal);
+    ctor public AnimatedVectorValue(androidx.animation.ValueHolder<V> valueHolder, androidx.animation.AnimationClockObservable clock);
+    ctor public AnimatedVectorValue(V initVal, androidx.animation.AnimationClockObservable clock);
   }
 
   public abstract class AnimationBuilder<T> {
diff --git a/ui/ui-animation-core/api/restricted_0.1.0-dev04.txt b/ui/ui-animation-core/api/restricted_0.1.0-dev04.txt
index e1b1920..61912a7 100644
--- a/ui/ui-animation-core/api/restricted_0.1.0-dev04.txt
+++ b/ui/ui-animation-core/api/restricted_0.1.0-dev04.txt
@@ -2,9 +2,10 @@
 package androidx.animation {
 
   public final class AnimatedFloat extends androidx.animation.BaseAnimatedValue<java.lang.Float,androidx.animation.AnimationVector1D> {
-    ctor public AnimatedFloat(androidx.animation.ValueHolder<java.lang.Float> valueHolder);
-    ctor public AnimatedFloat(float initVal);
-    method public void doAnimationFrame$lintWithKotlin(long time);
+    ctor public AnimatedFloat(androidx.animation.ValueHolder<java.lang.Float> valueHolder, androidx.animation.AnimationClockObservable clock);
+    ctor public AnimatedFloat(float initVal, androidx.animation.AnimationClockObservable clock);
+    ctor @Deprecated public AnimatedFloat(androidx.animation.ValueHolder<java.lang.Float> valueHolder);
+    method public void doAnimationFrame$lintWithKotlin(long timeMillis);
     method public float getVelocity();
     method public void setBounds(float min = Float.NEGATIVE_INFINITY, float max = Float.POSITIVE_INFINITY);
     method public void snapTo(float targetValue);
@@ -12,7 +13,7 @@
   }
 
   public final class AnimatedValue<T, V extends androidx.animation.AnimationVector> extends androidx.animation.BaseAnimatedValue<T,V> {
-    ctor public AnimatedValue(androidx.animation.ValueHolder<T> valueHolder, androidx.animation.TwoWayConverter<T,V> typeConverter);
+    ctor public AnimatedValue(androidx.animation.ValueHolder<T> valueHolder, androidx.animation.TwoWayConverter<T,V> typeConverter, androidx.animation.AnimationClockObservable clock);
     method public V getVelocity();
     property public final V velocity;
   }
@@ -23,8 +24,8 @@
   }
 
   public final class AnimatedVectorValue<V extends androidx.animation.AnimationVector> extends androidx.animation.BaseAnimatedValue<V,V> {
-    ctor public AnimatedVectorValue(androidx.animation.ValueHolder<V> valueHolder);
-    ctor public AnimatedVectorValue(V initVal);
+    ctor public AnimatedVectorValue(androidx.animation.ValueHolder<V> valueHolder, androidx.animation.AnimationClockObservable clock);
+    ctor public AnimatedVectorValue(V initVal, androidx.animation.AnimationClockObservable clock);
   }
 
   public abstract class AnimationBuilder<T> {
diff --git a/ui/ui-animation-core/api/restricted_current.txt b/ui/ui-animation-core/api/restricted_current.txt
index e1b1920..61912a7 100644
--- a/ui/ui-animation-core/api/restricted_current.txt
+++ b/ui/ui-animation-core/api/restricted_current.txt
@@ -2,9 +2,10 @@
 package androidx.animation {
 
   public final class AnimatedFloat extends androidx.animation.BaseAnimatedValue<java.lang.Float,androidx.animation.AnimationVector1D> {
-    ctor public AnimatedFloat(androidx.animation.ValueHolder<java.lang.Float> valueHolder);
-    ctor public AnimatedFloat(float initVal);
-    method public void doAnimationFrame$lintWithKotlin(long time);
+    ctor public AnimatedFloat(androidx.animation.ValueHolder<java.lang.Float> valueHolder, androidx.animation.AnimationClockObservable clock);
+    ctor public AnimatedFloat(float initVal, androidx.animation.AnimationClockObservable clock);
+    ctor @Deprecated public AnimatedFloat(androidx.animation.ValueHolder<java.lang.Float> valueHolder);
+    method public void doAnimationFrame$lintWithKotlin(long timeMillis);
     method public float getVelocity();
     method public void setBounds(float min = Float.NEGATIVE_INFINITY, float max = Float.POSITIVE_INFINITY);
     method public void snapTo(float targetValue);
@@ -12,7 +13,7 @@
   }
 
   public final class AnimatedValue<T, V extends androidx.animation.AnimationVector> extends androidx.animation.BaseAnimatedValue<T,V> {
-    ctor public AnimatedValue(androidx.animation.ValueHolder<T> valueHolder, androidx.animation.TwoWayConverter<T,V> typeConverter);
+    ctor public AnimatedValue(androidx.animation.ValueHolder<T> valueHolder, androidx.animation.TwoWayConverter<T,V> typeConverter, androidx.animation.AnimationClockObservable clock);
     method public V getVelocity();
     property public final V velocity;
   }
@@ -23,8 +24,8 @@
   }
 
   public final class AnimatedVectorValue<V extends androidx.animation.AnimationVector> extends androidx.animation.BaseAnimatedValue<V,V> {
-    ctor public AnimatedVectorValue(androidx.animation.ValueHolder<V> valueHolder);
-    ctor public AnimatedVectorValue(V initVal);
+    ctor public AnimatedVectorValue(androidx.animation.ValueHolder<V> valueHolder, androidx.animation.AnimationClockObservable clock);
+    ctor public AnimatedVectorValue(V initVal, androidx.animation.AnimationClockObservable clock);
   }
 
   public abstract class AnimationBuilder<T> {
diff --git a/ui/ui-animation-core/src/main/java/androidx/animation/AnimatedValue.kt b/ui/ui-animation-core/src/main/java/androidx/animation/AnimatedValue.kt
index d5a1f17..df585f6 100644
--- a/ui/ui-animation-core/src/main/java/androidx/animation/AnimatedValue.kt
+++ b/ui/ui-animation-core/src/main/java/androidx/animation/AnimatedValue.kt
@@ -17,11 +17,9 @@
 package androidx.animation
 
 import android.util.Log
-import android.view.Choreographer
 import androidx.animation.AnimationEndReason.BoundReached
 import androidx.animation.AnimationEndReason.Interrupted
 import androidx.animation.AnimationEndReason.TargetReached
-
 /**
  * This is the base class for [AnimatedValue]. It contains all the functionality of AnimatedValue.
  * It is intended to be used as a base class for the other classes (such as [AnimatedFloat] to build
@@ -36,10 +34,12 @@
  * @param typeConverter A two way type converter that converts from value to [AnimationVector1D],
  *                      [AnimationVector2D], [AnimationVector3D], or [AnimationVector4D], and vice
  *                      versa.
+ * @param clock An animation clock observable controlling the progression of the animated value
  */
 sealed class BaseAnimatedValue<T, V : AnimationVector>(
     private val valueHolder: ValueHolder<T>,
-    typeConverter: TwoWayConverter<T, V>
+    internal val typeConverter: TwoWayConverter<T, V>,
+    private val clock: AnimationClockObservable
 ) {
 
     /**
@@ -50,8 +50,9 @@
      */
     constructor(
         initVal: T,
-        typeConverter: TwoWayConverter<T, V>
-    ) : this(ValueHolder(initVal), typeConverter)
+        typeConverter: TwoWayConverter<T, V>,
+        clock: AnimationClockObservable
+    ) : this(ValueHolder(initVal), typeConverter, clock)
 
     /**
      * Current value of the animation.
@@ -81,7 +82,6 @@
      */
     internal var velocityVector: V = typeConverter.createNewVector()
 
-    internal val typeConverter: TwoWayConverter<T, V> = typeConverter
     internal var onEnd: ((AnimationEndReason, T) -> Unit)? = null
     private lateinit var anim: AnimationWrapper<T, V>
     private var startTime: Long = Unset
@@ -89,10 +89,9 @@
     // end of the animation.
     private var lastFrameTime: Long = Unset
 
-    private var frameCallback = object : Choreographer.FrameCallback {
-        override fun doFrame(frameTimeNanos: Long) {
-            // TODO: Refactor out all the dependencies on Choreographer
-            doAnimationFrame(frameTimeNanos / 1000000L)
+    private var animationClockObserver = object : AnimationClockObserver {
+        override fun onAnimationFrame(frameTimeMillis: Long) {
+            doAnimationFrame(frameTimeMillis)
         }
     }
 
@@ -211,33 +210,27 @@
         onEnd?.invoke(endReason, endValue)
     }
 
-    internal open fun doAnimationFrame(time: Long) {
+    internal open fun doAnimationFrame(timeMillis: Long) {
         val playtime: Long
         if (startTime == Unset) {
-            startTime = time
+            startTime = timeMillis
             playtime = 0
         } else {
-            playtime = time - startTime
+            playtime = timeMillis - startTime
         }
 
-        lastFrameTime = time
+        lastFrameTime = timeMillis
         value = anim.getValue(playtime)
         velocityVector = anim.getVelocity(playtime)
         val animationFinished = anim.isFinished(playtime)
-        if (!animationFinished) {
-            Choreographer.getInstance().postFrameCallback(frameCallback)
-            if (DEBUG) {
-                Log.w(
-                    "AnimValue",
-                    "value = $value, playtime = $playtime, velocity: $velocityVector"
-                )
-            }
-        } else {
-            if (DEBUG) {
-                Log.w("AnimValue", "value = $value, playtime = $playtime, animation finished")
-            }
-            endAnimation()
+        if (DEBUG) {
+            val debugLogMessage = if (animationFinished)
+                "value = $value, playtime = $playtime, animation finished"
+            else
+                "value = $value, playtime = $playtime, velocity: $velocityVector"
+            Log.w("AnimValue", debugLogMessage)
         }
+        if (animationFinished) endAnimation()
     }
 
     internal fun startAnimation(anim: AnimationWrapper<T, V>) {
@@ -255,7 +248,7 @@
         } else {
             startTime = Unset
             isRunning = true
-            Choreographer.getInstance().postFrameCallback(frameCallback)
+            clock.subscribe(animationClockObserver)
         }
         if (DEBUG) {
             Log.w("AnimValue", "start animation")
@@ -263,7 +256,7 @@
     }
 
     internal fun endAnimation(endReason: AnimationEndReason = TargetReached) {
-        Choreographer.getInstance().removeFrameCallback(frameCallback)
+        clock.unsubscribe(animationClockObserver)
         isRunning = false
         startTime = Unset
         lastFrameTime = Unset
@@ -288,17 +281,19 @@
  */
 class AnimatedValue<T, V : AnimationVector>(
     valueHolder: ValueHolder<T>,
-    typeConverter: TwoWayConverter<T, V>
-) : BaseAnimatedValue<T, V>(valueHolder, typeConverter) {
+    typeConverter: TwoWayConverter<T, V>,
+    clock: AnimationClockObservable
+) : BaseAnimatedValue<T, V>(valueHolder, typeConverter, clock) {
     val velocity: V
         get() = velocityVector
 }
 
 // TODO class description
 class AnimatedVectorValue<V : AnimationVector>(
-    valueHolder: ValueHolder<V>
-) : BaseAnimatedValue<V, V>(valueHolder, valueHolder.value.createPassThroughConverter()) {
-    constructor(initVal: V) : this(ValueHolder(initVal))
+    valueHolder: ValueHolder<V>,
+    clock: AnimationClockObservable
+) : BaseAnimatedValue<V, V>(valueHolder, valueHolder.value.createPassThroughConverter(), clock) {
+    constructor(initVal: V, clock: AnimationClockObservable) : this(ValueHolder(initVal), clock)
 }
 
 /**
@@ -309,11 +304,16 @@
  *
  * @param valueHolder A value holder of Float type whose value field will be updated during
  *                    animations
+ * @param clock An animation clock observable controlling the progression of the animated value
  */
 class AnimatedFloat(
-    valueHolder: ValueHolder<Float>
-) : BaseAnimatedValue<Float, AnimationVector1D>(valueHolder, FloatToVectorConverter) {
-    constructor(initVal: Float) : this(ValueHolder(initVal))
+    valueHolder: ValueHolder<Float>,
+    clock: AnimationClockObservable
+) : BaseAnimatedValue<Float, AnimationVector1D>(valueHolder, FloatToVectorConverter, clock) {
+    constructor(initVal: Float, clock: AnimationClockObservable) : this(ValueHolder(initVal), clock)
+
+    @Deprecated("This method is to support existing APIs not providing clocks.")
+    constructor(valueHolder: ValueHolder<Float>) : this(valueHolder, DefaultAnimationClock())
 
     private var min: Float = Float.NEGATIVE_INFINITY
     private var max: Float = Float.POSITIVE_INFINITY
@@ -339,8 +339,8 @@
         super.snapTo(targetValue.coerceIn(min, max))
     }
 
-    override fun doAnimationFrame(time: Long) {
-        super.doAnimationFrame(time)
+    override fun doAnimationFrame(timeMillis: Long) {
+        super.doAnimationFrame(timeMillis)
         if (value < min) {
             value = min
             endAnimation(BoundReached)
diff --git a/ui/ui-animation-core/src/test/java/androidx/animation/AnimatedValueTest.kt b/ui/ui-animation-core/src/test/java/androidx/animation/AnimatedValueTest.kt
new file mode 100644
index 0000000..ea043bb
--- /dev/null
+++ b/ui/ui-animation-core/src/test/java/androidx/animation/AnimatedValueTest.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2019 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 androidx.animation
+
+import junit.framework.TestCase.assertEquals
+import junit.framework.TestCase.assertNotNull
+import junit.framework.TestCase.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class AnimatedValueTest {
+    private lateinit var clock: ManualAnimationClock
+
+    @Before
+    fun init() {
+        clock = ManualAnimationClock(0L)
+    }
+
+    @Test
+    fun testAnimation() {
+        val animatedFloat = AnimatedFloat(0f, clock)
+        animatedFloat.animateTo(1f)
+        clock.clockTimeMillis += 100000L
+        assertEquals(1f, animatedFloat.value, epsilon)
+    }
+
+    @Test
+    fun testInitialValue() {
+        val animatedFloat = AnimatedFloat(1.2f, clock)
+        animatedFloat.animateTo(100f)
+        assertEquals(1.2f, animatedFloat.value, epsilon)
+    }
+
+    @Test
+    fun testTargetValue() {
+        val animatedFloat = AnimatedFloat(0f, clock)
+        animatedFloat.animateTo(2f)
+        animatedFloat.animateTo(1.5f)
+        assertEquals(1.5f, animatedFloat.targetValue, epsilon)
+    }
+
+    @Test
+    fun testProgressionUp() {
+        val animatedFloat = AnimatedFloat(0f, clock)
+
+        animatedFloat.animateTo(1f)
+
+        clock.clockTimeMillis = 0L
+        val valueAtTimeZero = animatedFloat.value
+
+        clock.clockTimeMillis = 1L
+        val valueAtTimeOne = animatedFloat.value
+
+        assertTrue(valueAtTimeOne > valueAtTimeZero)
+    }
+
+    @Test
+    fun testProgressionDown() {
+        val animatedFloat = AnimatedFloat(0f, clock)
+
+        animatedFloat.animateTo(-1f)
+
+        clock.clockTimeMillis = 0L
+        val valueAtTimeZero = animatedFloat.value
+
+        clock.clockTimeMillis = 1L
+        val valueAtTimeOne = animatedFloat.value
+
+        assertTrue(valueAtTimeOne < valueAtTimeZero)
+    }
+
+    @Test
+    fun testEndCallback() {
+        val animatedFloat = AnimatedFloat(0f, clock)
+
+        var animationEndReason: AnimationEndReason? = null
+        var animationEndValue: Float? = null
+
+        animatedFloat.animateTo(1f) { reason, value ->
+            animationEndReason = reason
+            animationEndValue = value
+        }
+
+        clock.clockTimeMillis += 100000L
+
+        assertNotNull(animationEndValue)
+        assertNotNull(animationEndReason)
+
+        assertEquals(1f, animationEndValue!!, epsilon)
+        assertEquals(AnimationEndReason.TargetReached, animationEndReason)
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-animation-core/src/test/java/androidx/animation/TypeConverterTest.kt b/ui/ui-animation-core/src/test/java/androidx/animation/TypeConverterTest.kt
index 6a557f1..a145548 100644
--- a/ui/ui-animation-core/src/test/java/androidx/animation/TypeConverterTest.kt
+++ b/ui/ui-animation-core/src/test/java/androidx/animation/TypeConverterTest.kt
@@ -27,7 +27,7 @@
     fun testFloatToVectorConverter() {
         verifyFloatConverter(FloatToVectorConverter)
         verifyFloatConverter(FloatPropKey().typeConverter)
-        verifyFloatConverter(AnimatedFloat(5f).typeConverter)
+        verifyFloatConverter(AnimatedFloat(5f, ManualAnimationClock(0L)).typeConverter)
     }
 
     @Test
@@ -48,7 +48,7 @@
     }
 
     private fun <V : AnimationVector> verifyV2VConverter(value: V) {
-        val converter = AnimatedVectorValue(value).typeConverter
+        val converter = AnimatedVectorValue(value, ManualAnimationClock(0L)).typeConverter
         assertEquals(converter.convertFromVector(value), converter.convertToVector(value))
     }
 
diff --git a/ui/ui-animation/api/0.1.0-dev04.txt b/ui/ui-animation/api/0.1.0-dev04.txt
index 2e5f447..7a78e4b 100644
--- a/ui/ui-animation/api/0.1.0-dev04.txt
+++ b/ui/ui-animation/api/0.1.0-dev04.txt
@@ -2,9 +2,9 @@
 package androidx.ui.animation {
 
   public final class AnimatedValueEffectsKt {
-    method public static androidx.animation.AnimatedValue<androidx.ui.graphics.Color,androidx.animation.AnimationVector4D> animatedColor(androidx.ui.graphics.Color initVal);
-    method public static androidx.animation.AnimatedFloat animatedFloat(float initVal);
-    method public static <T, V extends androidx.animation.AnimationVector> androidx.animation.AnimatedValue<T,V> animatedValue(T? initVal, androidx.animation.TwoWayConverter<T,V> converter);
+    method public static androidx.animation.AnimatedValue<androidx.ui.graphics.Color,androidx.animation.AnimationVector4D> animatedColor(androidx.ui.graphics.Color initVal, androidx.animation.AnimationClockObservable clock = ambient(AnimationClockAmbient));
+    method public static androidx.animation.AnimatedFloat animatedFloat(float initVal, androidx.animation.AnimationClockObservable clock = ambient(AnimationClockAmbient));
+    method public static <T, V extends androidx.animation.AnimationVector> androidx.animation.AnimatedValue<T,V> animatedValue(T? initVal, androidx.animation.TwoWayConverter<T,V> converter, androidx.animation.AnimationClockObservable clock = ambient(AnimationClockAmbient));
   }
 
   public final class ColorPropKey implements androidx.animation.PropKey<androidx.ui.graphics.Color,androidx.animation.AnimationVector4D> {
diff --git a/ui/ui-animation/api/current.txt b/ui/ui-animation/api/current.txt
index 2e5f447..7a78e4b 100644
--- a/ui/ui-animation/api/current.txt
+++ b/ui/ui-animation/api/current.txt
@@ -2,9 +2,9 @@
 package androidx.ui.animation {
 
   public final class AnimatedValueEffectsKt {
-    method public static androidx.animation.AnimatedValue<androidx.ui.graphics.Color,androidx.animation.AnimationVector4D> animatedColor(androidx.ui.graphics.Color initVal);
-    method public static androidx.animation.AnimatedFloat animatedFloat(float initVal);
-    method public static <T, V extends androidx.animation.AnimationVector> androidx.animation.AnimatedValue<T,V> animatedValue(T? initVal, androidx.animation.TwoWayConverter<T,V> converter);
+    method public static androidx.animation.AnimatedValue<androidx.ui.graphics.Color,androidx.animation.AnimationVector4D> animatedColor(androidx.ui.graphics.Color initVal, androidx.animation.AnimationClockObservable clock = ambient(AnimationClockAmbient));
+    method public static androidx.animation.AnimatedFloat animatedFloat(float initVal, androidx.animation.AnimationClockObservable clock = ambient(AnimationClockAmbient));
+    method public static <T, V extends androidx.animation.AnimationVector> androidx.animation.AnimatedValue<T,V> animatedValue(T? initVal, androidx.animation.TwoWayConverter<T,V> converter, androidx.animation.AnimationClockObservable clock = ambient(AnimationClockAmbient));
   }
 
   public final class ColorPropKey implements androidx.animation.PropKey<androidx.ui.graphics.Color,androidx.animation.AnimationVector4D> {
diff --git a/ui/ui-animation/api/public_plus_experimental_0.1.0-dev04.txt b/ui/ui-animation/api/public_plus_experimental_0.1.0-dev04.txt
index 2e5f447..7a78e4b 100644
--- a/ui/ui-animation/api/public_plus_experimental_0.1.0-dev04.txt
+++ b/ui/ui-animation/api/public_plus_experimental_0.1.0-dev04.txt
@@ -2,9 +2,9 @@
 package androidx.ui.animation {
 
   public final class AnimatedValueEffectsKt {
-    method public static androidx.animation.AnimatedValue<androidx.ui.graphics.Color,androidx.animation.AnimationVector4D> animatedColor(androidx.ui.graphics.Color initVal);
-    method public static androidx.animation.AnimatedFloat animatedFloat(float initVal);
-    method public static <T, V extends androidx.animation.AnimationVector> androidx.animation.AnimatedValue<T,V> animatedValue(T? initVal, androidx.animation.TwoWayConverter<T,V> converter);
+    method public static androidx.animation.AnimatedValue<androidx.ui.graphics.Color,androidx.animation.AnimationVector4D> animatedColor(androidx.ui.graphics.Color initVal, androidx.animation.AnimationClockObservable clock = ambient(AnimationClockAmbient));
+    method public static androidx.animation.AnimatedFloat animatedFloat(float initVal, androidx.animation.AnimationClockObservable clock = ambient(AnimationClockAmbient));
+    method public static <T, V extends androidx.animation.AnimationVector> androidx.animation.AnimatedValue<T,V> animatedValue(T? initVal, androidx.animation.TwoWayConverter<T,V> converter, androidx.animation.AnimationClockObservable clock = ambient(AnimationClockAmbient));
   }
 
   public final class ColorPropKey implements androidx.animation.PropKey<androidx.ui.graphics.Color,androidx.animation.AnimationVector4D> {
diff --git a/ui/ui-animation/api/public_plus_experimental_current.txt b/ui/ui-animation/api/public_plus_experimental_current.txt
index 2e5f447..7a78e4b 100644
--- a/ui/ui-animation/api/public_plus_experimental_current.txt
+++ b/ui/ui-animation/api/public_plus_experimental_current.txt
@@ -2,9 +2,9 @@
 package androidx.ui.animation {
 
   public final class AnimatedValueEffectsKt {
-    method public static androidx.animation.AnimatedValue<androidx.ui.graphics.Color,androidx.animation.AnimationVector4D> animatedColor(androidx.ui.graphics.Color initVal);
-    method public static androidx.animation.AnimatedFloat animatedFloat(float initVal);
-    method public static <T, V extends androidx.animation.AnimationVector> androidx.animation.AnimatedValue<T,V> animatedValue(T? initVal, androidx.animation.TwoWayConverter<T,V> converter);
+    method public static androidx.animation.AnimatedValue<androidx.ui.graphics.Color,androidx.animation.AnimationVector4D> animatedColor(androidx.ui.graphics.Color initVal, androidx.animation.AnimationClockObservable clock = ambient(AnimationClockAmbient));
+    method public static androidx.animation.AnimatedFloat animatedFloat(float initVal, androidx.animation.AnimationClockObservable clock = ambient(AnimationClockAmbient));
+    method public static <T, V extends androidx.animation.AnimationVector> androidx.animation.AnimatedValue<T,V> animatedValue(T? initVal, androidx.animation.TwoWayConverter<T,V> converter, androidx.animation.AnimationClockObservable clock = ambient(AnimationClockAmbient));
   }
 
   public final class ColorPropKey implements androidx.animation.PropKey<androidx.ui.graphics.Color,androidx.animation.AnimationVector4D> {
diff --git a/ui/ui-animation/api/restricted_0.1.0-dev04.txt b/ui/ui-animation/api/restricted_0.1.0-dev04.txt
index 2e5f447..7a78e4b 100644
--- a/ui/ui-animation/api/restricted_0.1.0-dev04.txt
+++ b/ui/ui-animation/api/restricted_0.1.0-dev04.txt
@@ -2,9 +2,9 @@
 package androidx.ui.animation {
 
   public final class AnimatedValueEffectsKt {
-    method public static androidx.animation.AnimatedValue<androidx.ui.graphics.Color,androidx.animation.AnimationVector4D> animatedColor(androidx.ui.graphics.Color initVal);
-    method public static androidx.animation.AnimatedFloat animatedFloat(float initVal);
-    method public static <T, V extends androidx.animation.AnimationVector> androidx.animation.AnimatedValue<T,V> animatedValue(T? initVal, androidx.animation.TwoWayConverter<T,V> converter);
+    method public static androidx.animation.AnimatedValue<androidx.ui.graphics.Color,androidx.animation.AnimationVector4D> animatedColor(androidx.ui.graphics.Color initVal, androidx.animation.AnimationClockObservable clock = ambient(AnimationClockAmbient));
+    method public static androidx.animation.AnimatedFloat animatedFloat(float initVal, androidx.animation.AnimationClockObservable clock = ambient(AnimationClockAmbient));
+    method public static <T, V extends androidx.animation.AnimationVector> androidx.animation.AnimatedValue<T,V> animatedValue(T? initVal, androidx.animation.TwoWayConverter<T,V> converter, androidx.animation.AnimationClockObservable clock = ambient(AnimationClockAmbient));
   }
 
   public final class ColorPropKey implements androidx.animation.PropKey<androidx.ui.graphics.Color,androidx.animation.AnimationVector4D> {
diff --git a/ui/ui-animation/api/restricted_current.txt b/ui/ui-animation/api/restricted_current.txt
index 2e5f447..7a78e4b 100644
--- a/ui/ui-animation/api/restricted_current.txt
+++ b/ui/ui-animation/api/restricted_current.txt
@@ -2,9 +2,9 @@
 package androidx.ui.animation {
 
   public final class AnimatedValueEffectsKt {
-    method public static androidx.animation.AnimatedValue<androidx.ui.graphics.Color,androidx.animation.AnimationVector4D> animatedColor(androidx.ui.graphics.Color initVal);
-    method public static androidx.animation.AnimatedFloat animatedFloat(float initVal);
-    method public static <T, V extends androidx.animation.AnimationVector> androidx.animation.AnimatedValue<T,V> animatedValue(T? initVal, androidx.animation.TwoWayConverter<T,V> converter);
+    method public static androidx.animation.AnimatedValue<androidx.ui.graphics.Color,androidx.animation.AnimationVector4D> animatedColor(androidx.ui.graphics.Color initVal, androidx.animation.AnimationClockObservable clock = ambient(AnimationClockAmbient));
+    method public static androidx.animation.AnimatedFloat animatedFloat(float initVal, androidx.animation.AnimationClockObservable clock = ambient(AnimationClockAmbient));
+    method public static <T, V extends androidx.animation.AnimationVector> androidx.animation.AnimatedValue<T,V> animatedValue(T? initVal, androidx.animation.TwoWayConverter<T,V> converter, androidx.animation.AnimationClockObservable clock = ambient(AnimationClockAmbient));
   }
 
   public final class ColorPropKey implements androidx.animation.PropKey<androidx.ui.graphics.Color,androidx.animation.AnimationVector4D> {
diff --git a/ui/ui-animation/src/main/java/androidx/ui/animation/AnimatedValueEffects.kt b/ui/ui-animation/src/main/java/androidx/ui/animation/AnimatedValueEffects.kt
index 2185bcd..26d3dae 100644
--- a/ui/ui-animation/src/main/java/androidx/ui/animation/AnimatedValueEffects.kt
+++ b/ui/ui-animation/src/main/java/androidx/ui/animation/AnimatedValueEffects.kt
@@ -18,13 +18,16 @@
 
 import androidx.animation.AnimatedFloat
 import androidx.animation.AnimatedValue
+import androidx.animation.AnimationClockObservable
 import androidx.animation.TwoWayConverter
 import androidx.compose.Model
 import androidx.animation.ValueHolder
 import androidx.animation.AnimationVector
 import androidx.animation.AnimationVector4D
 import androidx.compose.Composable
+import androidx.compose.ambient
 import androidx.compose.remember
+import androidx.ui.core.AnimationClockAmbient
 import androidx.ui.graphics.Color
 
 /**
@@ -39,8 +42,9 @@
 @Composable
 fun <T, V : AnimationVector> animatedValue(
     initVal: T,
-    converter: TwoWayConverter<T, V>
-): AnimatedValue<T, V> = remember { AnimatedValue(AnimValueHolder(initVal), converter) }
+    converter: TwoWayConverter<T, V>,
+    clock: AnimationClockObservable = ambient(AnimationClockAmbient)
+): AnimatedValue<T, V> = remember { AnimatedValue(AnimValueHolder(initVal), converter, clock) }
 
 /**
  * The animatedValue effect creates an [AnimatedFloat] and positionally memoizes it. When the
@@ -50,8 +54,11 @@
  * @param initVal Initial value to set [AnimatedFloat] to.
  */
 @Composable
-fun animatedFloat(initVal: Float): AnimatedFloat =
-    remember { AnimatedFloat(AnimValueHolder(initVal)) }
+fun animatedFloat(
+    initVal: Float,
+    clock: AnimationClockObservable = ambient(AnimationClockAmbient)
+): AnimatedFloat =
+    remember { AnimatedFloat(AnimValueHolder(initVal), clock) }
 
 /**
  * The animatedValue effect creates an [AnimatedValue] of [Color] and positionally memoizes it. When
@@ -61,10 +68,19 @@
  * @param initVal Initial value to set [AnimatedValue] to.
  */
 @Composable
-fun animatedColor(initVal: Color): AnimatedValue<Color, AnimationVector4D> =
-    remember { AnimatedValue(AnimValueHolder(initVal), ColorToVectorConverter(initVal.colorSpace)) }
+fun animatedColor(
+    initVal: Color,
+    clock: AnimationClockObservable = ambient(AnimationClockAmbient)
+): AnimatedValue<Color, AnimationVector4D> =
+    remember {
+        AnimatedValue(
+            valueHolder = AnimValueHolder(initVal),
+            typeConverter = ColorToVectorConverter(initVal.colorSpace),
+            clock = clock
+        )
+    }
 
 @Model
-private class AnimValueHolder<T> (
+private class AnimValueHolder<T>(
     override var value: T
 ) : ValueHolder<T>
diff --git a/ui/ui-foundation/src/main/java/androidx/ui/foundation/animation/AnimatedValueHolder.kt b/ui/ui-foundation/src/main/java/androidx/ui/foundation/animation/AnimatedValueHolder.kt
index fd519f0..6390624 100644
--- a/ui/ui-foundation/src/main/java/androidx/ui/foundation/animation/AnimatedValueHolder.kt
+++ b/ui/ui-foundation/src/main/java/androidx/ui/foundation/animation/AnimatedValueHolder.kt
@@ -33,6 +33,7 @@
 @Model
 class AnimatedValueHolder(initial: Float) : ValueHolder<Float> {
 
+    @Suppress("DEPRECATION")
     val animatedFloat = AnimatedFloat(ListeneableValueHolder(initial, { value = it }))
 
     /**