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