Merge branch 'wip_sync'
This commit is contained in:
commit
2c7cd1c880
@ -23,16 +23,10 @@ import android.widget.RelativeLayout.LayoutParams;
|
||||
public class AndroidMap extends Map {
|
||||
|
||||
private final MapView mMapView;
|
||||
private boolean mWaitRedraw;
|
||||
final GLView mGLView;
|
||||
boolean mPausing = false;
|
||||
|
||||
private final Runnable mRedrawRequest = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
redrawMapInternal(false);
|
||||
}
|
||||
};
|
||||
private volatile boolean mWaitRedraw;
|
||||
private volatile boolean mPausing;
|
||||
|
||||
public AndroidMap(MapView mapView) {
|
||||
super();
|
||||
@ -45,8 +39,6 @@ public class AndroidMap extends Map {
|
||||
android.view.ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
|
||||
mapView.addView(mGLView, params);
|
||||
|
||||
//mGestureDetector =
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -60,9 +52,9 @@ public class AndroidMap extends Map {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void updateMap(boolean requestRender) {
|
||||
if (requestRender && !mClearMap && !mPausing) // && mInitialized)
|
||||
mGLView.requestRender();
|
||||
public void updateMap(boolean redraw) {
|
||||
//if (redraw && !mClearMap && !mPausing)
|
||||
// mGLView.requestRender();
|
||||
|
||||
if (!mWaitRedraw) {
|
||||
mWaitRedraw = true;
|
||||
@ -71,26 +63,29 @@ public class AndroidMap extends Map {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void render() {
|
||||
public void render() {
|
||||
if (mPausing)
|
||||
return;
|
||||
|
||||
if (mClearMap)
|
||||
updateMap(false);
|
||||
else
|
||||
mGLView.requestRender();
|
||||
}
|
||||
|
||||
synchronized void redrawMapInternal(boolean forceRedraw) {
|
||||
boolean clear = mClearMap;
|
||||
mWaitRedraw = false;
|
||||
private final Runnable mRedrawRequest = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
redrawMapInternal();
|
||||
}
|
||||
};
|
||||
|
||||
if (forceRedraw && !clear)
|
||||
mGLView.requestRender();
|
||||
void redrawMapInternal() {
|
||||
mWaitRedraw = false;
|
||||
|
||||
updateLayers();
|
||||
|
||||
if (clear) {
|
||||
mGLView.requestRender();
|
||||
mClearMap = false;
|
||||
}
|
||||
mGLView.requestRender();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -103,9 +98,7 @@ public class AndroidMap extends Map {
|
||||
return mMapView.postDelayed(action, delay);
|
||||
}
|
||||
|
||||
|
||||
public synchronized void pause(boolean pause) {
|
||||
mPausing = pause;
|
||||
}
|
||||
|
||||
public void pause(boolean pause) {
|
||||
mPausing = pause;
|
||||
}
|
||||
}
|
||||
|
@ -24,9 +24,12 @@ import org.oscim.map.Map;
|
||||
import org.oscim.tiling.TileLoader;
|
||||
import org.oscim.tiling.TileManager;
|
||||
import org.oscim.tiling.TileRenderer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class TileLayer<T extends TileLoader> extends Layer implements Map.UpdateListener {
|
||||
//static final Logger log = LoggerFactory.getLogger(TileLayer.class);
|
||||
static final Logger log = LoggerFactory.getLogger(TileLayer.class);
|
||||
|
||||
private final static int MAX_ZOOMLEVEL = 17;
|
||||
private final static int MIN_ZOOMLEVEL = 2;
|
||||
private final static int CACHE_LIMIT = 250;
|
||||
@ -37,8 +40,6 @@ public abstract class TileLayer<T extends TileLoader> extends Layer implements M
|
||||
protected final int mNumTileLoader = 4;
|
||||
protected final ArrayList<T> mTileLoader;
|
||||
|
||||
protected boolean mInitial = true;
|
||||
|
||||
public TileLayer(Map map) {
|
||||
this(map, MIN_ZOOMLEVEL, MAX_ZOOMLEVEL, CACHE_LIMIT);
|
||||
}
|
||||
@ -71,10 +72,13 @@ public abstract class TileLayer<T extends TileLoader> extends Layer implements M
|
||||
|
||||
@Override
|
||||
public void onMapUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
|
||||
if (clear || mInitial) {
|
||||
mRenderLayer.clearTiles();
|
||||
mTileManager.init(mInitial);
|
||||
mInitial = false;
|
||||
if (clear) {
|
||||
// sync with TileRenderer
|
||||
synchronized (mRenderLayer) {
|
||||
mRenderLayer.clearTiles();
|
||||
mTileManager.init();
|
||||
}
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
@ -87,16 +91,13 @@ public abstract class TileLayer<T extends TileLoader> extends Layer implements M
|
||||
for (T loader : mTileLoader) {
|
||||
loader.pause();
|
||||
loader.interrupt();
|
||||
try {
|
||||
loader.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
loader.cleanup();
|
||||
|
||||
//try {
|
||||
// tileWorker.join(10000);
|
||||
//} catch (InterruptedException e) {
|
||||
// // restore the interrupted status
|
||||
// Thread.currentThread().interrupt();
|
||||
//}
|
||||
}
|
||||
mTileManager.destroy();
|
||||
}
|
||||
|
||||
void notifyLoaders() {
|
||||
@ -110,11 +111,12 @@ public abstract class TileLayer<T extends TileLoader> extends Layer implements M
|
||||
if (!loader.isPausing())
|
||||
loader.pause();
|
||||
}
|
||||
if (wait) {
|
||||
for (T loader : mTileLoader) {
|
||||
if (!loader.isPausing())
|
||||
loader.awaitPausing();
|
||||
}
|
||||
if (!wait)
|
||||
return;
|
||||
|
||||
for (T loader : mTileLoader) {
|
||||
if (!loader.isPausing())
|
||||
loader.awaitPausing();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,8 @@
|
||||
*/
|
||||
package org.oscim.layers.tile.vector;
|
||||
|
||||
import java.util.concurrent.CancellationException;
|
||||
|
||||
import org.oscim.core.GeometryBuffer.GeometryType;
|
||||
import org.oscim.core.MapElement;
|
||||
import org.oscim.core.MercatorProjection;
|
||||
@ -131,14 +133,18 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac
|
||||
|
||||
mTile = tile;
|
||||
mTile.layers = new ElementLayers();
|
||||
|
||||
// query database, which calls 'process' callback
|
||||
QueryResult result = mTileDataSource.executeQuery(mTile, this);
|
||||
|
||||
mTile = null;
|
||||
|
||||
clearState();
|
||||
|
||||
QueryResult result = null;
|
||||
try {
|
||||
// query database, which calls 'process' callback
|
||||
result = mTileDataSource.executeQuery(mTile, this);
|
||||
} catch (CancellationException e) {
|
||||
log.debug("canceled {}", mTile);
|
||||
} catch (Exception e) {
|
||||
log.debug("{}", e);
|
||||
} finally {
|
||||
mTile = null;
|
||||
clearState();
|
||||
}
|
||||
return (result == QueryResult.SUCCESS);
|
||||
}
|
||||
|
||||
@ -205,8 +211,12 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac
|
||||
|
||||
@Override
|
||||
public void process(MapElement element) {
|
||||
|
||||
clearState();
|
||||
|
||||
if (isCanceled())
|
||||
throw new CancellationException();
|
||||
|
||||
mElement = element;
|
||||
|
||||
if (element.type == GeometryType.POINT) {
|
||||
|
@ -28,7 +28,7 @@ public class LabelLayer extends Layer implements Map.InputListener, Map.UpdateLi
|
||||
static final Logger log = LoggerFactory.getLogger(LabelLayer.class);
|
||||
private final TextRenderer mTextRenderer;
|
||||
|
||||
private int multi;
|
||||
//private int multi;
|
||||
|
||||
public LabelLayer(Map map, TileRenderer tileRenderLayer) {
|
||||
super(map);
|
||||
@ -49,19 +49,19 @@ public class LabelLayer extends Layer implements Map.InputListener, Map.UpdateLi
|
||||
|
||||
@Override
|
||||
public void onMotionEvent(MotionEvent e) {
|
||||
int action = e.getAction() & MotionEvent.ACTION_MASK;
|
||||
if (action == MotionEvent.ACTION_POINTER_DOWN) {
|
||||
multi++;
|
||||
mTextRenderer.hold(true);
|
||||
} else if (action == MotionEvent.ACTION_POINTER_UP) {
|
||||
multi--;
|
||||
if (multi == 0)
|
||||
mTextRenderer.hold(false);
|
||||
} else if (action == MotionEvent.ACTION_CANCEL) {
|
||||
multi = 0;
|
||||
log.debug("cancel " + multi);
|
||||
mTextRenderer.hold(false);
|
||||
}
|
||||
// int action = e.getAction() & MotionEvent.ACTION_MASK;
|
||||
// if (action == MotionEvent.ACTION_POINTER_DOWN) {
|
||||
// multi++;
|
||||
// mTextRenderer.hold(true);
|
||||
// } else if (action == MotionEvent.ACTION_POINTER_UP) {
|
||||
// multi--;
|
||||
// if (multi == 0)
|
||||
// mTextRenderer.hold(false);
|
||||
// } else if (action == MotionEvent.ACTION_CANCEL) {
|
||||
// multi = 0;
|
||||
// log.debug("cancel " + multi);
|
||||
// mTextRenderer.hold(false);
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -51,6 +51,7 @@ import org.oscim.tiling.TileRenderer;
|
||||
import org.oscim.tiling.TileSet;
|
||||
import org.oscim.utils.FastMath;
|
||||
import org.oscim.utils.OBB2D;
|
||||
import org.oscim.utils.async.ContinuousTask;
|
||||
import org.oscim.utils.pool.Pool;
|
||||
|
||||
class TextRenderer extends ElementRenderer {
|
||||
@ -143,6 +144,8 @@ class TextRenderer extends ElementRenderer {
|
||||
|
||||
//mActiveTiles = new HashMap<MapTile, LabelTile>();
|
||||
mRelabelCnt = 0;
|
||||
|
||||
mLabelTask = new LabelTask(map);
|
||||
}
|
||||
|
||||
// remove Label l from mLabels and return l.next
|
||||
@ -274,6 +277,108 @@ class TextRenderer extends ElementRenderer {
|
||||
return dx;
|
||||
}
|
||||
|
||||
private Label updateWayLabels(MapTile t, Label l, float dx, float dy, double scale,
|
||||
ElementLayers dbg) {
|
||||
|
||||
for (TextItem ti = t.labels; ti != null; ti = ti.next) {
|
||||
if (ti.text.caption)
|
||||
continue;
|
||||
|
||||
// acquire a TextItem to add to TextLayer
|
||||
if (l == null)
|
||||
l = getLabel();
|
||||
|
||||
// check if path at current scale is long enough for text
|
||||
if (dbg == null && ti.width > ti.length * scale)
|
||||
continue;
|
||||
|
||||
l.clone(ti);
|
||||
l.move(ti, dx, dy, (float) scale);
|
||||
|
||||
// set line endpoints relative to view to be able to
|
||||
// check intersections with label from other tiles
|
||||
float w = (ti.x2 - ti.x1) / 2f;
|
||||
float h = (ti.y2 - ti.y1) / 2f;
|
||||
l.bbox = null;
|
||||
l.x1 = l.x - w;
|
||||
l.y1 = l.y - h;
|
||||
l.x2 = l.x + w;
|
||||
l.y2 = l.y + h;
|
||||
|
||||
if (!wayIsVisible(l))
|
||||
continue;
|
||||
|
||||
byte overlaps = -1;
|
||||
|
||||
if (l.bbox == null)
|
||||
l.bbox = new OBB2D(l.x, l.y, l.x1, l.y1,
|
||||
l.width + MIN_WAY_DIST,
|
||||
l.text.fontHeight + MIN_WAY_DIST);
|
||||
else
|
||||
l.bbox.set(l.x, l.y, l.x1, l.y1,
|
||||
l.width + MIN_WAY_DIST,
|
||||
l.text.fontHeight + MIN_WAY_DIST);
|
||||
|
||||
if (dbg == null || ti.width < ti.length * scale)
|
||||
overlaps = checkOverlap(l);
|
||||
|
||||
if (dbg != null)
|
||||
Debug.addDebugBox(dbg, l, ti, overlaps, false, (float) scale);
|
||||
|
||||
if (overlaps == 0) {
|
||||
addLabel(l);
|
||||
l.item = TextItem.copy(ti);
|
||||
l.tile = t;
|
||||
l.active = mRelabelCnt;
|
||||
l = null;
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
private Label updateNodeLabels(MapTile t, Label l, float dx, float dy, double scale, float cos,
|
||||
float sin) {
|
||||
O: for (TextItem ti = t.labels; ti != null; ti = ti.next) {
|
||||
if (!ti.text.caption)
|
||||
continue;
|
||||
|
||||
// acquire a TextItem to add to TextLayer
|
||||
if (l == null)
|
||||
l = getLabel();
|
||||
|
||||
l.clone(ti);
|
||||
l.move(ti, dx, dy, (float) scale);
|
||||
if (!nodeIsVisible(l))
|
||||
continue;
|
||||
|
||||
if (l.bbox == null)
|
||||
l.bbox = new OBB2D();
|
||||
|
||||
l.bbox.setNormalized(l.x, l.y, cos, -sin,
|
||||
l.width + MIN_CAPTION_DIST,
|
||||
l.text.fontHeight + MIN_CAPTION_DIST,
|
||||
l.text.dy);
|
||||
|
||||
for (Label lp = mLabels; lp != null;) {
|
||||
if (l.bbox.overlaps(lp.bbox)) {
|
||||
if (l.text.priority < lp.text.priority) {
|
||||
lp = removeLabel(lp);
|
||||
continue;
|
||||
}
|
||||
continue O;
|
||||
}
|
||||
lp = (Label) lp.next;
|
||||
}
|
||||
|
||||
addLabel(l);
|
||||
l.item = TextItem.copy(ti);
|
||||
l.tile = t;
|
||||
l.active = mRelabelCnt;
|
||||
l = null;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
boolean updateLabels() {
|
||||
// nextLayer is not loaded yet
|
||||
if (mNextLayer.ready)
|
||||
@ -400,118 +505,30 @@ class TextRenderer extends ElementRenderer {
|
||||
/* add way labels */
|
||||
for (int i = 0, n = mTileSet.cnt; i < n; i++) {
|
||||
MapTile t = tiles[i];
|
||||
if (!t.state(MapTile.STATE_READY))
|
||||
continue;
|
||||
|
||||
float dx = (float) (t.tileX * Tile.SIZE - tileX);
|
||||
float dy = (float) (t.tileY * Tile.SIZE - tileY);
|
||||
dx = flipLongitude(dx, maxx);
|
||||
|
||||
for (TextItem ti = t.labels; ti != null; ti = ti.next) {
|
||||
|
||||
if (ti.text.caption)
|
||||
synchronized (t) {
|
||||
if (!t.state(MapTile.STATE_READY))
|
||||
continue;
|
||||
|
||||
// acquire a TextItem to add to TextLayer
|
||||
if (l == null)
|
||||
l = getLabel();
|
||||
float dx = (float) (t.tileX * Tile.SIZE - tileX);
|
||||
float dy = (float) (t.tileY * Tile.SIZE - tileY);
|
||||
dx = flipLongitude(dx, maxx);
|
||||
|
||||
// check if path at current scale is long enough for text
|
||||
if (dbg == null && ti.width > ti.length * scale)
|
||||
continue;
|
||||
|
||||
l.clone(ti);
|
||||
l.move(ti, dx, dy, (float) scale);
|
||||
|
||||
// set line endpoints relative to view to be able to
|
||||
// check intersections with label from other tiles
|
||||
float w = (ti.x2 - ti.x1) / 2f;
|
||||
float h = (ti.y2 - ti.y1) / 2f;
|
||||
l.bbox = null;
|
||||
l.x1 = l.x - w;
|
||||
l.y1 = l.y - h;
|
||||
l.x2 = l.x + w;
|
||||
l.y2 = l.y + h;
|
||||
|
||||
if (!wayIsVisible(l))
|
||||
continue;
|
||||
|
||||
byte overlaps = -1;
|
||||
|
||||
if (l.bbox == null)
|
||||
l.bbox = new OBB2D(l.x, l.y, l.x1, l.y1,
|
||||
l.width + MIN_WAY_DIST,
|
||||
l.text.fontHeight + MIN_WAY_DIST);
|
||||
else
|
||||
l.bbox.set(l.x, l.y, l.x1, l.y1,
|
||||
l.width + MIN_WAY_DIST,
|
||||
l.text.fontHeight + MIN_WAY_DIST);
|
||||
|
||||
if (dbg == null || ti.width < ti.length * scale)
|
||||
overlaps = checkOverlap(l);
|
||||
|
||||
if (dbg != null)
|
||||
Debug.addDebugBox(dbg, l, ti, overlaps, false, (float) scale);
|
||||
|
||||
if (overlaps == 0) {
|
||||
addLabel(l);
|
||||
l.item = TextItem.copy(ti);
|
||||
l.tile = t;
|
||||
l.active = mRelabelCnt;
|
||||
l = null;
|
||||
}
|
||||
l = updateWayLabels(t, l, dx, dy, scale, dbg);
|
||||
}
|
||||
}
|
||||
|
||||
/* add caption */
|
||||
for (int i = 0, n = mTileSet.cnt; i < n; i++) {
|
||||
MapTile t = tiles[i];
|
||||
if (!t.state(MapTile.STATE_READY))
|
||||
continue;
|
||||
|
||||
float dx = (float) (t.tileX * Tile.SIZE - tileX);
|
||||
float dy = (float) (t.tileY * Tile.SIZE - tileY);
|
||||
dx = flipLongitude(dx, maxx);
|
||||
|
||||
O: for (TextItem ti = t.labels; ti != null; ti = ti.next) {
|
||||
if (!ti.text.caption)
|
||||
synchronized (t) {
|
||||
if (!t.state(MapTile.STATE_READY))
|
||||
continue;
|
||||
|
||||
// acquire a TextItem to add to TextLayer
|
||||
if (l == null)
|
||||
l = getLabel();
|
||||
float dx = (float) (t.tileX * Tile.SIZE - tileX);
|
||||
float dy = (float) (t.tileY * Tile.SIZE - tileY);
|
||||
dx = flipLongitude(dx, maxx);
|
||||
|
||||
l.clone(ti);
|
||||
l.move(ti, dx, dy, (float) scale);
|
||||
if (!nodeIsVisible(l))
|
||||
continue;
|
||||
|
||||
//l.setAxisAlignedBBox();
|
||||
|
||||
if (l.bbox == null)
|
||||
l.bbox = new OBB2D();
|
||||
|
||||
l.bbox.setNormalized(l.x, l.y, cos, -sin,
|
||||
l.width + MIN_CAPTION_DIST,
|
||||
l.text.fontHeight + MIN_CAPTION_DIST,
|
||||
l.text.dy);
|
||||
|
||||
for (Label lp = mLabels; lp != null;) {
|
||||
if (l.bbox.overlaps(lp.bbox)) {
|
||||
if (l.text.priority < lp.text.priority) {
|
||||
lp = removeLabel(lp);
|
||||
continue;
|
||||
}
|
||||
continue O;
|
||||
}
|
||||
lp = (Label) lp.next;
|
||||
}
|
||||
|
||||
addLabel(l);
|
||||
l.item = TextItem.copy(ti);
|
||||
l.tile = t;
|
||||
l.active = mRelabelCnt;
|
||||
l = null;
|
||||
l = updateNodeLabels(t, l, dx, dy, scale, cos, sin);
|
||||
}
|
||||
}
|
||||
|
||||
@ -541,25 +558,27 @@ class TextRenderer extends ElementRenderer {
|
||||
|
||||
for (int i = 0, n = mTileSet.cnt; i < n; i++) {
|
||||
MapTile t = tiles[i];
|
||||
if (!t.state(MapTile.STATE_READY))
|
||||
continue;
|
||||
|
||||
float dx = (float) (t.tileX * Tile.SIZE - tileX);
|
||||
float dy = (float) (t.tileY * Tile.SIZE - tileY);
|
||||
dx = flipLongitude(dx, maxx);
|
||||
|
||||
for (SymbolItem ti = t.symbols; ti != null; ti = ti.next) {
|
||||
if (ti.texRegion == null)
|
||||
synchronized (t) {
|
||||
if (!t.state(MapTile.STATE_READY))
|
||||
continue;
|
||||
|
||||
SymbolItem s = SymbolItem.pool.get();
|
||||
float dx = (float) (t.tileX * Tile.SIZE - tileX);
|
||||
float dy = (float) (t.tileY * Tile.SIZE - tileY);
|
||||
dx = flipLongitude(dx, maxx);
|
||||
|
||||
s.texRegion = ti.texRegion;
|
||||
s.x = (float) ((dx + ti.x) * scale);
|
||||
s.y = (float) ((dy + ti.y) * scale);
|
||||
s.billboard = true;
|
||||
for (SymbolItem ti = t.symbols; ti != null; ti = ti.next) {
|
||||
if (ti.texRegion == null)
|
||||
continue;
|
||||
|
||||
sl.addSymbol(s);
|
||||
SymbolItem s = SymbolItem.pool.get();
|
||||
|
||||
s.texRegion = ti.texRegion;
|
||||
s.x = (float) ((dx + ti.x) * scale);
|
||||
s.y = (float) ((dy + ti.y) * scale);
|
||||
s.billboard = true;
|
||||
|
||||
sl.addSymbol(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -588,11 +607,6 @@ class TextRenderer extends ElementRenderer {
|
||||
public synchronized void update(MapPosition pos, boolean changed,
|
||||
Matrices matrices) {
|
||||
|
||||
//if (System.currentTimeMillis() - lastDraw > 1000){
|
||||
// updateLabels();
|
||||
// lastDraw = System.currentTimeMillis();
|
||||
//
|
||||
//}
|
||||
if (mNextLayer.ready) {
|
||||
// exchange current with next layers
|
||||
TextureLayers tmp = mCurLayer;
|
||||
@ -615,127 +629,68 @@ class TextRenderer extends ElementRenderer {
|
||||
compile();
|
||||
}
|
||||
|
||||
if (mRequestClear)
|
||||
cleanup();
|
||||
|
||||
//if (!mHolding)
|
||||
postLabelTask();
|
||||
}
|
||||
|
||||
/* private */LabelTask mLabelTask;
|
||||
/* private */long mLastRun;
|
||||
/* private */boolean mRequestRun;
|
||||
/* private */boolean mRequestClear;
|
||||
/* private */boolean mRelabel;
|
||||
|
||||
class LabelTask implements Runnable {
|
||||
private boolean isCancelled;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
boolean labelsChanged = false;
|
||||
if (isCancelled) {
|
||||
return;
|
||||
}
|
||||
long now = System.currentTimeMillis();
|
||||
//log.debug("relabel after " + (now - mLastRun));
|
||||
mLastRun = now;
|
||||
|
||||
labelsChanged = updateLabels();
|
||||
|
||||
if (!isCancelled && labelsChanged)
|
||||
mMap.render();
|
||||
|
||||
mLabelTask = null;
|
||||
mRequestRun = false;
|
||||
isCancelled = false;
|
||||
|
||||
if (mRelabel) {
|
||||
mRelabel = false;
|
||||
postLabelTask();
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
isCancelled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* private */void cleanup() {
|
||||
mLabels = (Label) mPool.releaseAll(mLabels);
|
||||
mTileSet.releaseTiles();
|
||||
mLabelTask = null;
|
||||
mRequestClear = false;
|
||||
}
|
||||
|
||||
private final Runnable mLabelUpdate = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mLabelTask == null) {
|
||||
mLabelTask = new LabelTask();
|
||||
mMap.addTask(mLabelTask);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* private */void postLabelTask() {
|
||||
synchronized (mLabelUpdate) {
|
||||
if (mRequestRun) {
|
||||
mRelabel = true;
|
||||
} else {
|
||||
mRequestRun = true;
|
||||
long delay = (mLastRun + MAX_RELABEL_DELAY) - System.currentTimeMillis();
|
||||
//log.debug("relabel in: " + delay);
|
||||
mMap.postDelayed(mLabelUpdate, Math.max(delay, 0));
|
||||
}
|
||||
}
|
||||
mLabelTask.submit((mLastRun + MAX_RELABEL_DELAY) - System.currentTimeMillis());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void render(MapPosition pos, Matrices m) {
|
||||
|
||||
layers.vbo.bind();
|
||||
GLState.test(false, false);
|
||||
|
||||
float scale = (float) (mMapPosition.scale / pos.scale);
|
||||
|
||||
setMatrix(pos, m, true);
|
||||
|
||||
if (layers.baseLayers != null) {
|
||||
for (RenderElement l = layers.baseLayers; l != null;) {
|
||||
if (l.type == RenderElement.POLYGON) {
|
||||
l = PolygonLayer.Renderer.draw(pos, l, m, true, 1, false);
|
||||
} else {
|
||||
float div = scale * (float) (pos.scale / (1 << pos.zoomLevel));
|
||||
l = LineLayer.Renderer.draw(layers, l, pos, m, div, 0);
|
||||
synchronized (layers) {
|
||||
layers.vbo.bind();
|
||||
if (layers.baseLayers != null) {
|
||||
for (RenderElement l = layers.baseLayers; l != null;) {
|
||||
if (l.type == RenderElement.POLYGON) {
|
||||
l = PolygonLayer.Renderer.draw(pos, l, m, true, 1, false);
|
||||
} else {
|
||||
float div = scale * (float) (pos.scale / (1 << pos.zoomLevel));
|
||||
l = LineLayer.Renderer.draw(layers, l, pos, m, div, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setMatrix(pos, m, false);
|
||||
|
||||
for (RenderElement l = layers.textureLayers; l != null;)
|
||||
l = TextureLayer.Renderer.draw(l, scale, m);
|
||||
}
|
||||
|
||||
setMatrix(pos, m, false);
|
||||
|
||||
for (RenderElement l = layers.textureLayers; l != null;)
|
||||
l = TextureLayer.Renderer.draw(l, scale, m);
|
||||
}
|
||||
|
||||
//private boolean mHolding;
|
||||
final class LabelTask extends ContinuousTask {
|
||||
|
||||
/**
|
||||
* @param enable layer updates
|
||||
*/
|
||||
public synchronized void hold(boolean enable) {
|
||||
// mHolding = enable;
|
||||
// if (!enable)
|
||||
// runLabelTask();
|
||||
public LabelTask(Map map) {
|
||||
super(map, 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doWork() {
|
||||
|
||||
if (updateLabels())
|
||||
mMap.render();
|
||||
|
||||
mLastRun = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
clearLabelsInternal();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void clearLabels() {
|
||||
if (mRequestRun) {
|
||||
mRequestClear = true;
|
||||
//mRelabel = true;
|
||||
} else {
|
||||
cleanup();
|
||||
//postLabelTask();
|
||||
}
|
||||
private final LabelTask mLabelTask;
|
||||
|
||||
/* private */long mLastRun;
|
||||
|
||||
/* private */void clearLabelsInternal() {
|
||||
mLabels = (Label) mPool.releaseAll(mLabels);
|
||||
mTileSet.releaseTiles();
|
||||
}
|
||||
|
||||
public void clearLabels() {
|
||||
mLabelTask.cancel();
|
||||
}
|
||||
}
|
||||
|
@ -90,10 +90,6 @@ public class MapRenderer {
|
||||
|
||||
private static volatile boolean mUpdateColor = false;
|
||||
|
||||
// drawlock to synchronize Main- and GL-Thread
|
||||
// static ReentrantLock tilelock = new ReentrantLock();
|
||||
public static Object drawlock = new Object();
|
||||
|
||||
public static long frametime;
|
||||
|
||||
// Do not use the same buffer to upload data within a frame twice
|
||||
@ -210,13 +206,8 @@ public class MapRenderer {
|
||||
}
|
||||
|
||||
public void onDrawFrame() {
|
||||
|
||||
// prevent main thread recreating all tiles (updateMap)
|
||||
// while rendering is going on.
|
||||
synchronized (drawlock) {
|
||||
frametime = System.currentTimeMillis();
|
||||
draw();
|
||||
}
|
||||
frametime = System.currentTimeMillis();
|
||||
draw();
|
||||
|
||||
mBufferPool.releaseBuffers();
|
||||
}
|
||||
|
@ -61,6 +61,8 @@ public class MapTile extends Tile {
|
||||
*/
|
||||
public final static byte STATE_ERROR = 1 << 3;
|
||||
|
||||
public final static byte STATE_CANCEL = 1 << 4;
|
||||
|
||||
/**
|
||||
* absolute tile coordinates: tileX,Y / Math.pow(2, zoomLevel)
|
||||
*/
|
||||
@ -89,7 +91,7 @@ public class MapTile extends Tile {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tile is in view region. Set by GLRenderer.
|
||||
* Tile is in view region. Set by TileRenderer.
|
||||
*/
|
||||
public boolean isVisible;
|
||||
|
||||
@ -100,7 +102,6 @@ public class MapTile extends Tile {
|
||||
|
||||
/**
|
||||
* to avoid drawing a tile twice per frame
|
||||
* FIXME what if multiple layers use the same tile?
|
||||
*/
|
||||
int lastDraw = 0;
|
||||
|
||||
|
@ -42,6 +42,7 @@ public abstract class TileLoader extends PausableThread {
|
||||
|
||||
@Override
|
||||
protected void doWork() {
|
||||
|
||||
MapTile tile = mTileManager.getTileJob();
|
||||
|
||||
if (tile == null)
|
||||
@ -53,7 +54,7 @@ public abstract class TileLoader extends PausableThread {
|
||||
success = executeJob(tile);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (isInterrupted())
|
||||
|
@ -17,9 +17,9 @@
|
||||
|
||||
package org.oscim.tiling;
|
||||
|
||||
import static org.oscim.tiling.MapTile.STATE_CANCEL;
|
||||
import static org.oscim.tiling.MapTile.STATE_LOADING;
|
||||
import static org.oscim.tiling.MapTile.STATE_NEW_DATA;
|
||||
import static org.oscim.tiling.MapTile.STATE_NONE;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -29,7 +29,6 @@ import org.oscim.core.Tile;
|
||||
import org.oscim.map.Map;
|
||||
import org.oscim.map.Viewport;
|
||||
import org.oscim.renderer.BufferObject;
|
||||
import org.oscim.renderer.MapRenderer;
|
||||
import org.oscim.utils.FastMath;
|
||||
import org.oscim.utils.ScanBox;
|
||||
import org.oscim.utils.quadtree.QuadTree;
|
||||
@ -132,11 +131,6 @@ public class TileManager {
|
||||
mUpdateSerial = 0;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
// there might be some leaks in here
|
||||
// ... free static pools
|
||||
}
|
||||
|
||||
private int[] mZoomTable;
|
||||
|
||||
public void setZoomTable(int[] zoomLevel) {
|
||||
@ -144,40 +138,23 @@ public class TileManager {
|
||||
|
||||
}
|
||||
|
||||
public void init(boolean first) {
|
||||
public void init() {
|
||||
// pass VBOs and VertexItems back to pools
|
||||
for (int i = 0; i < mTilesSize; i++)
|
||||
clearTile(mTiles[i]);
|
||||
|
||||
// sync with GLRender thread
|
||||
// ... and labeling thread?
|
||||
synchronized (MapRenderer.drawlock) {
|
||||
// clear references to cached MapTiles
|
||||
Arrays.fill(mTiles, null);
|
||||
mTilesSize = 0;
|
||||
mTilesCount = 0;
|
||||
|
||||
if (!first) {
|
||||
// pass VBOs and VertexItems back to pools
|
||||
for (int i = 0; i < mTilesSize; i++)
|
||||
clearTile(mTiles[i]);
|
||||
}
|
||||
// set up TileSet large enough to hold current tiles
|
||||
int num = Math.max(mMap.getWidth(), mMap.getHeight());
|
||||
int size = Tile.SIZE >> 1;
|
||||
int numTiles = (num * num) / (size * size) * 4;
|
||||
|
||||
// FIXME any of this still needed?
|
||||
// mInitialized is set when surface changed
|
||||
// and VBOs might be lost
|
||||
// VertexPool.init();
|
||||
// clear cache index
|
||||
// QuadTree.init();
|
||||
|
||||
// clear references to cached MapTiles
|
||||
Arrays.fill(mTiles, null);
|
||||
mTilesSize = 0;
|
||||
mTilesCount = 0;
|
||||
|
||||
// set up TileSet large enough to hold current tiles
|
||||
int num = Math.max(mMap.getWidth(), mMap.getHeight());
|
||||
int size = Tile.SIZE >> 1;
|
||||
int numTiles = (num * num) / (size * size) * 4;
|
||||
|
||||
mNewTiles = new TileSet(numTiles);
|
||||
mCurrentTiles = new TileSet(numTiles);
|
||||
log.debug("max tiles: " + numTiles);
|
||||
|
||||
}
|
||||
mNewTiles = new TileSet(numTiles);
|
||||
mCurrentTiles = new TileSet(numTiles);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -187,7 +164,7 @@ public class TileManager {
|
||||
* @param pos
|
||||
* current MapPosition
|
||||
*/
|
||||
public synchronized boolean update(MapPosition pos) {
|
||||
public boolean update(MapPosition pos) {
|
||||
// clear JobQueue and set tiles to state == NONE.
|
||||
// one could also append new tiles and sort in JobQueue
|
||||
// but this has the nice side-effect that MapWorkers dont
|
||||
@ -405,13 +382,14 @@ public class TileManager {
|
||||
if (t == null)
|
||||
return;
|
||||
|
||||
t.clear();
|
||||
|
||||
mIndex.remove(t);
|
||||
|
||||
// QuadTree.remove(t);
|
||||
t.state = STATE_NONE;
|
||||
synchronized (t) {
|
||||
// still belongs to TileLoader thread
|
||||
if (t.state != STATE_LOADING)
|
||||
t.clear();
|
||||
|
||||
t.state = STATE_CANCEL;
|
||||
mIndex.remove(t);
|
||||
}
|
||||
mTilesCount--;
|
||||
}
|
||||
|
||||
@ -549,8 +527,7 @@ public class TileManager {
|
||||
* @return caller does not care
|
||||
*/
|
||||
public void jobCompleted(MapTile tile, boolean success) {
|
||||
|
||||
if (!success) {
|
||||
if (!success || tile.state == STATE_CANCEL) {
|
||||
tile.clear();
|
||||
return;
|
||||
}
|
||||
|
@ -64,8 +64,11 @@ public class TileRenderer extends LayerRenderer {
|
||||
mAlpha = alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* synced with clearTiles
|
||||
*/
|
||||
@Override
|
||||
protected void update(MapPosition pos, boolean positionChanged, Matrices m) {
|
||||
protected synchronized void update(MapPosition pos, boolean positionChanged, Matrices m) {
|
||||
|
||||
if (mAlpha == 0) {
|
||||
mTileManager.releaseTiles(mDrawTiles);
|
||||
@ -106,9 +109,7 @@ public class TileRenderer extends LayerRenderer {
|
||||
public void clearTiles() {
|
||||
// Clear all references to MapTiles as all current
|
||||
// tiles will also be removed from TileManager.
|
||||
synchronized (MapRenderer.drawlock) {
|
||||
mDrawTiles = new TileSet();
|
||||
}
|
||||
mDrawTiles = new TileSet();
|
||||
}
|
||||
|
||||
/** compile tile layer data and upload to VBOs */
|
||||
|
@ -56,6 +56,7 @@ public class LwHttp {
|
||||
private Socket mSocket;
|
||||
private OutputStream mCommandStream;
|
||||
private InputStream mResponseStream;
|
||||
private OutputStream mCacheOutputStream;
|
||||
private long mLastRequest = 0;
|
||||
private SocketAddress mSockAddr;
|
||||
|
||||
@ -106,40 +107,34 @@ public class LwHttp {
|
||||
}
|
||||
|
||||
static class Buffer extends BufferedInputStream {
|
||||
final OutputStream mCache;
|
||||
final OutputStream mCacheOutputstream;
|
||||
|
||||
public Buffer(InputStream is, OutputStream cache) {
|
||||
super(is, 4096);
|
||||
mCache = cache;
|
||||
mCacheOutputstream = cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int read() throws IOException {
|
||||
public int read() throws IOException {
|
||||
int data = super.read();
|
||||
if (data >= 0)
|
||||
mCache.write(data);
|
||||
mCacheOutputstream.write(data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int read(byte[] buffer, int offset, int byteCount)
|
||||
public int read(byte[] buffer, int offset, int byteCount)
|
||||
throws IOException {
|
||||
int len = super.read(buffer, offset, byteCount);
|
||||
|
||||
if (len >= 0)
|
||||
mCache.write(buffer, offset, len);
|
||||
mCacheOutputstream.write(buffer, offset, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
OutputStream mCacheOutputStream;
|
||||
|
||||
public void setOutputStream(OutputStream outputStream) {
|
||||
mCacheOutputStream = outputStream;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (mSocket != null) {
|
||||
try {
|
||||
@ -177,6 +172,10 @@ public class LwHttp {
|
||||
while (end < read && (buf[end] != '\n'))
|
||||
end++;
|
||||
|
||||
if (end == BUFFER_SIZE) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (buf[end] != '\n')
|
||||
continue;
|
||||
|
||||
@ -209,7 +208,7 @@ public class LwHttp {
|
||||
|
||||
if (!ok) {
|
||||
String line = new String(buf, pos, end - pos - 1);
|
||||
log.debug(">" + line + "< ");
|
||||
log.debug("> {} <", line);
|
||||
}
|
||||
|
||||
pos += (end - pos) + 1;
|
||||
@ -255,12 +254,14 @@ public class LwHttp {
|
||||
mMaxReq = RESPONSE_EXPECTED_LIVES;
|
||||
// log.debug("create connection");
|
||||
} else {
|
||||
// FIXME not sure if this is correct way to drain socket
|
||||
int avail = mResponseStream.available();
|
||||
if (avail > 0) {
|
||||
log.debug("Consume left-over bytes: " + avail);
|
||||
while ((avail = mResponseStream.available()) > 0)
|
||||
mResponseStream.read(buffer);
|
||||
log.debug("left-over bytes: " + avail);
|
||||
close();
|
||||
lwHttpConnect();
|
||||
// FIXME not sure if this is correct way to drain socket
|
||||
//while ((avail = mResponseStream.available()) > 0)
|
||||
// mResponseStream.read(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -353,8 +354,16 @@ public class LwHttp {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void requestCompleted() {
|
||||
public void setOutputStream(OutputStream outputStream) {
|
||||
mCacheOutputStream = outputStream;
|
||||
}
|
||||
|
||||
public void requestCompleted(boolean keepConnection) {
|
||||
mLastRequest = System.nanoTime();
|
||||
mCacheOutputStream = null;
|
||||
|
||||
if (!keepConnection)
|
||||
close();
|
||||
}
|
||||
|
||||
public int getContentLength() {
|
||||
|
@ -30,10 +30,6 @@ import org.oscim.utils.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
public abstract class PbfTileDataSource implements ITileDataSource {
|
||||
static final Logger log = LoggerFactory.getLogger(PbfTileDataSource.class);
|
||||
|
||||
@ -48,66 +44,55 @@ public abstract class PbfTileDataSource implements ITileDataSource {
|
||||
|
||||
@Override
|
||||
public QueryResult executeQuery(MapTile tile, ITileDataSink sink) {
|
||||
boolean success = true;
|
||||
|
||||
ITileCache.TileWriter cacheWriter = null;
|
||||
|
||||
if (mTileCache != null) {
|
||||
ITileCache.TileReader c = mTileCache.getTile(tile);
|
||||
if (c == null) {
|
||||
// create new cache entry
|
||||
cacheWriter = mTileCache.writeTile(tile);
|
||||
mConn.setOutputStream(cacheWriter.getOutputStream());
|
||||
} else {
|
||||
InputStream is = c.getInputStream();
|
||||
try {
|
||||
InputStream is = c.getInputStream();
|
||||
if (mTileDecoder.decode(tile, sink, is, c.getBytes())) {
|
||||
IOUtils.closeQuietly(is);
|
||||
return QueryResult.SUCCESS;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IOUtils.closeQuietly(is);
|
||||
}
|
||||
log.debug(tile + " Cache read failed");
|
||||
}
|
||||
}
|
||||
|
||||
boolean success = false;
|
||||
try {
|
||||
if (cacheWriter != null)
|
||||
mConn.setOutputStream(cacheWriter.getOutputStream());
|
||||
|
||||
InputStream is;
|
||||
if (!mConn.sendRequest(tile)) {
|
||||
log.debug(tile + " Request failed");
|
||||
success = false;
|
||||
} else if ((is = mConn.readHeader()) != null) {
|
||||
log.debug("{} Request failed", tile);
|
||||
} else if ((is = mConn.readHeader()) == null) {
|
||||
log.debug("{} Network Error", tile);
|
||||
} else {
|
||||
int bytes = mConn.getContentLength();
|
||||
success = mTileDecoder.decode(tile, sink, is, bytes);
|
||||
if (!success)
|
||||
log.debug(tile + " Decoding failed");
|
||||
} else {
|
||||
log.debug(tile + " Network Error");
|
||||
success = false;
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
log.debug(tile + " Socket exception: " + e.getMessage());
|
||||
success = false;
|
||||
log.debug("{} Socket exception: {}", tile, e.getMessage());
|
||||
} catch (SocketTimeoutException e) {
|
||||
log.debug(tile + " Socket Timeout");
|
||||
success = false;
|
||||
log.debug("{} Socket Timeout", tile);
|
||||
} catch (UnknownHostException e) {
|
||||
log.debug(tile + " No Network");
|
||||
success = false;
|
||||
} catch (Exception e) {
|
||||
log.debug("{} No Network", tile);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
success = false;
|
||||
} finally {
|
||||
mConn.requestCompleted(success);
|
||||
|
||||
if (cacheWriter != null)
|
||||
cacheWriter.complete(success);
|
||||
}
|
||||
|
||||
mConn.requestCompleted();
|
||||
|
||||
if (cacheWriter != null)
|
||||
cacheWriter.complete(success);
|
||||
|
||||
if (success)
|
||||
mConn.close();
|
||||
|
||||
return success ? QueryResult.SUCCESS : QueryResult.FAILED;
|
||||
}
|
||||
|
||||
|
@ -17,12 +17,18 @@
|
||||
*/
|
||||
package org.oscim.utils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* An abstract base class for threads which support pausing and resuming.
|
||||
*/
|
||||
public abstract class PausableThread extends Thread {
|
||||
private final static Logger log = LoggerFactory.getLogger(PausableThread.class);
|
||||
private final static boolean DEBUG = false;
|
||||
|
||||
private boolean mPausing = true;
|
||||
private boolean mShouldPause;
|
||||
private boolean mShouldPause = false;
|
||||
|
||||
/**
|
||||
* Causes the current thread to wait until this thread is pausing.
|
||||
@ -30,8 +36,10 @@ public abstract class PausableThread extends Thread {
|
||||
public final void awaitPausing() {
|
||||
synchronized (this) {
|
||||
while (!isInterrupted() && !isPausing()) {
|
||||
if (DEBUG)
|
||||
log.debug("await {}", getThreadName());
|
||||
try {
|
||||
wait(100);
|
||||
wait(10);
|
||||
} catch (InterruptedException e) {
|
||||
// restore the interrupted status
|
||||
Thread.currentThread().interrupt();
|
||||
@ -42,17 +50,13 @@ public abstract class PausableThread extends Thread {
|
||||
|
||||
@Override
|
||||
public void interrupt() {
|
||||
if (DEBUG)
|
||||
log.debug("interrupt {}", getThreadName());
|
||||
|
||||
// first acquire the monitor which is used to call wait()
|
||||
synchronized (this) {
|
||||
super.interrupt();
|
||||
}
|
||||
|
||||
//try {
|
||||
// this.join(10000);
|
||||
//} catch (InterruptedException e) {
|
||||
// // restore the interrupted status
|
||||
// Thread.currentThread().interrupt();
|
||||
//}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,14 +76,16 @@ public abstract class PausableThread extends Thread {
|
||||
}
|
||||
}
|
||||
|
||||
public final synchronized boolean isCanceled() {
|
||||
return mShouldPause;
|
||||
}
|
||||
|
||||
/**
|
||||
* The paused thread should continue with its work.
|
||||
*/
|
||||
public final synchronized void proceed() {
|
||||
if (mShouldPause) {
|
||||
mShouldPause = false;
|
||||
mPausing = false;
|
||||
afterPause();
|
||||
notify();
|
||||
}
|
||||
}
|
||||
@ -102,6 +108,14 @@ public abstract class PausableThread extends Thread {
|
||||
interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
if (mPausing) {
|
||||
mPausing = false;
|
||||
afterPause();
|
||||
}
|
||||
|
||||
if (DEBUG)
|
||||
log.debug("resume {}", getThreadName());
|
||||
}
|
||||
|
||||
if (isInterrupted()) {
|
||||
@ -116,6 +130,11 @@ public abstract class PausableThread extends Thread {
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG)
|
||||
log.debug("finish {}", getThreadName());
|
||||
|
||||
mPausing = true;
|
||||
|
||||
afterRun();
|
||||
}
|
||||
|
||||
|
91
vtm/src/org/oscim/utils/async/ContinuousTask.java
Normal file
91
vtm/src/org/oscim/utils/async/ContinuousTask.java
Normal file
@ -0,0 +1,91 @@
|
||||
package org.oscim.utils.async;
|
||||
|
||||
import org.oscim.map.Map;
|
||||
|
||||
public abstract class ContinuousTask implements Runnable {
|
||||
private final Map mMap;
|
||||
|
||||
protected boolean mRunning;
|
||||
protected boolean mWait;
|
||||
protected boolean mCancel;
|
||||
protected boolean mDelayed;
|
||||
|
||||
protected long mMinDelay;
|
||||
|
||||
public ContinuousTask(Map map, long minDelay) {
|
||||
mMap = map;
|
||||
mMinDelay = minDelay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
synchronized (this) {
|
||||
//System.out.println("run " + mRunning + " "
|
||||
// + mCancel + " " + mDelayed + " " + mWait);
|
||||
|
||||
if (mCancel) {
|
||||
mCancel = false;
|
||||
mRunning = false;
|
||||
mDelayed = false;
|
||||
mWait = false;
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
if (mDelayed) {
|
||||
// entered on main-loop
|
||||
mDelayed = false;
|
||||
mWait = false;
|
||||
// unset running temporarily
|
||||
mRunning = false;
|
||||
submit(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
doWork();
|
||||
|
||||
synchronized (this) {
|
||||
mRunning = false;
|
||||
|
||||
if (mCancel)
|
||||
cleanup();
|
||||
else if (mWait)
|
||||
submit(mMinDelay);
|
||||
|
||||
mCancel = false;
|
||||
mWait = false;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void doWork();
|
||||
|
||||
public abstract void cleanup();
|
||||
|
||||
public synchronized void submit(long delay) {
|
||||
//System.out.println("submit " + mRunning + " " + mCancel + " " + delay);
|
||||
|
||||
if (mRunning) {
|
||||
mWait = true;
|
||||
return;
|
||||
}
|
||||
mRunning = true;
|
||||
if (delay <= 0) {
|
||||
mMap.addTask(this);
|
||||
return;
|
||||
}
|
||||
|
||||
mDelayed = true;
|
||||
mMap.postDelayed(this, delay);
|
||||
|
||||
}
|
||||
|
||||
public synchronized void cancel() {
|
||||
if (mRunning) {
|
||||
mCancel = true;
|
||||
return;
|
||||
}
|
||||
|
||||
cleanup();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user