Improved gestures: parallel system and samples #253
This commit is contained in:
parent
71f7c45b21
commit
ba93445259
@ -3,6 +3,7 @@
|
|||||||
## New since 0.6.0
|
## New since 0.6.0
|
||||||
|
|
||||||
- Mapsforge multiple map files [#208](https://github.com/mapsforge/vtm/issues/208)
|
- Mapsforge multiple map files [#208](https://github.com/mapsforge/vtm/issues/208)
|
||||||
|
- Improved gestures implementation [#253](https://github.com/mapsforge/vtm/issues/253)
|
||||||
- Polygon label position enhancements [#80](https://github.com/mapsforge/vtm/issues/80)
|
- Polygon label position enhancements [#80](https://github.com/mapsforge/vtm/issues/80)
|
||||||
- vtm-web modules update [#51](https://github.com/mapsforge/vtm/issues/51)
|
- vtm-web modules update [#51](https://github.com/mapsforge/vtm/issues/51)
|
||||||
- Mapbox vector tiles [#57](https://github.com/mapsforge/vtm/issues/57)
|
- Mapbox vector tiles [#57](https://github.com/mapsforge/vtm/issues/57)
|
||||||
|
@ -59,6 +59,9 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".MultiMapActivity"
|
android:name=".MultiMapActivity"
|
||||||
android:configChanges="keyboardHidden|orientation|screenSize" />
|
android:configChanges="keyboardHidden|orientation|screenSize" />
|
||||||
|
<activity
|
||||||
|
android:name=".NewGesturesActivity"
|
||||||
|
android:configChanges="keyboardHidden|orientation|screenSize" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".OsmJsonMapActivity"
|
android:name=".OsmJsonMapActivity"
|
||||||
android:configChanges="keyboardHidden|orientation|screenSize" />
|
android:configChanges="keyboardHidden|orientation|screenSize" />
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 devemux86
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.oscim.android.test;
|
||||||
|
|
||||||
|
import org.oscim.map.Map;
|
||||||
|
|
||||||
|
public class NewGesturesActivity extends MarkerOverlayActivity {
|
||||||
|
|
||||||
|
public NewGesturesActivity() {
|
||||||
|
super();
|
||||||
|
Map.NEW_GESTURES = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
|
||||||
|
// Revert gestures for other activities
|
||||||
|
Map.NEW_GESTURES = false;
|
||||||
|
}
|
||||||
|
}
|
@ -53,6 +53,7 @@ public class Samples extends Activity {
|
|||||||
linearLayout.addView(createButton(VectorLayerMapActivity.class));
|
linearLayout.addView(createButton(VectorLayerMapActivity.class));
|
||||||
linearLayout.addView(createButton(MultiMapActivity.class));
|
linearLayout.addView(createButton(MultiMapActivity.class));
|
||||||
linearLayout.addView(createButton(MapFragmentActivity.class));
|
linearLayout.addView(createButton(MapFragmentActivity.class));
|
||||||
|
linearLayout.addView(createButton(NewGesturesActivity.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Button createButton(final Class<?> clazz) {
|
private Button createButton(final Class<?> clazz) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012 Hannes Janetzek
|
* Copyright 2012 Hannes Janetzek
|
||||||
|
* Copyright 2016 devemux86
|
||||||
*
|
*
|
||||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||||
*
|
*
|
||||||
@ -21,11 +22,13 @@ import android.content.Context;
|
|||||||
import android.opengl.GLSurfaceView;
|
import android.opengl.GLSurfaceView;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
|
import android.view.GestureDetector;
|
||||||
|
|
||||||
import org.oscim.android.canvas.AndroidGraphics;
|
import org.oscim.android.canvas.AndroidGraphics;
|
||||||
import org.oscim.android.gl.AndroidGL;
|
import org.oscim.android.gl.AndroidGL;
|
||||||
import org.oscim.android.gl.GlConfigChooser;
|
import org.oscim.android.gl.GlConfigChooser;
|
||||||
import org.oscim.android.input.AndroidMotionEvent;
|
import org.oscim.android.input.AndroidMotionEvent;
|
||||||
|
import org.oscim.android.input.GestureHandler;
|
||||||
import org.oscim.backend.CanvasAdapter;
|
import org.oscim.backend.CanvasAdapter;
|
||||||
import org.oscim.backend.GLAdapter;
|
import org.oscim.backend.GLAdapter;
|
||||||
import org.oscim.map.Map;
|
import org.oscim.map.Map;
|
||||||
@ -51,6 +54,7 @@ public class MapView extends GLSurfaceView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected final AndroidMap mMap;
|
protected final AndroidMap mMap;
|
||||||
|
protected GestureDetector mGestureDetector;
|
||||||
protected final AndroidMotionEvent mMotionEvent;
|
protected final AndroidMotionEvent mMotionEvent;
|
||||||
|
|
||||||
public MapView(Context context) {
|
public MapView(Context context) {
|
||||||
@ -91,6 +95,12 @@ public class MapView extends GLSurfaceView {
|
|||||||
mMap.clearMap();
|
mMap.clearMap();
|
||||||
mMap.updateMap(false);
|
mMap.updateMap(false);
|
||||||
|
|
||||||
|
if (!Map.NEW_GESTURES) {
|
||||||
|
GestureHandler gestureHandler = new GestureHandler(mMap);
|
||||||
|
mGestureDetector = new GestureDetector(context, gestureHandler);
|
||||||
|
mGestureDetector.setOnDoubleTapListener(gestureHandler);
|
||||||
|
}
|
||||||
|
|
||||||
mMotionEvent = new AndroidMotionEvent();
|
mMotionEvent = new AndroidMotionEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,6 +122,11 @@ public class MapView extends GLSurfaceView {
|
|||||||
if (!isClickable())
|
if (!isClickable())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (mGestureDetector != null) {
|
||||||
|
if (mGestureDetector.onTouchEvent(motionEvent))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
mMap.input.fire(null, mMotionEvent.wrap(motionEvent));
|
mMap.input.fire(null, mMotionEvent.wrap(motionEvent));
|
||||||
mMotionEvent.recycle();
|
mMotionEvent.recycle();
|
||||||
return true;
|
return true;
|
||||||
|
97
vtm-android/src/org/oscim/android/input/GestureHandler.java
Normal file
97
vtm-android/src/org/oscim/android/input/GestureHandler.java
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 Hannes Janetzek
|
||||||
|
* Copyright 2016 devemux86
|
||||||
|
*
|
||||||
|
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.oscim.android.input;
|
||||||
|
|
||||||
|
import android.view.GestureDetector.OnDoubleTapListener;
|
||||||
|
import android.view.GestureDetector.OnGestureListener;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
|
import org.oscim.event.Gesture;
|
||||||
|
import org.oscim.map.Map;
|
||||||
|
|
||||||
|
public class GestureHandler implements OnGestureListener, OnDoubleTapListener {
|
||||||
|
private final AndroidMotionEvent mMotionEvent;
|
||||||
|
private final Map mMap;
|
||||||
|
|
||||||
|
// Quick scale (double tap + swipe)
|
||||||
|
protected boolean quickScale;
|
||||||
|
|
||||||
|
public GestureHandler(Map map) {
|
||||||
|
mMotionEvent = new AndroidMotionEvent();
|
||||||
|
mMap = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OnGestureListener */
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onSingleTapUp(MotionEvent e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onShowPress(MotionEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLongPress(MotionEvent e) {
|
||||||
|
// Quick scale (no long press)
|
||||||
|
if (quickScale)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mMap.handleGesture(Gesture.LONG_PRESS, mMotionEvent.wrap(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onDown(MotionEvent e) {
|
||||||
|
quickScale = false;
|
||||||
|
|
||||||
|
return mMap.handleGesture(Gesture.PRESS, mMotionEvent.wrap(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OnDoubleTapListener */
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onSingleTapConfirmed(MotionEvent e) {
|
||||||
|
return mMap.handleGesture(Gesture.TAP, mMotionEvent.wrap(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onDoubleTapEvent(MotionEvent e) {
|
||||||
|
int action = e.getActionMasked();
|
||||||
|
|
||||||
|
// Quick scale
|
||||||
|
quickScale = (action == MotionEvent.ACTION_MOVE);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onDoubleTap(MotionEvent e) {
|
||||||
|
return mMap.handleGesture(Gesture.DOUBLE_TAP, mMotionEvent.wrap(e));
|
||||||
|
}
|
||||||
|
}
|
@ -85,11 +85,11 @@ public abstract class GdxMap implements ApplicationListener {
|
|||||||
mMapRenderer.onSurfaceChanged(w, h);
|
mMapRenderer.onSurfaceChanged(w, h);
|
||||||
|
|
||||||
InputMultiplexer mux = new InputMultiplexer();
|
InputMultiplexer mux = new InputMultiplexer();
|
||||||
mGestureDetector = new GestureDetector(new LayerHandler(mMap));
|
if (!Map.NEW_GESTURES) {
|
||||||
mux.addProcessor(mGestureDetector);
|
mGestureDetector = new GestureDetector(new LayerHandler(mMap));
|
||||||
|
mux.addProcessor(mGestureDetector);
|
||||||
|
}
|
||||||
mux.addProcessor(new InputHandler(this));
|
mux.addProcessor(new InputHandler(this));
|
||||||
//mux.addProcessor(new GestureDetector(20, 0.5f, 2, 0.05f,
|
|
||||||
// new MapController(mMap)));
|
|
||||||
mux.addProcessor(new MotionHandler(mMap));
|
mux.addProcessor(new MotionHandler(mMap));
|
||||||
|
|
||||||
Gdx.input.setInputProcessor(mux);
|
Gdx.input.setInputProcessor(mux);
|
||||||
|
@ -22,7 +22,6 @@ import com.badlogic.gdx.InputProcessor;
|
|||||||
|
|
||||||
import org.oscim.event.MotionEvent;
|
import org.oscim.event.MotionEvent;
|
||||||
import org.oscim.map.Map;
|
import org.oscim.map.Map;
|
||||||
import org.oscim.utils.ArrayUtils;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
28
vtm-playground/src/org/oscim/test/NewGesturesTest.java
Normal file
28
vtm-playground/src/org/oscim/test/NewGesturesTest.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 devemux86
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.oscim.test;
|
||||||
|
|
||||||
|
import org.oscim.gdx.GdxMapApp;
|
||||||
|
import org.oscim.map.Map;
|
||||||
|
|
||||||
|
public class NewGesturesTest extends MarkerLayerTest {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Map.NEW_GESTURES = true;
|
||||||
|
|
||||||
|
GdxMapApp.init();
|
||||||
|
GdxMapApp.run(new NewGesturesTest());
|
||||||
|
}
|
||||||
|
}
|
@ -18,14 +18,13 @@ import static org.mockito.Mockito.when;
|
|||||||
|
|
||||||
public class MapEventLayerTest {
|
public class MapEventLayerTest {
|
||||||
private MapEventLayer layer;
|
private MapEventLayer layer;
|
||||||
private Map mockMap;
|
|
||||||
private ViewController mockViewport;
|
private ViewController mockViewport;
|
||||||
private Animator mockAnimator;
|
private Animator mockAnimator;
|
||||||
private ArgumentCaptor<Float> argumentCaptor;
|
private ArgumentCaptor<Float> argumentCaptor;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
mockMap = Mockito.mock(Map.class);
|
Map mockMap = Mockito.mock(Map.class);
|
||||||
mockViewport = Mockito.mock(ViewController.class);
|
mockViewport = Mockito.mock(ViewController.class);
|
||||||
mockAnimator = Mockito.mock(Animator.class);
|
mockAnimator = Mockito.mock(Animator.class);
|
||||||
layer = new MapEventLayer(mockMap);
|
layer = new MapEventLayer(mockMap);
|
||||||
@ -94,12 +93,12 @@ public class MapEventLayerTest {
|
|||||||
layer.onTouchEvent(new TestMotionEvent(MotionEvent.ACTION_UP, 1, 2));
|
layer.onTouchEvent(new TestMotionEvent(MotionEvent.ACTION_UP, 1, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestMotionEvent extends MotionEvent {
|
private class TestMotionEvent extends MotionEvent {
|
||||||
final int action;
|
final int action;
|
||||||
final float x;
|
final float x;
|
||||||
final float y;
|
final float y;
|
||||||
|
|
||||||
public TestMotionEvent(int action, float x, float y) {
|
TestMotionEvent(int action, float x, float y) {
|
||||||
this.action = action;
|
this.action = action;
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
|
@ -34,7 +34,7 @@ public interface Gesture {
|
|||||||
final class TripleTap implements Gesture {
|
final class TripleTap implements Gesture {
|
||||||
}
|
}
|
||||||
|
|
||||||
class TwoFingerTap implements Gesture {
|
final class TwoFingerTap implements Gesture {
|
||||||
}
|
}
|
||||||
|
|
||||||
Gesture PRESS = new Press();
|
Gesture PRESS = new Press();
|
||||||
|
42
vtm/src/org/oscim/layers/AbstractMapEventLayer.java
Normal file
42
vtm/src/org/oscim/layers/AbstractMapEventLayer.java
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 devemux86
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.oscim.layers;
|
||||||
|
|
||||||
|
import org.oscim.map.Map;
|
||||||
|
|
||||||
|
public abstract class AbstractMapEventLayer extends Layer {
|
||||||
|
|
||||||
|
public AbstractMapEventLayer(Map map) {
|
||||||
|
super(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void enableRotation(boolean enable);
|
||||||
|
|
||||||
|
public abstract boolean rotationEnabled();
|
||||||
|
|
||||||
|
public abstract void enableTilt(boolean enable);
|
||||||
|
|
||||||
|
public abstract boolean tiltEnabled();
|
||||||
|
|
||||||
|
public abstract void enableMove(boolean enable);
|
||||||
|
|
||||||
|
public abstract boolean moveEnabled();
|
||||||
|
|
||||||
|
public abstract void enableZoom(boolean enable);
|
||||||
|
|
||||||
|
public abstract boolean zoomEnabled();
|
||||||
|
|
||||||
|
public abstract void setFixOnCenter(boolean enable);
|
||||||
|
}
|
@ -22,15 +22,11 @@ import org.oscim.core.MapPosition;
|
|||||||
import org.oscim.core.Tile;
|
import org.oscim.core.Tile;
|
||||||
import org.oscim.event.Event;
|
import org.oscim.event.Event;
|
||||||
import org.oscim.event.Gesture;
|
import org.oscim.event.Gesture;
|
||||||
|
import org.oscim.event.GestureListener;
|
||||||
import org.oscim.event.MotionEvent;
|
import org.oscim.event.MotionEvent;
|
||||||
import org.oscim.map.Map;
|
import org.oscim.map.Map;
|
||||||
import org.oscim.map.Map.InputListener;
|
import org.oscim.map.Map.InputListener;
|
||||||
import org.oscim.map.ViewController;
|
import org.oscim.map.ViewController;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.Timer;
|
|
||||||
import java.util.TimerTask;
|
|
||||||
|
|
||||||
import static org.oscim.backend.CanvasAdapter.dpi;
|
import static org.oscim.backend.CanvasAdapter.dpi;
|
||||||
import static org.oscim.utils.FastMath.withinSquaredDist;
|
import static org.oscim.utils.FastMath.withinSquaredDist;
|
||||||
@ -41,9 +37,7 @@ import static org.oscim.utils.FastMath.withinSquaredDist;
|
|||||||
* TODO rewrite using gesture primitives to build more complex gestures:
|
* TODO rewrite using gesture primitives to build more complex gestures:
|
||||||
* maybe something similar to this https://github.com/ucbvislab/Proton
|
* maybe something similar to this https://github.com/ucbvislab/Proton
|
||||||
*/
|
*/
|
||||||
public class MapEventLayer extends Layer implements InputListener {
|
public class MapEventLayer extends AbstractMapEventLayer implements InputListener, GestureListener {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(MapEventLayer.class);
|
|
||||||
|
|
||||||
private boolean mEnableRotate = true;
|
private boolean mEnableRotate = true;
|
||||||
private boolean mEnableTilt = true;
|
private boolean mEnableTilt = true;
|
||||||
@ -62,12 +56,8 @@ public class MapEventLayer extends Layer implements InputListener {
|
|||||||
private boolean mDoTilt;
|
private boolean mDoTilt;
|
||||||
|
|
||||||
private boolean mDown;
|
private boolean mDown;
|
||||||
|
private boolean mDoubleTap;
|
||||||
private boolean mDragZoom;
|
private boolean mDragZoom;
|
||||||
private boolean mTwoFingers;
|
|
||||||
private boolean mTwoFingersDone;
|
|
||||||
private int mTaps;
|
|
||||||
private long mStartDown;
|
|
||||||
private MotionEvent mLastTap;
|
|
||||||
|
|
||||||
private float mPrevX1;
|
private float mPrevX1;
|
||||||
private float mPrevY1;
|
private float mPrevY1;
|
||||||
@ -89,30 +79,18 @@ public class MapEventLayer extends Layer implements InputListener {
|
|||||||
private static final float PINCH_ROTATE_THRESHOLD = 0.2f;
|
private static final float PINCH_ROTATE_THRESHOLD = 0.2f;
|
||||||
private static final float PINCH_ROTATE_THRESHOLD2 = 0.5f;
|
private static final float PINCH_ROTATE_THRESHOLD2 = 0.5f;
|
||||||
|
|
||||||
//TODO Should be initialized with platform specific defaults
|
|
||||||
/**
|
/**
|
||||||
* 100 ms since start of move to reduce fling scroll
|
* 100 ms since start of move to reduce fling scroll
|
||||||
*/
|
*/
|
||||||
private static final long FLING_MIN_THRESHOLD = 100;
|
private static final float FLING_MIN_THREHSHOLD = 100;
|
||||||
private static final long DOUBLE_TAP_THRESHOLD = 300;
|
|
||||||
private static final long LONG_PRESS_THRESHOLD = 500;
|
|
||||||
|
|
||||||
private final VelocityTracker mTracker;
|
private final VelocityTracker mTracker;
|
||||||
private final Timer mTimer;
|
|
||||||
private TimerTask mTimerTask;
|
|
||||||
|
|
||||||
private final MapPosition mapPosition = new MapPosition();
|
private final MapPosition mapPosition = new MapPosition();
|
||||||
|
|
||||||
public MapEventLayer(Map map) {
|
public MapEventLayer(Map map) {
|
||||||
super(map);
|
super(map);
|
||||||
mTracker = new VelocityTracker();
|
mTracker = new VelocityTracker();
|
||||||
mTimer = new Timer();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDetach() {
|
|
||||||
mTimer.cancel();
|
|
||||||
mTimer.purge();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -120,34 +98,42 @@ public class MapEventLayer extends Layer implements InputListener {
|
|||||||
onTouchEvent(motionEvent);
|
onTouchEvent(motionEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void enableRotation(boolean enable) {
|
public void enableRotation(boolean enable) {
|
||||||
mEnableRotate = enable;
|
mEnableRotate = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean rotationEnabled() {
|
public boolean rotationEnabled() {
|
||||||
return mEnableRotate;
|
return mEnableRotate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void enableTilt(boolean enable) {
|
public void enableTilt(boolean enable) {
|
||||||
mEnableTilt = enable;
|
mEnableTilt = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean tiltEnabled() {
|
public boolean tiltEnabled() {
|
||||||
return mEnableTilt;
|
return mEnableTilt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void enableMove(boolean enable) {
|
public void enableMove(boolean enable) {
|
||||||
mEnableMove = enable;
|
mEnableMove = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean moveEnabled() {
|
public boolean moveEnabled() {
|
||||||
return mEnableMove;
|
return mEnableMove;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void enableZoom(boolean enable) {
|
public void enableZoom(boolean enable) {
|
||||||
mEnableScale = enable;
|
mEnableScale = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean zoomEnabled() {
|
public boolean zoomEnabled() {
|
||||||
return mEnableScale;
|
return mEnableScale;
|
||||||
}
|
}
|
||||||
@ -155,62 +141,29 @@ public class MapEventLayer extends Layer implements InputListener {
|
|||||||
/**
|
/**
|
||||||
* When enabled zoom- and rotation-gestures will not move the viewport.
|
* When enabled zoom- and rotation-gestures will not move the viewport.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void setFixOnCenter(boolean enable) {
|
public void setFixOnCenter(boolean enable) {
|
||||||
mFixOnCenter = enable;
|
mFixOnCenter = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean onTouchEvent(final MotionEvent e) {
|
boolean onTouchEvent(MotionEvent e) {
|
||||||
|
|
||||||
int action = getAction(e);
|
int action = getAction(e);
|
||||||
final long time = e.getTime();
|
|
||||||
|
|
||||||
if (action == MotionEvent.ACTION_DOWN) {
|
if (action == MotionEvent.ACTION_DOWN) {
|
||||||
if (mTimerTask != null) {
|
mMap.animator().cancel();
|
||||||
mTimerTask.cancel();
|
|
||||||
mTimer.purge();
|
|
||||||
mTimerTask = null;
|
|
||||||
}
|
|
||||||
mMap.handleGesture(Gesture.PRESS, e);
|
|
||||||
mDown = true;
|
|
||||||
mStartDown = time;
|
|
||||||
if (mTaps > 0) {
|
|
||||||
float mx = e.getX(0) - mLastTap.getX();
|
|
||||||
float my = e.getY(0) - mLastTap.getY();
|
|
||||||
if (isMinimalMove(mx, my)) {
|
|
||||||
mTaps = 0;
|
|
||||||
log.debug("tap {} {}", mLastTap.getX(), mLastTap.getY());
|
|
||||||
mMap.handleGesture(Gesture.TAP, mLastTap);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mMap.animator().cancel();
|
|
||||||
|
|
||||||
mStartMove = -1;
|
mStartMove = -1;
|
||||||
mDragZoom = false;
|
mDoubleTap = false;
|
||||||
mTwoFingers = false;
|
mDragZoom = false;
|
||||||
mTwoFingersDone = false;
|
|
||||||
|
|
||||||
mTimerTask = new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (mTwoFingers || mStartMove != -1)
|
|
||||||
return;
|
|
||||||
mMap.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
log.debug("long press {} {}", e.getX(), e.getY());
|
|
||||||
mMap.handleGesture(Gesture.LONG_PRESS, e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
mTimer.schedule(mTimerTask, LONG_PRESS_THRESHOLD);
|
|
||||||
}
|
|
||||||
|
|
||||||
mPrevX1 = e.getX(0);
|
mPrevX1 = e.getX(0);
|
||||||
mPrevY1 = e.getY(0);
|
mPrevY1 = e.getY(0);
|
||||||
|
|
||||||
|
mDown = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!mDown) {
|
if (!(mDown || mDoubleTap)) {
|
||||||
/* no down event received */
|
/* no down event received */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -221,12 +174,17 @@ public class MapEventLayer extends Layer implements InputListener {
|
|||||||
}
|
}
|
||||||
if (action == MotionEvent.ACTION_UP) {
|
if (action == MotionEvent.ACTION_UP) {
|
||||||
mDown = false;
|
mDown = false;
|
||||||
if (mTimerTask != null) {
|
if (mDoubleTap && !mDragZoom) {
|
||||||
mTimerTask.cancel();
|
float pivotX = 0, pivotY = 0;
|
||||||
mTimer.purge();
|
if (!mFixOnCenter) {
|
||||||
mTimerTask = null;
|
pivotX = mPrevX1 - mMap.getWidth() / 2;
|
||||||
}
|
pivotY = mPrevY1 - mMap.getHeight() / 2;
|
||||||
if (mStartMove > 0) {
|
}
|
||||||
|
|
||||||
|
/* handle double tap zoom */
|
||||||
|
mMap.animator().animateZoom(300, 2, pivotX, pivotY);
|
||||||
|
|
||||||
|
} else if (mStartMove > 0) {
|
||||||
/* handle fling gesture */
|
/* handle fling gesture */
|
||||||
mTracker.update(e.getX(), e.getY(), e.getTime());
|
mTracker.update(e.getX(), e.getY(), e.getTime());
|
||||||
float vx = mTracker.getVelocityX();
|
float vx = mTracker.getVelocityX();
|
||||||
@ -234,86 +192,16 @@ public class MapEventLayer extends Layer implements InputListener {
|
|||||||
|
|
||||||
/* reduce velocity for short moves */
|
/* reduce velocity for short moves */
|
||||||
float t = e.getTime() - mStartMove;
|
float t = e.getTime() - mStartMove;
|
||||||
if (t < FLING_MIN_THRESHOLD) {
|
if (t < FLING_MIN_THREHSHOLD) {
|
||||||
t = t / FLING_MIN_THRESHOLD;
|
t = t / FLING_MIN_THREHSHOLD;
|
||||||
vy *= t * t;
|
vy *= t * t;
|
||||||
vx *= t * t;
|
vx *= t * t;
|
||||||
}
|
}
|
||||||
doFling(vx, vy);
|
doFling(vx, vy);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (time - mStartDown > LONG_PRESS_THRESHOLD) {
|
|
||||||
log.debug(" not a tap");
|
|
||||||
// this was not a tap
|
|
||||||
mTaps = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mTaps > 0) {
|
|
||||||
if ((time - mLastTap.getTime()) >= DOUBLE_TAP_THRESHOLD) {
|
|
||||||
mTaps = 1;
|
|
||||||
log.debug("tap {} {}", mLastTap.getX(), mLastTap.getY());
|
|
||||||
mMap.handleGesture(Gesture.TAP, mLastTap);
|
|
||||||
} else {
|
|
||||||
mTaps += 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mTaps = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mLastTap != null) {
|
|
||||||
mLastTap.recycle();
|
|
||||||
}
|
|
||||||
mLastTap = e.copy();
|
|
||||||
|
|
||||||
if (mTaps == 3) {
|
|
||||||
mTaps = 0;
|
|
||||||
log.debug("triple tap {} {}", e.getX(), e.getY());
|
|
||||||
mMap.handleGesture(Gesture.TRIPLE_TAP, e);
|
|
||||||
} else if (mTaps == 2) {
|
|
||||||
mTimerTask = new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
mTaps = 0;
|
|
||||||
if (mDragZoom)
|
|
||||||
return;
|
|
||||||
mMap.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
log.debug("double tap {} {}", e.getX(), e.getY());
|
|
||||||
if (!mMap.handleGesture(Gesture.DOUBLE_TAP, e)) {
|
|
||||||
/* handle double tap zoom */
|
|
||||||
final float pivotX = mFixOnCenter ? 0 : mPrevX1 - mMap.getWidth() / 2;
|
|
||||||
final float pivotY = mFixOnCenter ? 0 : mPrevY1 - mMap.getHeight() / 2;
|
|
||||||
mMap.animator().animateZoom(300, 2, pivotX, pivotY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
mTimer.schedule(mTimerTask, DOUBLE_TAP_THRESHOLD);
|
|
||||||
} else {
|
|
||||||
mTimerTask = new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
mTaps = 0;
|
|
||||||
if (!mTwoFingers && mStartMove == -1) {
|
|
||||||
mMap.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
log.debug("tap {} {}", e.getX(), e.getY());
|
|
||||||
mMap.handleGesture(Gesture.TAP, e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
mTimer.schedule(mTimerTask, DOUBLE_TAP_THRESHOLD);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (action == MotionEvent.ACTION_CANCEL) {
|
if (action == MotionEvent.ACTION_CANCEL) {
|
||||||
mTaps = 0;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (action == MotionEvent.ACTION_POINTER_DOWN) {
|
if (action == MotionEvent.ACTION_POINTER_DOWN) {
|
||||||
@ -322,12 +210,6 @@ public class MapEventLayer extends Layer implements InputListener {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (action == MotionEvent.ACTION_POINTER_UP) {
|
if (action == MotionEvent.ACTION_POINTER_UP) {
|
||||||
if (e.getPointerCount() == 2 && !mTwoFingersDone) {
|
|
||||||
log.debug("two finger tap");
|
|
||||||
if (!mMap.handleGesture(Gesture.TWO_FINGER_TAP, e)) {
|
|
||||||
mMap.animator().animateZoom(300, 0.5, 0f, 0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateMulti(e);
|
updateMulti(e);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -355,7 +237,12 @@ public class MapEventLayer extends Layer implements InputListener {
|
|||||||
mPrevY1 = y1;
|
mPrevY1 = y1;
|
||||||
|
|
||||||
/* double-tap drag zoom */
|
/* double-tap drag zoom */
|
||||||
if (mTaps == 1) {
|
if (mDoubleTap) {
|
||||||
|
/* just ignore first move event to set mPrevX/Y */
|
||||||
|
if (!mDown) {
|
||||||
|
mDown = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!mDragZoom && !isMinimalMove(mx, my)) {
|
if (!mDragZoom && !isMinimalMove(mx, my)) {
|
||||||
mPrevX1 -= mx;
|
mPrevX1 -= mx;
|
||||||
mPrevY1 -= my;
|
mPrevY1 -= my;
|
||||||
@ -418,7 +305,6 @@ public class MapEventLayer extends Layer implements InputListener {
|
|||||||
mCanScale = false;
|
mCanScale = false;
|
||||||
mCanRotate = false;
|
mCanRotate = false;
|
||||||
mDoTilt = true;
|
mDoTilt = true;
|
||||||
mTwoFingersDone = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -445,7 +331,6 @@ public class MapEventLayer extends Layer implements InputListener {
|
|||||||
/* start rotate, disable tilt */
|
/* start rotate, disable tilt */
|
||||||
mDoRotate = true;
|
mDoRotate = true;
|
||||||
mCanTilt = false;
|
mCanTilt = false;
|
||||||
mTwoFingersDone = true;
|
|
||||||
|
|
||||||
mAngle = rad;
|
mAngle = rad;
|
||||||
} else if (!mDoScale) {
|
} else if (!mDoScale) {
|
||||||
@ -465,7 +350,6 @@ public class MapEventLayer extends Layer implements InputListener {
|
|||||||
mDoRotate = true;
|
mDoRotate = true;
|
||||||
mCanRotate = true;
|
mCanRotate = true;
|
||||||
mAngle = rad;
|
mAngle = rad;
|
||||||
mTwoFingersDone = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,7 +365,6 @@ public class MapEventLayer extends Layer implements InputListener {
|
|||||||
|
|
||||||
mCanTilt = false;
|
mCanTilt = false;
|
||||||
mDoScale = true;
|
mDoScale = true;
|
||||||
mTwoFingersDone = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mDoScale || mDoRotate) {
|
if (mDoScale || mDoRotate) {
|
||||||
@ -530,8 +413,6 @@ public class MapEventLayer extends Layer implements InputListener {
|
|||||||
mPrevY1 = e.getY(0);
|
mPrevY1 = e.getY(0);
|
||||||
|
|
||||||
if (cnt == 2) {
|
if (cnt == 2) {
|
||||||
mTwoFingers = true;
|
|
||||||
|
|
||||||
mDoScale = false;
|
mDoScale = false;
|
||||||
mDoRotate = false;
|
mDoRotate = false;
|
||||||
mDoTilt = false;
|
mDoTilt = false;
|
||||||
@ -564,6 +445,15 @@ public class MapEventLayer extends Layer implements InputListener {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onGesture(Gesture g, MotionEvent e) {
|
||||||
|
if (g == Gesture.DOUBLE_TAP) {
|
||||||
|
mDoubleTap = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private static class VelocityTracker {
|
private static class VelocityTracker {
|
||||||
/* sample window, 200ms */
|
/* sample window, 200ms */
|
||||||
private static final int MAX_MS = 200;
|
private static final int MAX_MS = 200;
|
||||||
|
643
vtm/src/org/oscim/layers/MapEventLayer2.java
Normal file
643
vtm/src/org/oscim/layers/MapEventLayer2.java
Normal file
@ -0,0 +1,643 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 Hannes Janetzek
|
||||||
|
* Copyright 2016 devemux86
|
||||||
|
* Copyright 2016 Andrey Novikov
|
||||||
|
*
|
||||||
|
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.oscim.layers;
|
||||||
|
|
||||||
|
import org.oscim.core.MapPosition;
|
||||||
|
import org.oscim.core.Tile;
|
||||||
|
import org.oscim.event.Event;
|
||||||
|
import org.oscim.event.Gesture;
|
||||||
|
import org.oscim.event.MotionEvent;
|
||||||
|
import org.oscim.map.Map;
|
||||||
|
import org.oscim.map.Map.InputListener;
|
||||||
|
import org.oscim.map.ViewController;
|
||||||
|
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
|
import static org.oscim.backend.CanvasAdapter.dpi;
|
||||||
|
import static org.oscim.utils.FastMath.withinSquaredDist;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes Viewport by handling move, fling, scale, rotation and tilt gestures.
|
||||||
|
* <p/>
|
||||||
|
* TODO rewrite using gesture primitives to build more complex gestures:
|
||||||
|
* maybe something similar to this https://github.com/ucbvislab/Proton
|
||||||
|
*/
|
||||||
|
public class MapEventLayer2 extends AbstractMapEventLayer implements InputListener {
|
||||||
|
|
||||||
|
private boolean mEnableRotate = true;
|
||||||
|
private boolean mEnableTilt = true;
|
||||||
|
private boolean mEnableMove = true;
|
||||||
|
private boolean mEnableScale = true;
|
||||||
|
private boolean mFixOnCenter = false;
|
||||||
|
|
||||||
|
/* possible state transitions */
|
||||||
|
private boolean mCanScale;
|
||||||
|
private boolean mCanRotate;
|
||||||
|
private boolean mCanTilt;
|
||||||
|
|
||||||
|
/* current gesture state */
|
||||||
|
private boolean mDoRotate;
|
||||||
|
private boolean mDoScale;
|
||||||
|
private boolean mDoTilt;
|
||||||
|
|
||||||
|
private boolean mDown;
|
||||||
|
private boolean mDragZoom;
|
||||||
|
private boolean mTwoFingers;
|
||||||
|
private boolean mTwoFingersDone;
|
||||||
|
private int mTaps;
|
||||||
|
private long mStartDown;
|
||||||
|
private MotionEvent mLastTap;
|
||||||
|
|
||||||
|
private float mPrevX1;
|
||||||
|
private float mPrevY1;
|
||||||
|
private float mPrevX2;
|
||||||
|
private float mPrevY2;
|
||||||
|
|
||||||
|
private double mAngle;
|
||||||
|
private double mPrevPinchWidth;
|
||||||
|
private long mStartMove;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2mm as minimal distance to start move: dpi / 25.4
|
||||||
|
*/
|
||||||
|
private static final float MIN_SLOP = 25.4f / 2;
|
||||||
|
|
||||||
|
private static final float PINCH_ZOOM_THRESHOLD = MIN_SLOP / 2;
|
||||||
|
private static final float PINCH_TILT_THRESHOLD = MIN_SLOP / 2;
|
||||||
|
private static final float PINCH_TILT_SLOPE = 0.75f;
|
||||||
|
private static final float PINCH_ROTATE_THRESHOLD = 0.2f;
|
||||||
|
private static final float PINCH_ROTATE_THRESHOLD2 = 0.5f;
|
||||||
|
|
||||||
|
//TODO Should be initialized with platform specific defaults
|
||||||
|
/**
|
||||||
|
* 100 ms since start of move to reduce fling scroll
|
||||||
|
*/
|
||||||
|
private static final long FLING_MIN_THRESHOLD = 100;
|
||||||
|
private static final long DOUBLE_TAP_THRESHOLD = 300;
|
||||||
|
private static final long LONG_PRESS_THRESHOLD = 500;
|
||||||
|
|
||||||
|
private final VelocityTracker mTracker;
|
||||||
|
private final Timer mTimer;
|
||||||
|
private TimerTask mTimerTask;
|
||||||
|
|
||||||
|
private final MapPosition mapPosition = new MapPosition();
|
||||||
|
|
||||||
|
public MapEventLayer2(Map map) {
|
||||||
|
super(map);
|
||||||
|
mTracker = new VelocityTracker();
|
||||||
|
mTimer = new Timer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDetach() {
|
||||||
|
mTimer.cancel();
|
||||||
|
mTimer.purge();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInputEvent(Event e, MotionEvent motionEvent) {
|
||||||
|
onTouchEvent(motionEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enableRotation(boolean enable) {
|
||||||
|
mEnableRotate = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean rotationEnabled() {
|
||||||
|
return mEnableRotate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enableTilt(boolean enable) {
|
||||||
|
mEnableTilt = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tiltEnabled() {
|
||||||
|
return mEnableTilt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enableMove(boolean enable) {
|
||||||
|
mEnableMove = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean moveEnabled() {
|
||||||
|
return mEnableMove;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enableZoom(boolean enable) {
|
||||||
|
mEnableScale = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean zoomEnabled() {
|
||||||
|
return mEnableScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When enabled zoom- and rotation-gestures will not move the viewport.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setFixOnCenter(boolean enable) {
|
||||||
|
mFixOnCenter = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean onTouchEvent(final MotionEvent e) {
|
||||||
|
int action = getAction(e);
|
||||||
|
final long time = e.getTime();
|
||||||
|
|
||||||
|
if (action == MotionEvent.ACTION_DOWN) {
|
||||||
|
if (mTimerTask != null) {
|
||||||
|
mTimerTask.cancel();
|
||||||
|
mTimer.purge();
|
||||||
|
mTimerTask = null;
|
||||||
|
}
|
||||||
|
mMap.handleGesture(Gesture.PRESS, e);
|
||||||
|
mDown = true;
|
||||||
|
mStartDown = time;
|
||||||
|
if (mTaps > 0) {
|
||||||
|
float mx = e.getX(0) - mLastTap.getX();
|
||||||
|
float my = e.getY(0) - mLastTap.getY();
|
||||||
|
if (isMinimalMove(mx, my)) {
|
||||||
|
mTaps = 0;
|
||||||
|
//log.debug("tap {} {}", mLastTap.getX(), mLastTap.getY());
|
||||||
|
mMap.handleGesture(Gesture.TAP, mLastTap);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mMap.animator().cancel();
|
||||||
|
|
||||||
|
mStartMove = -1;
|
||||||
|
mDragZoom = false;
|
||||||
|
mTwoFingers = false;
|
||||||
|
mTwoFingersDone = false;
|
||||||
|
|
||||||
|
mTimerTask = new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (mTwoFingers || mStartMove != -1)
|
||||||
|
return;
|
||||||
|
mMap.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
//log.debug("long press {} {}", e.getX(), e.getY());
|
||||||
|
mMap.handleGesture(Gesture.LONG_PRESS, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mTimer.schedule(mTimerTask, LONG_PRESS_THRESHOLD);
|
||||||
|
}
|
||||||
|
|
||||||
|
mPrevX1 = e.getX(0);
|
||||||
|
mPrevY1 = e.getY(0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!mDown) {
|
||||||
|
/* no down event received */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == MotionEvent.ACTION_MOVE) {
|
||||||
|
onActionMove(e);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (action == MotionEvent.ACTION_UP) {
|
||||||
|
mDown = false;
|
||||||
|
if (mTimerTask != null) {
|
||||||
|
mTimerTask.cancel();
|
||||||
|
mTimer.purge();
|
||||||
|
mTimerTask = null;
|
||||||
|
}
|
||||||
|
if (mStartMove > 0) {
|
||||||
|
/* handle fling gesture */
|
||||||
|
mTracker.update(e.getX(), e.getY(), e.getTime());
|
||||||
|
float vx = mTracker.getVelocityX();
|
||||||
|
float vy = mTracker.getVelocityY();
|
||||||
|
|
||||||
|
/* reduce velocity for short moves */
|
||||||
|
float t = e.getTime() - mStartMove;
|
||||||
|
if (t < FLING_MIN_THRESHOLD) {
|
||||||
|
t = t / FLING_MIN_THRESHOLD;
|
||||||
|
vy *= t * t;
|
||||||
|
vx *= t * t;
|
||||||
|
}
|
||||||
|
doFling(vx, vy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time - mStartDown > LONG_PRESS_THRESHOLD) {
|
||||||
|
//log.debug(" not a tap");
|
||||||
|
// this was not a tap
|
||||||
|
mTaps = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mTaps > 0) {
|
||||||
|
if ((time - mLastTap.getTime()) >= DOUBLE_TAP_THRESHOLD) {
|
||||||
|
mTaps = 1;
|
||||||
|
//log.debug("tap {} {}", mLastTap.getX(), mLastTap.getY());
|
||||||
|
mMap.handleGesture(Gesture.TAP, mLastTap);
|
||||||
|
} else {
|
||||||
|
mTaps += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mTaps = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mLastTap != null) {
|
||||||
|
mLastTap.recycle();
|
||||||
|
}
|
||||||
|
mLastTap = e.copy();
|
||||||
|
|
||||||
|
if (mTaps == 3) {
|
||||||
|
mTaps = 0;
|
||||||
|
//log.debug("triple tap {} {}", e.getX(), e.getY());
|
||||||
|
mMap.handleGesture(Gesture.TRIPLE_TAP, e);
|
||||||
|
} else if (mTaps == 2) {
|
||||||
|
mTimerTask = new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
mTaps = 0;
|
||||||
|
if (mDragZoom)
|
||||||
|
return;
|
||||||
|
mMap.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
//log.debug("double tap {} {}", e.getX(), e.getY());
|
||||||
|
if (!mMap.handleGesture(Gesture.DOUBLE_TAP, e)) {
|
||||||
|
/* handle double tap zoom */
|
||||||
|
final float pivotX = mFixOnCenter ? 0 : mPrevX1 - mMap.getWidth() / 2;
|
||||||
|
final float pivotY = mFixOnCenter ? 0 : mPrevY1 - mMap.getHeight() / 2;
|
||||||
|
mMap.animator().animateZoom(300, 2, pivotX, pivotY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mTimer.schedule(mTimerTask, DOUBLE_TAP_THRESHOLD);
|
||||||
|
} else {
|
||||||
|
mTimerTask = new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
mTaps = 0;
|
||||||
|
if (!mTwoFingers && mStartMove == -1) {
|
||||||
|
mMap.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
//log.debug("tap {} {}", e.getX(), e.getY());
|
||||||
|
mMap.handleGesture(Gesture.TAP, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mTimer.schedule(mTimerTask, DOUBLE_TAP_THRESHOLD);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (action == MotionEvent.ACTION_CANCEL) {
|
||||||
|
mTaps = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (action == MotionEvent.ACTION_POINTER_DOWN) {
|
||||||
|
mStartMove = -1;
|
||||||
|
updateMulti(e);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (action == MotionEvent.ACTION_POINTER_UP) {
|
||||||
|
if (e.getPointerCount() == 2 && !mTwoFingersDone) {
|
||||||
|
//log.debug("two finger tap");
|
||||||
|
if (!mMap.handleGesture(Gesture.TWO_FINGER_TAP, e)) {
|
||||||
|
mMap.animator().animateZoom(300, 0.5, 0f, 0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateMulti(e);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getAction(MotionEvent e) {
|
||||||
|
return e.getAction() & MotionEvent.ACTION_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onActionMove(MotionEvent e) {
|
||||||
|
ViewController mViewport = mMap.viewport();
|
||||||
|
float x1 = e.getX(0);
|
||||||
|
float y1 = e.getY(0);
|
||||||
|
|
||||||
|
float mx = x1 - mPrevX1;
|
||||||
|
float my = y1 - mPrevY1;
|
||||||
|
|
||||||
|
float width = mMap.getWidth();
|
||||||
|
float height = mMap.getHeight();
|
||||||
|
|
||||||
|
if (e.getPointerCount() < 2) {
|
||||||
|
mPrevX1 = x1;
|
||||||
|
mPrevY1 = y1;
|
||||||
|
|
||||||
|
/* double-tap drag zoom */
|
||||||
|
if (mTaps == 1) {
|
||||||
|
if (!mDragZoom && !isMinimalMove(mx, my)) {
|
||||||
|
mPrevX1 -= mx;
|
||||||
|
mPrevY1 -= my;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO limit scale properly
|
||||||
|
mDragZoom = true;
|
||||||
|
mViewport.scaleMap(1 + my / (height / 6), 0, 0);
|
||||||
|
mMap.updateMap(true);
|
||||||
|
mStartMove = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* simple move */
|
||||||
|
if (!mEnableMove)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mStartMove < 0) {
|
||||||
|
if (!isMinimalMove(mx, my)) {
|
||||||
|
mPrevX1 -= mx;
|
||||||
|
mPrevY1 -= my;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mStartMove = e.getTime();
|
||||||
|
mTracker.start(x1, y1, mStartMove);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mViewport.moveMap(mx, my);
|
||||||
|
mTracker.update(x1, y1, e.getTime());
|
||||||
|
mMap.updateMap(true);
|
||||||
|
if (mMap.viewport().getMapPosition(mapPosition))
|
||||||
|
mMap.events.fire(Map.MOVE_EVENT, mapPosition);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mStartMove = -1;
|
||||||
|
|
||||||
|
float x2 = e.getX(1);
|
||||||
|
float y2 = e.getY(1);
|
||||||
|
float dx = (x1 - x2);
|
||||||
|
float dy = (y1 - y2);
|
||||||
|
|
||||||
|
double rotateBy = 0;
|
||||||
|
float scaleBy = 1;
|
||||||
|
float tiltBy = 0;
|
||||||
|
|
||||||
|
mx = ((x1 + x2) - (mPrevX1 + mPrevX2)) / 2;
|
||||||
|
my = ((y1 + y2) - (mPrevY1 + mPrevY2)) / 2;
|
||||||
|
|
||||||
|
if (mCanTilt) {
|
||||||
|
float slope = (dx == 0) ? 0 : dy / dx;
|
||||||
|
|
||||||
|
if (Math.abs(slope) < PINCH_TILT_SLOPE) {
|
||||||
|
|
||||||
|
if (mDoTilt) {
|
||||||
|
tiltBy = my / 5;
|
||||||
|
} else if (Math.abs(my) > (dpi / PINCH_TILT_THRESHOLD)) {
|
||||||
|
/* enter exclusive tilt mode */
|
||||||
|
mCanScale = false;
|
||||||
|
mCanRotate = false;
|
||||||
|
mDoTilt = true;
|
||||||
|
mTwoFingersDone = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double pinchWidth = Math.sqrt(dx * dx + dy * dy);
|
||||||
|
double deltaPinch = pinchWidth - mPrevPinchWidth;
|
||||||
|
|
||||||
|
if (mCanRotate) {
|
||||||
|
double rad = Math.atan2(dy, dx);
|
||||||
|
double r = rad - mAngle;
|
||||||
|
|
||||||
|
if (mDoRotate) {
|
||||||
|
double da = rad - mAngle;
|
||||||
|
|
||||||
|
if (Math.abs(da) > 0.0001) {
|
||||||
|
rotateBy = da;
|
||||||
|
mAngle = rad;
|
||||||
|
|
||||||
|
deltaPinch = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
r = Math.abs(r);
|
||||||
|
if (r > PINCH_ROTATE_THRESHOLD) {
|
||||||
|
/* start rotate, disable tilt */
|
||||||
|
mDoRotate = true;
|
||||||
|
mCanTilt = false;
|
||||||
|
mTwoFingersDone = true;
|
||||||
|
|
||||||
|
mAngle = rad;
|
||||||
|
} else if (!mDoScale) {
|
||||||
|
/* reduce pinch trigger by the amount of rotation */
|
||||||
|
deltaPinch *= 1 - (r / PINCH_ROTATE_THRESHOLD);
|
||||||
|
} else {
|
||||||
|
mPrevPinchWidth = pinchWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (mDoScale && mEnableRotate) {
|
||||||
|
/* re-enable rotation when higher threshold is reached */
|
||||||
|
double rad = Math.atan2(dy, dx);
|
||||||
|
double r = rad - mAngle;
|
||||||
|
|
||||||
|
if (r > PINCH_ROTATE_THRESHOLD2) {
|
||||||
|
/* start rotate again */
|
||||||
|
mDoRotate = true;
|
||||||
|
mCanRotate = true;
|
||||||
|
mAngle = rad;
|
||||||
|
mTwoFingersDone = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mCanScale || mDoRotate) {
|
||||||
|
if (!(mDoScale || mDoRotate)) {
|
||||||
|
/* enter exclusive scale mode */
|
||||||
|
if (Math.abs(deltaPinch) > (dpi / PINCH_ZOOM_THRESHOLD)) {
|
||||||
|
|
||||||
|
if (!mDoRotate) {
|
||||||
|
mPrevPinchWidth = pinchWidth;
|
||||||
|
mCanRotate = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCanTilt = false;
|
||||||
|
mDoScale = true;
|
||||||
|
mTwoFingersDone = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mDoScale || mDoRotate) {
|
||||||
|
scaleBy = (float) (pinchWidth / mPrevPinchWidth);
|
||||||
|
mPrevPinchWidth = pinchWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(mDoRotate || mDoScale || mDoTilt))
|
||||||
|
return;
|
||||||
|
|
||||||
|
float pivotX = 0, pivotY = 0;
|
||||||
|
|
||||||
|
if (!mFixOnCenter) {
|
||||||
|
pivotX = (x2 + x1) / 2 - width / 2;
|
||||||
|
pivotY = (y2 + y1) / 2 - height / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (mViewport) {
|
||||||
|
if (!mDoTilt) {
|
||||||
|
if (rotateBy != 0)
|
||||||
|
mViewport.rotateMap(rotateBy, pivotX, pivotY);
|
||||||
|
if (scaleBy != 1)
|
||||||
|
mViewport.scaleMap(scaleBy, pivotX, pivotY);
|
||||||
|
|
||||||
|
if (!mFixOnCenter)
|
||||||
|
mViewport.moveMap(mx, my);
|
||||||
|
} else {
|
||||||
|
if (tiltBy != 0 && mViewport.tiltMap(-tiltBy))
|
||||||
|
mViewport.moveMap(0, my / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mPrevX1 = x1;
|
||||||
|
mPrevY1 = y1;
|
||||||
|
mPrevX2 = x2;
|
||||||
|
mPrevY2 = y2;
|
||||||
|
|
||||||
|
mMap.updateMap(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateMulti(MotionEvent e) {
|
||||||
|
int cnt = e.getPointerCount();
|
||||||
|
|
||||||
|
mPrevX1 = e.getX(0);
|
||||||
|
mPrevY1 = e.getY(0);
|
||||||
|
|
||||||
|
if (cnt == 2) {
|
||||||
|
mTwoFingers = true;
|
||||||
|
|
||||||
|
mDoScale = false;
|
||||||
|
mDoRotate = false;
|
||||||
|
mDoTilt = false;
|
||||||
|
mCanScale = mEnableScale;
|
||||||
|
mCanRotate = mEnableRotate;
|
||||||
|
mCanTilt = mEnableTilt;
|
||||||
|
|
||||||
|
mPrevX2 = e.getX(1);
|
||||||
|
mPrevY2 = e.getY(1);
|
||||||
|
double dx = mPrevX1 - mPrevX2;
|
||||||
|
double dy = mPrevY1 - mPrevY2;
|
||||||
|
|
||||||
|
mAngle = Math.atan2(dy, dx);
|
||||||
|
mPrevPinchWidth = Math.sqrt(dx * dx + dy * dy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isMinimalMove(float mx, float my) {
|
||||||
|
float minSlop = (dpi / MIN_SLOP);
|
||||||
|
return !withinSquaredDist(mx, my, minSlop * minSlop);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean doFling(float velocityX, float velocityY) {
|
||||||
|
|
||||||
|
int w = Tile.SIZE * 5;
|
||||||
|
int h = Tile.SIZE * 5;
|
||||||
|
|
||||||
|
mMap.animator().animateFling(velocityX * 2, velocityY * 2,
|
||||||
|
-w, w, -h, h);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class VelocityTracker {
|
||||||
|
/* sample window, 200ms */
|
||||||
|
private static final int MAX_MS = 200;
|
||||||
|
private static final int SAMPLES = 32;
|
||||||
|
|
||||||
|
private float mLastX, mLastY;
|
||||||
|
private long mLastTime;
|
||||||
|
private int mNumSamples;
|
||||||
|
private int mIndex;
|
||||||
|
|
||||||
|
private float[] mMeanX = new float[SAMPLES];
|
||||||
|
private float[] mMeanY = new float[SAMPLES];
|
||||||
|
private int[] mMeanTime = new int[SAMPLES];
|
||||||
|
|
||||||
|
public void start(float x, float y, long time) {
|
||||||
|
mLastX = x;
|
||||||
|
mLastY = y;
|
||||||
|
mNumSamples = 0;
|
||||||
|
mIndex = SAMPLES;
|
||||||
|
mLastTime = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(float x, float y, long time) {
|
||||||
|
if (time == mLastTime)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (--mIndex < 0)
|
||||||
|
mIndex = SAMPLES - 1;
|
||||||
|
|
||||||
|
mMeanX[mIndex] = x - mLastX;
|
||||||
|
mMeanY[mIndex] = y - mLastY;
|
||||||
|
mMeanTime[mIndex] = (int) (time - mLastTime);
|
||||||
|
|
||||||
|
mLastTime = time;
|
||||||
|
mLastX = x;
|
||||||
|
mLastY = y;
|
||||||
|
|
||||||
|
mNumSamples++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getVelocity(float[] move) {
|
||||||
|
mNumSamples = Math.min(SAMPLES, mNumSamples);
|
||||||
|
|
||||||
|
double duration = 0;
|
||||||
|
double amount = 0;
|
||||||
|
|
||||||
|
for (int c = 0; c < mNumSamples; c++) {
|
||||||
|
int index = (mIndex + c) % SAMPLES;
|
||||||
|
|
||||||
|
float d = mMeanTime[index];
|
||||||
|
if (c > 0 && duration + d > MAX_MS)
|
||||||
|
break;
|
||||||
|
|
||||||
|
duration += d;
|
||||||
|
amount += move[index] * (d / duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (duration == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (float) ((amount * 1000) / duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
float getVelocityY() {
|
||||||
|
return getVelocity(mMeanY);
|
||||||
|
}
|
||||||
|
|
||||||
|
float getVelocityX() {
|
||||||
|
return getVelocity(mMeanX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -27,8 +27,10 @@ import org.oscim.event.EventDispatcher;
|
|||||||
import org.oscim.event.EventListener;
|
import org.oscim.event.EventListener;
|
||||||
import org.oscim.event.Gesture;
|
import org.oscim.event.Gesture;
|
||||||
import org.oscim.event.MotionEvent;
|
import org.oscim.event.MotionEvent;
|
||||||
|
import org.oscim.layers.AbstractMapEventLayer;
|
||||||
import org.oscim.layers.Layer;
|
import org.oscim.layers.Layer;
|
||||||
import org.oscim.layers.MapEventLayer;
|
import org.oscim.layers.MapEventLayer;
|
||||||
|
import org.oscim.layers.MapEventLayer2;
|
||||||
import org.oscim.layers.tile.TileLayer;
|
import org.oscim.layers.tile.TileLayer;
|
||||||
import org.oscim.layers.tile.vector.OsmTileLayer;
|
import org.oscim.layers.tile.vector.OsmTileLayer;
|
||||||
import org.oscim.layers.tile.vector.VectorTileLayer;
|
import org.oscim.layers.tile.vector.VectorTileLayer;
|
||||||
@ -45,7 +47,12 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
public abstract class Map implements TaskQueue {
|
public abstract class Map implements TaskQueue {
|
||||||
|
|
||||||
static final Logger log = LoggerFactory.getLogger(Map.class);
|
private static final Logger log = LoggerFactory.getLogger(Map.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true the {@link MapEventLayer2} will be used instead of default {@link MapEventLayer}.
|
||||||
|
*/
|
||||||
|
public static boolean NEW_GESTURES = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener interface for map update notifications.
|
* Listener interface for map update notifications.
|
||||||
@ -105,7 +112,7 @@ public abstract class Map implements TaskQueue {
|
|||||||
protected final Animator mAnimator;
|
protected final Animator mAnimator;
|
||||||
protected final MapPosition mMapPosition;
|
protected final MapPosition mMapPosition;
|
||||||
|
|
||||||
protected final MapEventLayer mEventLayer;
|
protected final AbstractMapEventLayer mEventLayer;
|
||||||
|
|
||||||
protected boolean mClearMap = true;
|
protected boolean mClearMap = true;
|
||||||
|
|
||||||
@ -134,12 +141,15 @@ public abstract class Map implements TaskQueue {
|
|||||||
mAsyncExecutor = new AsyncExecutor(4, this);
|
mAsyncExecutor = new AsyncExecutor(4, this);
|
||||||
mMapPosition = new MapPosition();
|
mMapPosition = new MapPosition();
|
||||||
|
|
||||||
mEventLayer = new MapEventLayer(this);
|
if (NEW_GESTURES)
|
||||||
|
mEventLayer = new MapEventLayer2(this);
|
||||||
|
else
|
||||||
|
mEventLayer = new MapEventLayer(this);
|
||||||
mLayers.add(0, mEventLayer);
|
mLayers.add(0, mEventLayer);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapEventLayer getEventLayer() {
|
public AbstractMapEventLayer getEventLayer() {
|
||||||
return mEventLayer;
|
return mEventLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user