From 9d91e7d8caa9f5662825717a8bb5e113d1e29b1d Mon Sep 17 00:00:00 2001 From: Chuck Greb Date: Fri, 2 May 2014 14:18:47 -0400 Subject: [PATCH 1/2] Inverts behavior of double touch drag gesture Per Android guidelines, double touch drag up should decrease content scale and double touch drag down should increase content scale. This is also the behavior in the official Google Maps Android application. http://developer.android.com/design/patterns/gestures.html --- .../org/oscim/layers/MapEventLayerTest.java | 106 ++++++++++++++++++ vtm/src/org/oscim/layers/MapEventLayer.java | 2 +- 2 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 vtm-tests/test/org/oscim/layers/MapEventLayerTest.java diff --git a/vtm-tests/test/org/oscim/layers/MapEventLayerTest.java b/vtm-tests/test/org/oscim/layers/MapEventLayerTest.java new file mode 100644 index 000000000..17efb3f8e --- /dev/null +++ b/vtm-tests/test/org/oscim/layers/MapEventLayerTest.java @@ -0,0 +1,106 @@ +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.verify; +import static org.mockito.Mockito.when; + +public class MapEventLayerTest { + private MapEventLayer layer; + private Map mockMap; + private ViewController mockViewport; + private Animator mockAnimator; + private ArgumentCaptor 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 doubleTouchDragUp_shouldDecreaseContentScale() throws Exception { + 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)); + verify(mockViewport).scaleMap(argumentCaptor.capture(), any(float.class), any(float.class)); + assertThat(argumentCaptor.getValue()).isLessThan(1); + } + + @Test + public void doubleTouchDragDown_shouldIncreaseContentScale() throws Exception { + 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)); + verify(mockViewport).scaleMap(argumentCaptor.capture(), any(float.class), any(float.class)); + assertThat(argumentCaptor.getValue()).isGreaterThan(1); + } + + 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; + } + } +} diff --git a/vtm/src/org/oscim/layers/MapEventLayer.java b/vtm/src/org/oscim/layers/MapEventLayer.java index 90f56cbe7..ee93c40fa 100644 --- a/vtm/src/org/oscim/layers/MapEventLayer.java +++ b/vtm/src/org/oscim/layers/MapEventLayer.java @@ -200,7 +200,7 @@ private boolean onActionMove(MotionEvent e) { return true; } // FIXME limit scale properly - mViewport.scaleMap(1 - my / (height / 6), 0, 0); + mViewport.scaleMap(1 + my / (height / 6), 0, 0); mMap.updateMap(true); mStartMove = -1; return true; From ac94d197c7884f5621b555fa8716584ea7467a90 Mon Sep 17 00:00:00 2001 From: Chuck Greb Date: Fri, 2 May 2014 14:49:33 -0400 Subject: [PATCH 2/2] Adds double tap to zoom --- .../org/oscim/layers/MapEventLayerTest.java | 47 +++++++++++++++++-- vtm/src/org/oscim/layers/MapEventLayer.java | 8 ++++ 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/vtm-tests/test/org/oscim/layers/MapEventLayerTest.java b/vtm-tests/test/org/oscim/layers/MapEventLayerTest.java index 17efb3f8e..bb84499ea 100644 --- a/vtm-tests/test/org/oscim/layers/MapEventLayerTest.java +++ b/vtm-tests/test/org/oscim/layers/MapEventLayerTest.java @@ -12,6 +12,7 @@ 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; @@ -39,22 +40,58 @@ public void shouldNotBeNull() throws Exception { assertThat(layer).isNotNull(); } + @Test + public void doubleTap_shouldAnimateZoom() throws Exception { + simulateDoubleTap(); + verify(mockAnimator).animateZoom(300, 2, 0, 0); + } + + @Test + public void doubleTap_shouldAnimateZoomAfterDoubleTouchDrag() throws Exception { + simulateDoubleTouchDragUp(); + simulateDoubleTap(); + verify(mockAnimator).animateZoom(300, 2, 0, 0); + } + + @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 { - 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)); + 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)); - verify(mockViewport).scaleMap(argumentCaptor.capture(), any(float.class), any(float.class)); - assertThat(argumentCaptor.getValue()).isGreaterThan(1); + layer.onTouchEvent(new TestMotionEvent(MotionEvent.ACTION_UP, 1, 2)); } class TestMotionEvent extends MotionEvent { diff --git a/vtm/src/org/oscim/layers/MapEventLayer.java b/vtm/src/org/oscim/layers/MapEventLayer.java index ee93c40fa..a30c4933f 100644 --- a/vtm/src/org/oscim/layers/MapEventLayer.java +++ b/vtm/src/org/oscim/layers/MapEventLayer.java @@ -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; @@ -136,6 +137,12 @@ public boolean onTouchEvent(MotionEvent e) { } if (action == MotionEvent.ACTION_UP) { mDown = false; + if (mDoubleTap && !mDrag) { + mMap.animator().animateZoom(300, 2, 0, 0); + } + + mDrag = false; + if (mStartMove < 0) return true; @@ -200,6 +207,7 @@ private boolean onActionMove(MotionEvent e) { return true; } // FIXME limit scale properly + mDrag = true; mViewport.scaleMap(1 + my / (height / 6), 0, 0); mMap.updateMap(true); mStartMove = -1;