| /* |
| * Copyright (C) 2010 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.view; |
| |
| import android.test.suitebuilder.annotation.Suppress; |
| import junit.framework.Assert; |
| |
| import android.test.InstrumentationTestCase; |
| import android.test.suitebuilder.annotation.MediumTest; |
| import android.view.animation.AccelerateInterpolator; |
| import android.view.animation.DecelerateInterpolator; |
| import android.view.animation.Interpolator; |
| import android.view.animation.LinearInterpolator; |
| |
| /** |
| * Exercises {@link android.view.VelocityTracker} to compute correct velocity.<br> |
| * To launch this test, use :<br> |
| * <code>./development/testrunner/runtest.py framework -c android.view.VelocityTest</code> |
| */ |
| public class VelocityTest extends InstrumentationTestCase { |
| |
| @MediumTest |
| public void testInitialCondiditions() { |
| VelocityTracker vt = VelocityTracker.obtain(); |
| assertNotNull(vt); |
| vt.recycle(); |
| } |
| |
| /** |
| * Test that {@link android.view.VelocityTracker}.clear() clears |
| * the previous values after a call to computeCurrentVelocity() |
| */ |
| @MediumTest |
| public void testClear() { |
| long t = System.currentTimeMillis(); |
| VelocityTracker vt = VelocityTracker.obtain(); |
| drag(vt, 100, 200, 100, 200, 10, t, 300); |
| vt.computeCurrentVelocity(1); |
| assertFalse("Velocity should not be null", vt.getXVelocity() == 0.0f); |
| assertFalse("Velocity should not be null", vt.getYVelocity() == 0.0f); |
| vt.clear(); |
| vt.computeCurrentVelocity(1); |
| assertEquals(0.0f, vt.getXVelocity()); |
| assertEquals(0.0f, vt.getYVelocity()); |
| vt.recycle(); |
| } |
| |
| @MediumTest |
| public void testDragAcceleration () { |
| long t = System.currentTimeMillis(); |
| VelocityTracker vt = VelocityTracker.obtain(); |
| drag(vt, 100, 200, 100, 200, 15, t, 400, new AccelerateInterpolator()); |
| vt.computeCurrentVelocity(1000); |
| assertGreater(250.0f, vt.getXVelocity()); |
| assertGreater(250.0f, vt.getYVelocity()); |
| vt.recycle(); |
| } |
| |
| @MediumTest |
| public void testDragDeceleration () { |
| long t = System.currentTimeMillis(); |
| VelocityTracker vt = VelocityTracker.obtain(); |
| drag(vt, 100, 200, 100, 200, 15, t, 400, new DecelerateInterpolator()); |
| vt.computeCurrentVelocity(1000); |
| assertLower(250.0f, vt.getXVelocity()); |
| assertLower(250.0f, vt.getYVelocity()); |
| vt.recycle(); |
| } |
| |
| @MediumTest |
| @Suppress // Failing. |
| public void testDragLinearHorizontal() { |
| long t = System.currentTimeMillis(); |
| VelocityTracker vt = VelocityTracker.obtain(); |
| // 100px in 400ms => 250px/s |
| drag(vt, 100, 200, 200, 200, 15, t, 400); |
| vt.computeCurrentVelocity(1000); |
| assertEquals(0.0f, vt.getYVelocity()); |
| assertEqualFuzzy(250.0f, vt.getXVelocity(), 4f); |
| vt.recycle(); |
| } |
| |
| @MediumTest |
| @Suppress // Failing. |
| public void testDragLinearVertical() { |
| long t = System.currentTimeMillis(); |
| VelocityTracker vt = VelocityTracker.obtain(); |
| // 100px in 400ms => 250px/s |
| drag(vt, 200, 200, 100, 200, 15, t, 400); |
| vt.computeCurrentVelocity(1000); |
| assertEquals(0.0f, vt.getXVelocity()); |
| assertEqualFuzzy(250.0f, vt.getYVelocity(), 4f); |
| vt.recycle(); |
| } |
| |
| /** |
| * Test dragging with two points only |
| * (velocity must be an exact value) |
| */ |
| @MediumTest |
| @Suppress // Failing. |
| public void testDragWith2Points () { |
| long t = System.currentTimeMillis(); |
| VelocityTracker vt = VelocityTracker.obtain(); |
| // 100px, 2 steps, 100ms => 1000px/s |
| drag(vt, 100, 200, 100, 200, 2, t, 100); |
| vt.computeCurrentVelocity(1000); |
| assertEquals(1000.0f, vt.getXVelocity()); |
| assertEquals(1000.0f, vt.getYVelocity()); |
| vt.recycle(); |
| } |
| |
| /** |
| * Velocity is independent of the number of points used during |
| * the same interval |
| */ |
| @MediumTest |
| @Suppress // Failing. |
| public void testStabilityInNbPoints () { |
| long t = System.currentTimeMillis(); |
| VelocityTracker vt = VelocityTracker.obtain(); |
| drag(vt, 100, 200, 100, 200, 10, t, 400); // 10 steps over 400ms |
| vt.computeCurrentVelocity(1); |
| float firstX = vt.getXVelocity(); |
| float firstY = vt.getYVelocity(); |
| vt.clear(); |
| drag(vt, 100, 200, 100, 200, 20, t, 400); // 20 steps over 400ms |
| vt.computeCurrentVelocity(1); |
| float secondX = vt.getXVelocity(); |
| float secondY = vt.getYVelocity(); |
| assertEqualFuzzy(firstX, secondX, 0.1f); |
| assertEqualFuzzy(firstY, secondY, 0.1f); |
| vt.recycle(); |
| } |
| |
| /** |
| * Velocity is independent of the time when the events occurs, |
| * it only depends on delays between the events. |
| */ |
| @MediumTest |
| public void testStabilityInTime () { |
| long t = System.currentTimeMillis(); |
| VelocityTracker vt = VelocityTracker.obtain(); |
| drag(vt, 100, 200, 100, 200, 10, t, 400); |
| vt.computeCurrentVelocity(1); |
| float firstX = vt.getXVelocity(); |
| float firstY = vt.getYVelocity(); |
| vt.clear(); |
| drag(vt, 100, 200, 100, 200, 10, t + 3600*1000, 400); // on hour later |
| vt.computeCurrentVelocity(1); |
| float secondX = vt.getXVelocity(); |
| float secondY = vt.getYVelocity(); |
| assertEqualFuzzy(firstX, secondX, 0.1f); |
| assertEqualFuzzy(firstY, secondY, 0.1f); |
| vt.recycle(); |
| } |
| |
| /** |
| * Velocity is independent of the position of the events, |
| * it only depends on their relative distance. |
| */ |
| @MediumTest |
| public void testStabilityInSpace () { |
| long t = System.currentTimeMillis(); |
| VelocityTracker vt = VelocityTracker.obtain(); |
| drag(vt, 100, 200, 100, 200, 10, t, 400); |
| vt.computeCurrentVelocity(1); |
| float firstX = vt.getXVelocity(); |
| float firstY = vt.getYVelocity(); |
| vt.clear(); |
| drag(vt, 200, 300, 200, 300, 10, t, 400); // 100px further |
| vt.computeCurrentVelocity(1); |
| float secondX = vt.getXVelocity(); |
| float secondY = vt.getYVelocity(); |
| assertEqualFuzzy(firstX, secondX, 0.1f); |
| assertEqualFuzzy(firstY, secondY, 0.1f); |
| vt.recycle(); |
| } |
| |
| /** |
| * Test that calls to {@link android.view.VelocityTracker}.computeCurrentVelocity() |
| * will output same values when using the same data. |
| */ |
| @MediumTest |
| public void testStabilityOfComputation() { |
| long t = System.currentTimeMillis(); |
| VelocityTracker vt = VelocityTracker.obtain(); |
| drag(vt, 100, 200, 100, 200, 10, t, 300); |
| vt.computeCurrentVelocity(1); |
| float firstX = vt.getXVelocity(); |
| float firstY = vt.getYVelocity(); |
| vt.computeCurrentVelocity(1); |
| float secondX = vt.getXVelocity(); |
| float secondY = vt.getYVelocity(); |
| assertEquals(firstX, secondX); |
| assertEquals(firstY, secondY); |
| vt.recycle(); |
| } |
| |
| /** |
| * Test the units parameter of {@link android.view.VelocityTracker}.computeCurrentVelocity() |
| */ |
| @MediumTest |
| public void testStabilityOfUnits() { |
| long t = System.currentTimeMillis(); |
| VelocityTracker vt = VelocityTracker.obtain(); |
| drag(vt, 100, 200, 100, 200, 10, t, 300); |
| vt.computeCurrentVelocity(1); |
| float firstX = vt.getXVelocity(); |
| float firstY = vt.getYVelocity(); |
| vt.computeCurrentVelocity(1000); |
| float secondX = vt.getXVelocity(); |
| float secondY = vt.getYVelocity(); |
| assertEqualFuzzy(firstX, secondX / 1000.0f, 0.1f); |
| assertEqualFuzzy(firstY, secondY / 1000.0f, 0.1f); |
| vt.recycle(); |
| } |
| |
| /** |
| * Simulate a drag by giving directly MotionEvents to |
| * the VelocityTracker using a linear interpolator |
| */ |
| private void drag(VelocityTracker vt, int startX, int endX, int startY, int endY, int steps, |
| long startime, int duration) { |
| drag(vt, startX, endX, startY, endY, steps, startime, duration, new LinearInterpolator()); |
| } |
| |
| /** |
| * Simulate a drag by giving directly MotionEvents to |
| * the VelocityTracker using a given interpolator |
| */ |
| private void drag(VelocityTracker vt, int startX, int endX, int startY, int endY, int steps, |
| long startime, int duration, Interpolator interpolator) { |
| addMotionEvent(vt, startX, startY, startime, MotionEvent.ACTION_DOWN); |
| float dt = duration / (float)steps; |
| int distX = endX - startX; |
| int distY = endY - startY; |
| for (int i=1; i<steps-1; i++) { |
| float ii = interpolator.getInterpolation(i / (float)steps); |
| int x = (int) (startX + distX * ii); |
| int y = (int) (startY + distY * ii); |
| long time = startime + (int) (i * dt); |
| addMotionEvent(vt, x, y, time, MotionEvent.ACTION_MOVE); |
| } |
| addMotionEvent(vt, endX, endY, startime + duration, MotionEvent.ACTION_UP); |
| } |
| |
| private void addMotionEvent(VelocityTracker vt, int x, int y, long time, int action) { |
| MotionEvent me = MotionEvent.obtain(time, time, action, x, y, 0); |
| vt.addMovement(me); |
| me.recycle(); |
| } |
| |
| /** |
| * Float imprecision of the average computations and filtering |
| * (removing last MotionEvent for N > 3) implies that tests |
| * accepts some approximated values. |
| */ |
| private void assertEqualFuzzy(float expected, float actual, float threshold) { |
| boolean fuzzyEqual = actual >= expected - threshold && actual <= expected + threshold; |
| Assert.assertTrue("Expected: <"+expected+"> but was: <"+actual+ |
| "> while accepting a variation of: <"+threshold+">", fuzzyEqual); |
| } |
| |
| private void assertGreater(float minExpected, float actual) { |
| Assert.assertTrue("Expected: minimum <"+minExpected+"> but was: <"+actual+">", |
| actual > minExpected); |
| } |
| |
| private void assertLower(float maxExpected, float actual) { |
| Assert.assertTrue("Expected: maximum <"+maxExpected+"> but was: <"+actual+">", |
| actual < maxExpected); |
| } |
| } |