package org.robolectric.shadows;
import static org.assertj.core.api.Assertions.assertThat;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Shadows;
import org.robolectric.TestRunners;
@RunWith(TestRunners.MultiApiSelfTest.class)
public class VelocityTrackerTest {
VelocityTracker velocityTracker;
@Before
public void setUp() {
velocityTracker = VelocityTracker.obtain();
}
@Test
public void handlesXMovement() {
velocityTracker.addMovement(doMotion(0, 0, 0));
velocityTracker.addMovement(doMotion(20, 20, 0));
velocityTracker.computeCurrentVelocity(1);
// active pointer
assertThat(velocityTracker.getXVelocity()).isEqualTo(1);
assertThat(velocityTracker.getXVelocity(0)).isEqualTo(1);
// inactive pointer
assertThat(velocityTracker.getXVelocity(10)).isEqualTo(0);
}
@Test
public void handlesYMovement() {
velocityTracker.addMovement(doMotion(0, 0, 0));
velocityTracker.addMovement(doMotion(20, 0, 20));
velocityTracker.computeCurrentVelocity(1);
// active pointer
assertThat(velocityTracker.getYVelocity()).isEqualTo(1);
assertThat(velocityTracker.getYVelocity(0)).isEqualTo(1);
// inactive pointer
assertThat(velocityTracker.getYVelocity(10)).isEqualTo(0);
}
@Test
public void handlesXAndYMovement() {
velocityTracker.addMovement(doMotion(0, 0, 0));
velocityTracker.addMovement(doMotion(20, 20, 40));
velocityTracker.computeCurrentVelocity(1);
assertThat(velocityTracker.getXVelocity()).isEqualTo(1);
assertThat(velocityTracker.getYVelocity()).isEqualTo(2);
}
@Test
public void handlesWindowing_positive() {
velocityTracker.addMovement(doMotion(0, 0, 0));
velocityTracker.addMovement(doMotion(20, 10000, 10000));
velocityTracker.computeCurrentVelocity(1, 10);
assertThat(velocityTracker.getXVelocity()).isEqualTo(10);
assertThat(velocityTracker.getYVelocity()).isEqualTo(10);
}
@Test
public void handlesWindowing_negative() {
velocityTracker.addMovement(doMotion(0, 0, 0));
velocityTracker.addMovement(doMotion(20, -10000, -10000));
velocityTracker.computeCurrentVelocity(1, 10);
assertThat(velocityTracker.getXVelocity()).isEqualTo(-10);
assertThat(velocityTracker.getYVelocity()).isEqualTo(-10);
}
@Test
public void handlesMultiplePointers() {
// pointer 0 active
velocityTracker.addMovement(doMotion(0, 0, 0));
// pointer 1 active
velocityTracker.addMovement(doMotion(20, 40, 40, 0, 0));
velocityTracker.addMovement(doMotion(40, 80, 80, 20, 20));
velocityTracker.computeCurrentVelocity(1);
// active pointer
assertThat(velocityTracker.getXVelocity()).isEqualTo(1);
assertThat(velocityTracker.getXVelocity(1)).isEqualTo(1);
// inactive pointer
assertThat(velocityTracker.getXVelocity(0)).isEqualTo(2f);
}
@Test
public void handlesClearing() {
velocityTracker.addMovement(doMotion(0, 0, 0));
velocityTracker.addMovement(doMotion(20, 20, 20));
velocityTracker.computeCurrentVelocity(1);
velocityTracker.clear();
assertThat(velocityTracker.getXVelocity()).isEqualTo(0);
assertThat(velocityTracker.getYVelocity()).isEqualTo(0);
velocityTracker.computeCurrentVelocity(1);
assertThat(velocityTracker.getXVelocity()).isEqualTo(0);
assertThat(velocityTracker.getYVelocity()).isEqualTo(0);
}
@Test
public void clearsOnDown() {
velocityTracker.addMovement(doMotion(0, 0, 0));
velocityTracker.addMovement(doMotion(20, 20, 20));
velocityTracker.computeCurrentVelocity(1);
velocityTracker.addMovement(doPointerDown(40, 40, 40));
velocityTracker.computeCurrentVelocity(1);
assertThat(velocityTracker.getXVelocity()).isEqualTo(0);
assertThat(velocityTracker.getYVelocity()).isEqualTo(0);
}
private static MotionEvent doMotion(long time, float x, float y) {
return MotionEvent.obtain(0, time, MotionEvent.ACTION_MOVE, x, y, 0);
}
private static MotionEvent doPointerDown(long time, float x, float y) {
return MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, x, y, 0);
}
/**
* Construct a new MotionEvent involving two pointers at {@code time}. Pointer 2 will be
* considered active.
*/
private static MotionEvent doMotion(
long time, float pointer1X, float pointer1Y, float pointer2X, float pointer2Y) {
MotionEvent event =
MotionEvent.obtain(0, time, MotionEvent.ACTION_MOVE, pointer2X, pointer2Y, 0);
ShadowMotionEvent shadowEvent = Shadows.shadowOf(event);
shadowEvent.setPointer2(pointer1X, pointer1Y);
shadowEvent.setPointerIndex(0);
// we put our active pointer (the second one down) first, so flip the IDs so that they match up
// properly
shadowEvent.setPointerIds(1, 0);
return event;
}
}