Merge "Add tests for ValueAnimator"
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
new file mode 100644
index 0000000..f3b8137
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
@@ -0,0 +1,438 @@
+/*
+* Copyright (C) 2015 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 android.animation;
+
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class ValueAnimatorTests extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
+    private ValueAnimator a1;
+    private ValueAnimator a2;
+
+    // Tolerance of error in calculations related to duration, frame time, etc. due to frame delay.
+    private final static long TOLERANCE = 100; // ms
+    private final static long POLL_INTERVAL = 100; // ms
+
+    public ValueAnimatorTests() {
+        super(BasicAnimatorActivity.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        a1 = ValueAnimator.ofFloat(0, 1f).setDuration(300);
+        a2 = ValueAnimator.ofInt(100, 200).setDuration(500);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        a1 = null;
+        a2 = null;
+    }
+
+    @SmallTest
+    public void testStartDelay() throws Throwable {
+        final ValueAnimator a = ValueAnimator.ofFloat(5f, 20f);
+        assertEquals(a.getStartDelay(), 0);
+        final long delay = 200;
+        a.setStartDelay(delay);
+        assertEquals(a.getStartDelay(), delay);
+
+        final MyUpdateListener listener = new MyUpdateListener();
+        a.addUpdateListener(listener);
+        final long[] startTime = new long[1];
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // Test the time between isRunning() and isStarted()
+                assertFalse(a.isStarted());
+                assertFalse(a.isRunning());
+                a.start();
+                startTime[0] = SystemClock.uptimeMillis();
+                assertTrue(a.isStarted());
+                assertFalse(a.isRunning());
+            }
+        });
+
+        Thread.sleep(a.getTotalDuration());
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(listener.wasRunning);
+                assertTrue(listener.firstRunningFrameTime - startTime[0] >= delay);
+            }
+        });
+
+        Thread.sleep(a.getTotalDuration());
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(a.isStarted());
+            }
+        });
+    }
+
+    @SmallTest
+    public void testListenerCallbacks() throws Throwable {
+        final MyListener l1 = new MyListener();
+        final MyListener l2 = new MyListener();
+        a1.addListener(l1);
+        a2.addListener(l2);
+        a2.setStartDelay(400);
+
+        assertFalse(l1.startCalled);
+        assertFalse(l1.cancelCalled);
+        assertFalse(l1.endCalled);
+        assertFalse(l2.startCalled);
+        assertFalse(l2.cancelCalled);
+        assertFalse(l2.endCalled);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                a1.start();
+                a2.start();
+            }
+        });
+
+        long wait = 0;
+        Thread.sleep(POLL_INTERVAL);
+        wait += POLL_INTERVAL;
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(l1.cancelCalled);
+                a1.cancel();
+                assertTrue(l1.cancelCalled);
+                assertTrue(l1.endCalled);
+            }
+        });
+
+        while (wait < a2.getStartDelay()) {
+            runTestOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    // Make sure a2's start listener isn't called during start delay.
+                    assertTrue(l1.startCalled);
+                    assertFalse(l2.startCalled);
+                }
+            });
+            Thread.sleep(POLL_INTERVAL);
+            wait += POLL_INTERVAL;
+        }
+
+        long delay = Math.max(a1.getTotalDuration(), a2.getTotalDuration()) + TOLERANCE;
+        Thread.sleep(delay);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // a1 is canceled.
+                assertTrue(l1.startCalled);
+                assertTrue(l1.cancelCalled);
+                assertTrue(l1.endCalled);
+
+                // a2 is supposed to finish normally
+                assertTrue(l2.startCalled);
+                assertFalse(l2.cancelCalled);
+                assertTrue(l2.endCalled);
+            }
+        });
+    }
+
+    @SmallTest
+    public void testIsStarted() throws Throwable {
+        assertFalse(a1.isStarted());
+        assertFalse(a2.isStarted());
+        assertFalse(a1.isRunning());
+        assertFalse(a2.isRunning());
+        final long startDelay = 150;
+        a1.setStartDelay(startDelay);
+        final long[] startTime = new long[1];
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                a1.start();
+                a2.start();
+                startTime[0] = SystemClock.uptimeMillis();
+                assertTrue(a1.isStarted());
+                assertTrue(a2.isStarted());
+            }
+        });
+        long delayMs = 0;
+        while (delayMs < startDelay) {
+            Thread.sleep(POLL_INTERVAL);
+            delayMs += POLL_INTERVAL;
+            runTestOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    if (SystemClock.uptimeMillis() - startTime[0] < startDelay) {
+                        assertFalse(a1.isRunning());
+                    }
+                }
+            });
+        }
+
+        Thread.sleep(startDelay);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(a1.isRunning());
+                assertTrue(a2.isRunning());
+            }
+        });
+
+        long delay = Math.max(a1.getTotalDuration(), a2.getTotalDuration()) * 2;
+        Thread.sleep(delay);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(a1.isStarted());
+                assertFalse(a1.isRunning());
+                assertFalse(a2.isStarted());
+                assertFalse(a2.isRunning());
+            }
+        });
+    }
+
+    @SmallTest
+    public void testPause() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(a1.isPaused());
+                assertFalse(a2.isPaused());
+
+                a1.start();
+                a2.start();
+
+                assertFalse(a1.isPaused());
+                assertFalse(a2.isPaused());
+                assertTrue(a1.isStarted());
+                assertTrue(a2.isStarted());
+            }
+        });
+
+        Thread.sleep(POLL_INTERVAL);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(a1.isRunning());
+                assertTrue(a2.isRunning());
+                a1.pause();
+                assertTrue(a1.isPaused());
+                assertFalse(a2.isPaused());
+                assertTrue(a1.isRunning());
+            }
+        });
+
+        Thread.sleep(a2.getTotalDuration());
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // By this time, a2 should have finished, and a1 is still paused
+                assertFalse(a2.isStarted());
+                assertFalse(a2.isRunning());
+                assertTrue(a1.isStarted());
+                assertTrue(a1.isRunning());
+                assertTrue(a1.isPaused());
+
+                a1.resume();
+            }
+        });
+
+        Thread.sleep(POLL_INTERVAL);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(a1.isRunning());
+                assertTrue(a1.isStarted());
+                assertFalse(a1.isPaused());
+            }
+        });
+
+        Thread.sleep(a1.getTotalDuration());
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // a1 should finish by now.
+                assertFalse(a1.isRunning());
+                assertFalse(a1.isStarted());
+                assertFalse(a1.isPaused());
+            }
+        });
+
+    }
+
+    @SmallTest
+    public void testPauseListener() throws Throwable {
+        MyPauseListener l1 = new MyPauseListener();
+        MyPauseListener l2 = new MyPauseListener();
+        a1.addPauseListener(l1);
+        a2.addPauseListener(l2);
+
+        assertFalse(l1.pauseCalled);
+        assertFalse(l1.resumeCalled);
+        assertFalse(l2.pauseCalled);
+        assertFalse(l2.resumeCalled);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                a1.start();
+                a2.start();
+            }
+        });
+
+        Thread.sleep(a1.getTotalDuration() / 2);
+        a1.pause();
+
+        Thread.sleep(a2.getTotalDuration());
+
+        // Only a1's pause listener should be called.
+        assertTrue(l1.pauseCalled);
+        assertFalse(l1.resumeCalled);
+        a1.resume();
+
+        Thread.sleep(a1.getTotalDuration());
+
+        assertTrue(l1.pauseCalled);
+        assertTrue(l1.resumeCalled);
+        assertFalse(l2.pauseCalled);
+        assertFalse(l2.resumeCalled);
+    }
+
+    @SmallTest
+    public void testResume() throws Throwable {
+        final MyUpdateListener l1 = new MyUpdateListener();
+        final long totalDuration = a1.getTotalDuration();
+        a1.addUpdateListener(l1);
+        // Set a longer duration on a1 for this test
+        a1.setDuration(1000);
+        assertTrue(l1.firstRunningFrameTime < 0);
+        assertTrue(l1.lastUpdateTime < 0);
+
+        final long[] lastUpdate = new long[1];
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                a1.start();
+            }
+        });
+
+        Thread.sleep(totalDuration / 2);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(l1.firstRunningFrameTime > 0);
+                assertTrue(l1.lastUpdateTime > l1.firstRunningFrameTime);
+                lastUpdate[0] = l1.lastUpdateTime;
+                a1.pause();
+            }
+        });
+
+        Thread.sleep(totalDuration);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // There should be no update after pause()
+                assertEquals(lastUpdate[0], l1.lastUpdateTime);
+                a1.resume();
+            }
+        });
+
+        do {
+            Thread.sleep(POLL_INTERVAL);
+            runTestOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    assertTrue(l1.lastUpdateTime > lastUpdate[0]);
+                    lastUpdate[0] = l1.lastUpdateTime;
+                }
+            });
+        } while (!a1.isStarted());
+
+        // Time between pause and resume: totalDuration
+        long entireSpan = totalDuration * 2;
+        long frameDelta = l1.lastUpdateTime - l1.firstRunningFrameTime;
+        assertTrue(Math.abs(entireSpan - frameDelta) < TOLERANCE);
+    }
+
+    class MyUpdateListener implements ValueAnimator.AnimatorUpdateListener {
+        boolean wasRunning = false;
+        long firstRunningFrameTime = -1;
+        long lastUpdateTime = -1;
+
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            lastUpdateTime = SystemClock.uptimeMillis();
+            if (animation.isRunning() && !wasRunning) {
+                // Delay has passed
+                firstRunningFrameTime = lastUpdateTime;
+                wasRunning = animation.isRunning();
+            }
+        }
+    }
+
+    class MyListener implements Animator.AnimatorListener {
+        boolean startCalled = false;
+        boolean cancelCalled = false;
+        boolean endCalled = false;
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+            startCalled = true;
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            endCalled = true;
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            cancelCalled = true;
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+
+        }
+    }
+
+    class MyPauseListener implements Animator.AnimatorPauseListener {
+        boolean pauseCalled = false;
+        boolean resumeCalled = false;
+
+        @Override
+        public void onAnimationPause(Animator animation) {
+            pauseCalled = true;
+        }
+
+        @Override
+        public void onAnimationResume(Animator animation) {
+            resumeCalled = true;
+        }
+    }
+}