package org.mapsforge.android.maps;
import android.app.Application;
import android.content.Context;
import android.util.Log;
import com.google.android.gms.maps.model.TileProvider;
import org.mapsforge.core.graphics.TileBitmap;
import org.mapsforge.core.model.Tile;
import org.mapsforge.map.android.graphics.AndroidGraphicFactory;
import org.mapsforge.map.datastore.MapDataStore;
import org.mapsforge.map.layer.cache.InMemoryTileCache;
import org.mapsforge.map.layer.cache.TileCache;
import org.mapsforge.map.layer.hills.HillsRenderConfig;
import org.mapsforge.map.layer.labels.TileBasedLabelStore;
import org.mapsforge.map.layer.renderer.DatabaseRenderer;
import org.mapsforge.map.layer.renderer.RendererJob;
import org.mapsforge.map.model.DisplayModel;
import org.mapsforge.map.model.FixedTileSizeDisplayModel;
import org.mapsforge.map.rendertheme.InternalRenderTheme;
import org.mapsforge.map.rendertheme.XmlRenderTheme;
import org.mapsforge.map.rendertheme.rule.RenderThemeFuture;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class MapsforgeTileProvider implements TileProvider {
private static final float MAPSFORGE_TILE_PROVIDER_VERSION=1f;
private static final String TAG= MapsforgeTileProvider.class.getSimpleName();
private static final int TILE_SIZE=256;
private static boolean androidGraphicFactoryCreated=false;
private final ByteArrayOutputStream byteArrayOutputStream;
private final boolean cacheLabels;
private final DatabaseRenderer databaseRenderer;
private final DisplayModel displayModel;
private final TileCache inMemoryTileCache;
private final boolean isTransparent;
private final boolean labelsOnly;
private final MapDataStore mapDataStore;
private final com.google.android.gms.maps.model.Tile noTileTile;
private final RenderThemeFuture renderThemeFuture;
private final float textScale;
public MapsforgeTileProvider(Context context, MapsforgeTileProviderOptions mapsForgeTileProviderOptions){
if(!androidGraphicFactoryCreated){
AndroidGraphicFactory.createInstance((Application) context.getApplicationContext());
androidGraphicFactoryCreated=true;
}
byteArrayOutputStream=new ByteArrayOutputStream(mapsForgeTileProviderOptions.outputStreamCapacity);
cacheLabels=mapsForgeTileProviderOptions.cacheLabels;
displayModel = new FixedTileSizeDisplayModel(TILE_SIZE);
inMemoryTileCache = new InMemoryTileCache(mapsForgeTileProviderOptions.tileCacheCapacity);
isTransparent=mapsForgeTileProviderOptions.isTransparent;
labelsOnly=mapsForgeTileProviderOptions.labelsOnly;
this.mapDataStore=mapsForgeTileProviderOptions.mapDataStore;
noTileTile=mapsForgeTileProviderOptions.noTileTile;
textScale=mapsForgeTileProviderOptions.textScale;
renderThemeFuture = new RenderThemeFuture(
AndroidGraphicFactory.INSTANCE,
mapsForgeTileProviderOptions.xmlRenderTheme,
displayModel);
Thread renderThemeFutureThread = new Thread(renderThemeFuture);
renderThemeFutureThread.start();
TileBasedLabelStore tileBasedLabelStore = new TileBasedLabelStore(inMemoryTileCache.getCapacityFirstLevel());
databaseRenderer = new DatabaseRenderer(
mapDataStore,
AndroidGraphicFactory.INSTANCE,
inMemoryTileCache,
tileBasedLabelStore,
mapsForgeTileProviderOptions.renderLabels,
cacheLabels,
mapsForgeTileProviderOptions.hillsRenderConfig);
}
public void close(){
try {
byteArrayOutputStream.close();
} catch (IOException e) {
Log.e(TAG, null, e);
}
renderThemeFuture.cancel(true); // needed or useful?
inMemoryTileCache.destroy();
mapDataStore.close();
}
@Override
public synchronized com.google.android.gms.maps.model.Tile getTile(int x, int y, int zoom) {
com.google.android.gms.maps.model.Tile googleTile;
final org.mapsforge.core.model.Tile mapsforgeTile = new Tile(x, y, (byte) zoom, TILE_SIZE);
if(mapDataStore.supportsTile(mapsforgeTile)){
final RendererJob rendererJob = new RendererJob(mapsforgeTile, mapDataStore, renderThemeFuture, displayModel, textScale, isTransparent, labelsOnly);
try {
final TileBitmap tileBitmap = databaseRenderer.executeJob(rendererJob);
inMemoryTileCache.put(rendererJob, tileBitmap);
tileBitmap.compress(byteArrayOutputStream);
googleTile=new com.google.android.gms.maps.model.Tile(TILE_SIZE, TILE_SIZE, byteArrayOutputStream.toByteArray());
byteArrayOutputStream.reset();
} catch (IOException e) {
Log.e(TAG, null, e);
googleTile=null;
}
} else {
googleTile=noTileTile;
}
return googleTile;
}
public static class MapsforgeTileProviderOptions {
private static final boolean CACHE_LABELS=true;
private static final HillsRenderConfig HILLS_RENDER_CONFIG=null;
private static final boolean IS_TRANSPARENT=true;
private static final boolean LABELS_ONLY=false;
private static final int OUTPUT_STREAM_CAPACITY=(256*1024);
private static final boolean RENDER_LABELS=true;
private static final float TEXT_SCALE=1f;
private static final int TILE_CACHE_CAPACITY=32;
protected boolean cacheLabels=CACHE_LABELS;
protected HillsRenderConfig hillsRenderConfig=HILLS_RENDER_CONFIG;
protected boolean isTransparent=IS_TRANSPARENT;
protected boolean labelsOnly=LABELS_ONLY;
protected MapDataStore mapDataStore=null;
protected com.google.android.gms.maps.model.Tile noTileTile=com.google.android.gms.maps.model.TileProvider.NO_TILE;
protected int outputStreamCapacity=OUTPUT_STREAM_CAPACITY;
protected boolean renderLabels=RENDER_LABELS;
protected float textScale=TEXT_SCALE;
protected int tileCacheCapacity=TILE_CACHE_CAPACITY;
protected XmlRenderTheme xmlRenderTheme=InternalRenderTheme.OSMARENDER;
public void setCacheLabels(boolean cacheLabels){
this.cacheLabels=cacheLabels;
}
public void setLabelsOnly(boolean labelsOnly) {
this.labelsOnly = labelsOnly;
}
public void setMapDataStore(MapDataStore mapDataStore) {
this.mapDataStore = mapDataStore;
}
public void setNoTileTile(com.google.android.gms.maps.model.Tile noTileTile){
this.noTileTile=noTileTile;
}
public void setOutputStreamCapacity(int outputStreamCapacity) {
this.outputStreamCapacity = outputStreamCapacity;
}
public void setRenderLabels(boolean renderLabels) {
this.renderLabels = renderLabels;
}
public void setRenderTheme(XmlRenderTheme xmlRenderTheme){
this.xmlRenderTheme=xmlRenderTheme;
}
public void setTextScale(float textScale) {
this.textScale = textScale;
}
public void setTileCacheCapacity(int tileCacheCapacity) {
this.tileCacheCapacity = tileCacheCapacity;
}
public void setTransparent(boolean transparent) {
isTransparent = transparent;
}
}
}