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