1 package org.robolectric.shadows; 2 3 import static org.assertj.core.api.Assertions.assertThat; 4 5 import android.view.MotionEvent; 6 import android.view.VelocityTracker; 7 import org.junit.Before; 8 import org.junit.Test; 9 import org.junit.runner.RunWith; 10 import org.robolectric.RobolectricTestRunner; 11 import org.robolectric.Shadows; 12 13 @RunWith(RobolectricTestRunner.class) 14 public class VelocityTrackerTest { 15 VelocityTracker velocityTracker; 16 17 @Before 18 public void setUp() { 19 velocityTracker = VelocityTracker.obtain(); 20 } 21 22 @Test 23 public void handlesXMovement() { 24 velocityTracker.addMovement(doMotion(0, 0, 0)); 25 velocityTracker.addMovement(doMotion(20, 20, 0)); 26 velocityTracker.computeCurrentVelocity(1); 27 28 // active pointer 29 assertThat(velocityTracker.getXVelocity()).isEqualTo(1); 30 assertThat(velocityTracker.getXVelocity(0)).isEqualTo(1); 31 // inactive pointer 32 assertThat(velocityTracker.getXVelocity(10)).isEqualTo(0); 33 } 34 35 @Test 36 public void handlesYMovement() { 37 velocityTracker.addMovement(doMotion(0, 0, 0)); 38 velocityTracker.addMovement(doMotion(20, 0, 20)); 39 velocityTracker.computeCurrentVelocity(1); 40 41 // active pointer 42 assertThat(velocityTracker.getYVelocity()).isEqualTo(1); 43 assertThat(velocityTracker.getYVelocity(0)).isEqualTo(1); 44 // inactive pointer 45 assertThat(velocityTracker.getYVelocity(10)).isEqualTo(0); 46 } 47 48 @Test 49 public void handlesXAndYMovement() { 50 velocityTracker.addMovement(doMotion(0, 0, 0)); 51 velocityTracker.addMovement(doMotion(20, 20, 40)); 52 velocityTracker.computeCurrentVelocity(1); 53 54 assertThat(velocityTracker.getXVelocity()).isEqualTo(1); 55 assertThat(velocityTracker.getYVelocity()).isEqualTo(2); 56 } 57 58 @Test 59 public void handlesWindowing_positive() { 60 velocityTracker.addMovement(doMotion(0, 0, 0)); 61 velocityTracker.addMovement(doMotion(20, 10000, 10000)); 62 velocityTracker.computeCurrentVelocity(1, 10); 63 64 assertThat(velocityTracker.getXVelocity()).isEqualTo(10); 65 assertThat(velocityTracker.getYVelocity()).isEqualTo(10); 66 } 67 68 @Test 69 public void handlesWindowing_negative() { 70 velocityTracker.addMovement(doMotion(0, 0, 0)); 71 velocityTracker.addMovement(doMotion(20, -10000, -10000)); 72 velocityTracker.computeCurrentVelocity(1, 10); 73 74 assertThat(velocityTracker.getXVelocity()).isEqualTo(-10); 75 assertThat(velocityTracker.getYVelocity()).isEqualTo(-10); 76 } 77 78 @Test 79 public void handlesMultiplePointers() { 80 // pointer 0 active 81 velocityTracker.addMovement(doMotion(0, 0, 0)); 82 // pointer 1 active 83 velocityTracker.addMovement(doMotion(20, 40, 40, 0, 0)); 84 velocityTracker.addMovement(doMotion(40, 80, 80, 20, 20)); 85 velocityTracker.computeCurrentVelocity(1); 86 87 // active pointer 88 assertThat(velocityTracker.getXVelocity()).isEqualTo(1); 89 assertThat(velocityTracker.getXVelocity(1)).isEqualTo(1); 90 // inactive pointer 91 assertThat(velocityTracker.getXVelocity(0)).isEqualTo(2f); 92 } 93 94 @Test 95 public void handlesClearing() { 96 velocityTracker.addMovement(doMotion(0, 0, 0)); 97 velocityTracker.addMovement(doMotion(20, 20, 20)); 98 velocityTracker.computeCurrentVelocity(1); 99 velocityTracker.clear(); 100 101 assertThat(velocityTracker.getXVelocity()).isEqualTo(0); 102 assertThat(velocityTracker.getYVelocity()).isEqualTo(0); 103 velocityTracker.computeCurrentVelocity(1); 104 assertThat(velocityTracker.getXVelocity()).isEqualTo(0); 105 assertThat(velocityTracker.getYVelocity()).isEqualTo(0); 106 } 107 108 @Test 109 public void clearsOnDown() { 110 velocityTracker.addMovement(doMotion(0, 0, 0)); 111 velocityTracker.addMovement(doMotion(20, 20, 20)); 112 velocityTracker.computeCurrentVelocity(1); 113 velocityTracker.addMovement(doPointerDown(40, 40, 40)); 114 velocityTracker.computeCurrentVelocity(1); 115 116 assertThat(velocityTracker.getXVelocity()).isEqualTo(0); 117 assertThat(velocityTracker.getYVelocity()).isEqualTo(0); 118 } 119 120 private static MotionEvent doMotion(long time, float x, float y) { 121 return MotionEvent.obtain(0, time, MotionEvent.ACTION_MOVE, x, y, 0); 122 } 123 124 private static MotionEvent doPointerDown(long time, float x, float y) { 125 return MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, x, y, 0); 126 } 127 128 /** 129 * Construct a new MotionEvent involving two pointers at {@code time}. Pointer 2 will be 130 * considered active. 131 */ 132 private static MotionEvent doMotion( 133 long time, float pointer1X, float pointer1Y, float pointer2X, float pointer2Y) { 134 MotionEvent event = 135 MotionEvent.obtain(0, time, MotionEvent.ACTION_MOVE, pointer2X, pointer2Y, 0); 136 ShadowMotionEvent shadowEvent = Shadows.shadowOf(event); 137 shadowEvent.setPointer2(pointer1X, pointer1Y); 138 shadowEvent.setPointerIndex(0); 139 // we put our active pointer (the second one down) first, so flip the IDs so that they match up 140 // properly 141 shadowEvent.setPointerIds(1, 0); 142 143 return event; 144 } 145 } 146