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