refactor and document Map

- merge Layers into Map
- change UpdateEvent to Map.UpdateListener
- make updateLayers protected
This commit is contained in:
Hannes Janetzek 2013-09-17 22:35:41 +02:00
parent 9a82c24a89
commit 4f1b3f262b
10 changed files with 294 additions and 360 deletions

View File

@ -19,8 +19,6 @@ import java.net.URL;
import org.oscim.backend.canvas.Bitmap; import org.oscim.backend.canvas.Bitmap;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.event.MapEvent;
import org.oscim.event.UpdateEvent;
import org.oscim.gdx.client.GwtBitmap; import org.oscim.gdx.client.GwtBitmap;
import org.oscim.layers.tile.TileLayer; import org.oscim.layers.tile.TileLayer;
import org.oscim.layers.tile.bitmap.TileSource.FadeStep; import org.oscim.layers.tile.bitmap.TileSource.FadeStep;
@ -50,66 +48,33 @@ public class BitmapTileLayer extends TileLayer<TileLoader> {
mFade = mTileSource.getFadeSteps(); mFade = mTileSource.getFadeSteps();
} }
// @Override
// public void onUpdate(MapPosition pos, boolean changed, boolean clear) {
// super.onUpdate(pos, changed, clear);
//
// if (mFade == null) {
// mRenderLayer.setBitmapAlpha(1);
// return;
// }
//
// float alpha = 0;
// for (FadeStep f : mFade) {
// if (pos.scale < f.scaleStart || pos.scale > f.scaleEnd)
// continue;
//
// if (f.alphaStart == f.alphaEnd) {
// alpha = f.alphaStart;
// break;
// }
// double range = f.scaleEnd / f.scaleStart;
// float a = (float)((range - (pos.scale / f.scaleStart)) / range);
// a = FastMath.clamp(a, 0, 1);
// // interpolate alpha between start and end
// alpha = a * f.alphaStart + (1 - a) * f.alphaEnd;
// break;
// }
//
// mRenderLayer.setBitmapAlpha(alpha);
// }
@Override @Override
public void handleEvent(MapEvent event) { public void onMapUpdate(MapPosition pos, boolean changed, boolean clear) {
super.handleEvent(event); super.onMapUpdate(pos, changed, clear);
if (event instanceof UpdateEvent) { if (mFade == null) {
mRenderLayer.setBitmapAlpha(1);
return;
}
if (mFade == null) { float alpha = 0;
mRenderLayer.setBitmapAlpha(1); for (FadeStep f : mFade) {
return; if (pos.scale < f.scaleStart || pos.scale > f.scaleEnd)
} continue;
MapPosition pos = mMap.getMapPosition();
float alpha = 0; if (f.alphaStart == f.alphaEnd) {
for (FadeStep f : mFade) { alpha = f.alphaStart;
if (pos.scale < f.scaleStart || pos.scale > f.scaleEnd)
continue;
if (f.alphaStart == f.alphaEnd) {
alpha = f.alphaStart;
break;
}
double range = f.scaleEnd / f.scaleStart;
float a = (float) ((range - (pos.scale / f.scaleStart)) / range);
a = FastMath.clamp(a, 0, 1);
// interpolate alpha between start and end
alpha = a * f.alphaStart + (1 - a) * f.alphaEnd;
break; break;
} }
double range = f.scaleEnd / f.scaleStart;
mRenderLayer.setBitmapAlpha(alpha); float a = (float) ((range - (pos.scale / f.scaleStart)) / range);
a = FastMath.clamp(a, 0, 1);
// interpolate alpha between start and end
alpha = a * f.alphaStart + (1 - a) * f.alphaEnd;
break;
} }
mRenderLayer.setBitmapAlpha(alpha);
} }
@Override @Override

View File

@ -82,6 +82,33 @@ public abstract class GdxMap implements ApplicationListener {
}, delay / 1000f); }, delay / 1000f);
return true; return true;
} }
/**
* Update all Layers on Main thread.
*
* @param forceRedraw
* also render frame FIXME (does nothing atm)
*/
private void redrawMapInternal(boolean forceRedraw) {
// FIXME needed?
GLState.blend(false);
GLState.test(false, false);
updateLayers();
mRenderRequest = true;
Gdx.graphics.requestRendering();
}
/* private */boolean mWaitRedraw;
private final Runnable mRedrawRequest = new Runnable() {
@Override
public void run() {
mWaitRedraw = false;
redrawMapInternal(false);
}
};
}; };
mMapRenderer = new MapRenderer(mMap); mMapRenderer = new MapRenderer(mMap);
@ -200,30 +227,6 @@ public abstract class GdxMap implements ApplicationListener {
public void resume() { public void resume() {
} }
/**
* Update all Layers on Main thread.
*
* @param forceRedraw
* also render frame FIXME (does nothing atm)
*/
void redrawMapInternal(boolean forceRedraw) {
GLState.blend(false);
GLState.test(false, false);
mMap.updateLayers();
mRenderRequest = true;
Gdx.graphics.requestRendering();
}
/* private */boolean mWaitRedraw;
private final Runnable mRedrawRequest = new Runnable() {
@Override
public void run() {
mWaitRedraw = false;
redrawMapInternal(false);
}
};
class TouchHandler implements InputProcessor { class TouchHandler implements InputProcessor {

View File

@ -0,0 +1,19 @@
package org.oscim.event;
import java.util.ArrayList;
import java.util.List;
public abstract class Dispatcher<T> {
protected List<T> listeners = new ArrayList<T>();
public void addListener(T l) {
if (!listeners.contains(l))
listeners.add(l);
}
public void removeListener(T l) {
listeners.remove(l);
}
public abstract void dispatch();
}

View File

@ -0,0 +1,5 @@
package org.oscim.event;
public interface IListener {
}

View File

@ -1,16 +0,0 @@
package org.oscim.event;
public class UpdateEvent extends MapEvent {
private static final long serialVersionUID = 1L;
public static final String TYPE = "UpdateEvent";
public UpdateEvent(Object source) {
super(source);
}
public boolean positionChanged;
public boolean clearMap;
}

View File

@ -16,16 +16,14 @@ package org.oscim.layers.tile;
import java.util.ArrayList; import java.util.ArrayList;
import org.oscim.event.EventListener; import org.oscim.core.MapPosition;
import org.oscim.event.MapEvent;
import org.oscim.event.UpdateEvent;
import org.oscim.layers.Layer; import org.oscim.layers.Layer;
import org.oscim.map.Map; import org.oscim.map.Map;
import org.oscim.tiling.TileLoader; import org.oscim.tiling.TileLoader;
import org.oscim.tiling.TileManager; import org.oscim.tiling.TileManager;
import org.oscim.tiling.TileRenderer; import org.oscim.tiling.TileRenderer;
public abstract class TileLayer<T extends TileLoader> extends Layer implements EventListener { public abstract class TileLayer<T extends TileLoader> extends Layer implements Map.UpdateListener {
//private final static String TAG = TileLayer.class.getName(); //private final static String TAG = TileLayer.class.getName();
private final static int MAX_ZOOMLEVEL = 17; private final static int MAX_ZOOMLEVEL = 17;
private final static int MIN_ZOOMLEVEL = 2; private final static int MIN_ZOOMLEVEL = 2;
@ -61,8 +59,6 @@ public abstract class TileLayer<T extends TileLoader> extends Layer implements E
// RenderLayer is working in GL Thread and actually // RenderLayer is working in GL Thread and actually
// drawing loaded tiles to screen. // drawing loaded tiles to screen.
mRenderer = mRenderLayer = new TileRenderer(mTileManager); mRenderer = mRenderLayer = new TileRenderer(mTileManager);
map.addListener(UpdateEvent.TYPE, this);
} }
abstract protected T createLoader(TileManager tm); abstract protected T createLoader(TileManager tm);
@ -71,55 +67,32 @@ public abstract class TileLayer<T extends TileLoader> extends Layer implements E
return (TileRenderer) mRenderer; return (TileRenderer) mRenderer;
} }
// @Override
// public void onUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
//
// if (clear || mInitial) {
// mRenderLayer.clearTiles();
// mTileManager.init(mInitial);
// mInitial = false;
// changed = true;
// }
//
// if (changed && mTileManager.update(mapPosition))
// notifyLoaders();
// }
@Override @Override
public void handleEvent(MapEvent event) { public void onMapUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
if (event instanceof UpdateEvent) { if (clear || mInitial) {
mRenderLayer.clearTiles();
UpdateEvent e = (UpdateEvent) event; mTileManager.init(mInitial);
mInitial = false;
boolean changed = e.positionChanged; changed = true;
if (e.clearMap || mInitial) {
mRenderLayer.clearTiles();
mTileManager.init(mInitial);
mInitial = false;
changed = true;
}
if (changed && mTileManager.update(mMap.getMapPosition()))
notifyLoaders();
} }
if (changed && mTileManager.update(mapPosition))
notifyLoaders();
} }
@Override @Override
public void onDetach() { public void onDetach() {
mMap.removeListener(UpdateEvent.TYPE, this);
for (T loader : mTileLoader) { for (T loader : mTileLoader) {
loader.pause(); loader.pause();
loader.interrupt(); loader.interrupt();
loader.cleanup(); loader.cleanup();
// try { //try {
// tileWorker.join(10000); // tileWorker.join(10000);
// } catch (InterruptedException e) { //} catch (InterruptedException e) {
// // restore the interrupted status // // restore the interrupted status
// Thread.currentThread().interrupt(); // Thread.currentThread().interrupt();
// } //}
} }
mTileManager.destroy(); mTileManager.destroy();
} }

View File

@ -24,8 +24,6 @@ import org.oscim.backend.CanvasAdapter;
import org.oscim.backend.canvas.Bitmap; import org.oscim.backend.canvas.Bitmap;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.event.MapEvent;
import org.oscim.event.UpdateEvent;
import org.oscim.layers.tile.TileLayer; import org.oscim.layers.tile.TileLayer;
import org.oscim.layers.tile.bitmap.TileSource.FadeStep; import org.oscim.layers.tile.bitmap.TileSource.FadeStep;
import org.oscim.map.Map; import org.oscim.map.Map;
@ -53,66 +51,33 @@ public class BitmapTileLayer extends TileLayer<TileLoader> {
} }
// @Override
// public void onUpdate(MapPosition pos, boolean changed, boolean clear) {
// super.onUpdate(pos, changed, clear);
//
// if (mFade == null) {
// mRenderLayer.setBitmapAlpha(1);
// return;
// }
//
// float alpha = 0;
// for (FadeStep f : mFade) {
// if (pos.scale < f.scaleStart || pos.scale > f.scaleEnd)
// continue;
//
// if (f.alphaStart == f.alphaEnd) {
// alpha = f.alphaStart;
// break;
// }
// double range = f.scaleEnd / f.scaleStart;
// float a = (float)((range - (pos.scale / f.scaleStart)) / range);
// a = FastMath.clamp(a, 0, 1);
// // interpolate alpha between start and end
// alpha = a * f.alphaStart + (1 - a) * f.alphaEnd;
// break;
// }
//
// mRenderLayer.setBitmapAlpha(alpha);
// }
@Override @Override
public void handleEvent(MapEvent event) { public void onMapUpdate(MapPosition pos, boolean changed, boolean clear) {
super.handleEvent(event); super.onMapUpdate(pos, changed, clear);
if (event instanceof UpdateEvent){ if (mFade == null) {
mRenderLayer.setBitmapAlpha(1);
return;
}
if (mFade == null) { float alpha = 0;
mRenderLayer.setBitmapAlpha(1); for (FadeStep f : mFade) {
return; if (pos.scale < f.scaleStart || pos.scale > f.scaleEnd)
} continue;
MapPosition pos = mMap.getMapPosition();
float alpha = 0; if (f.alphaStart == f.alphaEnd) {
for (FadeStep f : mFade) { alpha = f.alphaStart;
if (pos.scale < f.scaleStart || pos.scale > f.scaleEnd)
continue;
if (f.alphaStart == f.alphaEnd) {
alpha = f.alphaStart;
break;
}
double range = f.scaleEnd / f.scaleStart;
float a = (float)((range - (pos.scale / f.scaleStart)) / range);
a = FastMath.clamp(a, 0, 1);
// interpolate alpha between start and end
alpha = a * f.alphaStart + (1 - a) * f.alphaEnd;
break; break;
} }
double range = f.scaleEnd / f.scaleStart;
mRenderLayer.setBitmapAlpha(alpha); float a = (float)((range - (pos.scale / f.scaleStart)) / range);
a = FastMath.clamp(a, 0, 1);
// interpolate alpha between start and end
alpha = a * f.alphaStart + (1 - a) * f.alphaEnd;
break;
} }
mRenderLayer.setBitmapAlpha(alpha);
} }
@Override @Override

View File

@ -15,15 +15,15 @@
package org.oscim.layers.tile.vector.labeling; package org.oscim.layers.tile.vector.labeling;
import org.oscim.backend.Log; import org.oscim.backend.Log;
import org.oscim.core.MapPosition;
import org.oscim.event.EventListener; import org.oscim.event.EventListener;
import org.oscim.event.MapEvent; import org.oscim.event.MapEvent;
import org.oscim.event.MotionEvent; import org.oscim.event.MotionEvent;
import org.oscim.event.UpdateEvent;
import org.oscim.layers.Layer; import org.oscim.layers.Layer;
import org.oscim.map.Map; import org.oscim.map.Map;
import org.oscim.tiling.TileRenderer; import org.oscim.tiling.TileRenderer;
public class LabelLayer extends Layer implements EventListener { public class LabelLayer extends Layer implements EventListener, Map.UpdateListener {
private final static String TAG = LabelLayer.class.getName(); private final static String TAG = LabelLayer.class.getName();
private final TextRenderer mTextRenderer; private final TextRenderer mTextRenderer;
@ -31,7 +31,7 @@ public class LabelLayer extends Layer implements EventListener {
public LabelLayer(Map map, TileRenderer tileRenderLayer) { public LabelLayer(Map map, TileRenderer tileRenderLayer) {
super(map); super(map);
map.addListener(UpdateEvent.TYPE, this);
map.addListener(MotionEvent.TYPE, this); map.addListener(MotionEvent.TYPE, this);
//mTextLayer = new org.oscim.renderer.layers.TextRenderLayer(map, tileRenderLayer); //mTextLayer = new org.oscim.renderer.layers.TextRenderLayer(map, tileRenderLayer);
@ -41,7 +41,6 @@ public class LabelLayer extends Layer implements EventListener {
@Override @Override
public void onDetach() { public void onDetach() {
mMap.removeListener(UpdateEvent.TYPE, this);
mMap.removeListener(MotionEvent.TYPE, this); mMap.removeListener(MotionEvent.TYPE, this);
// TODO stop and clear labeling thread // TODO stop and clear labeling thread
@ -50,13 +49,7 @@ public class LabelLayer extends Layer implements EventListener {
@Override @Override
public void handleEvent(MapEvent event) { public void handleEvent(MapEvent event) {
if (event instanceof UpdateEvent) { if (event instanceof MotionEvent) {
UpdateEvent e = (UpdateEvent) event;
if (e.clearMap)
mTextRenderer.clearLabels();
} else if (event instanceof MotionEvent) {
MotionEvent e = (MotionEvent) event; MotionEvent e = (MotionEvent) event;
int action = e.getAction() & MotionEvent.ACTION_MASK; int action = e.getAction() & MotionEvent.ACTION_MASK;
@ -75,11 +68,11 @@ public class LabelLayer extends Layer implements EventListener {
} }
} }
// @Override @Override
// public void onUpdate(MapPosition mapPosition, boolean changed, boolean clear) { public void onMapUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
// if (clear) if (clear)
// mTextRenderer.clearLabels(); mTextRenderer.clearLabels();
// } }
// @Override // @Override
// public boolean onTouchEvent(MotionEvent e) { // public boolean onTouchEvent(MotionEvent e) {

View File

@ -1,109 +0,0 @@
/*
* Copyright 2012 osmdroid authors
* Copyright 2013 Hannes Janetzek
*
* 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.map;
import java.util.AbstractList;
import java.util.concurrent.CopyOnWriteArrayList;
import org.oscim.layers.Layer;
import org.oscim.renderer.LayerRenderer;
public class Layers extends AbstractList<Layer> {
//private final static String TAG = Layers.class.getName();
private final CopyOnWriteArrayList<Layer> mLayerList;
Layers() {
mLayerList = new CopyOnWriteArrayList<Layer>();
}
@Override
public synchronized Layer get(int index) {
return mLayerList.get(index);
}
@Override
public synchronized int size() {
return mLayerList.size();
}
@Override
public synchronized void add(int index, Layer element) {
mLayerList.add(index, element);
mDirtyLayers = true;
}
@Override
public synchronized Layer remove(int index) {
mDirtyLayers = true;
return mLayerList.remove(index);
}
@Override
public synchronized Layer set(int index, Layer element) {
mDirtyLayers = true;
return mLayerList.set(index, element);
}
private boolean mDirtyLayers;
private LayerRenderer[] mLayerRenderer;
public LayerRenderer[] getLayerRenderer() {
if (mDirtyLayers)
updateLayers();
return mLayerRenderer;
}
public void destroy() {
if (mDirtyLayers)
updateLayers();
for (Layer o : mLayers)
o.onDetach();
}
Layer[] mLayers;
private synchronized void updateLayers() {
if (!mDirtyLayers)
return;
mLayers = new Layer[mLayerList.size()];
int numRenderLayers = 0;
for (int i = 0, n = mLayerList.size(); i < n; i++) {
Layer o = mLayerList.get(i);
if (o.getRenderer() != null)
numRenderLayers++;
mLayers[i] = o;
}
mLayerRenderer = new LayerRenderer[numRenderLayers];
for (int i = 0, cntR = 0, n = mLayerList.size(); i < n; i++) {
Layer o = mLayerList.get(i);
LayerRenderer l = o.getRenderer();
if (l != null)
mLayerRenderer[cntR++] = l;
}
mDirtyLayers = false;
}
}

View File

@ -14,20 +14,24 @@
*/ */
package org.oscim.map; package org.oscim.map;
import java.util.AbstractList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.CopyOnWriteArrayList;
import org.oscim.backend.Log; import org.oscim.backend.Log;
import org.oscim.core.BoundingBox; import org.oscim.core.BoundingBox;
import org.oscim.core.GeoPoint;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.core.MercatorProjection;
import org.oscim.event.Dispatcher;
import org.oscim.event.EventDispatcher; import org.oscim.event.EventDispatcher;
import org.oscim.event.EventListener; import org.oscim.event.EventListener;
import org.oscim.event.IListener;
import org.oscim.event.MotionEvent; import org.oscim.event.MotionEvent;
import org.oscim.event.UpdateEvent; import org.oscim.layers.Layer;
import org.oscim.layers.MapEventLayer; import org.oscim.layers.MapEventLayer;
import org.oscim.layers.tile.bitmap.BitmapTileLayer; import org.oscim.layers.tile.bitmap.BitmapTileLayer;
import org.oscim.layers.tile.vector.VectorTileLayer; import org.oscim.layers.tile.vector.VectorTileLayer;
import org.oscim.layers.tile.vector.VectorTileLoader; import org.oscim.renderer.LayerRenderer;
import org.oscim.renderer.MapRenderer; import org.oscim.renderer.MapRenderer;
import org.oscim.theme.IRenderTheme; import org.oscim.theme.IRenderTheme;
import org.oscim.theme.InternalRenderTheme; import org.oscim.theme.InternalRenderTheme;
@ -94,16 +98,21 @@ public abstract class Map implements EventDispatcher {
private InternalRenderTheme mCurrentTheme; private InternalRenderTheme mCurrentTheme;
/**
* Utility function to set theme of base vector-layer and
* use map background color from theme.
*/
public void setTheme(InternalRenderTheme theme) { public void setTheme(InternalRenderTheme theme) {
if (mBaseLayer == null) { if (mBaseLayer == null) {
Log.e(TAG, "No base layer set"); Log.e(TAG, "No base layer set");
throw new IllegalStateException(); throw new IllegalStateException();
} }
if (mCurrentTheme == theme){ if (mCurrentTheme == theme) {
Log.d(TAG, "same theme: " + theme); Log.d(TAG, "same theme: " + theme);
return; return;
} }
IRenderTheme t = ThemeLoader.load(theme); IRenderTheme t = ThemeLoader.load(theme);
if (t == null) { if (t == null) {
Log.e(TAG, "Invalid theme"); Log.e(TAG, "Invalid theme");
@ -126,7 +135,7 @@ public abstract class Map implements EventDispatcher {
* Request call to onUpdate for all layers. This function can * Request call to onUpdate for all layers. This function can
* be called from any thread. Request will be handled on main * be called from any thread. Request will be handled on main
* thread. * thread.
* *
* @param forceRedraw pass true to render next frame * @param forceRedraw pass true to render next frame
*/ */
public abstract void updateMap(boolean forceRedraw); public abstract void updateMap(boolean forceRedraw);
@ -151,16 +160,21 @@ public abstract class Map implements EventDispatcher {
/** /**
* Post a task to run on a shared worker-thread. Only use for * Post a task to run on a shared worker-thread. Only use for
* tasks running less than a second! * tasks running less than a second!
* */ */
public void addTask(Runnable task){ public void addTask(Runnable task) {
mAsyncExecutor.post(task); mAsyncExecutor.post(task);
} }
/**
* Return screen width in pixel.
*/
public abstract int getWidth(); public abstract int getWidth();
/**
* Return screen height in pixel.
*/
public abstract int getHeight(); public abstract int getHeight();
/** /**
* Request to clear all layers before rendering next frame * Request to clear all layers before rendering next frame
*/ */
@ -169,27 +183,9 @@ public abstract class Map implements EventDispatcher {
} }
/** /**
* Do not call directly! This function is run on main-loop * This function is run on main-loop before rendering a frame.
* before rendering a frame. * Caution: Do not call directly!
*/ */
public void updateLayers() {
boolean changed = false;
// get the current MapPosition
changed |= mViewport.getMapPosition(mMapPosition);
//mLayers.onUpdate(mMapPosition, changed, mClearMap);
UpdateEvent e = new UpdateEvent(this);
e.clearMap = mClearMap;
e.positionChanged = changed;
for (EventListener l : mUpdateListeners)
l.handleEvent(e);
mClearMap = false;
}
public void setDebugSettings(DebugSettings debugSettings) { public void setDebugSettings(DebugSettings debugSettings) {
mDebugSettings = debugSettings; mDebugSettings = debugSettings;
//MapTileLoader.setDebugSettings(debugSettings); //MapTileLoader.setDebugSettings(debugSettings);
@ -197,6 +193,9 @@ public abstract class Map implements EventDispatcher {
public DebugSettings getDebugSettings() { public DebugSettings getDebugSettings() {
return mDebugSettings; return mDebugSettings;
protected void updateLayers() {
mUpdateDispatcher.dispatch();
} }
public void setMapPosition(MapPosition mapPosition) { public void setMapPosition(MapPosition mapPosition) {
@ -242,32 +241,169 @@ public abstract class Map implements EventDispatcher {
return mAnimator; return mAnimator;
} }
ArrayList<EventListener> mUpdateListeners = new ArrayList<EventListener>();
ArrayList<EventListener> mMotionListeners = new ArrayList<EventListener>(); ArrayList<EventListener> mMotionListeners = new ArrayList<EventListener>();
@Override @Override
public void addListener(String type, EventListener listener) { public void addListener(String type, EventListener listener) {
if (type == UpdateEvent.TYPE) if (type == MotionEvent.TYPE)
mUpdateListeners.add(listener);
else if (type == MotionEvent.TYPE)
mMotionListeners.add(listener); mMotionListeners.add(listener);
} }
@Override @Override
public void removeListener(String type, EventListener listener) { public void removeListener(String type, EventListener listener) {
if (type == UpdateEvent.TYPE) if (type == MotionEvent.TYPE)
mUpdateListeners.remove(listener);
else if (type == MotionEvent.TYPE)
mMotionListeners.remove(listener); mMotionListeners.remove(listener);
} }
public MapPosition getMapPosition() {
return mMapPosition;
}
public void handleMotionEvent(MotionEvent e) { public void handleMotionEvent(MotionEvent e) {
for (EventListener l : mMotionListeners) for (EventListener l : mMotionListeners)
l.handleEvent(e); l.handleEvent(e);
} }
/**
* Listener interface for map update notifications.
*
* NOTE: Layers implementing this interface they will be automatically
* registered when the layer is added to the map and unresitered when
* the layer is removed.
*/
public interface UpdateListener extends IListener {
void onMapUpdate(MapPosition mapPosition, boolean positionChanged, boolean clear);
}
private class UpdateDispatcher extends Dispatcher<UpdateListener> {
@Override
public void dispatch() {
boolean changed = false;
// get the current MapPosition
changed |= mViewport.getMapPosition(mMapPosition);
for (UpdateListener l : listeners)
l.onMapUpdate(mMapPosition, changed, mClearMap);
mClearMap = false;
}
}
private final UpdateDispatcher mUpdateDispatcher = new UpdateDispatcher();
/**
* Register UpdateListener
*/
public void addUpdateListener(UpdateListener l) {
mUpdateDispatcher.addListener(l);
}
/**
* Unregister UpdateListener
*/
public void removeUpdateListener(UpdateListener l) {
mUpdateDispatcher.removeListener(l);
}
public final class Layers extends AbstractList<Layer> {
private final CopyOnWriteArrayList<Layer> mLayerList;
Layers() {
mLayerList = new CopyOnWriteArrayList<Layer>();
}
@Override
public synchronized Layer get(int index) {
return mLayerList.get(index);
}
@Override
public synchronized int size() {
return mLayerList.size();
}
@Override
public synchronized void add(int index, Layer layer) {
if (mLayerList.contains(layer))
throw new IllegalArgumentException("layer added twice");
if (layer instanceof UpdateListener)
addUpdateListener((UpdateListener) layer);
mLayerList.add(index, layer);
mDirtyLayers = true;
}
@Override
public synchronized Layer remove(int index) {
mDirtyLayers = true;
Layer remove = mLayerList.remove(index);
if (remove instanceof UpdateListener)
removeUpdateListener((UpdateListener) remove);
return remove;
}
@Override
public synchronized Layer set(int index, Layer layer) {
if (mLayerList.contains(layer))
throw new IllegalArgumentException("layer added twice");
mDirtyLayers = true;
Layer remove = mLayerList.set(index, layer);
if (remove instanceof UpdateListener)
removeUpdateListener((UpdateListener) remove);
return remove;
}
private boolean mDirtyLayers;
private LayerRenderer[] mLayerRenderer;
public LayerRenderer[] getLayerRenderer() {
if (mDirtyLayers)
updateLayers();
return mLayerRenderer;
}
public void destroy() {
if (mDirtyLayers)
updateLayers();
for (Layer o : mLayers)
o.onDetach();
}
Layer[] mLayers;
private synchronized void updateLayers() {
if (!mDirtyLayers)
return;
mLayers = new Layer[mLayerList.size()];
int numRenderLayers = 0;
for (int i = 0, n = mLayerList.size(); i < n; i++) {
Layer o = mLayerList.get(i);
if (o.getRenderer() != null)
numRenderLayers++;
mLayers[i] = o;
}
mLayerRenderer = new LayerRenderer[numRenderLayers];
for (int i = 0, cntR = 0, n = mLayerList.size(); i < n; i++) {
Layer o = mLayerList.get(i);
LayerRenderer l = o.getRenderer();
if (l != null)
mLayerRenderer[cntR++] = l;
}
mDirtyLayers = false;
}
}
} }