Update POI/transport loading thread and not interrupt main loading thread
This commit is contained in:
commit
bc6f8e4c72
11 changed files with 446 additions and 257 deletions
|
@ -10,10 +10,14 @@ 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
|
||||
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -26,6 +26,6 @@ public interface AmenityIndexRepository {
|
|||
String filterId, List<Amenity> toFill, boolean fillFound);
|
||||
|
||||
public void evaluateCachedAmenities(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom,
|
||||
PoiFilter filter, List<Amenity> toFill);
|
||||
PoiFilter filter, ResultMatcher<Amenity> matcher);
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Amenity> toFill) {
|
||||
cTopLatitude = topLatitude + (topLatitude - bottomLatitude);
|
||||
cBottomLatitude = bottomLatitude - (topLatitude - bottomLatitude);
|
||||
cLeftLongitude = leftLongitude - (rightLongitude - leftLongitude);
|
||||
cRightLongitude = rightLongitude + (rightLongitude - leftLongitude);
|
||||
PoiFilter filter, ResultMatcher<Amenity> 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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -102,11 +102,13 @@ public class AmenityIndexRepositoryOdb extends BaseLocationIndexRepository<Ameni
|
|||
cFilterId = null;
|
||||
}
|
||||
|
||||
public void evaluateCachedAmenities(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, PoiFilter filter, List<Amenity> toFill){
|
||||
cTopLatitude = topLatitude + (topLatitude -bottomLatitude);
|
||||
cBottomLatitude = bottomLatitude - (topLatitude -bottomLatitude);
|
||||
cLeftLongitude = leftLongitude - (rightLongitude - leftLongitude);
|
||||
cRightLongitude = rightLongitude + (rightLongitude - leftLongitude);
|
||||
@Override
|
||||
public void evaluateCachedAmenities(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom,
|
||||
PoiFilter filter, ResultMatcher<Amenity> 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
|
||||
|
@ -115,13 +117,11 @@ public class AmenityIndexRepositoryOdb extends BaseLocationIndexRepository<Ameni
|
|||
int sright = MapUtils.get31TileNumberX(cRightLongitude);
|
||||
int sbottom = MapUtils.get31TileNumberY(cBottomLatitude);
|
||||
int stop = MapUtils.get31TileNumberY(cTopLatitude);
|
||||
searchAmenities(stop, sleft, sbottom, sright, cZoom, filter, tempList, null);
|
||||
searchAmenities(stop, sleft, sbottom, sright, cZoom, filter, tempList, matcher);
|
||||
synchronized (this) {
|
||||
cachedObjects.clear();
|
||||
cachedObjects.addAll(tempList);
|
||||
}
|
||||
|
||||
checkCachedAmenities(topLatitude, leftLongitude, bottomLatitude, rightLongitude, cZoom, filter.getFilterId(), toFill);
|
||||
}
|
||||
|
||||
public synchronized boolean checkCachedAmenities(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, String filterId, List<Amenity> toFill, boolean fillFound){
|
||||
|
|
339
OsmAnd/src/net/osmand/plus/AsyncLoadingThread.java
Normal file
339
OsmAnd/src/net/osmand/plus/AsyncLoadingThread.java
Normal file
|
@ -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<Object> requests = new Stack<Object>();
|
||||
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<T> implements ResultMatcher<T> {
|
||||
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<Amenity> {
|
||||
private final List<AmenityIndexRepository> res;
|
||||
private final PoiFilter filter;
|
||||
private final int zoom;
|
||||
|
||||
public AmenityLoadRequest(List<AmenityIndexRepository> 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<TransportStop> {
|
||||
private final List<TransportIndexRepository> repos;
|
||||
private int zoom;
|
||||
|
||||
public TransportLoadRequest(List<TransportIndexRepository> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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<String, RegionAddressRepository> addressMap = new TreeMap<String, RegionAddressRepository>(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<AmenityIndexRepository> repos = new ArrayList<AmenityIndexRepository>();
|
||||
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<TransportStop> toFill){
|
||||
List<TransportIndexRepository> repos = new ArrayList<TransportIndexRepository>();
|
||||
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));
|
||||
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)));
|
||||
}
|
||||
|
||||
|
@ -828,177 +841,4 @@ public class ResourceManager {
|
|||
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<Object> requests = new Stack<Object>();
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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<TileSourceTemplate> 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,7 +222,11 @@ 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()) {
|
||||
return;
|
||||
|
@ -227,8 +234,6 @@ public class SQLiteTileSource implements ITileSource {
|
|||
if (exists(x, y, zoom)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
locked = true;
|
||||
ByteBuffer buf = ByteBuffer.allocate((int) fileToSave.length());
|
||||
FileInputStream is = new FileInputStream(fileToSave);
|
||||
int i = 0;
|
||||
|
@ -245,9 +250,6 @@ public class SQLiteTileSource implements ITileSource {
|
|||
statement.bindBlob(5, buf.array());
|
||||
statement.execute();
|
||||
statement.close();
|
||||
} finally {
|
||||
locked = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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<String> getRouteDescriptionsForStop(TransportStop stop, String format);
|
||||
|
||||
|
||||
public void evaluateCachedTransportStops(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, int limit, List<TransportStop> toFill);
|
||||
public void evaluateCachedTransportStops(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, int limit,
|
||||
ResultMatcher<TransportStop> matcher);
|
||||
|
||||
|
||||
public List<RouteInfoLocation> searchTransportRouteStops(double latitude, double longitude, LatLon locationToGo, int zoom);
|
||||
|
|
|
@ -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<TransportStop> 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<TransportStop> 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<TransportStop> searchTransportStops(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude,
|
||||
int limit, List<TransportStop> stops) {
|
||||
int limit, List<TransportStop> stops, ResultMatcher<TransportStop> 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<String> 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<TransportStop> toFill) {
|
||||
int zoom, int limit, ResultMatcher<TransportStop> 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<TransportStop> tempList = new ArrayList<TransportStop>();
|
||||
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<RouteInfoLocation> searchTransportRouteStops(double latitude, double longitude, LatLon locationToGo, int zoom) {
|
||||
long now = System.currentTimeMillis();
|
||||
final LatLon loc = new LatLon(latitude, longitude);
|
||||
|
|
|
@ -152,8 +152,10 @@ public class DownloadTilesDialog {
|
|||
instance.addDownloaderCallback(new IMapDownloaderCallback(){
|
||||
@Override
|
||||
public void tileDownloaded(DownloadRequest request) {
|
||||
if (request != null) {
|
||||
progressDlg.setProgress(progressDlg.getProgress() + 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Runnable r = new Runnable(){
|
||||
|
|
Loading…
Reference in a new issue