implement sqlite db

git-svn-id: https://osmand.googlecode.com/svn/trunk@366 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8
This commit is contained in:
Victor Shcherb 2010-07-19 19:28:29 +00:00
parent 3f8e13c79c
commit 3c85f1418e
12 changed files with 549 additions and 78 deletions

View file

@ -11,6 +11,7 @@ public class ToDoConstants {
// TODO ANDROID
// for 0.3
// 71. Implement different mechanism for tiles (big sqlite planet see rmaps)
// 1) doc, 2) test (update map, download from internet...), 3) add button menu create sqlite db
// Improvement : Show stops in the transport route on the map
// Improvement : show favorites on the map?
@ -19,7 +20,6 @@ public class ToDoConstants {
// Improvement : redesign poi selecting (show on map )
// Improvement : progress while loading tiles
// Improvement : download with wget
// Improvement : cloudmade as map?
// Yandex traffic : http://jgo.maps.yandex.net/tiles?l=trf
// Improvement : show route info after route is calculated and/or calculate route from context menu
// (continue follow previous route)

View file

@ -15,4 +15,8 @@ public interface ITileSource {
public String getTileFormat();
public int getBitDensity();
public boolean couldBeDownloadedFromInternet();
}

View file

@ -16,8 +16,9 @@ public class TileSourceManager {
private String urlToLoad;
private String ext;
private int avgSize;
private int bitDensity;
public TileSourceTemplate(String name, String urlToLoad, String ext, int maxZoom, int minZoom, int tileSize, int avgSize) {
public TileSourceTemplate(String name, String urlToLoad, String ext, int maxZoom, int minZoom, int tileSize, int bitDensity, int avgSize) {
this.maxZoom = maxZoom;
this.minZoom = minZoom;
this.name = name;
@ -25,8 +26,13 @@ public class TileSourceManager {
this.urlToLoad = urlToLoad;
this.ext = ext;
this.avgSize = avgSize;
this.bitDensity = bitDensity;
}
@Override
public int getBitDensity() {
return bitDensity;
}
public int getAverageSize(){
return avgSize;
@ -62,6 +68,11 @@ public class TileSourceManager {
return MessageFormat.format(urlToLoad, zoom+"", x+"", y+""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
@Override
public boolean couldBeDownloadedFromInternet() {
return true;
}
@Override
public int hashCode() {
@ -123,60 +134,60 @@ public class TileSourceManager {
public static TileSourceTemplate getMapnikSource(){
return new TileSourceTemplate("Mapnik", "http://tile.openstreetmap.org/{0}/{1}/{2}.png", ".png", 18, 1, 256, 18000); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
return new TileSourceTemplate("Mapnik", "http://tile.openstreetmap.org/{0}/{1}/{2}.png", ".png", 18, 1, 256, 8, 18000); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
}
public static TileSourceTemplate getOsmaRenderSource(){
return new TileSourceTemplate("OsmaRender", "http://tah.openstreetmap.org/Tiles/tile/{0}/{1}/{2}.png", ".png", 17, 1, 256, 18000); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
return new TileSourceTemplate("OsmaRender", "http://tah.openstreetmap.org/Tiles/tile/{0}/{1}/{2}.png", ".png", 17, 1, 256, 8, 18000); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
}
public static TileSourceTemplate getCycleMapSource(){
return new TileSourceTemplate("CycleMap", "http://b.andy.sandbox.cloudmade.com/tiles/cycle/{0}/{1}/{2}.png", ".png", 17, 0, 256, 18000); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
return new TileSourceTemplate("CycleMap", "http://b.andy.sandbox.cloudmade.com/tiles/cycle/{0}/{1}/{2}.png", ".png", 17, 0, 256, 32, 18000); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
}
public static TileSourceTemplate getAerialMapSource(){
return new TileSourceTemplate("OpenAerialMap", "http://tile.openaerialmap.org/tiles/1.0.0/openaerialmap-900913/{0}/{1}/{2}.jpg", ".jpg", 13, 0, 256, 18000); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
return new TileSourceTemplate("OpenAerialMap", "http://tile.openaerialmap.org/tiles/1.0.0/openaerialmap-900913/{0}/{1}/{2}.jpg", ".jpg", 13, 0, 256, 8, 18000); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
}
public static TileSourceTemplate getCloudMadeSource(){
return new TileSourceTemplate("Cloudmade", "http://tile.cloudmade.com/7ded028e030c5929b28bf823486ce84f/1/256/{0}/{1}/{2}.png", ".png", 18, 0, 256, 18000); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
return new TileSourceTemplate("Cloudmade", "http://tile.cloudmade.com/7ded028e030c5929b28bf823486ce84f/1/256/{0}/{1}/{2}.png", ".png", 18, 0, 256, 16, 18000); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
}
public static TileSourceTemplate getMapSurferSource(){
return new TileSourceTemplate("MapSurfer", "http://tiles1.mapsurfer.net/tms_r.ashx?z={0}&x={1}&y={2}", ".png", 19, 0, 256, 18000);//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
return new TileSourceTemplate("MapSurfer", "http://tiles1.mapsurfer.net/tms_r.ashx?z={0}&x={1}&y={2}", ".png", 19, 0, 256, 16, 18000);//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
public static TileSourceTemplate getNavigationDebugSource(){
return new TileSourceTemplate("NavigationDebug", "http://ec2-184-73-15-218.compute-1.amazonaws.com/6700/256/{0}/{1}/{2}.png", ".png", 18, 0, 256, 18000); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
return new TileSourceTemplate("NavigationDebug", "http://ec2-184-73-15-218.compute-1.amazonaws.com/6700/256/{0}/{1}/{2}.png", ".png", 18, 0, 256, 16, 18000); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
public static TileSourceTemplate getOpenPisteMapSource(){
return new TileSourceTemplate("OpenPisteMap", "http://openpistemap.org/tiles/contours/{0}/{1}/{2}.png", ".png", 17, 0, 256, 18000); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
return new TileSourceTemplate("OpenPisteMap", "http://openpistemap.org/tiles/contours/{0}/{1}/{2}.png", ".png", 17, 0, 256, 32, 18000); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
public static TileSourceTemplate getGoogleMapsSource(){
return new TileSourceTemplate("GoogleMaps", "http://mt3.google.com/vt/v=w2.97&x={1}&y={2}&z={0}", ".png", 19, 0, 256, 18000); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
return new TileSourceTemplate("GoogleMaps", "http://mt3.google.com/vt/v=w2.97&x={1}&y={2}&z={0}", ".png", 19, 0, 256, 16, 18000); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
public static TileSourceTemplate getGoogleMapsSatelliteSource(){
return new TileSourceTemplate("GoogleMaps Satellite", "http://khm1.google.com/kh/v=59&x={1}&y={2}&z={0}", ".jpg", 20, 0, 256, 18000); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
return new TileSourceTemplate("GoogleMaps Satellite", "http://khm1.google.com/kh/v=59&x={1}&y={2}&z={0}", ".jpg", 20, 0, 256, 32, 18000); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
public static TileSourceTemplate getGoogleMapsTerrainSource(){
return new TileSourceTemplate("GoogleMaps Terrain", "http://mt3.google.com/vt/v=w2p.111&hl=en&x={1}&y={2}&z={0}", ".jpg", 15, 0, 256, 18000); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
return new TileSourceTemplate("GoogleMaps Terrain", "http://mt3.google.com/vt/v=w2p.111&hl=en&x={1}&y={2}&z={0}", ".jpg", 15, 0, 256, 32, 18000); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
public static TileSourceTemplate getMicrosoftMapsSource(){
return new MicrosoftTileSourceTemplate("Microsoft Maps", 'r', "png", ".png", 19, 1, 256, 18000); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
return new MicrosoftTileSourceTemplate("Microsoft Maps", 'r', "png", ".png", 19, 1, 256, 16, 18000); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
public static TileSourceTemplate getMicrosoftEarthSource(){
return new MicrosoftTileSourceTemplate("Microsoft Earth", 'a', "jpg", ".jpg", 19, 1, 256, 18000); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
return new MicrosoftTileSourceTemplate("Microsoft Earth", 'a', "jpg", ".jpg", 19, 1, 256, 32, 18000); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
public static TileSourceTemplate getMicrosoftHybridSource(){
return new MicrosoftTileSourceTemplate("Microsoft Hybrid", 'h', "jpg", ".jpg", 19, 1, 256, 18000); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
return new MicrosoftTileSourceTemplate("Microsoft Hybrid", 'h', "jpg", ".jpg", 19, 1, 256, 32, 18000); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
@ -212,8 +223,8 @@ public class TileSourceManager {
private final String tileType;
public MicrosoftTileSourceTemplate(String name, char mapTypeChar , String type,
String ext, int maxZoom, int minZoom, int tileSize, int avgSize) {
super(name, null, ext, maxZoom, minZoom, tileSize, avgSize);
String ext, int maxZoom, int minZoom, int tileSize, int bitDensity, int avgSize) {
super(name, null, ext, maxZoom, minZoom, tileSize, bitDensity, avgSize);
this.mapTypeChar = mapTypeChar;
this.tileType = type;
}

View file

@ -65,7 +65,7 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
menuItem.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
for(int i=0; i<tiles.getItemCount(); i++){
for(int i=0; i<list.size() ; i++){
if(list.get(i).equals(l)){
((JCheckBoxMenuItem)tiles.getItem(i)).setSelected(true);
} else {

View file

@ -78,6 +78,7 @@ import com.osmand.data.City.CityType;
import com.osmand.data.index.DataIndexWriter;
import com.osmand.data.preparation.DataExtraction;
import com.osmand.map.IMapLocationListener;
import com.osmand.map.ITileSource;
import com.osmand.osm.Entity;
import com.osmand.osm.LatLon;
import com.osmand.osm.MapUtils;
@ -541,7 +542,11 @@ public class OsmExtractionUI implements IMapLocationListener {
JMenuItem exitMenu= new JMenuItem("Exit");
menu.add(exitMenu);
bar.add(MapPanel.getMenuToChooseSource(mapPanel));
JMenu tileSource = MapPanel.getMenuToChooseSource(mapPanel);
tileSource.addSeparator();
JMenuItem sqliteDB = new JMenuItem("Create sqlite database");
tileSource.add(sqliteDB);
bar.add(tileSource);
menu = new JMenu("Window");
bar.add(menu);
@ -573,6 +578,39 @@ public class OsmExtractionUI implements IMapLocationListener {
}
});
sqliteDB.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
final String regionName = region == null ? "Region" : region.getName();
final ITileSource map = mapPanel.getMap();
if(map != null){
try {
final ProgressDialog dlg = new ProgressDialog(frame, "Creating index");
dlg.setRunnable(new Runnable(){
@Override
public void run() {
try {
SQLiteBigPlanetIndex.createSQLiteDatabase(DataExtractionSettings.getSettings().getTilesDirectory(), regionName, map.getName());
} catch (SQLException e1) {
throw new IllegalArgumentException(e1);
} catch (IOException e1) {
throw new IllegalArgumentException(e1);
}
}
});
dlg.run();
} catch (InterruptedException e1) {
log.error("Interrupted", e1);
} catch (InvocationTargetException e1) {
ExceptionHandler.handle("Can't create big planet sqlite index", (Exception) e1.getCause());
}
}
}
});
exitMenu.addActionListener(new ActionListener(){
@Override

View file

@ -0,0 +1,109 @@
package com.osmand.swing;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import org.apache.commons.logging.Log;
import com.osmand.LogUtil;
public class SQLiteBigPlanetIndex {
private static final Log log = LogUtil.getLog(SQLiteBigPlanetIndex.class);
private static final int BATCH_SIZE = 50;
public static void createSQLiteDatabase(File dirWithTiles, String regionName, String tileSource) throws SQLException, IOException {
long now = System.currentTimeMillis();
try {
Class.forName("org.sqlite.JDBC"); //$NON-NLS-1$
} catch (ClassNotFoundException e) {
log.error("Illegal configuration", e); //$NON-NLS-1$
throw new IllegalStateException(e);
}
File fileToWrite = new File(dirWithTiles, regionName + "." + tileSource + ".sqlitedb");
fileToWrite.delete();
Connection conn = DriverManager.getConnection("jdbc:sqlite:" + fileToWrite.getAbsolutePath()); //$NON-NLS-1$
Statement statement = conn.createStatement();
statement.execute("CREATE TABLE tiles (x int, y int, z int, s int, image blob, PRIMARY KEY (x,y,z,s))");
statement.execute("CREATE INDEX IND on tiles (x,y,z,s)");
statement.execute("CREATE TABLE info(minzoom,maxzoom)");
statement.execute("CREATE TABLE android_metadata (locale TEXT)");
statement.close();
conn.setAutoCommit(false);
PreparedStatement pStatement = conn.prepareStatement("INSERT INTO tiles VALUES (?, ?, ?, ?, ?)");
int ch = 0;
int bufSize = 32 * 1024;
byte[] buf = new byte[bufSize];
int maxZoom = 17;
int minZoom = 1;
File rootDir = new File(dirWithTiles, tileSource);
for(File z : rootDir.listFiles()){
try {
int zoom = Integer.parseInt(z.getName());
for(File xDir : z.listFiles()){
try {
int x = Integer.parseInt(xDir.getName());
for(File f : xDir.listFiles()){
if(!f.isFile()){
continue;
}
try {
int i = f.getName().indexOf('.');
int y = Integer.parseInt(f.getName().substring(0, i));
buf = new byte[(int) f.length()];
if(zoom > maxZoom){
maxZoom = zoom;
}
if(zoom < minZoom){
minZoom = zoom;
}
FileInputStream is = new FileInputStream(f);
int l = is.read(buf);
if (l > 0) {
pStatement.setInt(1, x);
pStatement.setInt(2, y);
pStatement.setInt(3, zoom);
pStatement.setInt(4, 0);
pStatement.setBytes(5, buf);
pStatement.addBatch();
ch++;
if (ch >= BATCH_SIZE) {
pStatement.executeBatch();
ch = 0;
}
}
} catch (NumberFormatException e) {
}
}
} catch (NumberFormatException e) {
}
}
} catch (NumberFormatException e) {
}
}
if (ch > 0) {
pStatement.executeBatch();
ch = 0;
}
pStatement.close();
conn.commit();
conn.close();
log.info("Index created " + fileToWrite.getName() + " " + (System.currentTimeMillis() - now) + " ms");
}
}

View file

@ -1,5 +1,6 @@
package com.osmand;
import java.io.File;
import java.util.List;
import android.content.Context;
@ -7,6 +8,7 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.ActivityInfo;
import android.location.LocationManager;
import android.os.Environment;
import com.osmand.activities.RouteProvider.RouteService;
import com.osmand.activities.search.SearchHistoryHelper;
@ -278,6 +280,10 @@ public class OsmandSettings {
SharedPreferences prefs = ctx.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_WORLD_READABLE);
String tileName = prefs.getString(MAP_TILE_SOURCES, null);
if (tileName != null) {
if(tileName.endsWith(SQLiteTileSource.EXT)){
File file = new File(Environment.getExternalStorageDirectory(), ResourceManager.TILES_PATH);
return new SQLiteTileSource(new File(file, tileName));
}
List<TileSourceTemplate> list = TileSourceManager.getKnownSourceTemplates();
for (TileSourceTemplate l : list) {
if (l.getName().equals(tileName)) {

View file

@ -1,6 +1,7 @@
package com.osmand;
import java.io.File;
import java.io.IOException;
import java.text.Collator;
import java.text.MessageFormat;
import java.util.ArrayList;
@ -58,7 +59,7 @@ public class ResourceManager {
// it is not good investigated but no more than 64 (satellite images)
// Only 8 MB (from 16 Mb whole mem) available for images : image 64K * 128 = 8 MB (8 bit), 64 - 16 bit, 32 - 32 bit
protected final int maxImgCacheSize = 48;
protected int maxImgCacheSize = 48;
protected Map<String, Bitmap> cacheOfImages = new LinkedHashMap<String, Bitmap>();
protected Map<String, Boolean> imagesOnFS = new LinkedHashMap<String, Boolean>() ;
@ -107,7 +108,7 @@ public class ResourceManager {
} else if(f.getName().endsWith(".tile")){ //$NON-NLS-1$
imagesOnFS.put(prefix + f.getName(), Boolean.TRUE);
} else if(f.getName().endsWith(".sqlitedb")){ //$NON-NLS-1$
// TODO
// nothing to do here
}
}
@ -126,13 +127,34 @@ public class ResourceManager {
return getTileImageForMap(file, map, x, y, zoom, loadFromInternetIfNeeded, true, true);
}
public synchronized void tileDownloaded(String file){
imagesOnFS.put(file, Boolean.TRUE);
public synchronized void tileDownloaded(DownloadRequest request){
if(request instanceof TileLoadDownloadRequest){
TileLoadDownloadRequest req = ((TileLoadDownloadRequest) request);
imagesOnFS.put(req.tileId, Boolean.TRUE);
if(req.fileToSave != null && req.tileSource instanceof SQLiteTileSource){
try {
((SQLiteTileSource) req.tileSource).insertImage(req.xTile, req.yTile, req.zoom, req.fileToSave);
} catch (IOException e) {
log.warn("File "+req.fileToSave.getName() + " couldn't be read", e); //$NON-NLS-1$//$NON-NLS-2$
}
req.fileToSave.delete();
}
}
public synchronized boolean tileExistOnFileSystem(String file){
}
public synchronized boolean tileExistOnFileSystem(String file, ITileSource map, int x, int y, int zoom){
if(!imagesOnFS.containsKey(file)){
if(new File(dirWithTiles, file).exists()){
boolean ex = false;
if(map instanceof SQLiteTileSource){
ex = ((SQLiteTileSource) map).exists(x, y, zoom);
} else {
if(file == null){
file = calculateTileId(map, x, y, zoom);
}
ex = new File(dirWithTiles, file).exists();
}
if (ex) {
imagesOnFS.put(file, Boolean.TRUE);
} else {
imagesOnFS.put(file, null);
@ -157,68 +179,95 @@ public class ResourceManager {
protected StringBuilder builder = new StringBuilder(40);
public synchronized String calculateTileId(ITileSource map, int x, int y, int zoom){
builder.setLength(0);
builder.append(map.getName()).append('/').append(zoom). append('/').append(x).
builder.append(map.getName());
if(map instanceof SQLiteTileSource){
builder.append('@');
} else {
builder.append('/');
}
builder.append(zoom).append('/').append(x).
append('/').append(y).append(map.getTileFormat()).append(".tile"); //$NON-NLS-1$
String file = builder.toString();
return file;
}
protected synchronized Bitmap getTileImageForMap(String file, ITileSource map, int x, int y, int zoom,
protected synchronized Bitmap getTileImageForMap(String tileId, ITileSource map, int x, int y, int zoom,
boolean loadFromInternetIfNeeded, boolean sync, boolean loadFromFs, boolean deleteBefore) {
if (file == null) {
file = calculateTileId(map, x, y, zoom);
if(file == null){
if (tileId == null) {
tileId = calculateTileId(map, x, y, zoom);
if(tileId == null){
return null;
}
}
if(deleteBefore){
cacheOfImages.remove(file);
File f = new File(dirWithTiles, file);
cacheOfImages.remove(tileId);
if (map instanceof SQLiteTileSource) {
((SQLiteTileSource) map).deleteImage(x, y, zoom);
} else {
File f = new File(dirWithTiles, tileId);
if (f.exists()) {
f.delete();
imagesOnFS.put(file, null);
}
}
imagesOnFS.put(tileId, null);
}
if (loadFromFs && cacheOfImages.get(file) == null) {
if(!loadFromInternetIfNeeded && !tileExistOnFileSystem(file)){
if (loadFromFs && cacheOfImages.get(tileId) == null) {
if(!loadFromInternetIfNeeded && !tileExistOnFileSystem(tileId, map, x, y, zoom)){
return null;
}
String url = loadFromInternetIfNeeded ? map.getUrlToLoad(x, y, zoom) : null;
TileLoadDownloadRequest req = new TileLoadDownloadRequest(dirWithTiles, file, url, new File(dirWithTiles, file),
x, y, zoom);
File toSave = null;
if (url != null) {
if (map instanceof SQLiteTileSource) {
ITileSource base = ((SQLiteTileSource) map).getBase();
toSave = new File(dirWithTiles, calculateTileId(base, x, y, zoom));
} else {
toSave = new File(dirWithTiles, tileId);
}
}
TileLoadDownloadRequest req = new TileLoadDownloadRequest(dirWithTiles, url, toSave,
tileId, map, x, y, zoom);
if(sync){
return getRequestedImageTile(req);
} else {
asyncLoadingTiles.requestToLoadImage(req);
}
}
return cacheOfImages.get(file);
return cacheOfImages.get(tileId);
}
private Bitmap getRequestedImageTile(TileLoadDownloadRequest req){
if(req.fileToLoad == null || req.dirWithTiles == null){
if(req.tileId == null || req.dirWithTiles == null){
return null;
}
File en = new File(req.dirWithTiles, req.fileToLoad);
if (cacheOfImages.size() > maxImgCacheSize) {
clearTiles();
}
if (!downloader.isFileCurrentlyDownloaded(en) && req.dirWithTiles.canRead()) {
if (en.exists()) {
if (req.dirWithTiles.canRead() && !downloader.isFileCurrentlyDownloaded(req.fileToSave)) {
long time = System.currentTimeMillis();
cacheOfImages.put(req.fileToLoad, BitmapFactory.decodeFile(en.getAbsolutePath()));
if (log.isDebugEnabled()) {
log.debug("Loaded file : " + req.fileToLoad + " " + -(time - System.currentTimeMillis()) + " ms " + cacheOfImages.size()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
Bitmap bmp = null;
if (req.tileSource instanceof SQLiteTileSource) {
bmp = ((SQLiteTileSource) req.tileSource).getImage(req.xTile, req.yTile, req.zoom);
} else {
File en = new File(req.dirWithTiles, req.tileId);
if (en.exists()) {
bmp = BitmapFactory.decodeFile(en.getAbsolutePath());
}
}
if(cacheOfImages.get(req.fileToLoad) == null && req.url != null){
if (bmp != null) {
cacheOfImages.put(req.tileId, bmp);
if (log.isDebugEnabled()) {
log.debug("Loaded file : " + req.tileId + " " + -(time - System.currentTimeMillis()) + " ms " + cacheOfImages.size()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
if (cacheOfImages.get(req.tileId) == null && req.url != null) {
// TODO we could check that network is available (context is required)
// ConnectivityManager mgr = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
// NetworkInfo info = mgr.getActiveNetworkInfo();
@ -227,8 +276,9 @@ public class ResourceManager {
// }
downloader.requestToDownload(req);
}
}
return cacheOfImages.get(req.fileToLoad);
return cacheOfImages.get(req.tileId);
}
////////////////////////////////////////////// Working with indexes ////////////////////////////////////////////////
@ -444,6 +494,25 @@ public class ResourceManager {
}
public synchronized void setMapSource(ITileSource source){
log.info("Clear cache with new source " + cacheOfImages.size()); //$NON-NLS-1$
ArrayList<String> list = new ArrayList<String>(cacheOfImages.keySet());
// remove first images (as we think they are older)
for (int i = 0; i < list.size(); i ++) {
Bitmap bmp = cacheOfImages.remove(list.get(i));
if(bmp != null){
bmp.recycle();
}
}
if(source == null || source.getBitDensity() == 0){
maxImgCacheSize = 48;
} else {
maxImgCacheSize = 1024 / source.getBitDensity();
}
}
protected synchronized void clearTiles(){
log.info("Cleaning tiles - size = " + cacheOfImages.size()); //$NON-NLS-1$
ArrayList<String> list = new ArrayList<String>(cacheOfImages.keySet());
@ -462,14 +531,16 @@ public class ResourceManager {
private static class TileLoadDownloadRequest extends DownloadRequest {
public final String fileToLoad;
public final String tileId;
public final File dirWithTiles;
public final ITileSource tileSource;
public TileLoadDownloadRequest(File dirWithTiles,
String fileToLoad, String url, File fileToSave, int tileX, int tileY, int zoom) {
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.fileToLoad = fileToLoad;
tileSource = source;
this.tileId = tileId;
}
}
@ -533,7 +604,7 @@ public class ResourceManager {
Object req = requests.pop();
if (req instanceof TileLoadDownloadRequest) {
TileLoadDownloadRequest r = (TileLoadDownloadRequest) req;
if (cacheOfImages.get(r.fileToLoad) == null) {
if (cacheOfImages.get(r.tileId) == null) {
update |= getRequestedImageTile(r) != null;
}
} else if(req instanceof AmenityLoadRequest){

View file

@ -0,0 +1,194 @@
package com.osmand;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import com.osmand.map.ITileSource;
import com.osmand.map.TileSourceManager;
public class SQLiteTileSource implements ITileSource {
public static final String EXT = ".sqlitedb"; //$NON-NLS-1$
private ITileSource base;
private String name;
private SQLiteDatabase db;
private final File file;
public SQLiteTileSource(File f){
this.file = f;
int i = f.getName().lastIndexOf('.');
name = f.getName().substring(0, i);
i = name.lastIndexOf('.');
if(i > 0){
String sourceName = name.substring(i+1);
for(ITileSource is : TileSourceManager.getKnownSourceTemplates()){
if(is.getName().equalsIgnoreCase(sourceName)){
base = is;
break;
}
}
}
}
@Override
public int getBitDensity() {
return base != null ? base.getBitDensity() : 32;
}
@Override
public int getMaximumZoomSupported() {
return base != null ? base.getMaximumZoomSupported() : 17;
}
@Override
public int getMinimumZoomSupported() {
return base != null ? base.getMinimumZoomSupported() : 1;
}
@Override
public String getName() {
return name;
}
@Override
public String getTileFormat() {
return base != null ? base.getTileFormat() : ".png"; //$NON-NLS-1$
}
@Override
public int getTileSize() {
return base != null ? base.getTileSize() : 256;
}
@Override
public String getUrlToLoad(int x, int y, int zoom) {
if(getDatabase().isReadOnly()){
return null;
}
return base != null ? base.getUrlToLoad(x, y, zoom) : null;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((base == null) ? 0 : base.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SQLiteTileSource other = (SQLiteTileSource) obj;
if (base == null) {
if (other.base != null)
return false;
} else if (!base.equals(other.base))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
private SQLiteDatabase getDatabase(){
if(db == null){
db = SQLiteDatabase.openDatabase(file.getAbsolutePath(), null, 0);
}
return db;
}
public boolean exists(int x, int y, int zoom) {
Cursor cursor = getDatabase().rawQuery("SELECT 1 FROM tiles WHERE x = ? AND y = ? AND z = ?", new String[] {x+"", y+"",(17 - zoom)+""}); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
boolean e = cursor.moveToFirst();
cursor.close();
return e;
}
public Bitmap getImage(int x, int y, int zoom) {
Cursor cursor = getDatabase().rawQuery("SELECT image FROM tiles WHERE x = ? AND y = ? AND z = ?", new String[] {x+"", y+"",(17 - zoom)+""}); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
byte[] blob = null;
if(cursor.moveToFirst()) {
blob = cursor.getBlob(0);
}
cursor.close();
if(blob != null){
return BitmapFactory.decodeByteArray(blob, 0, blob.length);
}
return null;
}
public ITileSource getBase() {
return base;
}
public void deleteImage(int x, int y, int zoom) {
if(getDatabase().isReadOnly()){
return;
}
getDatabase().execSQL("DELETE FROM tiles WHERE x = ? AND y = ? AND z = ?", new String[] {x+"", y+"",(17 - zoom)+""}); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
}
private final int BUF_SIZE = 1024;
public void insertImage(int x, int y, int zoom, File fileToSave) throws IOException {
if(exists(x, y, zoom)){
return;
}
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 = getDatabase().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();
}
public void closeDB(){
if(db != null){
db.close();
db = null;
}
}
@Override
public boolean couldBeDownloadedFromInternet() {
if(getDatabase().isReadOnly() || base == null){
return false;
}
return base.couldBeDownloadedFromInternet();
}
}

View file

@ -57,6 +57,7 @@ import com.osmand.LogUtil;
import com.osmand.OsmandSettings;
import com.osmand.R;
import com.osmand.ResourceManager;
import com.osmand.SQLiteTileSource;
import com.osmand.Version;
import com.osmand.activities.FavouritesActivity.FavouritePoint;
import com.osmand.activities.FavouritesActivity.FavouritesDbHelper;
@ -67,6 +68,7 @@ import com.osmand.data.preparation.MapTileDownloader;
import com.osmand.data.preparation.MapTileDownloader.DownloadRequest;
import com.osmand.data.preparation.MapTileDownloader.IMapDownloaderCallback;
import com.osmand.map.IMapLocationListener;
import com.osmand.map.ITileSource;
import com.osmand.osm.LatLon;
import com.osmand.osm.MapUtils;
import com.osmand.views.AnimateDraggingMapThread;
@ -168,10 +170,10 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
public void tileDownloaded(DownloadRequest request) {
if(request != null && !request.error && request.fileToSave != null){
ResourceManager mgr = ResourceManager.getResourceManager();
String tile = mgr.calculateTileId(mapView.getMap(), request.xTile, request.yTile, request.zoom);
mgr.tileDownloaded(tile);
mgr.tileDownloaded(request);
}
mapView.tileDownloaded(request);
}
});
@ -588,8 +590,13 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
// routing helper with current activity
routingHelper = RoutingHelper.getInstance(this);
if(mapView.getMap() != OsmandSettings.getMapTileSource(this)){
mapView.setMap(OsmandSettings.getMapTileSource(this));
ITileSource source = OsmandSettings.getMapTileSource(this);
if(!Algoritms.objectEquals(mapView.getMap(), source)){
if(mapView.getMap() instanceof SQLiteTileSource){
((SQLiteTileSource)mapView.getMap()).closeDB();
}
ResourceManager.getResourceManager().setMapSource(source);
mapView.setMap(source);
}
if(!OsmandSettings.isRotateMapToBearing(this)){
mapView.setRotate(0);

View file

@ -1,6 +1,7 @@
package com.osmand.activities;
import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@ -34,6 +35,7 @@ import com.osmand.PoiFiltersHelper;
import com.osmand.ProgressDialogImplementation;
import com.osmand.R;
import com.osmand.ResourceManager;
import com.osmand.SQLiteTileSource;
import com.osmand.OsmandSettings.ApplicationMode;
import com.osmand.activities.RouteProvider.RouteService;
import com.osmand.map.TileSourceManager;
@ -101,6 +103,7 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
new BooleanPreference(OsmandSettings.SHOW_TRANSPORT_OVER_MAP, OsmandSettings.SHOW_TRANSPORT_OVER_MAP_DEF),
new BooleanPreference(OsmandSettings.SAVE_TRACK_TO_GPX, OsmandSettings.SAVE_TRACK_TO_GPX_DEF),
};
private BroadcastReceiver broadcastReceiver;
@ -157,13 +160,14 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
routeServiceEnabled.setOnPreferenceChangeListener(this);
registerReceiver(new BroadcastReceiver(){
broadcastReceiver = new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
routeServiceEnabled.setChecked(false);
}
}, new IntentFilter(NavigationService.OSMAND_STOP_SERVICE_ACTION));
};
registerReceiver(broadcastReceiver, new IntentFilter(NavigationService.OSMAND_STOP_SERVICE_ACTION));
}
@Override
@ -172,6 +176,12 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
updateAllSettings();
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(broadcastReceiver);
}
public void updateAllSettings(){
SharedPreferences prefs = getSharedPreferences(OsmandSettings.SHARED_PREFERENCES_NAME, Context.MODE_WORLD_READABLE);
for(BooleanPreference b : booleanPreferences){
@ -291,13 +301,34 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
List<TileSourceTemplate> list = TileSourceManager.getKnownSourceTemplates();
entries = new String[list.size()];
for (int i = 0; i < list.size(); i++) {
entries[i] = list.get(i).getName();
List<File> sqLiteFiles = new ArrayList<File>();
File dir = new File(Environment.getExternalStorageDirectory(), ResourceManager.TILES_PATH);
if (dir != null) {
for (File f : dir.listFiles()) {
if (f.getName().endsWith(SQLiteTileSource.EXT)) {
sqLiteFiles.add(f);
}
}
}
entries = new String[list.size() + sqLiteFiles.size()];
valueEntries = new String[list.size() + sqLiteFiles.size()];
for (int i = 0; i < list.size(); i++) {
entries[i + sqLiteFiles.size()] = list.get(i).getName();
valueEntries[i + sqLiteFiles.size()] = list.get(i).getName();
}
for (int i = 0; i < sqLiteFiles.size(); i++) {
String n = sqLiteFiles.get(i).getName();
entries[i] = n.substring(0, n.indexOf('.'));
valueEntries[i] = sqLiteFiles.get(i).getName();
}
tileSourcePreference.setEntries(entries);
tileSourcePreference.setEntryValues(entries);
tileSourcePreference.setEntryValues(valueEntries);
tileSourcePreference.setValue(OsmandSettings.getMapTileSourceName(this));
String mapName = " " +OsmandSettings.getMapTileSourceName(this); //$NON-NLS-1$
String summary = tileSourcePreference.getSummary().toString();

View file

@ -424,7 +424,7 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
Canvas canvas = holder.lockCanvas();
if (canvas != null) {
ResourceManager mgr = ResourceManager.getResourceManager();
boolean useInternet = OsmandSettings.isUsingInternetToDownloadTiles(getContext());
boolean useInternet = OsmandSettings.isUsingInternetToDownloadTiles(getContext()) && map.couldBeDownloadedFromInternet();
int maxLevel = OsmandSettings.getMaximumLevelToDownloadTile(getContext());
canvas.save();
canvas.rotate(rotate, w , h);
@ -441,7 +441,7 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
float y1 = (j + top - tileY) * ftileSize + h;
String ordImgTile = mgr.calculateTileId(map, left + i, top + j, nzoom);
// asking tile image async
boolean imgExist = mgr.tileExistOnFileSystem(ordImgTile);
boolean imgExist = mgr.tileExistOnFileSystem(ordImgTile, map, left + i, top + j, nzoom);
Bitmap bmp = null;
boolean originalBeLoaded = useInternet && nzoom <= maxLevel;
if (imgExist || originalBeLoaded) {
@ -461,10 +461,10 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
}
}
if(!originalBeLoaded && !imgExist){
if (mgr.tileExistOnFileSystem(imgTile2) || (useInternet && nzoom - 1 <= maxLevel)) {
if (mgr.tileExistOnFileSystem(imgTile2, map, (left + i) / 2, (top + j) / 2, nzoom - 1) || (useInternet && nzoom - 1 <= maxLevel)) {
bmp = mgr.getTileImageForMapAsync(imgTile2, map, (left + i) / 2, (top + j) / 2, nzoom - 1, useInternet);
div = 2;
} else if (mgr.tileExistOnFileSystem(imgTile4) || (useInternet && nzoom - 2 <= maxLevel)) {
} else if (mgr.tileExistOnFileSystem(imgTile4, map, (left + i) / 4, (top + j) / 4, nzoom - 2) || (useInternet && nzoom - 2 <= maxLevel)) {
bmp = mgr.getTileImageForMapAsync(imgTile4, map, (left + i) / 4, (top + j) / 4, nzoom - 2, useInternet);
div = 4;
}