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

Commit be5a8ac5 authored by Doris Liu's avatar Doris Liu
Browse files

Add tests for ValueAnimator

This CL contains a few tests for ValueAnimator around start/resume, listener
callbacks, state checks, and start delay.

Change-Id: Ib67f36c1b266faff69f66f945ed846f9f7eb1193
parent 8cf6d865
Loading
Loading
Loading
Loading
+438 −0
Original line number Diff line number Diff line
/*
* 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;
        }
    }
}