From bbd56254ae63c1da618ffd74b0457ab708b75490 Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Wed, 5 May 2010 22:29:58 +0000 Subject: [PATCH] reintroduce amenity layer (with layer framework for map) fixing bugs for map introduce Resource Manager & proper indexing poi trying to fix OutOfMemoryException git-svn-id: https://osmand.googlecode.com/svn/trunk@35 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8 --- .../src/com/osmand/DataExtraction.java | 62 +- .../src/com/osmand/MapPanel.java | 4 +- .../src/com/osmand/MapTileDownloader.java | 101 ++-- .../src/com/osmand/OsmandSettings.java | 2 - .../src/com/osmand/ToDoConstants.java | 16 +- .../src/com/osmand/data/Amenity.java | 140 +++++ .../src/com/osmand/data/Region.java | 8 +- OsmAnd/res/layout/main.xml | 2 +- OsmAnd/res/menu/map_menu.xml | 7 + OsmAnd/res/xml/settings_pref.xml | 2 +- OsmAnd/src/com/osmand/LogUtil.java | 4 +- OsmAnd/src/com/osmand/ResourceManager.java | 260 ++++++++ .../osmand/activities/MainMenuActivity.java | 3 + .../com/osmand/activities/MapActivity.java | 132 ++--- .../osmand/activities/SettingsActivity.java | 10 +- .../views/AnimateDraggingMapThread.java | 92 +++ .../src/com/osmand/views/OsmandMapLayer.java | 17 + .../com/osmand/views/OsmandMapTileView.java | 557 +++++++----------- OsmAnd/src/com/osmand/views/POIMapLayer.java | 189 +++--- 19 files changed, 939 insertions(+), 669 deletions(-) create mode 100644 DataExtractionOSM/src/com/osmand/data/Amenity.java create mode 100644 OsmAnd/res/menu/map_menu.xml create mode 100644 OsmAnd/src/com/osmand/ResourceManager.java create mode 100644 OsmAnd/src/com/osmand/views/AnimateDraggingMapThread.java create mode 100644 OsmAnd/src/com/osmand/views/OsmandMapLayer.java diff --git a/DataExtractionOSM/src/com/osmand/DataExtraction.java b/DataExtractionOSM/src/com/osmand/DataExtraction.java index bccd166a75..f35fff1992 100644 --- a/DataExtractionOSM/src/com/osmand/DataExtraction.java +++ b/DataExtractionOSM/src/com/osmand/DataExtraction.java @@ -47,6 +47,7 @@ import org.apache.tools.bzip2.CBZip2InputStream; import org.apache.tools.bzip2.CBZip2OutputStream; import org.xml.sax.SAXException; +import com.osmand.data.Amenity; import com.osmand.data.City; import com.osmand.data.DataTileManager; import com.osmand.data.Region; @@ -132,7 +133,7 @@ public class DataExtraction implements IMapLocationListener { // preloaded data final List places = new ArrayList(); final List buildings = new ArrayList(); - final List amenities = new ArrayList(); + final List amenities = new ArrayList(); // highways count final List mapWays = new ArrayList(); @@ -150,20 +151,8 @@ public class DataExtraction implements IMapLocationListener { @Override public boolean acceptNodeToLoad(Node n) { - if (n.getTag(OSMTagKey.AMENITY) != null) { - amenities.add(n); - } else if (n.getTag(OSMTagKey.SHOP) != null) { - // TODO temp solution - n.putTag(OSMTagKey.AMENITY.getValue(), OSMTagKey.SHOP.getValue()); - amenities.add(n); - } else if (n.getTag(OSMTagKey.LEISURE) != null) { - // TODO temp solution - n.putTag(OSMTagKey.AMENITY.getValue(), OSMTagKey.LEISURE.getValue()); - amenities.add(n); - } else if (n.getTag(OSMTagKey.TOURISM) != null) { - // TODO temp solution - n.putTag(OSMTagKey.AMENITY.getValue(), OSMTagKey.TOURISM.getValue()); - amenities.add(n); + if(Amenity.isAmenity(n)){ + amenities.add(new Amenity(n)); } if (n.getTag(OSMTagKey.PLACE) != null) { places.add(n); @@ -228,9 +217,9 @@ public class DataExtraction implements IMapLocationListener { } DataTileManager amenitiesManager = new DataTileManager(); - for(Node node : amenities){ - country.registerAmenity(node); - amenitiesManager.registerObject(node.getLatitude(), node.getLongitude(), node.getLatLon()); + for(Amenity a: amenities){ + country.registerAmenity(a); + amenitiesManager.registerObject(a.getNode().getLatitude(), a.getNode().getLongitude(), a.getNode().getLatLon()); } @@ -249,7 +238,9 @@ public class DataExtraction implements IMapLocationListener { runUI(country); List interestedObjects = new ArrayList(); // MapUtils.addIdsToList(places, interestedObjects); - MapUtils.addIdsToList(amenities, interestedObjects); + for(Amenity a : amenities){ + interestedObjects.add(a.getNode().getId()); + } // MapUtils.addIdsToList(mapWays, interestedObjects); // MapUtils.addIdsToList(buildings, interestedObjects); if (DefaultLauncherConstants.writeTestOsmFile != null) { @@ -440,21 +431,21 @@ public class DataExtraction implements IMapLocationListener { @Override public void locationChanged(final double newLatitude, final double newLongitude, Object source){ Region reg = (Region) amenitiesTree.getUserObject(); - List closestAmenities = reg.getClosestAmenities(newLatitude, newLongitude); - Collections.sort(closestAmenities, new Comparator(){ + List closestAmenities = reg.getClosestAmenities(newLatitude, newLongitude); + Collections.sort(closestAmenities, new Comparator(){ @Override - public int compare(Node o1, Node o2) { - return Double.compare(MapUtils.getDistance(o1, newLatitude, newLongitude), - MapUtils.getDistance(o2, newLatitude, newLongitude)); + public int compare(Amenity o1, Amenity o2) { + return Double.compare(MapUtils.getDistance(o1.getNode(), newLatitude, newLongitude), + MapUtils.getDistance(o2.getNode(), newLatitude, newLongitude)); } }); - Map> filter = new TreeMap>(); - for(Node n : closestAmenities){ - String type = n.getTag(OSMTagKey.AMENITY); + Map> filter = new TreeMap>(); + for(Amenity n : closestAmenities){ + String type = n.getType().toString(); if(!filter.containsKey(type)){ - filter.put(type, new ArrayList()); + filter.put(type, new ArrayList()); } filter.get(type).add(n); } @@ -470,11 +461,9 @@ public class DataExtraction implements IMapLocationListener { for(int i=0; i<15 && i < closestAmenities.size(); i++){ - Node n = closestAmenities.get(i); - String type = n.getTag(OSMTagKey.AMENITY); - String name = n.getTag(OSMTagKey.NAME); - int dist = (int) (MapUtils.getDistance(n, newLatitude, newLongitude)); - String str = type +" "+(name == null ? n.getId() : name) +" [" +dist+" m ]"; + Amenity n = closestAmenities.get(i); + int dist = (int) (MapUtils.getDistance(n.getNode(), newLatitude, newLongitude)); + String str = n.getSimpleFormat() + " [" +dist+" m ]"; ((DefaultMutableTreeNode)amenitiesTree.getChildAt(0)).add( new DataExtractionTreeNode(str, n)); } @@ -492,10 +481,9 @@ public class DataExtraction implements IMapLocationListener { } p.removeAllChildren(); - for (Node n : filter.get(s)) { - String name = n.getTag(OSMTagKey.NAME); - int dist = (int) (MapUtils.getDistance(n, newLatitude, newLongitude)); - String str = (name == null ? n.getId() : name) + " [" + dist + " m ]"; + for (Amenity n : filter.get(s)) { + int dist = (int) (MapUtils.getDistance(n.getNode(), newLatitude, newLongitude)); + String str = n.getSimpleFormat() + " [" + dist + " m ]"; DataExtractionTreeNode node = new DataExtractionTreeNode(str, n); p.add(node); } diff --git a/DataExtractionOSM/src/com/osmand/MapPanel.java b/DataExtractionOSM/src/com/osmand/MapPanel.java index 2f30c6b099..c498904679 100644 --- a/DataExtractionOSM/src/com/osmand/MapPanel.java +++ b/DataExtractionOSM/src/com/osmand/MapPanel.java @@ -238,7 +238,7 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback { if(loadIfNeeded && cache.get(file) == null){ String urlToLoad = map.getUrlToLoad(x, y, zoom); if (urlToLoad != null) { - downloader.requestToDownload(urlToLoad, new DownloadRequest(en, x, y, zoom)); + downloader.requestToDownload(new DownloadRequest(urlToLoad, en, x, y, zoom)); } } } @@ -248,7 +248,7 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback { } @Override - public void tileDownloaded(String dowloadedUrl, DownloadRequest request) { + public void tileDownloaded(DownloadRequest request) { int tileSize = getTileSize(); double xTileLeft = getXTile() - getSize().width / (2d * tileSize); double yTileUp = getYTile() - getSize().height / (2d * tileSize); diff --git a/DataExtractionOSM/src/com/osmand/MapTileDownloader.java b/DataExtractionOSM/src/com/osmand/MapTileDownloader.java index fbd0c2d9d7..bd1b740a3a 100644 --- a/DataExtractionOSM/src/com/osmand/MapTileDownloader.java +++ b/DataExtractionOSM/src/com/osmand/MapTileDownloader.java @@ -44,7 +44,14 @@ public class MapTileDownloader { */ public interface IMapDownloaderCallback { - public void tileDownloaded(String dowloadedUrl, DownloadRequest fileSaved); + /** + * Sometimes null cold be passed as request + * That means that there were a lot of requests but + * once method is called + * (in order to not create a collection of request & reduce calling times) + * @param fileSaved + */ + public void tileDownloaded(DownloadRequest request); } /** @@ -55,15 +62,18 @@ public class MapTileDownloader { public final int zoom; public final int xTile; public final int yTile; + public final String url; - public DownloadRequest(File fileToSave, int xTile, int yTile, int zoom) { + public DownloadRequest(String url, File fileToSave, int xTile, int yTile, int zoom) { + this.url = url; this.fileToSave = fileToSave; this.xTile = xTile; this.yTile = yTile; this.zoom = zoom; } - public DownloadRequest(File fileToSave) { + public DownloadRequest(String url, File fileToSave) { + this.url = url; this.fileToSave = fileToSave; xTile = -1; yTile = -1; @@ -100,68 +110,69 @@ public class MapTileDownloader { } } - public void requestToDownload(String url, DownloadRequest request){ + public void requestToDownload(DownloadRequest request){ if(DefaultLauncherConstants.TILE_DOWNLOAD_MAX_ERRORS > 0 && currentErrors > DefaultLauncherConstants.TILE_DOWNLOAD_MAX_ERRORS){ return; } + if(request.url == null){ + return; + } if (!isFileCurrentlyDownloaded(request.fileToSave)) { - threadPoolExecutor.execute(new DownloadMapWorker(url, request)); + threadPoolExecutor.execute(new DownloadMapWorker(request)); } } private class DownloadMapWorker implements Runnable, Comparable { private long time = System.currentTimeMillis(); - private final String downloadUrl; private DownloadRequest request; - private DownloadMapWorker(String downloadUrl, DownloadRequest request){ - this.downloadUrl = downloadUrl; + private DownloadMapWorker(DownloadRequest request){ this.request = request; } @Override public void run() { - try { - if(log.isDebugEnabled()){ - log.debug("Start downloading tile : " + downloadUrl); - } - URL url = new URL(downloadUrl); - URLConnection connection = url.openConnection(); - connection.setRequestProperty("User-Agent", DefaultLauncherConstants.APP_NAME+"/"+DefaultLauncherConstants.APP_VERSION); - BufferedInputStream inputStream = new BufferedInputStream(connection.getInputStream(), 8 * 1024); - try { - if (request != null && request.fileToSave != null) { - request.fileToSave.getParentFile().mkdirs(); - - FileOutputStream stream = new FileOutputStream(request.fileToSave); - currentlyDownloaded.add(request.fileToSave); - try { - Algoritms.streamCopy(inputStream, stream); - stream.flush(); - } finally { - currentlyDownloaded.remove(request.fileToSave); - Algoritms.closeStream(stream); - } - } - } finally { - Algoritms.closeStream(inputStream); - } - if(log.isDebugEnabled()){ - log.debug("Downloading tile : " + downloadUrl + " successfull " + (System.currentTimeMillis() - time) + " ms"); - } - if(callback != null){ - callback.tileDownloaded(downloadUrl, request); - } - } catch (UnknownHostException e) { - currentErrors++; - log.error("UnknownHostException, cannot download tile " + downloadUrl, e); - } catch (IOException e) { - currentErrors++; - log.warn("Cannot download tile : " + downloadUrl, e); + if(log.isDebugEnabled()){ + log.debug("Start downloading tile : " + request.url); } + if (request != null && request.fileToSave != null && request.url != null) { + currentlyDownloaded.add(request.fileToSave); + try { + request.fileToSave.getParentFile().mkdirs(); + URL url = new URL(request.url); + URLConnection connection = url.openConnection(); + connection.setRequestProperty("User-Agent", DefaultLauncherConstants.APP_NAME + "/" + + DefaultLauncherConstants.APP_VERSION); + BufferedInputStream inputStream = new BufferedInputStream(connection.getInputStream(), 8 * 1024); + FileOutputStream stream = null; + try { + stream = new FileOutputStream(request.fileToSave); + Algoritms.streamCopy(inputStream, stream); + stream.flush(); + } finally { + Algoritms.closeStream(inputStream); + Algoritms.closeStream(stream); + } + if (log.isDebugEnabled()) { + log.debug("Downloading tile : " + request.url + " successfull " + (System.currentTimeMillis() - time) + " ms"); + } + } catch (UnknownHostException e) { + currentErrors++; + log.error("UnknownHostException, cannot download tile " + request.url, e); + } catch (IOException e) { + currentErrors++; + log.warn("Cannot download tile : " + request.url, e); + } finally { + currentlyDownloaded.remove(request.fileToSave); + } + if (callback != null) { + callback.tileDownloaded(request); + } + } + } @Override diff --git a/DataExtractionOSM/src/com/osmand/OsmandSettings.java b/DataExtractionOSM/src/com/osmand/OsmandSettings.java index 2fd26fc74c..e8177fb9af 100644 --- a/DataExtractionOSM/src/com/osmand/OsmandSettings.java +++ b/DataExtractionOSM/src/com/osmand/OsmandSettings.java @@ -6,8 +6,6 @@ public class OsmandSettings { public static boolean useInternetToDownloadTiles = DefaultLauncherConstants.loadMissingImages; - public static boolean showGPSLocationOnMap = DefaultLauncherConstants.showGPSCoordinates; - public static ITileSource tileSource = DefaultLauncherConstants.MAP_defaultTileSource; public static boolean showPoiOverMap = true; diff --git a/DataExtractionOSM/src/com/osmand/ToDoConstants.java b/DataExtractionOSM/src/com/osmand/ToDoConstants.java index a90a3c5c46..4c4b68665a 100644 --- a/DataExtractionOSM/src/com/osmand/ToDoConstants.java +++ b/DataExtractionOSM/src/com/osmand/ToDoConstants.java @@ -9,18 +9,13 @@ package com.osmand; */ public class ToDoConstants { - - // use unknown implementation (not written)? How to see debug msgs? - // Explanation of how it works - // The task - public int CONFIG_COMMONS_LOGGING_IN_ANDROID = 1; - public int SAVE_SETTINGS_IN_ANDROID_BETWEEN_SESSION = 2; + // First of all switch off gps listener should be implemented public int IMPLEMENT_ON_STOP_RESUME_ACTIVITY = 3; // OsmandMapTileView.java have problem with class loading (LogFactory, MapTileDownloader) - - // it is not editable in editor + // it is not editable in editor ? public int MAKE_MAP_PANEL_EDITABLE_IN_EDITOR = 4; // common parts : work with cache on file system & in memory @@ -29,12 +24,11 @@ public class ToDoConstants { public int REVISE_MAP_ACTIVITY_HOLD_ALL_ZOOM_LATLON_IN_ONEPLACE = 6; + /** - * Resource should cache all resources & free them - * if there is no enough memory @see tile cache in tile view - * @see poi index in map activity + * Write activity to show something about authors / donation .... */ - public int INTRODUCE_RESOURCE_MANAGER = 7; + public int DESCRIBE_ABOUT_AUTHORS = 8; } diff --git a/DataExtractionOSM/src/com/osmand/data/Amenity.java b/DataExtractionOSM/src/com/osmand/data/Amenity.java new file mode 100644 index 0000000000..279e6a0b0b --- /dev/null +++ b/DataExtractionOSM/src/com/osmand/data/Amenity.java @@ -0,0 +1,140 @@ +package com.osmand.data; + +import java.util.LinkedHashMap; +import java.util.Map; + +import com.osmand.osm.Node; +import com.osmand.osm.OSMSettings.OSMTagKey; + +public class Amenity { + // http://wiki.openstreetmap.org/wiki/Amenity + public enum AmenityType { + SUSTENANCE, // restaurant, cafe ... + EDUCATION, // school, ... + TRANSPORTATION, // car_wash, parking, ... + FINANCE, // bank, atm, ... + HEALTHCARE, // hospital ... + ENTERTAINMENT, // cinema, ... (+! sauna, brothel) + TOURISM, // hotel, sights, museum .. + SHOP, // convenience (product), clothes... + LEISURE, // sport + OTHER, // grave-yard, police, post-office + } + private static Map prebuiltMap = new LinkedHashMap(); + static { + prebuiltMap.put("restaurant", AmenityType.SUSTENANCE); + prebuiltMap.put("food_court", AmenityType.SUSTENANCE); + prebuiltMap.put("fast_food", AmenityType.SUSTENANCE); + prebuiltMap.put("drinking_water", AmenityType.SUSTENANCE); + prebuiltMap.put("bbq", AmenityType.SUSTENANCE); + prebuiltMap.put("pub", AmenityType.SUSTENANCE); + prebuiltMap.put("bar", AmenityType.SUSTENANCE); + prebuiltMap.put("cafe", AmenityType.SUSTENANCE); + prebuiltMap.put("biergarten", AmenityType.SUSTENANCE); + + prebuiltMap.put("kindergarten", AmenityType.EDUCATION); + prebuiltMap.put("school", AmenityType.EDUCATION); + prebuiltMap.put("college", AmenityType.EDUCATION); + prebuiltMap.put("library", AmenityType.EDUCATION); + prebuiltMap.put("university", AmenityType.EDUCATION); + + prebuiltMap.put("ferry_terminal", AmenityType.TRANSPORTATION); + prebuiltMap.put("bicycle_parking", AmenityType.TRANSPORTATION); + prebuiltMap.put("bicycle_rental", AmenityType.TRANSPORTATION); + prebuiltMap.put("bus_station", AmenityType.TRANSPORTATION); + prebuiltMap.put("car_rental", AmenityType.TRANSPORTATION); + prebuiltMap.put("car_sharing", AmenityType.TRANSPORTATION); + prebuiltMap.put("car_wash", AmenityType.TRANSPORTATION); + prebuiltMap.put("grit_bin", AmenityType.TRANSPORTATION); + prebuiltMap.put("parking", AmenityType.TRANSPORTATION); + prebuiltMap.put("taxi", AmenityType.TRANSPORTATION); + + prebuiltMap.put("atm", AmenityType.FINANCE); + prebuiltMap.put("bank", AmenityType.FINANCE); + prebuiltMap.put("bureau_de_change", AmenityType.FINANCE); + + prebuiltMap.put("pharmacy", AmenityType.HEALTHCARE); + prebuiltMap.put("hospital", AmenityType.HEALTHCARE); + prebuiltMap.put("baby_hatch", AmenityType.HEALTHCARE); + prebuiltMap.put("dentist", AmenityType.HEALTHCARE); + prebuiltMap.put("doctors", AmenityType.HEALTHCARE); + prebuiltMap.put("veterinary", AmenityType.HEALTHCARE); + + prebuiltMap.put("architect_office", AmenityType.ENTERTAINMENT); + prebuiltMap.put("arts_centre", AmenityType.ENTERTAINMENT); + prebuiltMap.put("cinema", AmenityType.ENTERTAINMENT); + prebuiltMap.put("community_centre", AmenityType.ENTERTAINMENT); + prebuiltMap.put("fountain", AmenityType.ENTERTAINMENT); + prebuiltMap.put("nightclub", AmenityType.ENTERTAINMENT); + prebuiltMap.put("stripclub", AmenityType.ENTERTAINMENT); + prebuiltMap.put("studio", AmenityType.ENTERTAINMENT); + prebuiltMap.put("theatre", AmenityType.ENTERTAINMENT); + prebuiltMap.put("sauna", AmenityType.ENTERTAINMENT); + prebuiltMap.put("brothel", AmenityType.ENTERTAINMENT); + } + + + + private final Node node; + + public Amenity(Node node){ + this.node = node; + } + + public Node getNode() { + return node; + } + + public String getSubType(){ + if(node.getTag(OSMTagKey.AMENITY) != null){ + return node.getTag(OSMTagKey.AMENITY); + } else if(node.getTag(OSMTagKey.SHOP) != null){ + return node.getTag(OSMTagKey.SHOP); + } else if(node.getTag(OSMTagKey.TOURISM) != null){ + return node.getTag(OSMTagKey.TOURISM); + } else if(node.getTag(OSMTagKey.LEISURE) != null){ + return node.getTag(OSMTagKey.LEISURE); + } + return ""; + } + + public AmenityType getType(){ + if(node.getTag(OSMTagKey.SHOP) != null){ + return AmenityType.SHOP; + } else if(node.getTag(OSMTagKey.TOURISM) != null){ + return AmenityType.TOURISM; + } else if(node.getTag(OSMTagKey.LEISURE) != null){ + return AmenityType.LEISURE; + } else if(prebuiltMap.containsKey(node.getTag(OSMTagKey.AMENITY))){ + return prebuiltMap.get(node.getTag(OSMTagKey.AMENITY)); + } + return AmenityType.OTHER; + } + + public static boolean isAmenity(Node n){ + if(n.getTag(OSMTagKey.AMENITY) != null){ + return true; + } else if(n.getTag(OSMTagKey.SHOP) != null){ + return true; + } else if(n.getTag(OSMTagKey.LEISURE) != null){ + return true; + } else if(n.getTag(OSMTagKey.TOURISM) != null){ + return true; + } + return false; + } + + public String getSimpleFormat(){ + String name = node.getTag(OSMTagKey.NAME); + return getType().toString() +" : " + getSubType() + " " +(name == null ? node.getId() : name); + } + + @Override + public String toString() { + return getSimpleFormat(); + } + + + + +} diff --git a/DataExtractionOSM/src/com/osmand/data/Region.java b/DataExtractionOSM/src/com/osmand/data/Region.java index 13b72376fa..3c4e37edc9 100644 --- a/DataExtractionOSM/src/com/osmand/data/Region.java +++ b/DataExtractionOSM/src/com/osmand/data/Region.java @@ -17,7 +17,7 @@ import com.osmand.osm.OSMSettings.OSMTagKey; public class Region { private Entity entity; - private DataTileManager amenities = new DataTileManager(); + private DataTileManager amenities = new DataTileManager(); private Map> cities = new HashMap>(); { @@ -87,12 +87,12 @@ public class Region { return closest; } - public List getClosestAmenities(double latitude, double longitude){ + public List getClosestAmenities(double latitude, double longitude){ return amenities.getClosestObjects(latitude, longitude, 2); } - public void registerAmenity(Node n){ - amenities.registerObject(n.getLatitude(), n.getLongitude(), n); + public void registerAmenity(Amenity a){ + amenities.registerObject(a.getNode().getLatitude(), a.getNode().getLongitude(), a); } diff --git a/OsmAnd/res/layout/main.xml b/OsmAnd/res/layout/main.xml index d0f223ebb8..ba1575331b 100644 --- a/OsmAnd/res/layout/main.xml +++ b/OsmAnd/res/layout/main.xml @@ -5,7 +5,7 @@ android:layout_height="fill_parent"> - + diff --git a/OsmAnd/res/menu/map_menu.xml b/OsmAnd/res/menu/map_menu.xml new file mode 100644 index 0000000000..09fbfecbaa --- /dev/null +++ b/OsmAnd/res/menu/map_menu.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/OsmAnd/res/xml/settings_pref.xml b/OsmAnd/res/xml/settings_pref.xml index d354abae08..b5a346beeb 100644 --- a/OsmAnd/res/xml/settings_pref.xml +++ b/OsmAnd/res/xml/settings_pref.xml @@ -2,7 +2,7 @@ - + diff --git a/OsmAnd/src/com/osmand/LogUtil.java b/OsmAnd/src/com/osmand/LogUtil.java index 5385f26cc6..c4c0333766 100644 --- a/OsmAnd/src/com/osmand/LogUtil.java +++ b/OsmAnd/src/com/osmand/LogUtil.java @@ -85,7 +85,9 @@ public class LogUtil { @Override public boolean isDebugEnabled() { - return android.util.Log.isLoggable(TAG, android.util.Log.DEBUG); + // For debur purposes always true +// return android.util.Log.isLoggable(TAG, android.util.Log.DEBUG); + return true; } @Override diff --git a/OsmAnd/src/com/osmand/ResourceManager.java b/OsmAnd/src/com/osmand/ResourceManager.java new file mode 100644 index 0000000000..c8a3613251 --- /dev/null +++ b/OsmAnd/src/com/osmand/ResourceManager.java @@ -0,0 +1,260 @@ +package com.osmand; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Stack; + +import org.apache.commons.logging.Log; +import org.apache.tools.bzip2.CBZip2InputStream; +import org.xml.sax.SAXException; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Environment; + +import com.osmand.MapTileDownloader.DownloadRequest; +import com.osmand.data.Amenity; +import com.osmand.data.DataTileManager; +import com.osmand.map.ITileSource; +import com.osmand.osm.Entity; +import com.osmand.osm.Node; +import com.osmand.osm.io.OsmBaseStorage; + +/** + * Resource manager is responsible to work with all resources + * that could consume memory (especially with file resources). + * Such as indexes, tiles. + * Also it is responsible to create cache for that resources if they + * can't be loaded fully into memory & clear them on request. + * + */ +public class ResourceManager { + + private static final String POI_PATH = "osmand/poi/"; + private static final String TILES_PATH = "osmand/tiles/"; + + private static final Log log = LogUtil.getLog(ResourceManager.class); + + protected static ResourceManager manager = null; + + public static ResourceManager getResourceManager(){ + if(manager == null){ + manager = new ResourceManager(); + } + return manager; + } + + // it is not good investigated but no more than 64 (satellite images) + protected final int maxImgCacheSize = 64; + + private DataTileManager poiIndex = null; + + protected Map cacheOfImages = new LinkedHashMap(); + + protected File dirWithTiles ; + + private MapTileDownloader downloader = MapTileDownloader.getInstance(); + + public AsyncLoadingThread asyncLoadingTiles = new AsyncLoadingThread(); + + + + + public ResourceManager() { + // TODO start/stop this thread when needed? + asyncLoadingTiles.start(); + dirWithTiles = new File(Environment.getExternalStorageDirectory(), TILES_PATH); + } + + /// Working with tiles /// + public Bitmap getTileImageForMapAsync(ITileSource map, int x, int y, int zoom, boolean loadFromInternetIfNeeded) { + return getTileImageForMap(map, x, y, zoom, loadFromInternetIfNeeded, false); + } + + public Bitmap getTileImageForMapSync(ITileSource map, int x, int y, int zoom, boolean loadFromInternetIfNeeded) { + return getTileImageForMap(map, x, y, zoom, loadFromInternetIfNeeded, true); + } + + protected Bitmap getTileImageForMap(ITileSource map, int x, int y, int zoom, + boolean loadFromInternetIfNeeded, boolean sync) { + if (map == null) { + return null; + } + StringBuilder builder = new StringBuilder(40); + builder.append(map.getName()).append('/').append(zoom). append('/').append(x). + append('/').append(y).append(map.getTileFormat()).append(".tile"); + String file = builder.toString(); + if (cacheOfImages.get(file) == null) { + String url = loadFromInternetIfNeeded ? map.getUrlToLoad(x, y, zoom) : null; + TileLoadDownloadRequest req = new TileLoadDownloadRequest(dirWithTiles, file, url, new File(dirWithTiles, file), + x, y, zoom); + if(sync){ + return getRequestedImageTile(req); + } else { + asyncLoadingTiles.requestToLoadImage(req); + } + } + return cacheOfImages.get(file); + } + + + + private static class TileLoadDownloadRequest extends DownloadRequest { + + public final String fileToLoad; + public final File dirWithTiles; + + public TileLoadDownloadRequest(File dirWithTiles, + String fileToLoad, String url, File fileToSave, int tileX, int tileY, int zoom) { + super(url, fileToSave, tileX, tileY, zoom); + this.dirWithTiles = dirWithTiles; + this.fileToLoad = fileToLoad; + } + + } + public class AsyncLoadingThread extends Thread { + Stack requests = new Stack(); + + public AsyncLoadingThread(){ + super("Async loading tiles"); + } + + @Override + public void run() { + while(true){ + try { + boolean update = false; + while(!requests.isEmpty()){ + TileLoadDownloadRequest r = requests.pop(); + if(cacheOfImages.get(r.fileToLoad) == null) { + update |= getRequestedImageTile(r) != null; + } + } + if(update){ + // use downloader callback + downloader.getDownloaderCallback().tileDownloaded(null); + } + sleep(750); + } catch (InterruptedException e) { + log.error(e); + } catch (RuntimeException e){ + log.error(e); + } + } + } + + public void requestToLoadImage(TileLoadDownloadRequest req){ + requests.push(req); + } + }; + + private Bitmap getRequestedImageTile(TileLoadDownloadRequest req){ + if(req.fileToLoad == null || req.dirWithTiles == null){ + return null; + } + File en = new File(req.dirWithTiles, req.fileToLoad); + if (cacheOfImages.size() > maxImgCacheSize) { + onLowMemory(); + } + + if (!downloader.isFileCurrentlyDownloaded(en)) { + if (en.exists()) { + 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"); + } + } + + if(cacheOfImages.get(req.fileToLoad) == 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(); +// if (info != null && info.isConnected()) { +// downloader.requestToDownload(req); +// } + downloader.requestToDownload(req); + } + } + return cacheOfImages.get(req.fileToLoad); + } + + + // POI INDEX // + public void indexingPoi(){ + if (poiIndex == null) { + File file = new File(Environment.getExternalStorageDirectory(), POI_PATH); + poiIndex = new DataTileManager(); + if (file.exists() && file.canRead()) { + for (File f : file.listFiles()) { + if (f.getName().endsWith(".bz2") || f.getName().endsWith(".osm")) { + if (log.isDebugEnabled()) { + log.debug("Starting index POI " + f.getAbsolutePath()); + } + boolean zipped = f.getName().endsWith(".bz2"); + InputStream stream = null; + try { + OsmBaseStorage storage = new OsmBaseStorage(); + stream = new FileInputStream(f); + stream = new BufferedInputStream(stream); + if (zipped) { + if (stream.read() != 'B' || stream.read() != 'Z') { + log.error("Can't read poi file " + f.getAbsolutePath() + + "The source stream must start with the characters BZ if it is to be read as a BZip2 stream."); + continue; + } else { + stream = new CBZip2InputStream(stream); + } + } + storage.parseOSM(stream); + for (Entity e : storage.getRegisteredEntities().values()) { + if (e instanceof Node && Amenity.isAmenity((Node) e)) { + poiIndex.registerObject(((Node)e).getLatitude(), ((Node)e).getLongitude(), new Amenity((Node) e)); + } + } + if (log.isDebugEnabled()) { + log.debug("Finishing index POI " + f.getAbsolutePath()); + } + } catch (IOException e) { + log.error("Can't read poi file " + f.getAbsolutePath(), e); + } catch (SAXException e) { + log.error("Can't read poi file " + f.getAbsolutePath(), e); + } finally { + Algoritms.closeStream(stream); + } + } + } + } + } + } + + public DataTileManager getPoiIndex() { + if(poiIndex == null){ + indexingPoi(); + } + return poiIndex; + } + + + + /// On low memory method /// + public void onLowMemory() { + log.info("On low memory : cleaning tiles - size = " + cacheOfImages.size()); + ArrayList list = new ArrayList(cacheOfImages.keySet()); + // remove first images (as we think they are older) + for (int i = 0; i < list.size()/2; i ++) { + Bitmap bmp = cacheOfImages.remove(list.get(i)); + if(bmp != null){ + bmp.recycle(); + } + } + System.gc(); + } + +} diff --git a/OsmAnd/src/com/osmand/activities/MainMenuActivity.java b/OsmAnd/src/com/osmand/activities/MainMenuActivity.java index da3175b13d..a47c8d23b8 100644 --- a/OsmAnd/src/com/osmand/activities/MainMenuActivity.java +++ b/OsmAnd/src/com/osmand/activities/MainMenuActivity.java @@ -9,6 +9,7 @@ import android.view.View.OnClickListener; import android.widget.Button; import com.osmand.R; +import com.osmand.ResourceManager; public class MainMenuActivity extends Activity { @@ -47,5 +48,7 @@ public class MainMenuActivity extends Activity { MainMenuActivity.this.finish(); } }); + + ResourceManager.getResourceManager().indexingPoi(); } } diff --git a/OsmAnd/src/com/osmand/activities/MapActivity.java b/OsmAnd/src/com/osmand/activities/MapActivity.java index d5bf908deb..0cda4ee094 100644 --- a/OsmAnd/src/com/osmand/activities/MapActivity.java +++ b/OsmAnd/src/com/osmand/activities/MapActivity.java @@ -1,13 +1,6 @@ package com.osmand.activities; -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.apache.tools.bzip2.CBZip2InputStream; -import org.xml.sax.SAXException; +import java.text.MessageFormat; import android.app.Activity; import android.content.Intent; @@ -15,26 +8,21 @@ import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; -import android.os.Environment; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.view.Window; import android.view.View.OnClickListener; -import android.widget.Button; import android.widget.ImageButton; +import android.widget.Toast; import android.widget.ZoomControls; -import com.osmand.Algoritms; import com.osmand.IMapLocationListener; -import com.osmand.LogUtil; import com.osmand.OsmandSettings; import com.osmand.R; -import com.osmand.data.DataTileManager; -import com.osmand.osm.Entity; -import com.osmand.osm.LatLon; +import com.osmand.ResourceManager; import com.osmand.osm.MapUtils; -import com.osmand.osm.Node; -import com.osmand.osm.OSMSettings.OSMTagKey; -import com.osmand.osm.io.OsmBaseStorage; import com.osmand.views.OsmandMapTileView; import com.osmand.views.POIMapLayer; import com.osmand.views.PointOfView; @@ -53,12 +41,6 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat private PointOfView pointOfView; - private static final String TILES_PATH = "osmand/tiles/"; - private static final String POI_PATH = "osmand/poi/"; - private static final org.apache.commons.logging.Log log = LogUtil.getLog(MapActivity.class); - - private DataTileManager indexPOI; - private POIMapLayer poiMapLayer; @Override @@ -72,22 +54,23 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat setContentView(R.layout.main); mapView = (OsmandMapTileView) findViewById(R.id.MapView); - mapView.setFileWithTiles(new File(Environment.getExternalStorageDirectory(), TILES_PATH)); - mapView.addMapLocationListener(this); + mapView.setMapLocationListener(this); + poiMapLayer = new POIMapLayer(); + poiMapLayer.setNodeManager(ResourceManager.getResourceManager().getPoiIndex()); + mapView.addLayer(poiMapLayer); + ZoomControls zoomControls = (ZoomControls) findViewById(R.id.ZoomControls01); zoomControls.setOnZoomInClickListener(new OnClickListener() { @Override public void onClick(View v) { mapView.setZoom(mapView.getZoom() + 1); - poiMapLayer.setCurrentLocationAndZoom(poiMapLayer.getCurrentLocation(), mapView.getZoom()); } }); zoomControls.setOnZoomOutClickListener(new OnClickListener() { @Override public void onClick(View v) { mapView.setZoom(mapView.getZoom() - 1); - poiMapLayer.setCurrentLocationAndZoom(poiMapLayer.getCurrentLocation(), mapView.getZoom()); } }); @@ -109,6 +92,7 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat }); + backToMenu = (ImageButton)findViewById(R.id.BackToMenu); backToMenu.setOnClickListener(new OnClickListener(){ @Override @@ -122,63 +106,11 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE); service.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, this); - indexPOI = indexPOI(); - poiMapLayer = (POIMapLayer)findViewById(R.id.PoiMapLayer); - poiMapLayer.setNodeManager(indexPOI); + } - private static final boolean indexPOIFlag = false; - - public DataTileManager indexPOI(){ - File file = new File(Environment.getExternalStorageDirectory(), POI_PATH); - - DataTileManager r = new DataTileManager(); - if(file.exists() && file.canRead() && indexPOIFlag){ - for(File f : file.listFiles() ){ - if(f.getName().endsWith(".bz2") || f.getName().endsWith(".osm") ){ - if(log.isDebugEnabled()){ - log.debug("Starting index POI " + f.getAbsolutePath()); - } - boolean zipped = f.getName().endsWith(".bz2"); - InputStream stream = null; - try { - OsmBaseStorage storage = new OsmBaseStorage(); - stream = new FileInputStream(f); - stream = new BufferedInputStream(stream); - if (zipped) { - if (stream.read() != 'B' || stream.read() != 'Z') { - log.error("Can't read poi file " + f.getAbsolutePath() - + "The source stream must start with the characters BZ if it is to be read as a BZip2 stream."); - continue; - } else { - stream = new CBZip2InputStream(stream); - } - } - storage.parseOSM(stream); - for(Entity e : storage.getRegisteredEntities().values()){ - if(e instanceof Node && e.getTag(OSMTagKey.AMENITY) != null){ - Node n = (Node) e; - r.registerObject(n.getLatitude(), n.getLongitude(), n); - } - } - if(log.isDebugEnabled()){ - log.debug("Finishing index POI " + f.getAbsolutePath()); - } - } catch(IOException e){ - log.error("Can't read poi file " + f.getAbsolutePath(), e); - } catch (SAXException e) { - log.error("Can't read poi file " + f.getAbsolutePath(), e); - } finally { - Algoritms.closeStream(stream); - } - } - } - } - return r; - } - @Override @@ -251,32 +183,54 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat if(mapView.getMap() != OsmandSettings.tileSource){ mapView.setMap(OsmandSettings.tileSource); } - if((poiMapLayer.getVisibility() == View.VISIBLE) != OsmandSettings.showPoiOverMap){ + if(mapView.getLayers().contains(poiMapLayer) != OsmandSettings.showPoiOverMap){ if(OsmandSettings.showPoiOverMap){ - poiMapLayer.setVisibility(View.VISIBLE); + mapView.addLayer(poiMapLayer); } else { - poiMapLayer.setVisibility(View.INVISIBLE); + mapView.removeLayer(poiMapLayer); } } } + + @Override public void onLowMemory() { super.onLowMemory(); - mapView.onLowMemory(); + ResourceManager.getResourceManager().onLowMemory(); } @Override public void locationChanged(double newLatitude, double newLongitude, Object source) { // when user start dragging - if(source == mapView && lastKnownLocation != null){ + if(lastKnownLocation != null){ linkLocationWithMap = false; backToLocation.setVisibility(View.VISIBLE); } - poiMapLayer.setCurrentLocationAndZoom(new LatLon(newLatitude, newLongitude), mapView.getZoom()); - validatePointOfView(); - } + } + + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.map_menu, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if(item.getItemId() == R.id.map_show_location){ + float f= (Runtime.getRuntime().totalMemory())/ 1e6f; + String text = MessageFormat.format("Latitude : {0}, longitude : {1}, zoom : {2}, memory : {3}", mapView.getLatitude(), + mapView.getLongitude(), mapView.getZoom(), f); + Toast.makeText(this, text, Toast.LENGTH_SHORT).show(); + return true; + } else if (item.getItemId() == R.id.map_show_settings) { + final Intent settings = new Intent(MapActivity.this, SettingsActivity.class); + startActivity(settings); + return true; + } + return super.onOptionsItemSelected(item); + } } \ No newline at end of file diff --git a/OsmAnd/src/com/osmand/activities/SettingsActivity.java b/OsmAnd/src/com/osmand/activities/SettingsActivity.java index 62e4341efb..db954bb238 100644 --- a/OsmAnd/src/com/osmand/activities/SettingsActivity.java +++ b/OsmAnd/src/com/osmand/activities/SettingsActivity.java @@ -17,11 +17,9 @@ import com.osmand.map.TileSourceManager.TileSourceTemplate; public class SettingsActivity extends PreferenceActivity implements OnPreferenceChangeListener { private static final String use_internet_to_download_tiles = "use_internet_to_download_tiles"; - private static final String show_gps_location_text = "show_gps_location_text"; private static final String map_tile_sources = "map_tile_sources"; private static final String show_poi_over_map = "show_poi_over_map"; - private CheckBoxPreference showGpsLocation; private CheckBoxPreference showPoiOnMap; private CheckBoxPreference useInternetToDownloadTiles; private ListPreference tileSourcePreference; @@ -31,8 +29,6 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.settings_pref); PreferenceScreen screen = getPreferenceScreen(); - showGpsLocation =(CheckBoxPreference) screen.findPreference(show_gps_location_text); - showGpsLocation.setOnPreferenceChangeListener(this); useInternetToDownloadTiles =(CheckBoxPreference) screen.findPreference(use_internet_to_download_tiles); useInternetToDownloadTiles.setOnPreferenceChangeListener(this); showPoiOnMap =(CheckBoxPreference) screen.findPreference(show_poi_over_map); @@ -48,7 +44,6 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference protected void onResume() { super.onResume(); useInternetToDownloadTiles.setChecked(OsmandSettings.useInternetToDownloadTiles); - showGpsLocation.setChecked(OsmandSettings.showGPSLocationOnMap); showPoiOnMap.setChecked(OsmandSettings.showPoiOverMap); List list = TileSourceManager.getKnownSourceTemplates(); @@ -59,15 +54,14 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference tileSourcePreference.setEntries(entries); tileSourcePreference.setEntryValues(entries); tileSourcePreference.setValue(OsmandSettings.tileSource.getName()); + tileSourcePreference.setSummary(tileSourcePreference.getSummary() + "\t\t[" + OsmandSettings.tileSource.getName()+"]"); } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { - if(preference == showGpsLocation){ - OsmandSettings.showGPSLocationOnMap = (Boolean) newValue; - } else if(preference == showPoiOnMap){ + if(preference == showPoiOnMap){ OsmandSettings.showPoiOverMap = (Boolean) newValue; } else if(preference == useInternetToDownloadTiles){ OsmandSettings.useInternetToDownloadTiles = (Boolean) newValue; diff --git a/OsmAnd/src/com/osmand/views/AnimateDraggingMapThread.java b/OsmAnd/src/com/osmand/views/AnimateDraggingMapThread.java new file mode 100644 index 0000000000..16f2e8841a --- /dev/null +++ b/OsmAnd/src/com/osmand/views/AnimateDraggingMapThread.java @@ -0,0 +1,92 @@ +package com.osmand.views; + +/** + * Thread for animated dragging. + * Defines accelerator to stop dragging screen. + */ +public class AnimateDraggingMapThread implements Runnable { + public interface AnimateDraggingCallback { + public void dragTo(float curX, float curY, float newX, float newY); + } + + private float curX; + private float curY; + private float vx; + private float vy; + private float ax; + private float ay; + private byte dirX; + private byte dirY; + private long time; + private volatile boolean stopped; + private final float a = 0.001f; + + private volatile Thread currentThread = null; + private AnimateDraggingCallback callback = null; + + + @Override + public void run() { + currentThread = Thread.currentThread(); + try { + while (!stopped && (vx > 0 || vy > 0)) { + Thread.sleep((long) (40d / (Math.max(vx, vy) + 0.45))); + long curT = System.currentTimeMillis(); + int dt = (int) (curT - time); + float newX = vx > 0 ? curX + dirX * vx * dt : curX; + float newY = vy > 0 ? curY + dirY * vy * dt : curY; + if (!stopped && callback != null) { + callback.dragTo(curX, curY, newX, newY); + } + vx -= ax * dt; + vy -= ay * dt; + time = curT; + curX = newX; + curY = newY; + } + } catch (InterruptedException e) { + } + currentThread = null; + } + + + /** + * Stop dragging async + */ + public void stopDragging(){ + stopped = true; + } + + /** + * Stop dragging sync + */ + public void stopDraggingSync(){ + // wait until current thread != null + // TODO implement better method for waintg + stopped = true; + while(currentThread != null){} + } + + public void startDragging(float dTime, float startX, float startY, float endX, float endY){ + stopDraggingSync(); + vx = Math.abs((endX - startX)/dTime); + vy = Math.abs((endY - startY)/dTime); + dirX = (byte) (endX > startX ? 1 : -1); + dirY = (byte) (endY > startY ? 1 : -1); + ax = vx * a; + ay = vy * a; + time = System.currentTimeMillis(); + stopped = false; + Thread thread = new Thread(this,"Animatable dragging"); + thread.start(); + } + + public AnimateDraggingCallback getCallback() { + return callback; + } + + public void setCallback(AnimateDraggingCallback callback) { + this.callback = callback; + } +} + diff --git a/OsmAnd/src/com/osmand/views/OsmandMapLayer.java b/OsmAnd/src/com/osmand/views/OsmandMapLayer.java new file mode 100644 index 0000000000..ffaae1b6db --- /dev/null +++ b/OsmAnd/src/com/osmand/views/OsmandMapLayer.java @@ -0,0 +1,17 @@ +package com.osmand.views; + +import android.graphics.Canvas; +import android.view.MotionEvent; + +public interface OsmandMapLayer { + + + public void initLayer(OsmandMapTileView view); + + public void onDraw(Canvas canvas); + + public void destroyLayer(); + + public boolean onTouchEvent(MotionEvent event); + +} diff --git a/OsmAnd/src/com/osmand/views/OsmandMapTileView.java b/OsmAnd/src/com/osmand/views/OsmandMapTileView.java index b6121ff68a..31987c9aba 100644 --- a/OsmAnd/src/com/osmand/views/OsmandMapTileView.java +++ b/OsmAnd/src/com/osmand/views/OsmandMapTileView.java @@ -1,30 +1,19 @@ package com.osmand.views; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.text.MessageFormat; import java.util.ArrayList; -import java.util.Collections; -import java.util.Formatter; -import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import org.apache.commons.logging.Log; import android.content.Context; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Paint.Style; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.SurfaceHolder; @@ -36,28 +25,21 @@ import com.osmand.IMapLocationListener; import com.osmand.LogUtil; import com.osmand.MapTileDownloader; import com.osmand.OsmandSettings; +import com.osmand.ResourceManager; import com.osmand.MapTileDownloader.DownloadRequest; import com.osmand.MapTileDownloader.IMapDownloaderCallback; import com.osmand.map.ITileSource; import com.osmand.osm.MapUtils; +import com.osmand.views.AnimateDraggingMapThread.AnimateDraggingCallback; -public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCallback, Callback{ +public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCallback, Callback, AnimateDraggingCallback{ protected final int emptyTileDivisor = DefaultLauncherConstants.MAP_divNonLoadedImage; - protected final int maxImgCacheSize = 96; - protected int drawCoordinatesX = 0; - protected int drawCoordinatesY = 55; - protected final int timeForDraggingAnimation = 300; protected final int minimumDistanceForDraggingAnimation = 40; protected static final Log log = LogUtil.getLog(OsmandMapTileView.class); - /** - * file or directory with tiles - */ - private File fileWithTiles; - /** * zoom level */ @@ -70,24 +52,24 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall // name of source map private ITileSource map = null; - /** - * listeners - */ - private List listeners = new ArrayList(); + private IMapLocationListener locationListener; private MapTileDownloader downloader = MapTileDownloader.getInstance(); - Map cacheOfImages = new HashMap(); + private List layers = new ArrayList(); - private boolean isStartedDragging = false; - private double startDraggingX = 0d; - private double startDraggingY = 0d; - private PointF initStartDragging = null; + // UI Part + + private AnimateDraggingMapThread animatedDraggingThread; + + private PointF startDragging = null; + private PointF autoStartDragging = null; + private long autoStartDraggingTime = 0; Paint paintGrayFill; Paint paintWhiteFill; Paint paintBlack; - private AnimatedDragging animatedDraggingThread; + @@ -101,6 +83,7 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall initView(); } + /////////////////////////////// INITIALIZING UI PART /////////////////////////////////// public void initView(){ paintGrayFill = new Paint(); paintGrayFill.setColor(Color.GRAY); @@ -117,117 +100,46 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall setClickable(true); getHolder().addCallback(this); downloader.setDownloaderCallback(this); - asyncLoadingTiles.start(); + animatedDraggingThread = new AnimateDraggingMapThread(); + animatedDraggingThread.setCallback(this); } + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + prepareImage(); + } + @Override + public void surfaceCreated(SurfaceHolder holder) { + prepareImage(); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + // TODO clear cache ? + } + + public void addLayer(OsmandMapLayer layer){ + layers.add(layer); + layer.initLayer(this); + } + + public void removeLayer(OsmandMapLayer layer){ + layers.remove(layer); + layer.destroyLayer(); + } + + public List getLayers() { + return layers; + } + + + /////////////////////////// NON UI PART (could be extracted in common) ///////////////////////////// public int getTileSize() { return map == null ? 256 : map.getTileSize(); } - public void dragTo(double fromX, double fromY, double toX, double toY){ - double dx = (fromX - toX)/getTileSize(); - double dy = (fromY - toY)/getTileSize(); - this.latitude = MapUtils.getLatitudeFromTile(zoom, getYTile() + dy); - this.longitude = MapUtils.getLongitudeFromTile(zoom, getXTile() + dx); - prepareImage(); - // TODO -// fireMapLocationListeners(this); - } - - public class AnimatedDragging extends Thread { - private float curX; - private float curY; - private float vx; - private float vy; - private float ax; - private float ay; - private byte dirX; - private byte dirY; - private long time = System.currentTimeMillis(); - private boolean stopped; - private final float a = 0.0005f; - - public AnimatedDragging(float dTime, float startX, float startY, float endX, float endY) { - vx = Math.abs((endX - startX)/dTime); - vy = Math.abs((endY - startY)/dTime); - dirX = (byte) (endX > startX ? 1 : -1); - dirY = (byte) (endY > startY ? 1 : -1); - ax = vx * a; - ay = vy * a; - } - - @Override - public void run() { - try { - while ((vx > 0 || vy > 0) && !isStartedDragging && !stopped) { - sleep((long) (40d/(Math.max(vx, vy)+0.45))); - long curT = System.currentTimeMillis(); - int dt = (int) (curT - time); - float newX = vx > 0 ? curX + dirX * vx * dt : curX; - float newY = vy > 0 ? curY + dirY * vy * dt : curY; - if(!isStartedDragging){ - dragTo(curX, curY, newX, newY); - } - vx -= ax * dt; - vy -= ay * dt; - time = curT; - curX = newX; - curY = newY; - } - } catch (InterruptedException e) { - } - animatedDraggingThread = null; - } - - public void stopEvaluation(){ - stopped = true; - } - - } - - - - @Override - public boolean onTouchEvent(MotionEvent event) { - if(event.getAction() == MotionEvent.ACTION_DOWN) { - if(animatedDraggingThread != null){ - animatedDraggingThread.stopEvaluation(); - } - if(!isStartedDragging){ - startDraggingX = event.getX(); - startDraggingY = event.getY(); - isStartedDragging = true; - initStartDragging = new PointF(event.getX(), event.getY()); - } - } else if(event.getAction() == MotionEvent.ACTION_UP) { - if(isStartedDragging){ - dragTo(startDraggingX, startDraggingY, event.getX(), event.getY()); - if(event.getEventTime() - event.getDownTime() < timeForDraggingAnimation && - Math.abs(event.getX() - initStartDragging.x) + Math.abs(event.getY() - initStartDragging.y) > minimumDistanceForDraggingAnimation){ - float timeDist = (int) (event.getEventTime() - event.getDownTime()); - if(timeDist < 20){ - timeDist = 20; - } - animatedDraggingThread = new AnimatedDragging(timeDist, initStartDragging.x, initStartDragging.y, - event.getX(), event.getY()); - isStartedDragging = false; - animatedDraggingThread.start(); - } - isStartedDragging = false; - - } - } else if(event.getAction() == MotionEvent.ACTION_MOVE) { - if(isStartedDragging){ - dragTo(startDraggingX, startDraggingY, event.getX(), event.getY()); - startDraggingX = event.getX(); - startDraggingY = event.getY(); - } - } - return super.onTouchEvent(event); - } - public double getXTile(){ return MapUtils.getTileNumberX(zoom, longitude); } @@ -236,6 +148,63 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall return MapUtils.getTileNumberY(zoom, latitude); } + + public void setZoom(int zoom){ + if (map == null || (map.getMaximumZoomSupported() >= zoom && map.getMinimumZoomSupported() <= zoom)) { + animatedDraggingThread.stopDragging(); + this.zoom = zoom; + prepareImage(); + } + } + + public ITileSource getMap() { + return map; + } + + public void setMap(ITileSource map) { + this.map = map; + if(map.getMaximumZoomSupported() < this.zoom){ + zoom = map.getMaximumZoomSupported(); + } + if(map.getMinimumZoomSupported() > this.zoom){ + zoom = map.getMinimumZoomSupported(); + } + prepareImage(); + } + + public void setLatLon(double latitude, double longitude){ + animatedDraggingThread.stopDragging(); + this.latitude = latitude; + this.longitude = longitude; + prepareImage(); + } + + public double getLatitude() { + return latitude; + } + + public double getLongitude() { + return longitude; + } + + public int getZoom() { + return zoom; + } + + public void setMapLocationListener(IMapLocationListener l){ + locationListener = l; + } + + /** + * Adds listener to control when map is dragging + */ + public IMapLocationListener setMapLocationListener(){ + return locationListener; + } + + + //////////////////////////////// DRAWING MAP PART ///////////////////////////////////////////// + protected void drawEmptyTile(Canvas cvs, int x, int y){ int tileDiv = getTileSize() / emptyTileDivisor; for (int k1 = 0; k1 < emptyTileDivisor; k1++) { @@ -252,144 +221,12 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall } } - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - prepareImage(); - super.onSizeChanged(w, h, oldw, oldh); - } - - - public String getFileForImage (int x, int y, int zoom, String ext){ - return map.getName() +"/"+zoom+"/"+(x) +"/"+y+ext+".tile"; - } - - public AsyncLoadingThread asyncLoadingTiles = new AsyncLoadingThread(); - - public class AsyncLoadingThread extends Thread { - Map requests = Collections.synchronizedMap(new LinkedHashMap()); - - public AsyncLoadingThread(){ - super("Async loading tiles"); - } - - @Override - public void run() { - while(true){ - try { - boolean update = false; - while(!requests.isEmpty()){ - String f = requests.keySet().iterator().next(); - DownloadRequest r = requests.remove(f); - // TODO last param - getImageForTile(r.xTile, r.yTile, r.zoom, OsmandSettings.useInternetToDownloadTiles); - update = true; - } - if(update){ - prepareImage(); - } - sleep(350); - } catch (InterruptedException e) { - log.error(e); - } catch (RuntimeException e){ - log.error(e); - } - } - } - - public void requestToLoadImage(String s, DownloadRequest req){ - requests.put(s, req); - - } - }; - - private Bitmap getImageForTile(int x, int y, int zoom, boolean loadIfNeeded){ - String file = getFileForImage(x, y, zoom, map.getTileFormat()); - if(fileWithTiles == null || !fileWithTiles.canRead()){ - return null; - } - File en = new File(fileWithTiles, file); - if (cacheOfImages.size() > maxImgCacheSize) { - onLowMemory(); - } - - if (!downloader.isFileCurrentlyDownloaded(en)) { - if (en.exists()) { - long time = System.currentTimeMillis(); - cacheOfImages.put(file, BitmapFactory.decodeFile(en.getAbsolutePath())); - if (log.isDebugEnabled()) { - log.debug("Loaded file : " + file + " " + -(time - System.currentTimeMillis()) + " ms"); - } - } - - if(loadIfNeeded && cacheOfImages.get(file) == null){ - ConnectivityManager mgr = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo info = mgr.getActiveNetworkInfo(); - if (info != null && info.isConnected()) { - String urlToLoad = map.getUrlToLoad(x, y, zoom); - if (urlToLoad != null) { - downloader.requestToDownload(urlToLoad, new DownloadRequest(en, x, y, zoom)); - } - } - } - } - return cacheOfImages.get(file); - } - - public Bitmap getImageFor(int x, int y, int zoom, boolean loadIfNeeded) { - if (map == null) { - return null; - } - String file = getFileForImage(x, y, zoom, map.getTileFormat()); - if (cacheOfImages.get(file) == null && loadIfNeeded) { - // TODO use loadIfNeeded - asyncLoadingTiles.requestToLoadImage(file, new DownloadRequest(null, x, y, zoom)); - } - return cacheOfImages.get(file); - } - - - public void tileDownloaded(String dowloadedUrl, DownloadRequest request) { - int xTileLeft = (int) Math.floor(getXTile() - getWidth() / (2d * getTileSize())); - int yTileUp = (int) Math.floor(getYTile() - getHeight() / (2d * getTileSize())); - int startingX = (int) ((xTileLeft - getXTile()) * getTileSize() + getWidth() / 2); - int startingY = (int) ((yTileUp - getYTile()) * getTileSize() + getHeight() / 2); - int i = (request.xTile - xTileLeft) * getTileSize() + startingX; - int j = (request.yTile - yTileUp) * getTileSize() + startingY; - if (request.zoom == this.zoom && - (i + getTileSize() >= 0 && i < getWidth()) && (j + getTileSize() >= 0 && j < getHeight())) { - SurfaceHolder holder = getHolder(); - synchronized (holder) { - Canvas canvas = holder.lockCanvas(new Rect(i, j, getTileSize() + i, getTileSize() + j)); - if (canvas != null) { - try { - Bitmap bmp = getImageFor(request.xTile, request.yTile, zoom, true); - if (bmp == null) { - drawEmptyTile(canvas, i, j); - } else { - canvas.drawBitmap(bmp, i, j, null); - } - drawOverMap(canvas); - } finally { - holder.unlockCanvasAndPost(canvas); - } - } - } - } - } - private MessageFormat formatOverMap = new MessageFormat("Lat : {0}, lon : {1}, zoom : {2}, mem : {3}"); - java.util.Formatter formatterOMap = new java.util.Formatter(); - private ByteArrayOutputStream stream = new ByteArrayOutputStream(); private void drawOverMap(Canvas canvas){ canvas.drawCircle(getWidth() / 2, getHeight() / 2, 3, paintBlack); canvas.drawCircle(getWidth() / 2, getHeight() / 2, 6, paintBlack); - if (OsmandSettings.showGPSLocationOnMap) { - float f= (Runtime.getRuntime().totalMemory())/ 1e6f; - formatterOMap = new Formatter(); - canvas.drawText(formatterOMap.format("Lat : %.3f, lon : %.3f, zoom : %d, mem : %.3f", latitude, longitude, zoom, f).toString(), - drawCoordinatesX, drawCoordinatesY, paintBlack); -// canvas.drawText(formatOverMap.format(new Object[]{latitude, longitude, zoom, f}), drawCoordinatesX, -// drawCoordinatesY, paintBlack); + for(OsmandMapLayer layer : layers){ + layer.onDraw(canvas); } } @@ -413,7 +250,8 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall try { for (int i = 0; i * tileSize + startingX < width; i++) { for (int j = 0; j * tileSize + startingY < height; j++) { - Bitmap bmp = getImageFor(xTileLeft + i, yTileUp + j, zoom, true); + ResourceManager mgr = ResourceManager.getResourceManager(); + Bitmap bmp = mgr.getTileImageForMapAsync(map, xTileLeft + i, yTileUp + j, zoom, OsmandSettings.useInternetToDownloadTiles); if (bmp == null) { drawEmptyTile(canvas, i * tileSize + startingX, j * tileSize + startingY); } else { @@ -430,104 +268,119 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall } - - public void setZoom(int zoom){ - if (map == null || (map.getMaximumZoomSupported() >= zoom && map.getMinimumZoomSupported() <= zoom)) { - if(animatedDraggingThread != null){ - animatedDraggingThread.stopEvaluation(); - } - this.zoom = zoom; + public void tileDownloaded(DownloadRequest request) { + if(request == null){ + // we don't know exact images were changed prepareImage(); + return; } - } - - public File getFileWithTiles() { - return fileWithTiles; - } - - public ITileSource getMap() { - return map; - } - - public void setMap(ITileSource map) { - this.map = map; - if(map.getMaximumZoomSupported() < this.zoom){ - zoom = map.getMaximumZoomSupported(); - } - if(map.getMinimumZoomSupported() > this.zoom){ - zoom = map.getMinimumZoomSupported(); - } - prepareImage(); - } - - public void setFileWithTiles(File fileWithTiles) { - this.fileWithTiles = fileWithTiles; - prepareImage(); - } - - public void setLatLon(double latitude, double longitude){ - this.latitude = latitude; - this.longitude = longitude; - prepareImage(); - fireMapLocationListeners(null); - } - - public double getLatitude() { - return latitude; - } - - public double getLongitude() { - return longitude; - } - - public int getZoom() { - return zoom; - } - - - public void onLowMemory(){ - log.info("On low memory : cleaning tiles - size = " + cacheOfImages.size()); - ArrayList list = new ArrayList(cacheOfImages.keySet()); - // remove first images (as we think they are older) - for (int i = 0; i < list.size()/2; i ++) { - Bitmap bmp = cacheOfImages.remove(list.get(i)); - if(bmp != null){ - bmp.recycle(); + int xTileLeft = (int) Math.floor(getXTile() - getWidth() / (2d * getTileSize())); + int yTileUp = (int) Math.floor(getYTile() - getHeight() / (2d * getTileSize())); + int startingX = (int) ((xTileLeft - getXTile()) * getTileSize() + getWidth() / 2); + int startingY = (int) ((yTileUp - getYTile()) * getTileSize() + getHeight() / 2); + int i = (request.xTile - xTileLeft) * getTileSize() + startingX; + int j = (request.yTile - yTileUp) * getTileSize() + startingY; + if (request.zoom == this.zoom && + (i + getTileSize() >= 0 && i < getWidth()) && (j + getTileSize() >= 0 && j < getHeight())) { + SurfaceHolder holder = getHolder(); + synchronized (holder) { + Canvas canvas = holder.lockCanvas(new Rect(i, j, getTileSize() + i, getTileSize() + j)); + if (canvas != null) { + try { + ResourceManager mgr = ResourceManager.getResourceManager(); + Bitmap bmp = mgr.getTileImageForMapSync(map, request.xTile, request.yTile, zoom, false); + if (bmp == null) { + drawEmptyTile(canvas, i, j); + } else { + canvas.drawBitmap(bmp, i, j, null); + } + drawOverMap(canvas); + } finally { + holder.unlockCanvasAndPost(canvas); + } + } } } - System.gc(); } - public void addMapLocationListener(IMapLocationListener l){ - listeners.add(l); - } - public void removeMapLocationListener(IMapLocationListener l){ - listeners.remove(l); - } + /////////////////////////////////// DRAGGING PART /////////////////////////////////////// - protected void fireMapLocationListeners(Object source){ - for(IMapLocationListener l : listeners){ - l.locationChanged(latitude, longitude, source); + + @Override + public void dragTo(float fromX, float fromY, float toX, float toY){ + float dx = (fromX - toX)/getTileSize(); + float dy = (fromY - toY)/getTileSize(); + this.latitude = MapUtils.getLatitudeFromTile(zoom, getYTile() + dy); + this.longitude = MapUtils.getLongitudeFromTile(zoom, getXTile() + dx); + prepareImage(); + if(locationListener != null){ + locationListener.locationChanged(latitude, longitude, this); } } - - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - prepareImage(); + + + public boolean wasMapDraggingAccelerated(MotionEvent event){ + if(autoStartDragging == null){ + return false; + } + if(event.getEventTime() - autoStartDraggingTime < timeForDraggingAnimation){ + float dist = Math.abs(event.getX() - autoStartDragging.x) + Math.abs(event.getY() - autoStartDragging.y); + if(dist > minimumDistanceForDraggingAnimation){ + return true; + } + } + return false; } - + + @Override - public void surfaceCreated(SurfaceHolder holder) { - prepareImage(); - } - - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - // TODO clear cache ? + public boolean onTouchEvent(MotionEvent event) { + for (int i = layers.size() - 1; i >= 0; i--) { + if (layers.get(i).onTouchEvent(event)) { + return true; + } + } + if(event.getAction() == MotionEvent.ACTION_DOWN) { + animatedDraggingThread.stopDragging(); + if(startDragging == null){ + autoStartDragging = new PointF(event.getX(), event.getY()); + autoStartDraggingTime = event.getEventTime(); + startDragging = new PointF(event.getX(), event.getY()); + } + } else if(event.getAction() == MotionEvent.ACTION_UP) { + if(startDragging != null){ + dragTo(startDragging.x, startDragging.y, event.getX(), event.getY()); + startDragging = null; + if(wasMapDraggingAccelerated(event)){ + float timeDist = (int) (event.getEventTime() - autoStartDraggingTime); + if(timeDist < 20){ + timeDist = 20; + } + animatedDraggingThread.startDragging(timeDist, autoStartDragging.x, autoStartDragging.y, + event.getX(), event.getY()); + } + + } + } else if(event.getAction() == MotionEvent.ACTION_MOVE) { + if(startDragging != null){ + dragTo(startDragging.x, startDragging.y, event.getX(), event.getY()); + // save memory do not create new PointF + startDragging.x = event.getX(); + startDragging.y = event.getY(); + if(event.getEventTime() - autoStartDraggingTime > timeForDraggingAnimation){ + autoStartDraggingTime = event.getEventTime(); + autoStartDragging.x = event.getX(); + autoStartDragging.y = event.getY(); + } + } + } + return super.onTouchEvent(event); } + + } diff --git a/OsmAnd/src/com/osmand/views/POIMapLayer.java b/OsmAnd/src/com/osmand/views/POIMapLayer.java index c64a2c72ea..b29c4b5b3f 100644 --- a/OsmAnd/src/com/osmand/views/POIMapLayer.java +++ b/OsmAnd/src/com/osmand/views/POIMapLayer.java @@ -1,154 +1,111 @@ package com.osmand.views; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; -import org.apache.commons.logging.Log; - -import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; -import android.graphics.Point; -import android.util.AttributeSet; import android.view.MotionEvent; -import android.view.View; import android.widget.Toast; -import com.osmand.DefaultLauncherConstants; -import com.osmand.LogUtil; -import com.osmand.OsmandSettings; +import com.osmand.data.Amenity; import com.osmand.data.DataTileManager; -import com.osmand.map.ITileSource; -import com.osmand.osm.LatLon; import com.osmand.osm.MapUtils; -import com.osmand.osm.Node; -import com.osmand.osm.OSMSettings.OSMTagKey; -public class POIMapLayer extends View { - private DataTileManager nodeManager = null; - private LatLon currentLocation = null; - private int zoomLevel = DefaultLauncherConstants.MAP_startMapZoom; - private Map points = new LinkedHashMap(); +public class POIMapLayer implements OsmandMapLayer { + private static final int radiusClick = 2; // for 15 level zoom + + private DataTileManager nodeManager = null; private Paint pointUI; - private static final int radiusClick = 16; - private Toast previousShownToast =null; - private final static Log log = LogUtil.getLog(POIMapLayer.class); + private OsmandMapTileView view; + private List objects; - public POIMapLayer(Context context, AttributeSet attrs) { - super(context, attrs); - initUI(); - } - - public POIMapLayer(Context context) { - super(context); - initUI(); - } - - private void initUI() { - pointUI = new Paint(); - pointUI.setColor(Color.CYAN); - pointUI.setAlpha(150); - pointUI.setAntiAlias(true); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - for(Node n : points.keySet()){ - Point p = points.get(n); - canvas.drawCircle(p.x, p.y, radiusClick/2, pointUI); - } - } - - public void preparePoints() { - points.clear(); - if (nodeManager != null && currentLocation != null) { - double tileNumberX = MapUtils.getTileNumberX(zoomLevel, currentLocation.getLongitude()); - double tileNumberY = MapUtils.getTileNumberY(zoomLevel, currentLocation.getLatitude()); - double xTileLeft = tileNumberX - getWidth() / (2d * getTileSize()); - double xTileRight = tileNumberX + getWidth() / (2d * getTileSize()); - double yTileUp = tileNumberY - getHeight() / (2d * getTileSize()); - double yTileDown = tileNumberY + getHeight() / (2d * getTileSize()); - - List objects = nodeManager.getObjects(MapUtils.getLatitudeFromTile(zoomLevel, yTileUp), - MapUtils.getLongitudeFromTile(zoomLevel, xTileLeft), - MapUtils.getLatitudeFromTile(zoomLevel, yTileDown), - MapUtils.getLongitudeFromTile(zoomLevel, xTileRight)); - for (Node o : objects) { - double tileX = MapUtils.getTileNumberX(zoomLevel, o.getLongitude()); - int x = (int) ((tileX - xTileLeft) * getTileSize()); - double tileY = MapUtils.getTileNumberY(zoomLevel, o.getLatitude()); - int y = (int) ((tileY - yTileUp) * getTileSize()); - points.put(o, new Point(x, y)); - } - } - invalidate(); - } - + // TODO optimize all evaluations @Override public boolean onTouchEvent(MotionEvent event) { - if(event.getAction() == MotionEvent.ACTION_DOWN) { - - if(previousShownToast != null){ - previousShownToast.cancel(); - previousShownToast = null; - } - int x = (int) event.getX(); - int y = (int) event.getY(); - - for(Node n : points.keySet()){ - Point p = points.get(n); - if(Math.abs(p.x - x) <= radiusClick && Math.abs(p.y - y) <= radiusClick){ - StringBuilder b = new StringBuilder(); - b.append("This is an amenity : \n"); - b.append("type - ").append(n.getTag(OSMTagKey.AMENITY)).append("\n"); - if(n.getTag(OSMTagKey.NAME) != null){ - b.append("name - ").append(n.getTag(OSMTagKey.NAME)).append("\n"); - } - b.append("id - ").append(n.getId()); - - previousShownToast = Toast.makeText(getContext(), b.toString(), Toast.LENGTH_SHORT); - previousShownToast.show(); - // TODO use precision - log.debug("Precision is " + event.getXPrecision()); + if(event.getAction() == MotionEvent.ACTION_DOWN && objects != null) { + double tileNumberX = MapUtils.getTileNumberX(view.getZoom(), view.getLongitude()); + double tileNumberY = MapUtils.getTileNumberY(view.getZoom(), view.getLatitude()); + double xTileLeft = tileNumberX - view.getWidth() / (2d * getTileSize()); + double yTileUp = tileNumberY - view.getHeight() / (2d * getTileSize()); + int ex = (int) event.getX(); + int ey = (int) event.getY(); + int radius = getRadiusPoi(view.getZoom()) * 3 / 2; + for(Amenity n : objects){ + double tileX = MapUtils.getTileNumberX(view.getZoom(), n.getNode().getLongitude()); + int x = (int) ((tileX - xTileLeft) * getTileSize()); + double tileY = MapUtils.getTileNumberY(view.getZoom(), n.getNode().getLatitude()); + int y = (int) ((tileY - yTileUp) * getTileSize()); + if(Math.abs(x - ex) <= radius && Math.abs(y - ey) <= radius){ + Toast.makeText(view.getContext(), n.getSimpleFormat(), Toast.LENGTH_SHORT).show(); return true; } } } - return super.onTouchEvent(event); - } - - public void setCurrentLocationAndZoom(LatLon currentLocation, int zoom) { - this.currentLocation = currentLocation; - this.zoomLevel = zoom; - preparePoints(); +// return super.onTouchEvent(event); + return false; } public int getTileSize(){ - ITileSource source = OsmandSettings.tileSource; - return source == null ? 256 : source.getTileSize(); + return view.getTileSize(); } - public void setNodeManager(DataTileManager nodeManager) { + public void setNodeManager(DataTileManager nodeManager) { this.nodeManager = nodeManager; - preparePoints(); + if(view != null){ + view.prepareImage(); + } } - public LatLon getCurrentLocation() { - return currentLocation; - } - - public DataTileManager getNodeManager() { + public DataTileManager getNodeManager() { return nodeManager; } + @Override + public void initLayer(OsmandMapTileView view) { + this.view = view; + pointUI = new Paint(); + pointUI.setColor(Color.BLUE); + pointUI.setAlpha(150); + pointUI.setAntiAlias(true); + } - public int getZoomLevel() { - return zoomLevel; + public int getRadiusPoi(int zoom){ + if(zoom < 15){ + return 0; + } else { + return radiusClick << (zoom - 15); + } + } + + @Override + public void onDraw(Canvas canvas) { + if (nodeManager != null && view.getZoom() >= 15) { + double tileNumberX = MapUtils.getTileNumberX(view.getZoom(), view.getLongitude()); + double tileNumberY = MapUtils.getTileNumberY(view.getZoom(), view.getLatitude()); + double xTileLeft = tileNumberX - view.getWidth() / (2d * getTileSize()); + double xTileRight = tileNumberX + view.getWidth() / (2d * getTileSize()); + double yTileUp = tileNumberY - view.getHeight() / (2d * getTileSize()); + double yTileDown = tileNumberY + view.getHeight() / (2d * getTileSize()); + + objects = nodeManager.getObjects(MapUtils.getLatitudeFromTile(view.getZoom(), yTileUp), MapUtils + .getLongitudeFromTile(view.getZoom(), xTileLeft), MapUtils.getLatitudeFromTile(view.getZoom(), yTileDown), MapUtils + .getLongitudeFromTile(view.getZoom(), xTileRight)); + for (Amenity o : objects) { + double tileX = MapUtils.getTileNumberX(view.getZoom(), o.getNode().getLongitude()); + int x = (int) ((tileX - xTileLeft) * getTileSize()); + double tileY = MapUtils.getTileNumberY(view.getZoom(), o.getNode().getLatitude()); + int y = (int) ((tileY - yTileUp) * getTileSize()); + canvas.drawCircle(x, y, getRadiusPoi(view.getZoom()), pointUI); + } + } + } + + @Override + public void destroyLayer() { + } }