package net.osmand.core.android; import android.graphics.Bitmap; import java.io.IOException; import net.osmand.IndexConstants; import net.osmand.core.jni.AlphaChannelPresence; import net.osmand.core.jni.IMapDataProvider; import net.osmand.core.jni.MapStubStyle; import net.osmand.core.jni.SWIGTYPE_p_QByteArray; import net.osmand.core.jni.SwigUtilities; import net.osmand.core.jni.TileId; import net.osmand.core.jni.ZoomLevel; import net.osmand.core.jni.interface_ImageMapLayerProvider; import net.osmand.core.jni.IMapTiledDataProvider; import net.osmand.core.jni.ImageMapLayerProvider; import net.osmand.map.ITileSource; import net.osmand.map.MapTileDownloader; import net.osmand.plus.OsmandApplication; import net.osmand.plus.resources.AsyncLoadingThread; import net.osmand.plus.resources.ResourceManager; public class TileSourceProxyProvider extends interface_ImageMapLayerProvider { private final OsmandApplication app; private final ITileSource tileSource; public TileSourceProxyProvider(OsmandApplication app, ITileSource tileSource) { this.app = app; this.tileSource = tileSource; } @Override public MapStubStyle getDesiredStubsStyle() { return MapStubStyle.Unspecified; } @Override public ZoomLevel getMinZoom() { return ZoomLevel.swigToEnum(tileSource.getMinimumZoomSupported()); } @Override public ZoomLevel getMaxZoom() { return ZoomLevel.swigToEnum(tileSource.getMaximumZoomSupported()); } @Override public boolean supportsNaturalObtainData() { return true; } @Override public SWIGTYPE_p_QByteArray obtainImage(IMapTiledDataProvider.Request request) { byte[] image; try { ResourceManager rm = app.getResourceManager(); String tileFilename = rm.calculateTileId(tileSource, request.getTileId().getX(), request.getTileId().getY(), request.getZoom().swigValue()); final TileReadyCallback tileReadyCallback = new TileReadyCallback(tileSource, request.getTileId().getX(), request.getTileId().getY(), request.getZoom().swigValue()); rm.getMapTileDownloader().addDownloaderCallback(tileReadyCallback); while (rm.getTileImageForMapAsync(tileFilename, tileSource, request.getTileId().getX(), request.getTileId().getY(), request.getZoom().swigValue(), true) == null) { synchronized (tileReadyCallback.getSync()) { if (tileReadyCallback.isReady()) { break; } try { tileReadyCallback.getSync().wait(50); } catch (InterruptedException e) { } } } rm.getMapTileDownloader().removeDownloaderCallback(tileReadyCallback); image = tileSource.getBytes(request.getTileId().getX(), request.getTileId().getY(), request.getZoom().swigValue(), app.getAppPath(IndexConstants.TILES_INDEX_DIR).getAbsolutePath()); } catch(IOException e) { return SwigUtilities.emptyQByteArray(); } if (image == null) return SwigUtilities.emptyQByteArray(); return SwigUtilities.createQByteArrayAsCopyOf(image); } @Override public boolean supportsNaturalObtainDataAsync() { return false; } @Override public void obtainImageAsync(IMapTiledDataProvider.Request request, ImageMapLayerProvider.AsyncImage asyncImage) { //TODO: Launch the request via manager and after image is ready (or error is ready) // call asyncImage.submit() } @Override public long getTileSize() { return tileSource.getTileSize(); } @Override public float getTileDensityFactor() { return 1.0f; } @Override public AlphaChannelPresence getAlphaChannelPresence() { return AlphaChannelPresence.Unknown; } private static class TileReadyCallback implements MapTileDownloader.IMapDownloaderCallback { private final ITileSource tileSource; private final int x; private final int y; private final int zoom; private boolean ready = false; private final Object sync = new Object(); public TileReadyCallback(ITileSource tileSource, int x, int y, int zoom) { this.tileSource = tileSource; this.x = x; this.y = y; this.zoom = zoom; } public boolean isReady() { return ready; } public Object getSync() { return sync; } @Override public void tileDownloaded(MapTileDownloader.DownloadRequest request) { if (!(request instanceof AsyncLoadingThread.TileLoadDownloadRequest)) { return; } AsyncLoadingThread.TileLoadDownloadRequest tileLoadRequest = (AsyncLoadingThread.TileLoadDownloadRequest)request; if (tileSource != tileLoadRequest.tileSource || x != tileLoadRequest.xTile || y != tileLoadRequest.yTile || zoom != tileLoadRequest.zoom) { return; } synchronized (sync) { ready = true; sync.notifyAll(); } } } }