VelocityTest.java revision 7672ef046b40cc5a56fd36f152f848654c55a096
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
19import junit.framework.Assert;
20
21import android.test.InstrumentationTestCase;
22import android.test.suitebuilder.annotation.MediumTest;
23import android.view.animation.AccelerateInterpolator;
24import android.view.animation.DecelerateInterpolator;
25import android.view.animation.Interpolator;
26import android.view.animation.LinearInterpolator;
27
28/**
29 * Exercises {@link android.view.VelocityTracker} to compute correct velocity.<br>
30 * To launch this test, use :<br>
31 * <code>./development/testrunner/runtest.py framework -c android.view.VelocityTest</code>
32 */
33public class VelocityTest extends InstrumentationTestCase {
34
35    @MediumTest
36    public void testInitialCondiditions() {
37        VelocityTracker vt = VelocityTracker.obtain();
38        assertNotNull(vt);
39        vt.recycle();
40    }
41
42    /**
43     * Test that {@link android.view.VelocityTracker}.clear() clears
44     * the previous values after a call to computeCurrentVelocity()
45     */
46    @MediumTest
47    public void testClear() {
48        long t = System.currentTimeMillis();
49        VelocityTracker vt = VelocityTracker.obtain();
50        drag(vt, 100, 200, 100, 200, 10, t, 300);
51        vt.computeCurrentVelocity(1);
52        assertFalse("Velocity should not be null", vt.getXVelocity() == 0.0f);
53        assertFalse("Velocity should not be null", vt.getYVelocity() == 0.0f);
54        vt.clear();
55        vt.computeCurrentVelocity(1);
56        assertEquals(0.0f, vt.getXVelocity());
57        assertEquals(0.0f, vt.getYVelocity());
58        vt.recycle();
59    }
60
61    @MediumTest
62    public void testDragAcceleration () {
63        long t = System.currentTimeMillis();
64        VelocityTracker vt = VelocityTracker.obtain();
65        drag(vt, 100, 200, 100, 200, 15, t, 400, new AccelerateInterpolator());
66        vt.computeCurrentVelocity(1000);
67        assertGreater(250.0f, vt.getXVelocity());
68        assertGreater(250.0f, vt.getYVelocity());
69        vt.recycle();
70    }
71
72    @MediumTest
73    public void testDragDeceleration () {
74        long t = System.currentTimeMillis();
75        VelocityTracker vt = VelocityTracker.obtain();
76        drag(vt, 100, 200, 100, 200, 15, t, 400, new DecelerateInterpolator());
77        vt.computeCurrentVelocity(1000);
78        assertLower(250.0f, vt.getXVelocity());
79        assertLower(250.0f, vt.getYVelocity());
80        vt.recycle();
81    }
82
83    @MediumTest
84    public void testDragLinearHorizontal() {
85        long t = System.currentTimeMillis();
86        VelocityTracker vt = VelocityTracker.obtain();
87        // 100px in 400ms => 250px/s
88        drag(vt, 100, 200, 200, 200, 15, t, 400);
89        vt.computeCurrentVelocity(1000);
90        assertEquals(0.0f, vt.getYVelocity());
91        assertEqualFuzzy(250.0f, vt.getXVelocity(), 4f);
92        vt.recycle();
93    }
94
95    @MediumTest
96    public void testDragLinearVertical() {
97        long t = System.currentTimeMillis();
98        VelocityTracker vt = VelocityTracker.obtain();
99        // 100px in 400ms => 250px/s
100        drag(vt, 200, 200, 100, 200, 15, t, 400);
101        vt.computeCurrentVelocity(1000);
102        assertEquals(0.0f, vt.getXVelocity());
103        assertEqualFuzzy(250.0f, vt.getYVelocity(), 4f);
104        vt.recycle();
105    }
106
107    /**
108     * Test dragging with two points only
109     * (velocity must be an exact value)
110     */
111    @MediumTest
112    public void testDragWith2Points () {
113        long t = System.currentTimeMillis();
114        VelocityTracker vt = VelocityTracker.obtain();
115        // 100px, 2 steps, 100ms => 1000px/s
116        drag(vt, 100, 200, 100, 200, 2, t, 100);
117        vt.computeCurrentVelocity(1000);
118        assertEquals(1000.0f, vt.getXVelocity());
119        assertEquals(1000.0f, vt.getYVelocity());
120        vt.recycle();
121    }
122
123    /**
124     * Velocity is independent of the number of points used during
125     * the same interval
126     */
127    @MediumTest
128    public void testStabilityInNbPoints () {
129        long t = System.currentTimeMillis();
130        VelocityTracker vt = VelocityTracker.obtain();
131        drag(vt, 100, 200, 100, 200, 10, t, 400); // 10 steps over 400ms
132        vt.computeCurrentVelocity(1);
133        float firstX = vt.getXVelocity();
134        float firstY = vt.getYVelocity();
135        vt.clear();
136        drag(vt, 100, 200, 100, 200, 20, t, 400); // 20 steps over 400ms
137        vt.computeCurrentVelocity(1);
138        float secondX = vt.getXVelocity();
139        float secondY = vt.getYVelocity();
140        assertEqualFuzzy(firstX, secondX, 0.1f);
141        assertEqualFuzzy(firstY, secondY, 0.1f);
142        vt.recycle();
143    }
144
145    /**
146     * Velocity is independent of the time when the events occurs,
147     * it only depends on delays between the events.
148     */
149    @MediumTest
150    public void testStabilityInTime () {
151        long t = System.currentTimeMillis();
152        VelocityTracker vt = VelocityTracker.obtain();
153        drag(vt, 100, 200, 100, 200, 10, t, 400);
154        vt.computeCurrentVelocity(1);
155        float firstX = vt.getXVelocity();
156        float firstY = vt.getYVelocity();
157        vt.clear();
158        drag(vt, 100, 200, 100, 200, 10, t + 3600*1000, 400); // on hour later
159        vt.computeCurrentVelocity(1);
160        float secondX = vt.getXVelocity();
161        float secondY = vt.getYVelocity();
162        assertEqualFuzzy(firstX, secondX, 0.1f);
163        assertEqualFuzzy(firstY, secondY, 0.1f);
164        vt.recycle();
165    }
166
167    /**
168     * Velocity is independent of the position of the events,
169     * it only depends on their relative distance.
170     */
171    @MediumTest
172    public void testStabilityInSpace () {
173        long t = System.currentTimeMillis();
174        VelocityTracker vt = VelocityTracker.obtain();
175        drag(vt, 100, 200, 100, 200, 10, t, 400);
176        vt.computeCurrentVelocity(1);
177        float firstX = vt.getXVelocity();
178        float firstY = vt.getYVelocity();
179        vt.clear();
180        drag(vt, 200, 300, 200, 300, 10, t, 400); // 100px further
181        vt.computeCurrentVelocity(1);
182        float secondX = vt.getXVelocity();
183        float secondY = vt.getYVelocity();
184        assertEqualFuzzy(firstX, secondX, 0.1f);
185        assertEqualFuzzy(firstY, secondY, 0.1f);
186        vt.recycle();
187    }
188
189    /**
190     * Test that calls to {@link android.view.VelocityTracker}.computeCurrentVelocity()
191     * will output same values when using the same data.
192     */
193    @MediumTest
194    public void testStabilityOfComputation() {
195        long t = System.currentTimeMillis();
196        VelocityTracker vt = VelocityTracker.obtain();
197        drag(vt, 100, 200, 100, 200, 10, t, 300);
198        vt.computeCurrentVelocity(1);
199        float firstX = vt.getXVelocity();
200        float firstY = vt.getYVelocity();
201        vt.computeCurrentVelocity(1);
202        float secondX = vt.getXVelocity();
203        float secondY = vt.getYVelocity();
204        assertEquals(firstX, secondX);
205        assertEquals(firstY, secondY);
206        vt.recycle();
207    }
208
209    /**
210     * Test the units parameter of {@link android.view.VelocityTracker}.computeCurrentVelocity()
211     */
212    @MediumTest
213    public void testStabilityOfUnits() {
214        long t = System.currentTimeMillis();
215        VelocityTracker vt = VelocityTracker.obtain();
216        drag(vt, 100, 200, 100, 200, 10, t, 300);
217        vt.computeCurrentVelocity(1);
218        float firstX = vt.getXVelocity();
219        float firstY = vt.getYVelocity();
220        vt.computeCurrentVelocity(1000);
221        float secondX = vt.getXVelocity();
222        float secondY = vt.getYVelocity();
223        assertEqualFuzzy(firstX, secondX / 1000.0f, 0.1f);
224        assertEqualFuzzy(firstY, secondY / 1000.0f, 0.1f);
225        vt.recycle();
226    }
227
228    /**
229     * Simulate a drag by giving directly MotionEvents to
230     * the VelocityTracker using a linear interpolator
231     */
232    private void drag(VelocityTracker vt, int startX, int endX, int startY, int endY, int steps,
233            long startime, int duration) {
234        drag(vt, startX, endX, startY, endY, steps, startime, duration, new LinearInterpolator());
235    }
236
237    /**
238     * Simulate a drag by giving directly MotionEvents to
239     * the VelocityTracker using a given interpolator
240     */
241    private void drag(VelocityTracker vt, int startX, int endX, int startY, int endY, int steps,
242            long startime, int duration, Interpolator interpolator) {
243        addMotionEvent(vt, startX, startY, startime, MotionEvent.ACTION_DOWN);
244        float dt = duration / (float)steps;
245        int distX = endX - startX;
246        int distY = endY - startY;
247        for (int i=1; i<steps-1; i++) {
248            float ii = interpolator.getInterpolation(i / (float)steps);
249            int x = (int) (startX + distX * ii);
250            int y = (int) (startY + distY * ii);
251            long time = startime + (int) (i * dt);
252            addMotionEvent(vt, x, y, time, MotionEvent.ACTION_MOVE);
253        }
254        addMotionEvent(vt, endX, endY, startime + duration, MotionEvent.ACTION_UP);
255    }
256
257    private void addMotionEvent(VelocityTracker vt, int x, int y, long time, int action) {
258        MotionEvent me = MotionEvent.obtain(time, time, action, x, y, 0);
259        vt.addMovement(me);
260        me.recycle();
261    }
262
263    /**
264     * Float imprecision of the average computations and filtering
265     * (removing last MotionEvent for N > 3) implies that tests
266     *  accepts some approximated values.
267     */
268    private void assertEqualFuzzy(float expected, float actual, float threshold) {
269        boolean fuzzyEqual = actual >= expected - threshold && actual <= expected + threshold;
270        Assert.assertTrue("Expected: <"+expected+"> but was: <"+actual+
271                "> while accepting a variation of: <"+threshold+">", fuzzyEqual);
272    }
273
274    private void assertGreater(float minExpected, float actual) {
275        Assert.assertTrue("Expected: minimum <"+minExpected+"> but was: <"+actual+">",
276                actual > minExpected);
277    }
278
279    private void assertLower(float maxExpected, float actual) {
280        Assert.assertTrue("Expected: maximum <"+maxExpected+"> but was: <"+actual+">",
281                actual < maxExpected);
282    }
283}
284