Merge branch 'double-tap-to-zoom'

This commit is contained in:
Hannes Janetzek 2014-05-04 20:41:44 +02:00
commit 04ea503184
2 changed files with 169 additions and 26 deletions

View File

@ -0,0 +1,143 @@
package org.oscim.layers;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.oscim.event.Gesture;
import org.oscim.event.MotionEvent;
import org.oscim.map.Animator;
import org.oscim.map.Map;
import org.oscim.map.ViewController;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class MapEventLayerTest {
private MapEventLayer layer;
private Map mockMap;
private ViewController mockViewport;
private Animator mockAnimator;
private ArgumentCaptor<Float> argumentCaptor;
@Before
public void setUp() throws Exception {
mockMap = Mockito.mock(Map.class);
mockViewport = Mockito.mock(ViewController.class);
mockAnimator = Mockito.mock(Animator.class);
layer = new MapEventLayer(mockMap);
when(mockMap.viewport()).thenReturn(mockViewport);
when(mockMap.animator()).thenReturn(mockAnimator);
when(mockMap.getHeight()).thenReturn(6);
argumentCaptor = ArgumentCaptor.forClass(float.class);
}
@Test
public void shouldNotBeNull() throws Exception {
assertThat(layer).isNotNull();
}
@Test
public void doubleTap_shouldAnimateZoom() throws Exception {
simulateDoubleTap();
verify(mockAnimator).animateZoom(300, 2, 1.0f, -2.0f);
}
@Test
public void doubleTap_shouldAnimateZoomAfterDoubleTouchDrag() throws Exception {
simulateDoubleTouchDragUp();
simulateDoubleTap();
verify(mockAnimator).animateZoom(300, 2, 1.0f, -2.0f);
}
@Test
public void doubleTouchDrag_shouldNotAnimateZoom() throws Exception {
simulateDoubleTouchDragUp();
verify(mockAnimator, never()).animateZoom(any(long.class), any(double.class),
any(float.class), any(float.class));
}
@Test
public void doubleTouchDragUp_shouldDecreaseContentScale() throws Exception {
simulateDoubleTouchDragUp();
verify(mockViewport).scaleMap(argumentCaptor.capture(), any(float.class), any(float.class));
assertThat(argumentCaptor.getValue()).isLessThan(1);
}
@Test
public void doubleTouchDragDown_shouldIncreaseContentScale() throws Exception {
simulateDoubleTouchDragDown();
verify(mockViewport).scaleMap(argumentCaptor.capture(), any(float.class), any(float.class));
assertThat(argumentCaptor.getValue()).isGreaterThan(1);
}
private void simulateDoubleTap() {
layer.onTouchEvent(new TestMotionEvent(MotionEvent.ACTION_DOWN, 1, 1));
layer.onGesture(Gesture.DOUBLE_TAP, new TestMotionEvent(MotionEvent.ACTION_UP, 1, 1));
layer.onTouchEvent(new TestMotionEvent(MotionEvent.ACTION_UP, 1, 1));
}
private void simulateDoubleTouchDragUp() {
layer.onTouchEvent(new TestMotionEvent(MotionEvent.ACTION_DOWN, 1, 1));
layer.onGesture(Gesture.DOUBLE_TAP, new TestMotionEvent(MotionEvent.ACTION_MOVE, 1, 0));
layer.onTouchEvent(new TestMotionEvent(MotionEvent.ACTION_MOVE, 1, 0));
layer.onTouchEvent(new TestMotionEvent(MotionEvent.ACTION_UP, 1, 0));
}
private void simulateDoubleTouchDragDown() {
layer.onTouchEvent(new TestMotionEvent(MotionEvent.ACTION_DOWN, 1, 1));
layer.onGesture(Gesture.DOUBLE_TAP, new TestMotionEvent(MotionEvent.ACTION_MOVE, 1, 2));
layer.onTouchEvent(new TestMotionEvent(MotionEvent.ACTION_MOVE, 1, 2));
layer.onTouchEvent(new TestMotionEvent(MotionEvent.ACTION_UP, 1, 2));
}
class TestMotionEvent extends MotionEvent {
final int action;
final float x;
final float y;
public TestMotionEvent(int action, float x, float y) {
this.action = action;
this.x = x;
this.y = y;
}
@Override
public long getTime() {
return 0;
}
@Override
public int getAction() {
return action;
}
@Override
public float getX() {
return x;
}
@Override
public float getY() {
return y;
}
@Override
public float getX(int idx) {
return x;
}
@Override
public float getY(int idx) {
return y;
}
@Override
public int getPointerCount() {
return 0;
}
}
}

View File

@ -54,6 +54,7 @@ public class MapEventLayer extends Layer implements InputListener, GestureListen
private boolean mDown;
private boolean mDoubleTap;
private boolean mDrag;
private float mPrevX1;
private float mPrevY1;
@ -74,14 +75,12 @@ public class MapEventLayer extends Layer implements InputListener, GestureListen
protected static final float MIN_SLOP = 25.4f / 2;
/** 100 ms since start of move to reduce fling scroll */
protected static final float FLING_THREHSHOLD = 100;
protected static final float FLING_MIN_THREHSHOLD = 100;
//private final Viewport mViewport;
private final VelocityTracker mTracker;
public MapEventLayer(Map map) {
super(map);
//mViewport = map.viewport();
mTracker = new VelocityTracker();
}
@ -120,6 +119,7 @@ public class MapEventLayer extends Layer implements InputListener, GestureListen
mDoubleTap = false;
mStartMove = -1;
mDown = true;
mDrag = false;
mPrevX1 = e.getX(0);
mPrevY1 = e.getY(0);
@ -136,29 +136,33 @@ public class MapEventLayer extends Layer implements InputListener, GestureListen
}
if (action == MotionEvent.ACTION_UP) {
mDown = false;
if (mStartMove < 0)
return true;
if (mDoubleTap && !mDrag) {
/* handle double tap zoom */
mMap.animator().animateZoom(300, 2,
mPrevX1 - mMap.getWidth() / 2,
mPrevY1 - mMap.getHeight() / 2);
mTracker.update(e.getX(), e.getY(), e.getTime());
} else if (mStartMove > 0) {
/* handle fling gesture */
mTracker.update(e.getX(), e.getY(), e.getTime());
float vx = mTracker.getVelocityX();
float vy = mTracker.getVelocityY();
float vx = mTracker.getVelocityX();
float vy = mTracker.getVelocityY();
/* reduce velocity for short moves */
float t = e.getTime() - mStartMove;
if (t < FLING_MIN_THREHSHOLD) {
t = t / FLING_MIN_THREHSHOLD;
vy *= t * t;
vx *= t * t;
}
doFling(vx, vy);
/* reduce velocity for short moves */
float t = e.getTime() - mStartMove;
if (t < FLING_THREHSHOLD) {
t = t / FLING_THREHSHOLD;
vy *= t * t;
vx *= t * t;
}
doFling(vx, vy);
return true;
}
if (action == MotionEvent.ACTION_CANCEL) {
//mStartMove = -1;
mDown = false;
mDoubleTap = false;
return true;
return false;
}
if (action == MotionEvent.ACTION_POINTER_DOWN) {
mStartMove = -1;
@ -200,7 +204,8 @@ public class MapEventLayer extends Layer implements InputListener, GestureListen
return true;
}
// FIXME limit scale properly
mViewport.scaleMap(1 - my / (height / 6), 0, 0);
mDrag = true;
mViewport.scaleMap(1 + my / (height / 6), 0, 0);
mMap.updateMap(true);
mStartMove = -1;
return true;
@ -302,7 +307,6 @@ public class MapEventLayer extends Layer implements InputListener, GestureListen
}
if (mCanScale || mDoRotate) {
if (!(mDoScale || mDoRotate)) {
/* enter exclusive scale mode */
if (Math.abs(deltaPinch) > (CanvasAdapter.dpi
@ -330,9 +334,7 @@ public class MapEventLayer extends Layer implements InputListener, GestureListen
float fy = (y2 + y1) / 2 - height / 2;
synchronized (mViewport) {
if (!mDoTilt) {
if (rotateBy != 0)
mViewport.rotateMap(rotateBy, fx, fy);
if (scaleBy != 1)
@ -340,10 +342,8 @@ public class MapEventLayer extends Layer implements InputListener, GestureListen
mViewport.moveMap(mx, my);
} else {
if (tiltBy != 0) {
if (tiltBy != 0 && mViewport.tiltMap(-tiltBy))
mViewport.moveMap(0, my / 2);
mViewport.tiltMap(tiltBy);
}
}
}