diff --git a/OsmAnd-java/src/net/osmand/map/ITileSource.java b/OsmAnd-java/src/net/osmand/map/ITileSource.java index 0430afffda..67e55c9db0 100644 --- a/OsmAnd-java/src/net/osmand/map/ITileSource.java +++ b/OsmAnd-java/src/net/osmand/map/ITileSource.java @@ -1,28 +1,31 @@ package net.osmand.map; +import java.io.IOException; public interface ITileSource { - + public int getMaximumZoomSupported(); - + public String getName(); - + public int getTileSize(); - + public String getUrlToLoad(int x, int y, int zoom); - + + public byte[] getBytes(int x, int y, int zoom, String dirWithTiles) throws IOException; + public int getMinimumZoomSupported(); - + public String getTileFormat(); - + public int getBitDensity(); - + public boolean isEllipticYTile(); - + public boolean couldBeDownloadedFromInternet(); - + public int getExpirationTimeMillis(); - + public int getExpirationTimeMinutes(); - + } diff --git a/OsmAnd-java/src/net/osmand/map/TileSourceManager.java b/OsmAnd-java/src/net/osmand/map/TileSourceManager.java index e909d50380..0f9c220ac9 100644 --- a/OsmAnd-java/src/net/osmand/map/TileSourceManager.java +++ b/OsmAnd-java/src/net/osmand/map/TileSourceManager.java @@ -2,6 +2,7 @@ package net.osmand.map; import java.io.BufferedReader; import java.io.BufferedWriter; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -18,6 +19,7 @@ import java.util.List; import java.util.Map; import net.osmand.PlatformUtil; +import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; import org.xmlpull.v1.XmlPullParser; @@ -215,6 +217,27 @@ public class TileSourceManager { public String getRule() { return rule; } + + public String calculateTileId(int x, int y, int zoom) { + StringBuilder builder = new StringBuilder(getName()); + builder.append('/'); + builder.append(zoom).append('/').append(x).append('/').append(y).append(getTileFormat()).append(".tile"); //$NON-NLS-1$ //$NON-NLS-2$ + return builder.toString(); + } + + @Override + public byte[] getBytes(int x, int y, int zoom, String dirWithTiles) throws IOException { + File f = new File(dirWithTiles, calculateTileId(x, y, zoom)); + if (!f.exists()) + return null; + + ByteArrayOutputStream bous = new ByteArrayOutputStream(); + FileInputStream fis = new FileInputStream(f); + Algorithms.streamCopy(fis, bous); + fis.close(); + bous.close(); + return bous.toByteArray(); + } } private static Map readMetaInfoFile(File dir) { diff --git a/OsmAnd/src/net/osmand/core/android/CoreResourcesFromAndroidAssetsCustom.java b/OsmAnd/src/net/osmand/core/android/CoreResourcesFromAndroidAssetsCustom.java index 1ffd613062..aff480433c 100644 --- a/OsmAnd/src/net/osmand/core/android/CoreResourcesFromAndroidAssetsCustom.java +++ b/OsmAnd/src/net/osmand/core/android/CoreResourcesFromAndroidAssetsCustom.java @@ -2,6 +2,8 @@ package net.osmand.core.android; import java.io.BufferedReader; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -19,247 +21,272 @@ import net.osmand.core.jni.SWIGTYPE_p_QByteArray; import net.osmand.core.jni.SWIGTYPE_p_bool; import net.osmand.core.jni.SwigUtilities; import net.osmand.plus.OsmandApplication; +import net.osmand.util.Algorithms; +import android.annotation.TargetApi; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.AssetFileDescriptor; import android.content.res.AssetManager; +import android.os.Build; import android.util.Log; // This class provides reverse mapping from 'embed-resources.list' to files&folders scheme used by OsmAndCore_android.aar package +@TargetApi(Build.VERSION_CODES.GINGERBREAD) public class CoreResourcesFromAndroidAssetsCustom extends interface_ICoreResourcesProvider { - private static final String TAG = "CoreResourcesFromAndroidAssets"; - private static final String NATIVE_TAG = "CoreResourcesFromAndroidAssets"; + private static final String TAG = "CoreResourcesFromAndroidAssets"; + private static final String NATIVE_TAG = "CoreResourcesFromAndroidAssets"; - private CoreResourcesFromAndroidAssetsCustom(final Context context) { - _context = context; - } + private CoreResourcesFromAndroidAssetsCustom(final Context context) { + _context = context; + } - private boolean load() { - final AssetManager assetManager = _context.getResources().getAssets(); + private boolean load() { + final AssetManager assetManager = _context.getResources().getAssets(); - PackageInfo packageInfo = null; - try { - packageInfo = _context.getPackageManager().getPackageInfo(_context.getPackageName(), 0); - } catch(NameNotFoundException e) { - Log.e(TAG, "Failed to get own package info", e); - return false; - } - _bundleFilename = packageInfo.applicationInfo.sourceDir; - Log.i(TAG, "Located own package at '" + _bundleFilename + "'"); - - // Load the index - final List resourcesInBundle = new LinkedList(); - try { - final InputStream resourcesIndexStream = assetManager.open("OsmAndCore_ResourcesBundle.index", AssetManager.ACCESS_BUFFER); + PackageInfo packageInfo = null; + try { + packageInfo = _context.getPackageManager().getPackageInfo(_context.getPackageName(), 0); + } catch (NameNotFoundException e) { + Log.e(TAG, "Failed to get own package info", e); + return false; + } + _bundleFilename = packageInfo.applicationInfo.sourceDir; + Log.i(TAG, "Located own package at '" + _bundleFilename + "'"); - final BufferedReader resourcesIndexBufferedReader = new BufferedReader(new InputStreamReader(resourcesIndexStream)); - String resourceInBundle; - while ((resourceInBundle = resourcesIndexBufferedReader.readLine()) != null) - resourcesInBundle.add(resourceInBundle); - } catch (IOException e) { - Log.e(TAG, "Failed to read bundle index", e); - return false; - } - Log.i(TAG, "Application contains " + resourcesInBundle.size() + " resources"); + // Load the index + final List resourcesInBundle = new LinkedList(); + try { + final InputStream resourcesIndexStream = assetManager.open("OsmAndCore_ResourcesBundle.index", + AssetManager.ACCESS_BUFFER); - // Parse resources index - final Pattern resourceNameWithQualifiersRegExp = Pattern.compile("(?:\\[(.*)\\]/)(.*)"); - for (String resourceInBundle : resourcesInBundle) { - // Process resource name - String pureResourceName = resourceInBundle; - String[] qualifiers = null; - final Matcher resourceNameComponentsMatcher = resourceNameWithQualifiersRegExp.matcher(resourceInBundle); - if (resourceNameComponentsMatcher.matches()) { - qualifiers = resourceNameComponentsMatcher.group(1).split(";"); - pureResourceName = resourceNameComponentsMatcher.group(2); - } + final BufferedReader resourcesIndexBufferedReader = new BufferedReader(new InputStreamReader( + resourcesIndexStream)); + String resourceInBundle; + while ((resourceInBundle = resourcesIndexBufferedReader.readLine()) != null) + resourcesInBundle.add(resourceInBundle); + } catch (IOException e) { + Log.e(TAG, "Failed to read bundle index", e); + return false; + } + Log.i(TAG, "Application contains " + resourcesInBundle.size() + " resources"); - // Get location of this resource - final String path = "OsmAndCore_ResourcesBundle/" + resourceInBundle + ".qz"; - final File res = ((OsmandApplication) _context.getApplicationContext()).getAppPath(path); - final ResourceData resourceData = new ResourceData(); - if (!res.exists()) { + // Parse resources index + final Pattern resourceNameWithQualifiersRegExp = Pattern.compile("(?:\\[(.*)\\]/)(.*)"); + for (String resourceInBundle : resourcesInBundle) { + // Process resource name + String pureResourceName = resourceInBundle; + String[] qualifiers = null; + final Matcher resourceNameComponentsMatcher = resourceNameWithQualifiersRegExp.matcher(resourceInBundle); + if (resourceNameComponentsMatcher.matches()) { + qualifiers = resourceNameComponentsMatcher.group(1).split(";"); + pureResourceName = resourceNameComponentsMatcher.group(2); + } + + // Get location of this resource + final String path = "OsmAndCore_ResourcesBundle/" + resourceInBundle + ".qz"; + final File extractedPath = ((OsmandApplication) _context.getApplicationContext()).getAppPath(path); + final ResourceData resourceData = new ResourceData(); + if (!extractedPath.exists()) { try { - final AssetFileDescriptor resourceFd = assetManager.openFd(path); long declaredSize = resourceFd.getDeclaredLength(); resourceData.size = resourceFd.getLength(); resourceData.offset = resourceFd.getStartOffset(); - if(resourceData.offset == 0) { - Log.e(NATIVE_TAG, "Offset 0 is not properly supported!"); - continue; - } resourceData.path = new File(_bundleFilename); resourceFd.close(); if (declaredSize != resourceData.size) { Log.e(NATIVE_TAG, "Declared size does not match size for '" + resourceInBundle + "'"); continue; } + } catch (FileNotFoundException e) { + try { + final File containgDir = extractedPath.getParentFile(); + if (containgDir != null && !containgDir.exists()) + containgDir.mkdirs(); + extractedPath.createNewFile(); + + final InputStream resourceStream = assetManager.open(path, AssetManager.ACCESS_STREAMING); + final FileOutputStream fileStream = new FileOutputStream(extractedPath); + Algorithms.streamCopy(resourceStream, fileStream); + Algorithms.closeStream(fileStream); + Algorithms.closeStream(resourceStream); + } catch (IOException e2) { + if (extractedPath.exists()) + extractedPath.delete(); + + Log.e(NATIVE_TAG, "Failed to extract '" + resourceInBundle + "'", e2); + continue; + } + resourceData.offset = 0; + resourceData.path = extractedPath; + resourceData.size = resourceData.path.length(); } catch (IOException e) { Log.e(NATIVE_TAG, "Failed to locate '" + resourceInBundle + "'", e); continue; } - } else { resourceData.offset = 0; - resourceData.path = res; + resourceData.path = extractedPath; resourceData.size = resourceData.path.length(); } - // Get resource entry for this resource - ResourceEntry resourceEntry = _resources.get(pureResourceName); - if (resourceEntry == null) { - resourceEntry = new ResourceEntry(); - _resources.put(pureResourceName, resourceEntry); - } - if (qualifiers == null) { - resourceEntry.defaultVariant = resourceData; - } else { - for (String qualifier : qualifiers) { - final String[] qualifierComponents = qualifier.trim().split("="); - - if (qualifierComponents.length == 2 && qualifierComponents[0].equals("ddf")) { - float ddfValue; - try { - ddfValue = Float.parseFloat(qualifierComponents[1]); - } catch (NumberFormatException e) { - Log.e(TAG, "Unsupported value '" + qualifierComponents[1] + "' for DDF qualifier", e); - continue; - } + // Get resource entry for this resource + ResourceEntry resourceEntry = _resources.get(pureResourceName); + if (resourceEntry == null) { + resourceEntry = new ResourceEntry(); + _resources.put(pureResourceName, resourceEntry); + } + if (qualifiers == null) { + resourceEntry.defaultVariant = resourceData; + } else { + for (String qualifier : qualifiers) { + final String[] qualifierComponents = qualifier.trim().split("="); - if (resourceEntry.variantsByDisplayDensityFactor == null) - resourceEntry.variantsByDisplayDensityFactor = new TreeMap(); - resourceEntry.variantsByDisplayDensityFactor.put(ddfValue, resourceData); - } else { - Log.w(TAG, "Unsupported qualifier '" + qualifier.trim() + "'"); - } - } - } - } + if (qualifierComponents.length == 2 && qualifierComponents[0].equals("ddf")) { + float ddfValue; + try { + ddfValue = Float.parseFloat(qualifierComponents[1]); + } catch (NumberFormatException e) { + Log.e(TAG, "Unsupported value '" + qualifierComponents[1] + "' for DDF qualifier", e); + continue; + } - return true; - } - - private final Context _context; - private String _bundleFilename; - private final HashMap _resources = new HashMap(); - - private final class ResourceData { - public File path; - public long offset; - public long size; - } - private final class ResourceEntry { - public ResourceData defaultVariant; - public TreeMap variantsByDisplayDensityFactor; - } - - @Override - public SWIGTYPE_p_QByteArray getResource(String name, float displayDensityFactor, SWIGTYPE_p_bool ok_) { - final BoolPtr ok = BoolPtr.frompointer(ok_); - - final ResourceEntry resourceEntry = _resources.get(name); - if (resourceEntry == null || resourceEntry.variantsByDisplayDensityFactor == null) { - Log.w(TAG, "Requested resource [ddf=" + displayDensityFactor + "]'" + name + "' was not found"); - if (ok != null) - ok.assign(false); - return SwigUtilities.emptyQByteArray(); - } - - Map.Entry resourceDataEntry = resourceEntry.variantsByDisplayDensityFactor.ceilingEntry(displayDensityFactor); - if (resourceDataEntry == null) - resourceDataEntry = resourceEntry.variantsByDisplayDensityFactor.lastEntry(); - ResourceData resourceData = resourceDataEntry.getValue(); - Log.d(TAG, "Using ddf=" + resourceDataEntry.getKey() + " while looking for " + displayDensityFactor + " of '" + name + "'"); - System.out.println(resourceData.path.getAbsolutePath()); - final SWIGTYPE_p_QByteArray data ; - if(resourceData.offset == 0){ - data = SwigUtilities.qDecompress(SwigUtilities.readEntireFile( - resourceData.path.getAbsolutePath())); - } else { - data = SwigUtilities.qDecompress(SwigUtilities.readPartOfFile( - resourceData.path.getAbsolutePath(), resourceData.offset, resourceData.size)); + if (resourceEntry.variantsByDisplayDensityFactor == null) + resourceEntry.variantsByDisplayDensityFactor = new TreeMap(); + resourceEntry.variantsByDisplayDensityFactor.put(ddfValue, resourceData); + } else { + Log.w(TAG, "Unsupported qualifier '" + qualifier.trim() + "'"); + } + } + } } - if (data == null) { - Log.e(TAG, "Failed to load data of '" + name + "'"); - if (ok != null) - ok.assign(false); - return SwigUtilities.emptyQByteArray(); - } - if (ok != null) - ok.assign(true); - return data; - } + return true; + } - @Override - public SWIGTYPE_p_QByteArray getResource(String name, SWIGTYPE_p_bool ok_) { - final BoolPtr ok = BoolPtr.frompointer(ok_); - - final ResourceEntry resourceEntry = _resources.get(name); - if (resourceEntry == null) { - Log.w(TAG, "Requested resource '" + name + "' was not found"); - if (ok != null) - ok.assign(false); - return SwigUtilities.emptyQByteArray(); - } + private final Context _context; + private String _bundleFilename; + private final HashMap _resources = new HashMap(); - if (resourceEntry.defaultVariant == null) { - Log.w(TAG, "Requested resource '" + name + "' was not found"); - if (ok != null) - ok.assign(false); - return SwigUtilities.emptyQByteArray(); - } + private final class ResourceData { + public File path; + public long offset; + public long size; + } + + private final class ResourceEntry { + public ResourceData defaultVariant; + public TreeMap variantsByDisplayDensityFactor; + } + + @Override + public SWIGTYPE_p_QByteArray getResource(String name, float displayDensityFactor, SWIGTYPE_p_bool ok_) { + final BoolPtr ok = BoolPtr.frompointer(ok_); + + final ResourceEntry resourceEntry = _resources.get(name); + if (resourceEntry == null || resourceEntry.variantsByDisplayDensityFactor == null) { + Log.w(TAG, "Requested resource [ddf=" + displayDensityFactor + "]'" + name + "' was not found"); + if (ok != null) + ok.assign(false); + return SwigUtilities.emptyQByteArray(); + } + + Map.Entry resourceDataEntry = resourceEntry.variantsByDisplayDensityFactor + .ceilingEntry(displayDensityFactor); + if (resourceDataEntry == null) + resourceDataEntry = resourceEntry.variantsByDisplayDensityFactor.lastEntry(); + ResourceData resourceData = resourceDataEntry.getValue(); + Log.d(TAG, "Using ddf=" + resourceDataEntry.getKey() + " while looking for " + displayDensityFactor + " of '" + + name + "'"); + System.out.println(resourceData.path.getAbsolutePath()); + final SWIGTYPE_p_QByteArray data; + if (resourceData.offset == 0 && resourceData.size == resourceData.path.length()) { + data = SwigUtilities.qDecompress(SwigUtilities.readEntireFile(resourceData.path.getAbsolutePath())); + } else { + data = SwigUtilities.qDecompress(SwigUtilities.readPartOfFile(resourceData.path.getAbsolutePath(), + resourceData.offset, resourceData.size)); + } + if (data == null) { + Log.e(TAG, "Failed to load data of '" + name + "'"); + if (ok != null) + ok.assign(false); + return SwigUtilities.emptyQByteArray(); + } + + if (ok != null) + ok.assign(true); + return data; + } + + @Override + public SWIGTYPE_p_QByteArray getResource(String name, SWIGTYPE_p_bool ok_) { + final BoolPtr ok = BoolPtr.frompointer(ok_); + + final ResourceEntry resourceEntry = _resources.get(name); + if (resourceEntry == null) { + Log.w(TAG, "Requested resource '" + name + "' was not found"); + if (ok != null) + ok.assign(false); + return SwigUtilities.emptyQByteArray(); + } + + if (resourceEntry.defaultVariant == null) { + Log.w(TAG, "Requested resource '" + name + "' was not found"); + if (ok != null) + ok.assign(false); + return SwigUtilities.emptyQByteArray(); + } System.out.println(resourceEntry.defaultVariant.path.getAbsolutePath()); - final SWIGTYPE_p_QByteArray bt ; - if(resourceEntry.defaultVariant.offset == 0){ + final SWIGTYPE_p_QByteArray bt; + if (resourceEntry.defaultVariant.offset == 0 + && resourceEntry.defaultVariant.size == resourceEntry.defaultVariant.path.length()) { bt = SwigUtilities.readEntireFile(resourceEntry.defaultVariant.path.getAbsolutePath()); } else { bt = SwigUtilities.readPartOfFile(resourceEntry.defaultVariant.path.getAbsolutePath(), resourceEntry.defaultVariant.offset, resourceEntry.defaultVariant.size); } final SWIGTYPE_p_QByteArray data = SwigUtilities.qDecompress(bt); - if (data == null) { - Log.e(TAG, "Failed to load data of '" + name + "'"); - if (ok != null) - ok.assign(false); - return SwigUtilities.emptyQByteArray(); - } + if (data == null) { + Log.e(TAG, "Failed to load data of '" + name + "'"); + if (ok != null) + ok.assign(false); + return SwigUtilities.emptyQByteArray(); + } - if (ok != null) - ok.assign(true); - return data; - } + if (ok != null) + ok.assign(true); + return data; + } - @Override - public boolean containsResource(String name, float displayDensityFactor) { - final ResourceEntry resourceEntry = _resources.get(name); - if (resourceEntry == null || resourceEntry.variantsByDisplayDensityFactor == null) - return false; + @Override + public boolean containsResource(String name, float displayDensityFactor) { + final ResourceEntry resourceEntry = _resources.get(name); + if (resourceEntry == null || resourceEntry.variantsByDisplayDensityFactor == null) + return false; - // If there's variant for any DDF, it will be used - return true; - } + // If there's variant for any DDF, it will be used + return true; + } - @Override - public boolean containsResource(String name) { - final ResourceEntry resourceEntry = _resources.get(name); - if (resourceEntry == null) - return false; + @Override + public boolean containsResource(String name) { + final ResourceEntry resourceEntry = _resources.get(name); + if (resourceEntry == null) + return false; - if (resourceEntry.defaultVariant == null) - return false; + if (resourceEntry.defaultVariant == null) + return false; - return true; - } + return true; + } - public static CoreResourcesFromAndroidAssetsCustom loadFromCurrentApplication(final Context context) { - final CoreResourcesFromAndroidAssetsCustom bundle = new CoreResourcesFromAndroidAssetsCustom(context); + public static CoreResourcesFromAndroidAssetsCustom loadFromCurrentApplication(final Context context) { + final CoreResourcesFromAndroidAssetsCustom bundle = new CoreResourcesFromAndroidAssetsCustom(context); - if (!bundle.load()) - return null; + if (!bundle.load()) + return null; - return bundle; - } + return bundle; + } } diff --git a/OsmAnd/src/net/osmand/core/android/TileSourceProxyProvider.java b/OsmAnd/src/net/osmand/core/android/TileSourceProxyProvider.java new file mode 100644 index 0000000000..9d67ef5896 --- /dev/null +++ b/OsmAnd/src/net/osmand/core/android/TileSourceProxyProvider.java @@ -0,0 +1,64 @@ +package net.osmand.core.android; + +import java.io.IOException; + +import net.osmand.IndexConstants; +import net.osmand.core.jni.AlphaChannelPresence; +import net.osmand.core.jni.SWIGTYPE_p_QByteArray; +import net.osmand.core.jni.SwigUtilities; +import net.osmand.core.jni.TileId; +import net.osmand.core.jni.ZoomLevel; +import net.osmand.core.jni.interface_ImageMapLayerProvider; +import net.osmand.map.ITileSource; +import net.osmand.plus.OsmandApplication; + +public class TileSourceProxyProvider extends interface_ImageMapLayerProvider { + + private final OsmandApplication app; + private final ITileSource tileSource; + + public TileSourceProxyProvider(OsmandApplication app, ITileSource tileSource) { + this.app = app; + this.tileSource = tileSource; + } + + @Override + public ZoomLevel getMinZoom() { + return ZoomLevel.swigToEnum(tileSource.getMinimumZoomSupported()); + } + + @Override + public ZoomLevel getMaxZoom() { + return ZoomLevel.swigToEnum(tileSource.getMaximumZoomSupported()); + } + + @Override + public SWIGTYPE_p_QByteArray obtainImage(TileId tileId, ZoomLevel zoom) { + byte[] image; + try { + image = tileSource.getBytes(tileId.getX(), tileId.getY(), zoom.swigValue(), + app.getAppPath(IndexConstants.TILES_INDEX_DIR).getAbsolutePath()); + } catch(IOException e) { + return SwigUtilities.emptyQByteArray(); + } + if (image == null) + return SwigUtilities.emptyQByteArray(); + + return SwigUtilities.createQByteArrayAsCopyOf(image); + } + + @Override + public long getTileSize() { + return tileSource.getTileSize(); + } + + @Override + public float getTileDensityFactor() { + return 1.0f; + } + + @Override + public AlphaChannelPresence getAlphaChannelPresence() { + return AlphaChannelPresence.Unknown; + } +} diff --git a/OsmAnd/src/net/osmand/plus/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/OsmandSettings.java index 9e38b5ea85..80babd55c2 100644 --- a/OsmAnd/src/net/osmand/plus/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/OsmandSettings.java @@ -14,7 +14,6 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; - import net.osmand.IndexConstants; import net.osmand.StateChangedListener; import net.osmand.data.LatLon; @@ -28,6 +27,7 @@ import net.osmand.plus.api.SettingsAPI.SettingsEditor; import net.osmand.plus.render.RendererRegistry; import net.osmand.plus.routing.RouteProvider.RouteService; import net.osmand.render.RenderingRulesStorage; +import android.annotation.SuppressLint; import android.content.Context; import android.content.res.Configuration; import android.hardware.Sensor; @@ -989,18 +989,18 @@ public class OsmandSettings { public final CommonPreference SHOW_DESTINATION_ARROW = new BooleanPreference("show_destination_arrow", false).makeProfile(); // this value string is synchronized with settings_pref.xml preference name - public final CommonPreference MAP_OVERLAY = new StringPreference("map_overlay", null).makeGlobal(); + public final CommonPreference MAP_OVERLAY = new StringPreference("map_overlay", null).makeGlobal().cache(); // this value string is synchronized with settings_pref.xml preference name - public final CommonPreference MAP_UNDERLAY = new StringPreference("map_underlay", null).makeGlobal(); + public final CommonPreference MAP_UNDERLAY = new StringPreference("map_underlay", null).makeGlobal().cache(); // this value string is synchronized with settings_pref.xml preference name public final CommonPreference MAP_OVERLAY_TRANSPARENCY = new IntPreference("overlay_transparency", - 100).makeGlobal(); + 100).makeGlobal().cache(); // this value string is synchronized with settings_pref.xml preference name public final CommonPreference MAP_TRANSPARENCY = new IntPreference("map_transparency", - 255).makeGlobal(); + 255).makeGlobal().cache(); // this value string is synchronized with settings_pref.xml preference name public final CommonPreference MAP_TILE_SOURCES = new StringPreference("map_tile_sources", @@ -1160,6 +1160,7 @@ public class OsmandSettings { return writableSecondaryStorage; } + @SuppressLint("NewApi") public String getMatchingExternalFilesDir(String dir) { // only API 19 !! try { @@ -1183,6 +1184,7 @@ public class OsmandSettings { } } + @SuppressLint("NewApi") public List getWritableSecondaryStorageDirectorys() { // only API 19 !! // primary external storage directory diff --git a/OsmAnd/src/net/osmand/plus/SQLiteTileSource.java b/OsmAnd/src/net/osmand/plus/SQLiteTileSource.java index 5d603235f7..36e7f2fbc3 100644 --- a/OsmAnd/src/net/osmand/plus/SQLiteTileSource.java +++ b/OsmAnd/src/net/osmand/plus/SQLiteTileSource.java @@ -18,7 +18,6 @@ import net.osmand.plus.api.SQLiteAPI.SQLiteCursor; import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; -import org.apache.http.client.protocol.ClientContext; import android.database.sqlite.SQLiteDiskIOException; import android.graphics.Bitmap; @@ -262,7 +261,7 @@ public class SQLiteTileSource implements ITileSource { return db.isDbLockedByOtherThreads(); } - public Bitmap getImage(int x, int y, int zoom, long[] timeHolder) { + public byte[] getBytes(int x, int y, int zoom, String dirWithTiles, long[] timeHolder) throws IOException { SQLiteConnection db = getDatabase(); if(db == null){ return null; @@ -283,15 +282,7 @@ public class SQLiteTileSource implements ITileSource { } } cursor.close(); - if (blob != null) { - Bitmap bmp = null; - bmp = BitmapFactory.decodeByteArray(blob, 0, blob.length); - if(bmp == null) { - // broken image delete it - db.execSQL("DELETE FROM tiles WHERE x = ? AND y = ? AND z = ?", params); - } - return bmp; - } + return blob; } return null; } finally { @@ -301,6 +292,35 @@ public class SQLiteTileSource implements ITileSource { } } } + + @Override + public byte[] getBytes(int x, int y, int zoom, String dirWithTiles) throws IOException { + return getBytes(x, y, zoom, dirWithTiles, null); + } + + public Bitmap getImage(int x, int y, int zoom, long[] timeHolder) { + SQLiteConnection db = getDatabase(); + if(db == null){ + return null; + } + String[] params = new String[] { x + "", y + "", getFileZoom(zoom) + "" }; + byte[] blob; + try { + blob = getBytes(x, y, zoom, null, timeHolder); + } catch (IOException e) { + return null; + } + if (blob != null) { + Bitmap bmp = null; + bmp = BitmapFactory.decodeByteArray(blob, 0, blob.length); + if(bmp == null) { + // broken image delete it + db.execSQL("DELETE FROM tiles WHERE x = ? AND y = ? AND z = ?", params); + } + return bmp; + } + return null; + } public ITileSource getBase() { return base; diff --git a/OsmAnd/src/net/osmand/plus/render/MapVectorLayer.java b/OsmAnd/src/net/osmand/plus/render/MapVectorLayer.java index 04b718677d..2b4edd2897 100644 --- a/OsmAnd/src/net/osmand/plus/render/MapVectorLayer.java +++ b/OsmAnd/src/net/osmand/plus/render/MapVectorLayer.java @@ -1,14 +1,19 @@ package net.osmand.plus.render; import net.osmand.core.android.MapRendererView; +import net.osmand.core.android.TileSourceProxyProvider; +import net.osmand.core.jni.MapLayerConfiguration; import net.osmand.core.jni.PointI; import net.osmand.data.QuadPointDouble; import net.osmand.data.RotatedTileBox; +import net.osmand.map.ITileSource; +import net.osmand.plus.OsmandSettings; import net.osmand.plus.resources.ResourceManager; import net.osmand.plus.views.BaseMapLayer; import net.osmand.plus.views.MapTileLayer; import net.osmand.plus.views.OsmandMapTileView; import net.osmand.plus.views.corenative.NativeCoreContext; +import net.osmand.util.Algorithms; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; @@ -20,17 +25,20 @@ public class MapVectorLayer extends BaseMapLayer { private OsmandMapTileView view; private ResourceManager resourceManager; private Paint paintImg; - + private RectF destImage = new RectF(); private final MapTileLayer tileLayer; private boolean visible = false; private boolean oldRender = false; - - public MapVectorLayer(MapTileLayer tileLayer, boolean oldRender){ + private String cachedUnderlay; + private Integer cachedMapTransparency; + private String cachedOverlay; + private Integer cachedOverlayTransparency; + + public MapVectorLayer(MapTileLayer tileLayer, boolean oldRender) { this.tileLayer = tileLayer; this.oldRender = oldRender; } - @Override public void destroyLayer() { @@ -49,43 +57,39 @@ public class MapVectorLayer extends BaseMapLayer { paintImg.setFilterBitmap(true); paintImg.setAlpha(getAlpha()); } - + public boolean isVectorDataVisible() { - return visible && view.getZoom() >= view.getSettings().LEVEL_TO_SWITCH_VECTOR_RASTER.get(); + return visible && view.getZoom() >= view.getSettings().LEVEL_TO_SWITCH_VECTOR_RASTER.get(); } - - + public boolean isVisible() { return visible; } - + public void setVisible(boolean visible) { this.visible = visible; - if(!visible){ + if (!visible) { resourceManager.getRenderer().clearCache(); } } - + @Override public int getMaximumShownMapZoom() { return 23; } - + @Override public int getMinimumShownMapZoom() { return 1; } - @Override public void onDraw(Canvas canvas, RotatedTileBox tilesRect, DrawSettings drawSettings) { - + } - - + @Override - public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tilesRect, - DrawSettings drawSettings) { + public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tilesRect, DrawSettings drawSettings) { if (!visible) { return; } @@ -96,10 +100,46 @@ public class MapVectorLayer extends BaseMapLayer { final MapRendererView mapRenderer = view.getMapRenderer(); if (mapRenderer != null && !oldRender) { NativeCoreContext.getMapRendererContext().setNightMode(drawSettings.isNightMode()); + OsmandSettings st = view.getApplication().getSettings(); + if (!Algorithms.objectEquals(st.MAP_UNDERLAY.get(), cachedUnderlay)) { + cachedUnderlay = st.MAP_UNDERLAY.get(); + ITileSource tileSource = st.getTileSourceByName(cachedUnderlay, false); + if (tileSource != null) { + TileSourceProxyProvider prov = new TileSourceProxyProvider(view.getApplication(), tileSource); + mapRenderer.setMapLayerProvider(-1, prov.instantiateProxy(true)); + prov.swigReleaseOwnership(); + } else { + mapRenderer.resetMapLayerProvider(-1); + } + } + if (st.MAP_TRANSPARENCY.get() != cachedMapTransparency) { + cachedMapTransparency = st.MAP_TRANSPARENCY.get(); + MapLayerConfiguration mapLayerConfiguration = new MapLayerConfiguration(); + mapLayerConfiguration.setOpacity(((float)cachedMapTransparency) / 255.0f); + mapRenderer.setMapLayerConfiguration(0, mapLayerConfiguration); + } + if (!Algorithms.objectEquals(st.MAP_OVERLAY.get(), cachedOverlay)) { + cachedOverlay = st.MAP_OVERLAY.get(); + ITileSource tileSource = st.getTileSourceByName(cachedOverlay, false); + if (tileSource != null) { + TileSourceProxyProvider prov = new TileSourceProxyProvider(view.getApplication(), tileSource); + mapRenderer.setMapLayerProvider(1, prov.instantiateProxy(true)); + prov.swigReleaseOwnership(); + } else { + mapRenderer.resetMapLayerProvider(1); + } + } + if (st.MAP_OVERLAY_TRANSPARENCY.get() != cachedOverlayTransparency) { + cachedOverlayTransparency = st.MAP_OVERLAY_TRANSPARENCY.get(); + MapLayerConfiguration mapLayerConfiguration = new MapLayerConfiguration(); + mapLayerConfiguration.setOpacity(((float)cachedOverlayTransparency) / 255.0f); + mapRenderer.setMapLayerConfiguration(1, mapLayerConfiguration); + } // opengl renderer mapRenderer.setTarget(new PointI(tilesRect.getCenter31X(), tilesRect.getCenter31Y())); mapRenderer.setAzimuth(-tilesRect.getRotate()); - mapRenderer.setZoom((float) (tilesRect.getZoom() /*+ tilesRect.getZoomScale() */+ tilesRect.getZoomAnimation())); + mapRenderer.setZoom((float) (tilesRect.getZoom() /* + tilesRect.getZoomScale() */+ tilesRect + .getZoomAnimation())); } else { if (!view.isZooming()) { if (resourceManager.updateRenderedMapNeeded(tilesRect, drawSettings)) { @@ -122,7 +162,7 @@ public class MapVectorLayer extends BaseMapLayer { private boolean drawRenderedMap(Canvas canvas, Bitmap bmp, RotatedTileBox bmpLoc, RotatedTileBox currentViewport) { boolean shown = false; if (bmp != null && bmpLoc != null) { - float rot = - bmpLoc.getRotate(); + float rot = -bmpLoc.getRotate(); int cz = currentViewport.getZoom(); canvas.rotate(rot, currentViewport.getCenterPixelX(), currentViewport.getCenterPixelY()); final RotatedTileBox calc = currentViewport.copy(); @@ -134,7 +174,7 @@ public class MapVectorLayer extends BaseMapLayer { final float y1 = calc.getPixYFromTile(lt.x, lt.y, cz); final float y2 = calc.getPixYFromTile(rb.x, rb.y, cz); destImage.set(x1, y1, x2, y2); - if(!bmp.isRecycled()){ + if (!bmp.isRecycled()) { canvas.drawBitmap(bmp, null, destImage, paintImg); shown = true; } @@ -143,15 +183,14 @@ public class MapVectorLayer extends BaseMapLayer { return shown; } - @Override public void setAlpha(int alpha) { super.setAlpha(alpha); if (paintImg != null) { paintImg.setAlpha(alpha); } - } - + } + @Override public boolean onLongPressEvent(PointF point, RotatedTileBox tileBox) { return false; diff --git a/OsmAnd/src/net/osmand/plus/views/MapTileLayer.java b/OsmAnd/src/net/osmand/plus/views/MapTileLayer.java index 22d4e40848..ab4ba19ba0 100644 --- a/OsmAnd/src/net/osmand/plus/views/MapTileLayer.java +++ b/OsmAnd/src/net/osmand/plus/views/MapTileLayer.java @@ -12,6 +12,7 @@ import net.osmand.plus.R; import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin; import net.osmand.plus.resources.ResourceManager; import net.osmand.util.MapUtils; +import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; @@ -110,6 +111,7 @@ public class MapTileLayer extends BaseMapLayer { return mapTileAdapter; } + @SuppressLint("WrongCall") @Override public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings drawSettings) {