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 17 package android.view; 18 19 import junit.framework.Assert; 20 21 import android.test.InstrumentationTestCase; 22 import android.test.suitebuilder.annotation.MediumTest; 23 import android.view.animation.AccelerateInterpolator; 24 import android.view.animation.DecelerateInterpolator; 25 import android.view.animation.Interpolator; 26 import 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 */ 33 public 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