diff --git a/DataExtractionOSM/src/net/osmand/ToDoConstants.java b/DataExtractionOSM/src/net/osmand/ToDoConstants.java index 973ed56580..fb59afb98c 100644 --- a/DataExtractionOSM/src/net/osmand/ToDoConstants.java +++ b/DataExtractionOSM/src/net/osmand/ToDoConstants.java @@ -9,11 +9,15 @@ public class ToDoConstants { // == Osmand application (TODO 127) == + + // TODO support cancelling poi search request! Do it in another thread (Check is cancelled()!!!) TODO transport progress + // TODO redesign Directions using GPX file! (One menu directions <-> switch 'Route') + // TODO test if voice properly inititialized (first command!) + // TODO prepare C++ version of routing algorithm // Map Refactoring // Remove notification from OsmAndMapTileView (?) // Index version - // 1. POI inside obf // 2. Multiple attributes for one point (amenity=circle, type=...) @@ -21,13 +25,9 @@ public class ToDoConstants { // !|| 125 || Introduce service layer rather than singletons and put all related into new package (services). Review architecture. Split some big classes. || // === Common issues === -// || 104 || Add activity to show current loaded indexes and information about them (Issue 366) || -// || 123 || Improve gpx file showing (very slow for big files) (Issue 412) || // || 110 || Use android voice for pronounce command (could be used in future to pronounce street) (Issue 70) || -// || 97 || For voice navigation consider current speed of vehicle. Especially when speed > 50 pronounce more than 200 m (Issue 420) || // || 111 || Investigate showing street name while driving (Issue 286) || // || 86 || Allow to add/edit custom tags to POI objects (Issue 44) || -// || 92 || Support poi index with standard map index and unify POI categories (unify done +, works very slow) (Issue 417) || // || 113 || Calculate speed cameras/bumps on the road (announce about them) (Issue 418) || @@ -43,13 +43,16 @@ public class ToDoConstants { /////////////////////////// DONE ////////////////////////////// // DONE ANDROID : +// || 104 || Add activity to show current loaded indexes and information about them (Issue 366) || // || 112 || Investigate exiting/minimizing app (Issue 214) || // || 122 || Frozen sqlite db images (bug?). When images are loaded into sqlite the whole map is frozen (issue 413) || // || 120 || Show icons over poi circle (issue 414) || // || 119 || Dialog on main screen tips and tricks (Issue 415) || // || 118 || Config switching between maps on different zoom levels <14 (using raster), > 14 vector (Issue 419) || // || 124 || Animated transition using only raster images (?) - skip animations (!) - don not render vectoring for animations (Issue 238) || - +// || 92 || Support poi index with standard map index and unify POI categories (unify done +, works very slow) (Issue 417) || +// || 97 || For voice navigation consider current speed of vehicle. Especially when speed > 50 pronounce more than 200 m (Issue 420) || +// || 123 || Improve gpx file showing (very slow for big files) (Issue 412) || // DONE SWING } diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/IndexPoiCreator.java b/DataExtractionOSM/src/net/osmand/data/preparation/IndexPoiCreator.java index 37715a13ee..a8c6ecc5c5 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/IndexPoiCreator.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/IndexPoiCreator.java @@ -554,7 +554,6 @@ public class IndexPoiCreator extends AbstractIndexPartCreator { } public static void main(String[] args) throws SQLException, FileNotFoundException, IOException { - // TODO support cancelling poi search request! Do it in another thread (Check is cancelled()!!!) long time = System.currentTimeMillis(); IndexPoiCreator poiCreator = new IndexPoiCreator(); // String fileSqlte = "/home/victor/projects/OsmAnd/data/osm-gen/POI/Ru-mow.poi.odb"; diff --git a/OsmAnd/src/net/osmand/plus/AmenityIndexRepository.java b/OsmAnd/src/net/osmand/plus/AmenityIndexRepository.java index 1ab2e9c2aa..d13d2afced 100644 --- a/OsmAnd/src/net/osmand/plus/AmenityIndexRepository.java +++ b/OsmAnd/src/net/osmand/plus/AmenityIndexRepository.java @@ -26,6 +26,6 @@ public interface AmenityIndexRepository { String filterId, List toFill, boolean fillFound); public void evaluateCachedAmenities(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, - PoiFilter filter, List toFill); + PoiFilter filter, ResultMatcher matcher); } diff --git a/OsmAnd/src/net/osmand/plus/AmenityIndexRepositoryBinary.java b/OsmAnd/src/net/osmand/plus/AmenityIndexRepositoryBinary.java index 6a43d54840..4d8afd4cb7 100644 --- a/OsmAnd/src/net/osmand/plus/AmenityIndexRepositoryBinary.java +++ b/OsmAnd/src/net/osmand/plus/AmenityIndexRepositoryBinary.java @@ -141,11 +141,11 @@ public class AmenityIndexRepositoryBinary implements AmenityIndexRepository { @Override public void evaluateCachedAmenities(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, - PoiFilter filter, List toFill) { - cTopLatitude = topLatitude + (topLatitude - bottomLatitude); - cBottomLatitude = bottomLatitude - (topLatitude - bottomLatitude); - cLeftLongitude = leftLongitude - (rightLongitude - leftLongitude); - cRightLongitude = rightLongitude + (rightLongitude - leftLongitude); + PoiFilter filter, ResultMatcher matcher) { + cTopLatitude = topLatitude ; + cBottomLatitude = bottomLatitude ; + cLeftLongitude = leftLongitude ; + cRightLongitude = rightLongitude ; cFilterId = filter == null ? null : filter.getFilterId(); cZoom = zoom; // first of all put all entities in temp list in order to not freeze other read threads @@ -154,14 +154,12 @@ public class AmenityIndexRepositoryBinary implements AmenityIndexRepository { int sright = MapUtils.get31TileNumberX(cRightLongitude); int sbottom = MapUtils.get31TileNumberY(cBottomLatitude); int stop = MapUtils.get31TileNumberY(cTopLatitude); - searchAmenities(stop, sleft, sbottom, sright, zoom, filter, tempList, null); + searchAmenities(stop, sleft, sbottom, sright, zoom, filter, tempList, matcher); synchronized (this) { cachedObjects.clear(); cachedObjects.addAll(tempList); } - checkCachedAmenities(topLatitude, leftLongitude, bottomLatitude, rightLongitude, cZoom, filter.getFilterId(), toFill, true); - } diff --git a/OsmAnd/src/net/osmand/plus/AmenityIndexRepositoryOdb.java b/OsmAnd/src/net/osmand/plus/AmenityIndexRepositoryOdb.java index eeeb184ff9..3e10d3da4a 100644 --- a/OsmAnd/src/net/osmand/plus/AmenityIndexRepositoryOdb.java +++ b/OsmAnd/src/net/osmand/plus/AmenityIndexRepositoryOdb.java @@ -102,12 +102,14 @@ public class AmenityIndexRepositoryOdb extends BaseLocationIndexRepository toFill){ - cTopLatitude = topLatitude + (topLatitude -bottomLatitude); - cBottomLatitude = bottomLatitude - (topLatitude -bottomLatitude); - cLeftLongitude = leftLongitude - (rightLongitude - leftLongitude); - cRightLongitude = rightLongitude + (rightLongitude - leftLongitude); - cFilterId = filter == null? null :filter.getFilterId(); + @Override + public void evaluateCachedAmenities(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, + PoiFilter filter, ResultMatcher matcher) { + cTopLatitude = topLatitude; + cBottomLatitude = bottomLatitude; + cLeftLongitude = leftLongitude; + cRightLongitude = rightLongitude; + cFilterId = filter == null ? null : filter.getFilterId(); cZoom = zoom; // first of all put all entities in temp list in order to not freeze other read threads ArrayList tempList = new ArrayList(); @@ -115,13 +117,11 @@ public class AmenityIndexRepositoryOdb extends BaseLocationIndexRepository toFill, boolean fillFound){ diff --git a/OsmAnd/src/net/osmand/plus/AsyncLoadingThread.java b/OsmAnd/src/net/osmand/plus/AsyncLoadingThread.java new file mode 100644 index 0000000000..878643e072 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/AsyncLoadingThread.java @@ -0,0 +1,339 @@ +package net.osmand.plus; + +import java.io.File; +import java.util.List; +import java.util.Stack; + +import org.apache.commons.logging.Log; + +import android.os.Handler; +import android.os.Looper; + +import net.osmand.Algoritms; +import net.osmand.LogUtil; +import net.osmand.ResultMatcher; +import net.osmand.data.Amenity; +import net.osmand.data.MapTileDownloader; +import net.osmand.data.TransportStop; +import net.osmand.data.MapTileDownloader.DownloadRequest; +import net.osmand.data.MapTileDownloader.IMapDownloaderCallback; +import net.osmand.map.ITileSource; + +/** + * Thread to load map objects (POI, transport stops )async + */ +public class AsyncLoadingThread extends Thread { + + public static final int LIMIT_TRANSPORT = 200; + + private static final Log log = LogUtil.getLog(AsyncLoadingThread.class); + + private Handler asyncLoadingPoi; + private Handler asyncLoadingTransport; + + Stack requests = new Stack(); + AmenityLoadRequest poiLoadRequest = null; + TransportLoadRequest transportLoadRequest = null; + + private static final MapTileDownloader downloader = MapTileDownloader.getInstance(); + + private final ResourceManager resourceManger; + + public AsyncLoadingThread(ResourceManager resourceManger) { + super("Loader map objects (synchronizer)"); //$NON-NLS-1$ + this.resourceManger = resourceManger; + } + + private void startPoiLoadingThread() { + if (asyncLoadingPoi == null) { + Thread th = new Thread(new Runnable() { + @Override + public void run() { + Looper.prepare(); + asyncLoadingPoi = new Handler(); + Looper.loop(); + } + }, "Loading poi"); + th.start(); + } + while(asyncLoadingPoi != null){ + // wait + } + } + + private void startTransportLoadingThread() { + new Thread(new Runnable() { + @Override + public void run() { + Looper.prepare(); + asyncLoadingTransport = new Handler(); + Looper.loop(); + } + }, "Loading transport").start(); + while(asyncLoadingTransport != null){ + // wait + } + } + + private int calculateProgressStatus(){ + int progress = 0; + if (downloader.isSomethingBeingDownloaded()) { + progress = BusyIndicator.STATUS_GREEN; + } else if (resourceManger.getContext().getRoutingHelper().isRouteBeingCalculated()) { + progress = BusyIndicator.STATUS_BLUE; + } else if (!requests.isEmpty()) { + progress = BusyIndicator.STATUS_BLACK; + } else if(poiLoadRequest != null && !poiLoadRequest.isFinished()) { + progress = BusyIndicator.STATUS_BLACK; + } else if(transportLoadRequest != null && !transportLoadRequest.isFinished()) { + progress = BusyIndicator.STATUS_BLACK; + } + return progress; + } + + @Override + public void run() { + while (true) { + try { + boolean tileLoaded = false; + boolean amenityLoaded = false; + boolean transportLoaded = false; + boolean mapLoaded = false; + + int progress = calculateProgressStatus(); + synchronized (resourceManger) { + if (resourceManger.getBusyIndicator() != null) { + resourceManger.getBusyIndicator().updateStatus(progress); + } + } + while (!requests.isEmpty()) { + Object req = requests.pop(); + if (req instanceof TileLoadDownloadRequest) { + TileLoadDownloadRequest r = (TileLoadDownloadRequest) req; + tileLoaded |= resourceManger.getRequestedImageTile(r) != null; + } else if (req instanceof AmenityLoadRequest) { + if (!amenityLoaded) { + if (poiLoadRequest == null || asyncLoadingPoi == null) { + startPoiLoadingThread(); + poiLoadRequest = (AmenityLoadRequest) req; + asyncLoadingPoi.post(poiLoadRequest.prepareToRun()); + } else if (poiLoadRequest.recalculateRequest((AmenityLoadRequest) req)) { + poiLoadRequest = (AmenityLoadRequest) req; + asyncLoadingPoi.post(poiLoadRequest.prepareToRun()); + } + amenityLoaded = true; + } + } else if (req instanceof TransportLoadRequest) { + if (!transportLoaded) { + if (transportLoadRequest == null || asyncLoadingTransport == null) { + startTransportLoadingThread(); + transportLoadRequest = (TransportLoadRequest) req; + asyncLoadingTransport.post(transportLoadRequest.prepareToRun()); + } else if (transportLoadRequest.recalculateRequest((TransportLoadRequest) req)) { + transportLoadRequest = (TransportLoadRequest) req; + asyncLoadingTransport.post(transportLoadRequest.prepareToRun()); + } + transportLoaded = true; + } + } else if (req instanceof MapLoadRequest) { + if (!mapLoaded) { + MapLoadRequest r = (MapLoadRequest) req; + resourceManger.getRenderer().loadMap(r.tileBox, downloader.getDownloaderCallbacks()); + mapLoaded = true; + } + } + } + if (tileLoaded || amenityLoaded || transportLoaded || mapLoaded) { + // use downloader callback + for (IMapDownloaderCallback c : downloader.getDownloaderCallbacks()) { + c.tileDownloaded(null); + } + } + int newProgress = calculateProgressStatus(); + if (progress != newProgress) { + synchronized (resourceManger) { + if (resourceManger.getBusyIndicator() != null) { + resourceManger.getBusyIndicator().updateStatus(newProgress); + } + } + } + sleep(750); + } catch (InterruptedException e) { + log.error(e, e); + } catch (RuntimeException e) { + log.error(e, e); + } + } + } + + public void requestToLoadImage(TileLoadDownloadRequest req) { + requests.push(req); + } + + public void requestToLoadAmenities(AmenityLoadRequest req) { + requests.push(req); + } + + public void requestToLoadMap(MapLoadRequest req) { + requests.push(req); + } + + public void requestToLoadTransport(TransportLoadRequest req) { + requests.push(req); + } + + public boolean isFileCurrentlyDownloaded(File fileToSave) { + return downloader.isFileCurrentlyDownloaded(fileToSave); + } + + public void requestToDownload(TileLoadDownloadRequest req) { + downloader.requestToDownload(req); + } + + protected static class TileLoadDownloadRequest extends DownloadRequest { + + public final String tileId; + public final File dirWithTiles; + public final ITileSource tileSource; + + public TileLoadDownloadRequest(File dirWithTiles, String url, File fileToSave, String tileId, ITileSource source, int tileX, + int tileY, int zoom) { + super(url, fileToSave, tileX, tileY, zoom); + this.dirWithTiles = dirWithTiles; + this.tileSource = source; + this.tileId = tileId; + } + } + + protected static class MapObjectLoadRequest implements ResultMatcher { + protected double topLatitude; + protected double bottomLatitude; + protected double leftLongitude; + protected double rightLongitude; + protected boolean cancelled = false; + protected volatile boolean finished = false; + + public boolean isContains(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude) { + boolean inside = this.topLatitude >= topLatitude && this.leftLongitude <= leftLongitude + && this.rightLongitude >= rightLongitude && this.bottomLatitude <= bottomLatitude; + return inside; + } + + public void setBoundaries(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude) { + this.topLatitude = topLatitude; + this.bottomLatitude = bottomLatitude; + this.leftLongitude = leftLongitude; + this.rightLongitude = rightLongitude; + } + + public boolean isFinished() { + return finished; + } + + public void finish() { + finished = true; + // use downloader callback + for (IMapDownloaderCallback c : downloader.getDownloaderCallbacks()) { + c.tileDownloaded(null); + } + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public boolean publish(T object) { + return true; + } + + } + + protected static class AmenityLoadRequest extends MapObjectLoadRequest { + private final List res; + private final PoiFilter filter; + private final int zoom; + + public AmenityLoadRequest(List repos, int zoom, PoiFilter filter) { + super(); + this.res = repos; + this.zoom = zoom; + this.filter = filter; + } + + public Runnable prepareToRun() { + final double ntopLatitude = topLatitude + (topLatitude - bottomLatitude) / 2; + final double nbottomLatitude = bottomLatitude - (topLatitude - bottomLatitude) / 2; + final double nleftLongitude = leftLongitude - (rightLongitude - leftLongitude) / 2; + final double nrightLongitude = rightLongitude + (rightLongitude - leftLongitude) / 2; + setBoundaries(ntopLatitude, nleftLongitude, nbottomLatitude, nrightLongitude); + return new Runnable() { + @Override + public void run() { + for (AmenityIndexRepository repository : res) { + repository.evaluateCachedAmenities(ntopLatitude, nleftLongitude, nbottomLatitude, nrightLongitude, zoom, filter, + AmenityLoadRequest.this); + } + finish(); + } + }; + } + + public boolean recalculateRequest(AmenityLoadRequest req) { + if (this.zoom != req.zoom || !Algoritms.objectEquals(this.filter, req.filter)) { + return true; + } + return !isContains(req.topLatitude, req.leftLongitude, req.bottomLatitude, req.rightLongitude); + } + + } + + protected static class TransportLoadRequest extends MapObjectLoadRequest { + private final List repos; + private int zoom; + + public TransportLoadRequest(List repos, int zoom) { + super(); + this.repos = repos; + this.zoom = zoom; + } + + public Runnable prepareToRun() { + final double ntopLatitude = topLatitude + (topLatitude - bottomLatitude) / 2; + final double nbottomLatitude = bottomLatitude - (topLatitude - bottomLatitude) / 2; + final double nleftLongitude = leftLongitude - (rightLongitude - leftLongitude) / 2; + final double nrightLongitude = rightLongitude + (rightLongitude - leftLongitude) / 2; + setBoundaries(ntopLatitude, nleftLongitude, nbottomLatitude, nrightLongitude); + return new Runnable() { + @Override + public void run() { + for (TransportIndexRepository repository : repos) { + repository.evaluateCachedTransportStops(ntopLatitude, nleftLongitude, nbottomLatitude, nrightLongitude, zoom, + LIMIT_TRANSPORT, TransportLoadRequest.this); + } + finish(); + } + }; + } + + public boolean recalculateRequest(TransportLoadRequest req) { + if (this.zoom != req.zoom) { + return true; + } + return !isContains(req.topLatitude, req.leftLongitude, req.bottomLatitude, req.rightLongitude); + } + + } + + protected static class MapLoadRequest { + public final RotatedTileBox tileBox; + + public MapLoadRequest(RotatedTileBox tileBox) { + super(); + this.tileBox = tileBox; + } + } + + +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/ResourceManager.java b/OsmAnd/src/net/osmand/plus/ResourceManager.java index 048d562e8c..72678bdc37 100644 --- a/OsmAnd/src/net/osmand/plus/ResourceManager.java +++ b/OsmAnd/src/net/osmand/plus/ResourceManager.java @@ -15,7 +15,6 @@ import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Stack; import java.util.TreeMap; import net.osmand.Algoritms; @@ -27,13 +26,15 @@ import net.osmand.binary.BinaryMapIndexReader; import net.osmand.data.Amenity; import net.osmand.data.AmenityType; import net.osmand.data.IndexConstants; -import net.osmand.data.MapTileDownloader; import net.osmand.data.TransportStop; import net.osmand.data.MapTileDownloader.DownloadRequest; -import net.osmand.data.MapTileDownloader.IMapDownloaderCallback; import net.osmand.map.ITileSource; import net.osmand.osm.LatLon; import net.osmand.osm.MapUtils; +import net.osmand.plus.AsyncLoadingThread.AmenityLoadRequest; +import net.osmand.plus.AsyncLoadingThread.MapLoadRequest; +import net.osmand.plus.AsyncLoadingThread.TileLoadDownloadRequest; +import net.osmand.plus.AsyncLoadingThread.TransportLoadRequest; import net.osmand.plus.activities.OsmandApplication; import net.osmand.plus.render.BaseOsmandRender; import net.osmand.plus.render.MapRenderRepositories; @@ -70,7 +71,6 @@ public class ResourceManager { public static final String TEMP_SOURCE_TO_LOAD = "temp"; //$NON-NLS-1$ public static final String VECTOR_MAP = "#vector_map"; //$NON-NLS-1$ - public static final int LIMIT_TRANSPORT = 200; private static final Log log = LogUtil.getLog(ResourceManager.class); private static final String MINE_POI_DB = APP_DIR + "mine"+ IndexConstants.POI_INDEX_EXT; @@ -92,7 +92,7 @@ public class ResourceManager { private BusyIndicator busyIndicator; - private final MapTileDownloader downloader = MapTileDownloader.getInstance(); + // Indexes private final Map addressMap = new TreeMap(Collator.getInstance()); @@ -107,20 +107,18 @@ public class ResourceManager { protected final MapRenderRepositories renderer; - public final AsyncLoadingThread asyncLoadingTiles = new AsyncLoadingThread(); + public final AsyncLoadingThread asyncLoadingThread = new AsyncLoadingThread(this); protected boolean internetIsNotAccessible = false; protected AmenityIndexRepositoryOdb updatablePoiDb = null; - public ResourceManager(OsmandApplication context) { this.context = context; this.renderer = new MapRenderRepositories(context); - asyncLoadingTiles.start(); + asyncLoadingThread.start(); resetStoreDirectory(); - WindowManager mgr = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); DisplayMetrics dm = new DisplayMetrics(); mgr.getDefaultDisplay().getMetrics(dm); @@ -131,6 +129,7 @@ public class ResourceManager { maxImgCacheSize = (int) (tiles) ; } + public void resetStoreDirectory() { dirWithTiles = context.getSettings().extendOsmandPath(TILES_PATH); dirWithTiles.mkdirs(); @@ -283,7 +282,8 @@ public class ResourceManager { } if (loadFromFs && cacheOfImages.get(tileId) == null && map != null) { - if(!loadFromInternetIfNeeded && !tileExistOnFileSystem(tileId, map, x, y, zoom)){ + boolean locked = map instanceof SQLiteTileSource && ((SQLiteTileSource) map).isLocked(); + if(!loadFromInternetIfNeeded && !locked && !tileExistOnFileSystem(tileId, map, x, y, zoom)){ return null; } String url = loadFromInternetIfNeeded ? map.getUrlToLoad(x, y, zoom) : null; @@ -300,7 +300,7 @@ public class ResourceManager { if(sync){ return getRequestedImageTile(req); } else { - asyncLoadingTiles.requestToLoadImage(req); + asyncLoadingThread.requestToLoadImage(req); } } return cacheOfImages.get(tileId); @@ -308,14 +308,18 @@ public class ResourceManager { - private Bitmap getRequestedImageTile(TileLoadDownloadRequest req){ + protected Bitmap getRequestedImageTile(TileLoadDownloadRequest req){ if(req.tileId == null || req.dirWithTiles == null){ return null; } + Bitmap cacheBmp = cacheOfImages.get(req.tileId); + if (cacheBmp != null) { + return cacheBmp; + } if (cacheOfImages.size() > maxImgCacheSize) { clearTiles(); } - if (req.dirWithTiles.canRead() && !downloader.isFileCurrentlyDownloaded(req.fileToSave)) { + if (req.dirWithTiles.canRead() && !asyncLoadingThread.isFileCurrentlyDownloaded(req.fileToSave)) { long time = System.currentTimeMillis(); if (log.isDebugEnabled()) { log.debug("Start loaded file : " + req.tileId + " " + Thread.currentThread().getName()); //$NON-NLS-1$ //$NON-NLS-2$ @@ -343,7 +347,7 @@ public class ResourceManager { } if (cacheOfImages.get(req.tileId) == null && req.url != null) { - downloader.requestToDownload(req); + asyncLoadingThread.requestToDownload(req); } } @@ -667,18 +671,22 @@ public class ResourceManager { toFill.add(a); } } - } else { String filterId = filter == null ? null : filter.getFilterId(); + List repos = new ArrayList(); for (AmenityIndexRepository index : amenityRepositories) { if (index.checkContains(topLatitude, leftLongitude, bottomLatitude, rightLongitude)) { if (!index.checkCachedAmenities(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom, filterId, toFill, true)) { - asyncLoadingTiles.requestToLoadAmenities(new AmenityLoadRequest(index, topLatitude, leftLongitude, bottomLatitude, - rightLongitude, zoom, filter)); + repos.add(index); } } } + if(!repos.isEmpty()){ + AmenityLoadRequest req = new AmenityLoadRequest(repos, zoom, filter); + req.setBoundaries(topLatitude, leftLongitude, bottomLatitude, rightLongitude); + asyncLoadingThread.requestToLoadAmenities(req); + } } } @@ -705,14 +713,19 @@ public class ResourceManager { public void searchTransportAsync(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, List toFill){ - for(TransportIndexRepository index : transportRepositories){ - if(index.checkContains(topLatitude, leftLongitude, bottomLatitude, rightLongitude)){ - if(!index.checkCachedObjects(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom, toFill, true)){ - asyncLoadingTiles.requestToLoadTransport( - new TransportLoadRequest(index, topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom)); + List repos = new ArrayList(); + for (TransportIndexRepository index : transportRepositories) { + if (index.checkContains(topLatitude, leftLongitude, bottomLatitude, rightLongitude)) { + if (!index.checkCachedObjects(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom, toFill, true)) { + repos.add(index); } } } + if(!repos.isEmpty()){ + TransportLoadRequest req = new TransportLoadRequest(repos, zoom); + req.setBoundaries(topLatitude, leftLongitude, bottomLatitude, rightLongitude); + asyncLoadingThread.requestToLoadTransport(req); + } } ////////////////////////////////////////////// Working with map //////////////////////////////////////////////// @@ -722,7 +735,7 @@ public class ResourceManager { public void updateRendererMap(RotatedTileBox rotatedTileBox){ renderer.interruptLoadingMap(); - asyncLoadingTiles.requestToLoadMap( + asyncLoadingThread.requestToLoadMap( new MapLoadRequest(new RotatedTileBox(rotatedTileBox))); } @@ -820,185 +833,12 @@ public class ResourceManager { } - protected synchronized void clearTiles(){ + protected synchronized void clearTiles() { log.info("Cleaning tiles - size = " + cacheOfImages.size()); //$NON-NLS-1$ ArrayList list = new ArrayList(cacheOfImages.keySet()); // remove first images (as we think they are older) - for (int i = 0; i < list.size() /2; i ++) { + for (int i = 0; i < list.size() / 2; i++) { cacheOfImages.remove(list.get(i)); } } - - - private static class TileLoadDownloadRequest extends DownloadRequest { - - public final String tileId; - public final File dirWithTiles; - public final ITileSource tileSource; - - public TileLoadDownloadRequest(File dirWithTiles, String url, File fileToSave, - String tileId, ITileSource source, int tileX, int tileY, int zoom) { - super(url, fileToSave, tileX, tileY, zoom); - this.dirWithTiles = dirWithTiles; - this.tileSource = source; - this.tileId = tileId; - } - } - - private static class AmenityLoadRequest { - public final AmenityIndexRepository repository; - public final double topLatitude; - public final double bottomLatitude; - public final double leftLongitude; - public final double rightLongitude; - public final PoiFilter filter; - public final int zoom; - - public AmenityLoadRequest(AmenityIndexRepository repository, double topLatitude, double leftLongitude, - double bottomLatitude, double rightLongitude, int zoom, PoiFilter filter) { - super(); - this.bottomLatitude = bottomLatitude; - this.leftLongitude = leftLongitude; - this.repository = repository; - this.rightLongitude = rightLongitude; - this.topLatitude = topLatitude; - this.zoom = zoom; - this.filter = filter; - } - } - - - - private static class TransportLoadRequest { - public final TransportIndexRepository repository; - public final double topLatitude; - public final double bottomLatitude; - public final double leftLongitude; - public final double rightLongitude; - public final int zoom; - - public TransportLoadRequest(TransportIndexRepository repository, double topLatitude, double leftLongitude, - double bottomLatitude, double rightLongitude, int zoom) { - super(); - this.bottomLatitude = bottomLatitude; - this.leftLongitude = leftLongitude; - this.repository = repository; - this.rightLongitude = rightLongitude; - this.topLatitude = topLatitude; - this.zoom = zoom; - } - } - - private static class MapLoadRequest { - public final RotatedTileBox tileBox; - - public MapLoadRequest(RotatedTileBox tileBox) { - super(); - this.tileBox = tileBox; - } - } - - public class AsyncLoadingThread extends Thread { - Stack requests = new Stack(); - - public AsyncLoadingThread(){ - super("Loader map objects (tiles, poi)"); //$NON-NLS-1$ - } - - @Override - public void run() { - while(true){ - try { - boolean update = false; - boolean amenityLoaded = false; - boolean transportLoaded = false; - boolean mapLoaded = false; - int progress = 0; - if(downloader.isSomethingBeingDownloaded()){ - progress = BusyIndicator.STATUS_GREEN; - } - synchronized(ResourceManager.this){ - if(busyIndicator != null){ - if(context.getRoutingHelper().isRouteBeingCalculated()){ - progress = BusyIndicator.STATUS_BLUE; - } else if(!requests.isEmpty()){ - progress = BusyIndicator.STATUS_BLACK;; - } - busyIndicator.updateStatus(progress); - } - } - while(!requests.isEmpty()){ - Object req = requests.pop(); - if (req instanceof TileLoadDownloadRequest) { - TileLoadDownloadRequest r = (TileLoadDownloadRequest) req; - if (cacheOfImages.get(r.tileId) == null) { - update |= getRequestedImageTile(r) != null; - } - } else if(req instanceof AmenityLoadRequest){ - if(!amenityLoaded){ - AmenityLoadRequest r = (AmenityLoadRequest) req; - r.repository.evaluateCachedAmenities(r.topLatitude, r.leftLongitude, - r.bottomLatitude, r.rightLongitude, r.zoom, r.filter, null); - amenityLoaded = true; - } - } else if(req instanceof TransportLoadRequest){ - if(!transportLoaded){ - TransportLoadRequest r = (TransportLoadRequest) req; - r.repository.evaluateCachedTransportStops(r.topLatitude, r.leftLongitude, - r.bottomLatitude, r.rightLongitude, r.zoom, LIMIT_TRANSPORT, null); - transportLoaded = true; - } - } else if(req instanceof MapLoadRequest){ - if(!mapLoaded){ - MapLoadRequest r = (MapLoadRequest) req; - renderer.loadMap(r.tileBox, downloader.getDownloaderCallbacks()); - mapLoaded = true; - } - } - } - if(update || amenityLoaded || transportLoaded || mapLoaded){ - // use downloader callback - for(IMapDownloaderCallback c : downloader.getDownloaderCallbacks()){ - c.tileDownloaded(null); - } - } - boolean routeBeingCalculated = context.getRoutingHelper().isRouteBeingCalculated(); - if (progress != 0 || routeBeingCalculated || downloader.isSomethingBeingDownloaded()) { - synchronized (ResourceManager.this) { - if (busyIndicator != null) { - if(routeBeingCalculated){ - progress = BusyIndicator.STATUS_BLUE; - } else if(downloader.isSomethingBeingDownloaded()){ - progress = BusyIndicator.STATUS_GREEN; - } else { - progress = 0; - } - busyIndicator.updateStatus(progress); - } - } - } - sleep(750); - } catch (InterruptedException e) { - log.error(e, e); - } catch (RuntimeException e){ - log.error(e, e); - } - } - } - - public void requestToLoadImage(TileLoadDownloadRequest req){ - requests.push(req); - } - public void requestToLoadAmenities(AmenityLoadRequest req){ - requests.push(req); - } - - public void requestToLoadMap(MapLoadRequest req){ - requests.push(req); - } - - public void requestToLoadTransport(TransportLoadRequest req){ - requests.push(req); - } - }; -} \ No newline at end of file +} diff --git a/OsmAnd/src/net/osmand/plus/SQLiteTileSource.java b/OsmAnd/src/net/osmand/plus/SQLiteTileSource.java index addb29b666..fb4e92d6b5 100644 --- a/OsmAnd/src/net/osmand/plus/SQLiteTileSource.java +++ b/OsmAnd/src/net/osmand/plus/SQLiteTileSource.java @@ -34,7 +34,6 @@ public class SQLiteTileSource implements ITileSource { private final File file; private int minZoom = 1; private int maxZoom = 17; - private boolean locked = false; public SQLiteTileSource(File f, List toFindUrl){ this.file = f; @@ -185,7 +184,11 @@ public class SQLiteTileSource implements ITileSource { } public boolean isLocked() { - return locked; + SQLiteDatabase db = getDatabase(); + if(db == null){ + return false; + } + return db.isDbLockedByOtherThreads(); } public Bitmap getImage(int x, int y, int zoom) { @@ -219,36 +222,35 @@ public class SQLiteTileSource implements ITileSource { private final int BUF_SIZE = 1024; - public void insertImage(int x, int y, int zoom, File fileToSave) throws IOException { + /** + * Makes method synchronized to give a little more time for get methods and + * let all writing attempts to wait outside of this method + */ + public synchronized void insertImage(int x, int y, int zoom, File fileToSave) throws IOException { SQLiteDatabase db = getDatabase(); - if(db == null || db.isReadOnly()){ + if (db == null || db.isReadOnly()) { return; } - if(exists(x, y, zoom)){ + if (exists(x, y, zoom)) { return; } - try { - locked = true; - ByteBuffer buf = ByteBuffer.allocate((int) fileToSave.length()); - FileInputStream is = new FileInputStream(fileToSave); - int i = 0; - byte[] b = new byte[BUF_SIZE]; - while ((i = is.read(b, 0, BUF_SIZE)) > -1) { - buf.put(b, 0, i); - } + ByteBuffer buf = ByteBuffer.allocate((int) fileToSave.length()); + FileInputStream is = new FileInputStream(fileToSave); + int i = 0; + byte[] b = new byte[BUF_SIZE]; + while ((i = is.read(b, 0, BUF_SIZE)) > -1) { + buf.put(b, 0, i); + } + + SQLiteStatement statement = db.compileStatement("INSERT INTO tiles VALUES(?, ?, ?, ?, ?)"); //$NON-NLS-1$ + statement.bindLong(1, x); + statement.bindLong(2, y); + statement.bindLong(3, 17 - zoom); + statement.bindLong(4, 0); + statement.bindBlob(5, buf.array()); + statement.execute(); + statement.close(); - SQLiteStatement statement = db.compileStatement("INSERT INTO tiles VALUES(?, ?, ?, ?, ?)"); //$NON-NLS-1$ - statement.bindLong(1, x); - statement.bindLong(2, y); - statement.bindLong(3, 17 - zoom); - statement.bindLong(4, 0); - statement.bindBlob(5, buf.array()); - statement.execute(); - statement.close(); - } finally { - locked = false; - } - } public void closeDB(){ diff --git a/OsmAnd/src/net/osmand/plus/TransportIndexRepository.java b/OsmAnd/src/net/osmand/plus/TransportIndexRepository.java index d044bf7202..9cd2f5fb07 100644 --- a/OsmAnd/src/net/osmand/plus/TransportIndexRepository.java +++ b/OsmAnd/src/net/osmand/plus/TransportIndexRepository.java @@ -2,6 +2,7 @@ package net.osmand.plus; import java.util.List; +import net.osmand.ResultMatcher; import net.osmand.data.TransportRoute; import net.osmand.data.TransportStop; import net.osmand.osm.LatLon; @@ -27,7 +28,8 @@ public interface TransportIndexRepository { public List getRouteDescriptionsForStop(TransportStop stop, String format); - public void evaluateCachedTransportStops(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, int limit, List toFill); + public void evaluateCachedTransportStops(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, int limit, + ResultMatcher matcher); public List searchTransportRouteStops(double latitude, double longitude, LatLon locationToGo, int zoom); diff --git a/OsmAnd/src/net/osmand/plus/TransportIndexRepositoryBinary.java b/OsmAnd/src/net/osmand/plus/TransportIndexRepositoryBinary.java index e7b9638c3d..0ebe8ae508 100644 --- a/OsmAnd/src/net/osmand/plus/TransportIndexRepositoryBinary.java +++ b/OsmAnd/src/net/osmand/plus/TransportIndexRepositoryBinary.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Map; import net.osmand.LogUtil; +import net.osmand.ResultMatcher; import net.osmand.binary.BinaryMapIndexReader; import net.osmand.binary.BinaryMapIndexReader.SearchRequest; import net.osmand.data.TransportRoute; @@ -43,10 +44,12 @@ public class TransportIndexRepositoryBinary implements TransportIndexRepository return file.containTransportData(topLatitude, leftLongitude, bottomLatitude, rightLongitude); } + @Override public boolean checkCachedObjects(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, List toFill){ return checkCachedObjects(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom, toFill, false); } + @Override public synchronized boolean checkCachedObjects(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, List toFill, boolean fillFound){ boolean inside = cTopLatitude >= topLatitude && cLeftLongitude <= leftLongitude && cRightLongitude >= rightLongitude && cBottomLatitude <= bottomLatitude && cZoom == zoom; @@ -64,7 +67,7 @@ public class TransportIndexRepositoryBinary implements TransportIndexRepository } public List searchTransportStops(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, - int limit, List stops) { + int limit, List stops, ResultMatcher matcher) { long now = System.currentTimeMillis(); try { file.searchTransportIndex(BinaryMapIndexReader.buildSearchTransportRequest(MapUtils.get31TileNumberX(leftLongitude), @@ -88,6 +91,7 @@ public class TransportIndexRepositoryBinary implements TransportIndexRepository * 0} - ref, {1} - type, {2} - name, {3} - name_en * @return null if something goes wrong */ + @Override public List getRouteDescriptionsForStop(TransportStop stop, String format) { assert acceptTransportStop(stop); long now = System.currentTimeMillis(); @@ -114,8 +118,9 @@ public class TransportIndexRepositoryBinary implements TransportIndexRepository return res; } + @Override public void evaluateCachedTransportStops(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, - int zoom, int limit, List toFill) { + int zoom, int limit, ResultMatcher matcher) { cTopLatitude = topLatitude + (topLatitude - bottomLatitude); cBottomLatitude = bottomLatitude - (topLatitude - bottomLatitude); cLeftLongitude = leftLongitude - (rightLongitude - leftLongitude); @@ -123,16 +128,15 @@ public class TransportIndexRepositoryBinary implements TransportIndexRepository cZoom = zoom; // first of all put all entities in temp list in order to not freeze other read threads ArrayList tempList = new ArrayList(); - searchTransportStops(cTopLatitude, cLeftLongitude, cBottomLatitude, cRightLongitude, limit, tempList); + searchTransportStops(cTopLatitude, cLeftLongitude, cBottomLatitude, cRightLongitude, limit, tempList, matcher); synchronized (this) { cachedObjects.clear(); cachedObjects.addAll(tempList); } - checkCachedObjects(topLatitude, leftLongitude, bottomLatitude, rightLongitude, cZoom, toFill); } - + @Override public List searchTransportRouteStops(double latitude, double longitude, LatLon locationToGo, int zoom) { long now = System.currentTimeMillis(); final LatLon loc = new LatLon(latitude, longitude); diff --git a/OsmAnd/src/net/osmand/plus/activities/DownloadTilesDialog.java b/OsmAnd/src/net/osmand/plus/activities/DownloadTilesDialog.java index 2d28027044..4eb64f54f1 100644 --- a/OsmAnd/src/net/osmand/plus/activities/DownloadTilesDialog.java +++ b/OsmAnd/src/net/osmand/plus/activities/DownloadTilesDialog.java @@ -152,7 +152,9 @@ public class DownloadTilesDialog { instance.addDownloaderCallback(new IMapDownloaderCallback(){ @Override public void tileDownloaded(DownloadRequest request) { - progressDlg.setProgress(progressDlg.getProgress() + 1); + if (request != null) { + progressDlg.setProgress(progressDlg.getProgress() + 1); + } } });