diff --git a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java index 29172cc0db..322cf18932 100644 --- a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java +++ b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java @@ -3,6 +3,7 @@ package net.osmand.util; import java.net.URI; import java.net.URLDecoder; import java.net.URLEncoder; +import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -10,7 +11,8 @@ public class GeoPointParserUtil { public static void main(String[] args) { final int ilat = 34, ilon = -106; - final double dlat = 34.99, dlon = -106.61; + final double dlat = 34.99393, dlon = -106.61568; + final double longLat = 34.993933029174805, longLon = -106.615680694580078; final String name = "Treasure Island"; int z = GeoParsedPoint.NO_ZOOM; String url; @@ -18,68 +20,68 @@ public class GeoPointParserUtil { // geo:34,-106 url = "geo:" + ilat + "," + ilon; System.out.println("url: " + url); - GeoParsedPoint actual = GeoPointParserUtil.parse("geo", url); + GeoParsedPoint actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(ilat, ilon)); - // geo:34.99,-106.61 + // geo:34.99393,-106.61568 url = "geo:" + dlat + "," + dlon; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("geo", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon)); - // geo:34.99,-106.61?z=11 + // geo:34.99393,-106.61568?z=11 z = 11; url = "geo:" + dlat + "," + dlon + "?z=" + z; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("geo", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); - // geo:34.99,-106.61 (Treasure Island) + // geo:34.99393,-106.61568 (Treasure Island) url = "geo:" + dlat + "," + dlon + " (" + name + ")"; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("geo", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, name)); - // geo:34.99,-106.61?z=11 (Treasure Island) + // geo:34.99393,-106.61568?z=11 (Treasure Island) z = 11; url = "geo:" + dlat + "," + dlon + "?z=" + z + " (" + name + ")"; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("geo", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z, name)); - // geo:34.99,-106.61?q=34.99%2C-106.61 (Treasure Island) + // geo:34.99393,-106.61568?q=34.99393%2C-106.61568 (Treasure Island) z = GeoParsedPoint.NO_ZOOM; url = "geo:" + dlat + "," + dlon + "?q=" + dlat + "%2C" + dlon + " (" + name + ")"; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("geo", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z, name)); // 0,0?q=34,-106(Treasure Island) z = GeoParsedPoint.NO_ZOOM; url = "geo:0,0?q=" + ilat + "," + ilon + " (" + name + ")"; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("geo", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(ilat, ilon, z, name)); - // 0,0?q=34.99,-106.61(Treasure Island) + // 0,0?q=34.99393,-106.61568(Treasure Island) z = GeoParsedPoint.NO_ZOOM; url = "geo:0,0?q=" + dlat + "," + dlon + " (" + name + ")"; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("geo", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z, name)); - // geo:0,0?z=11&q=34.99,-106.61(Treasure Island) + // geo:0,0?z=11&q=34.99393,-106.61568(Treasure Island) z = 11; url = "geo:0,0?z=" + z + "&q=" + dlat + "," + dlon + " (" + name + ")"; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("geo", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z, name)); - // geo:0,0?z=11&q=34.99,-106.61 + // geo:0,0?z=11&q=34.99393,-106.61568 z = 11; url = "geo:0,0?z=" + z + "&q=" + dlat + "," + dlon; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("geo", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); // google calendar @@ -87,14 +89,14 @@ public class GeoPointParserUtil { String qstr = "760 West Genesee Street Syracuse NY 13204"; url = "geo:0,0?q=" + qstr; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("geo", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(qstr)); // geo:0,0?z=11&q=1600+Amphitheatre+Parkway,+CA qstr = "1600 Amphitheatre Parkway, CA"; url = "geo:0,0?z=11&q=" + URLEncoder.encode(qstr); System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("geo", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(qstr)); // geo:50.451300,30.569900?z=15&q=50.451300,30.569900 (Kiev) @@ -105,85 +107,140 @@ public class GeoPointParserUtil { url = "geo:50.451300,30.569900?z=15&q=50.451300,30.569900 (Kiev)"; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("geo", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(qlat, qlon, z, qname)); // http://download.osmand.net/go?lat=34&lon=-106&z=11 url = "http://download.osmand.net/go?lat=" + ilat + "&lon=" + ilon + "&z=" + z; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(ilat, ilon, z)); - // http://download.osmand.net/go?lat=34.99&lon=-106.61&z=11 + // http://download.osmand.net/go?lat=34.99393&lon=-106.61568&z=11 url = "http://download.osmand.net/go?lat=" + dlat + "&lon=" + dlon + "&z=" + z; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); - // http://openstreetmap.org/map=11/34/-106 - url = "http://openstreetmap.org/map=" + z + "/" + ilat + "/" + ilon; + // http://openstreetmap.org/#map=11/34/-106 + z = 11; + url = "http://openstreetmap.org/#map=" + z + "/" + ilat + "/" + ilon; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(ilat, ilon, z)); - // http://openstreetmap.org/map=11/34.99/-106.61 - url = "http://openstreetmap.org/map=" + z + "/" + dlat + "/" + dlon; + // http://openstreetmap.org/#map=11/34.99393/-106.61568 + url = "http://openstreetmap.org/#map=" + z + "/" + dlat + "/" + dlon; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + // http://openstreetmap.org/#11/34.99393/-106.61568 + url = "http://openstreetmap.org/#" + z + "/" + dlat + "/" + dlon; + System.out.println("url: " + url); + actual = GeoPointParserUtil.parse(url); + assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + + // https://www.openstreetmap.org/#map=11/49.563/17.291 + url = "https://www.openstreetmap.org/#map=" + z + "/" + dlat + "/" + dlon; + System.out.println("url: " + url); + actual = GeoPointParserUtil.parse(url); + assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + + // https://www.openstreetmap.org/?mlat=34.993933029174805&mlon=-106.61568069458008#map=11/34.99393/-106.61568 + url = "https://www.openstreetmap.org/?mlat=" + longLat + "&mlon=" + longLon + + "#map=" + z + "/" + dlat + "/" + dlon; + System.out.println("url: " + url); + actual = GeoPointParserUtil.parse(url); + assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + + // https://wiki.openstreetmap.org/wiki/Shortlink + + // http://osm.org/go/TyFSutZ-?m= + // https://www.openstreetmap.org/?mlat=34.993933029174805&mlon=-106.61568069458008#map=15/34.99393/-106.61568 + z = 15; + url = "http://osm.org/go/TyFYuF6P--?m="; + System.out.println("url: " + url); + actual = GeoPointParserUtil.parse(url); + assertApproximateGeoPoint(actual, new GeoParsedPoint(longLat, longLon, z)); + + // http://osm.org/go/TyFS-- + // http://www.openstreetmap.org/#map=3/34.99/-106.70 + z = 3; + url = "http://osm.org/go/TyFS--"; + System.out.println("url: " + url); + actual = GeoPointParserUtil.parse(url); + assertApproximateGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + + // http://osm.org/go/TyFYuF6P~~-?m // current shortlink format with "~" + // https://www.openstreetmap.org/?mlat=34.993933029174805&mlon=-106.61568069458008#map=15/34.99393/-106.61568 + z = 20; + url = "http://osm.org/go/TyFYuF6P~~-?m"; + System.out.println("url: " + url); + actual = GeoPointParserUtil.parse(url); + assertApproximateGeoPoint(actual, new GeoParsedPoint(longLat, longLon, z)); + + // http://osm.org/go/TyFYuF6P@@--?m= // old, deprecated shortlink format with "@" + // https://www.openstreetmap.org/?mlat=34.993933029174805&mlon=-106.61568069458008#map=15/34.99393/-106.61568 + z = 21; + url = "http://osm.org/go/TyFYuF6P@@--?m="; + System.out.println("url: " + url); + actual = GeoPointParserUtil.parse(url); + assertApproximateGeoPoint(actual, new GeoParsedPoint(longLat, longLon, z)); + // http://openstreetmap.de/zoom=11&lat=34&lon=-106 + z = 11; url = "http://openstreetmap.de/zoom=" + z + "&lat=" + ilat + "&lon=" + ilon; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(ilat, ilon, z)); - // http://openstreetmap.de/zoom=11&lat=34.99&lon=-106.61 + // http://openstreetmap.de/zoom=11&lat=34.99393&lon=-106.61568 url = "http://openstreetmap.de/zoom=" + z + "&lat=" + dlat + "&lon=" + dlon; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); - // http://openstreetmap.de/lat=34.99&lon=-106.61&zoom=11 + // http://openstreetmap.de/lat=34.99393&lon=-106.61568&zoom=11 url = "http://openstreetmap.de/lat=" + dlat + "&lon=" + dlon + "&zoom=" + z; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); // http://maps.google.com/maps/@34,-106,11z url = "http://maps.google.com/maps/@" + ilat + "," + ilon + "," + z + "z"; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(ilat, ilon, z)); - // http://maps.google.com/maps/@34.99,-106.61,11z + // http://maps.google.com/maps/@34.99393,-106.61568,11z url = "http://maps.google.com/maps/@" + dlat + "," + dlon + "," + z + "z"; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); // http://maps.google.com/maps/ll=34,-106,z=11 url = "http://maps.google.com/maps/ll=" + ilat + "," + ilon + ",z=" + z; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(ilat, ilon, z)); - // http://maps.google.com/maps/ll=34.99,-106.61,z=11 + // http://maps.google.com/maps/ll=34.99393,-106.61568,z=11 url = "http://maps.google.com/maps/ll=" + dlat + "," + dlon + ",z=" + z; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); // http://maps.google.com/maps/q=loc:34,-106&z=11 url = "http://maps.google.com/maps/q=loc:" + ilat + "," + ilon + "&z=" + z; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(ilat, ilon, z)); - // http://maps.google.com/maps/q=loc:34.99,-106.61&z=11 + // http://maps.google.com/maps/q=loc:34.99393,-106.61568&z=11 url = "http://maps.google.com/maps/q=loc:" + dlat + "," + dlon + "&z=" + z; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); // whatsapp @@ -191,112 +248,158 @@ public class GeoPointParserUtil { z = GeoParsedPoint.NO_ZOOM; url = "http://maps.google.com/maps/q=loc:" + ilat + "," + ilon + " (You)"; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(ilat, ilon, z)); // whatsapp - // http://maps.google.com/maps/q=loc:34.99,-106.61 (You) + // http://maps.google.com/maps/q=loc:34.99393,-106.61568 (You) z = GeoParsedPoint.NO_ZOOM; url = "http://maps.google.com/maps/q=loc:" + dlat + "," + dlon + " (You)"; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); // http://www.google.com/maps/search/food/34,-106,14z url = "http://www.google.com/maps/search/food/" + ilat + "," + ilon + "," + z + "z"; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(ilat, ilon, z)); - // http://www.google.com/maps/search/food/34.99,-106.61,14z + // http://www.google.com/maps/search/food/34.99393,-106.61568,14z url = "http://www.google.com/maps/search/food/" + dlat + "," + dlon + "," + z + "z"; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); // http://maps.google.com?saddr=Current+Location&daddr=34,-106 z = GeoParsedPoint.NO_ZOOM; url = "http://maps.google.com?saddr=Current+Location&daddr=" + ilat + "," + ilon; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(ilat, ilon, z)); - // http://maps.google.com?saddr=Current+Location&daddr=34.99,-106.61 + // http://maps.google.com?saddr=Current+Location&daddr=34.99393,-106.61568 z = GeoParsedPoint.NO_ZOOM; url = "http://maps.google.com?saddr=Current+Location&daddr=" + dlat + "," + dlon; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); // http://www.google.com/maps/dir/Current+Location/34,-106 z = GeoParsedPoint.NO_ZOOM; url = "http://www.google.com/maps/dir/Current+Location/" + ilat + "," + ilon; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(ilat, ilon, z)); - // http://www.google.com/maps/dir/Current+Location/34.99,-106.61 + // http://www.google.com/maps/dir/Current+Location/34.99393,-106.61568 z = GeoParsedPoint.NO_ZOOM; url = "http://www.google.com/maps/dir/Current+Location/" + dlat + "," + dlon; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); // http://maps.google.com/maps?q=34,-106 z = GeoParsedPoint.NO_ZOOM; url = "http://maps.google.com/maps?q=" + ilat + "," + ilon; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(ilat, ilon, z)); - // http://maps.google.com/maps?q=34.99,-106.61 + // http://maps.google.com/maps?q=34.99393,-106.61568 z = GeoParsedPoint.NO_ZOOM; url = "http://maps.google.com/maps?q=" + dlat + "," + dlon; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); // http://www.google.com/maps/place/760+West+Genesee+Street+Syracuse+NY+13204 qstr = "760+West+Genesee+Street+Syracuse+NY+13204"; url = "http://www.google.com/maps/place/" + qstr; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(qstr)); // http://maps.google.com/maps?q=760+West+Genesee+Street+Syracuse+NY+13204 qstr = "760+West+Genesee+Street+Syracuse+NY+13204"; url = "http://www.google.com/maps?q=" + qstr; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(qstr)); // http://maps.google.com/maps?daddr=760+West+Genesee+Street+Syracuse+NY+13204 qstr = "760+West+Genesee+Street+Syracuse+NY+13204"; url = "http://www.google.com/maps?daddr=" + qstr; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(qstr)); // http://www.google.com/maps/dir/Current+Location/760+West+Genesee+Street+Syracuse+NY+13204 qstr = "760+West+Genesee+Street+Syracuse+NY+13204"; url = "http://www.google.com/maps/dir/Current+Location/" + qstr; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(qstr)); // http://maps.yandex.ru/?ll=34,-106&z=11 z = 11; url = "http://maps.yandex.ru/?ll=" + ilat + "," + ilon + "&z=" + z; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(ilat, ilon, z)); - // http://maps.yandex.ru/?ll=34.99,-106.61&z=11 + // http://maps.yandex.ru/?ll=34.99393,-106.61568&z=11 z = 11; url = "http://maps.yandex.ru/?ll=" + dlat + "," + dlon + "&z=" + z; System.out.println("url: " + url); - actual = GeoPointParserUtil.parse("http", url); + actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + + // http://map.baidu.com/?l=13&tn=B_NORMAL_MAP&c=13748138,4889173&s=gibberish + z = 7; + int latint = ((int)(dlat * 100000)); + int lonint = ((int)(dlon * 100000)); + url = "http://map.baidu.com/?l=" + z + "&tn=B_NORMAL_MAP&c=" + latint + "," + lonint + "&s=gibberish"; + System.out.println("url: " + url); + actual = GeoPointParserUtil.parse(url); + assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + + /* URLs straight from various services, instead of generated here */ + + String urls[] = { + "https://openstreetmap.org/go/0LQ127-?m", + "http://osm.org/go/0LQ127-?m", + "http://osm.org/go/0EEQjE==", + "http://osm.org/go/0EEQjEEb", + "http://osm.org/go/0EE~jEEb", + "http://osm.org/go/0EE@jEEb", + "http://osm.org/go/~~~~", + "http://osm.org/go/@@@@", + "https://www.openstreetmap.org/#map=0/0/0", + "https://www.openstreetmap.org/#map=0/180/180", + "https://www.openstreetmap.org/#map=0/-180/-180", + "https://www.openstreetmap.org/#map=0/180.0/180.0", + "https://www.openstreetmap.org/#map=6/33.907/34.662", + "https://www.openstreetmap.org/?mlat=49.56275939941406&mlon=17.291107177734375#map=8/49.563/17.291", + }; + + for (String u : urls) { + System.out.println("url: " + u); + actual = GeoPointParserUtil.parse(u); + assert(actual != null); + System.out.println("Passed!"); + } + } + + private static boolean areCloseEnough(int a, int b) { + return a == b; + } + + private static boolean areCloseEnough(double a, double b, long howClose) { + long aRounded = (long) Math.round(a * Math.pow(10, howClose)); + long bRounded = (long) Math.round(b * Math.pow(10, howClose)); + System.out.println("areCloseEnough: " + aRounded + ", " + bRounded); + return aRounded == bRounded; } private static void assertGeoPoint(GeoParsedPoint actual, GeoParsedPoint expected) { @@ -304,7 +407,7 @@ public class GeoPointParserUtil { if (!expected.getQuery().equals(actual.getQuery())) throw new RuntimeException("Query param not equal"); } else { - double aLat = actual.getLat(), eLat = expected.getLat(), aLon = actual.getLon(), eLon = expected.getLon(); + double aLat = actual.getLatitude(), eLat = expected.getLatitude(), aLon = actual.getLongitude(), eLon = expected.getLongitude(); int aZoom = actual.getZoom(), eZoom = expected.getZoom(); String aName = actual.getName(), eName = expected.getName(); if (eName != null) { @@ -313,10 +416,10 @@ public class GeoPointParserUtil { + eName); } } - if (eLat != aLat) { + if (!areCloseEnough(eLat, aLat, 5)) { throw new RuntimeException("Latitude is not equal; actual=" + aLat + ", expected=" + eLat); } - if (eLon != aLon) { + if (!areCloseEnough(eLon, aLon, 5)) { throw new RuntimeException("Longitude is not equal; actual=" + aLon + ", expected=" + eLon); } if (eZoom != aZoom) { @@ -326,8 +429,35 @@ public class GeoPointParserUtil { System.out.println("Passed!"); } - private static String getQueryParameter(final String param, URI data) { - final String query = data.getQuery(); + private static void assertApproximateGeoPoint(GeoParsedPoint actual, GeoParsedPoint expected) { + if (expected.getQuery() != null) { + if (!expected.getQuery().equals(actual.getQuery())) + throw new RuntimeException("Query param not equal"); + } else { + double aLat = actual.getLatitude(), eLat = expected.getLatitude(), aLon = actual.getLongitude(), eLon = expected.getLongitude(); + int aZoom = actual.getZoom(), eZoom = expected.getZoom(); + String aName = actual.getName(), eName = expected.getName(); + if (eName != null) { + if (!aName.equals(eName)) { + throw new RuntimeException("Point name\\capture is not equal; actual=" + aName + ", expected=" + + eName); + } + } + if (((int)eLat) != ((int)aLat)) { + throw new RuntimeException("Latitude is not equal; actual=" + aLat + ", expected=" + eLat); + } + if (((int)eLon) != ((int)aLon)) { + throw new RuntimeException("Longitude is not equal; actual=" + aLon + ", expected=" + eLon); + } + if (eZoom != aZoom) { + throw new RuntimeException("Zoom is not equal; actual=" + aZoom + ", expected=" + eZoom); + } + } + System.out.println("Passed!"); + } + + private static String getQueryParameter(final String param, URI uri) { + final String query = uri.getQuery(); String value = null; if (query != null && query.contains(param)) { String[] params = query.split("&"); @@ -344,30 +474,34 @@ public class GeoPointParserUtil { /** * Parses geo and map intents: * - * @param scheme - * The intent scheme * @param uri * The URI object * @return {@link GeoParsedPoint} */ - public static GeoParsedPoint parse(final String scheme, final String uri) { - final URI data = URI.create(uri.replaceAll("\\s+", "+").replaceAll("%20", "+").replaceAll("%2C", ",")); + public static GeoParsedPoint parse(final String uriString) { + final URI uri = URI.create(uriString.replaceAll("\\s+", "+").replaceAll("%20", "+").replaceAll("%2C", ",")); + + String scheme = uri.getScheme(); + if (scheme == null) + return null; + else + scheme = scheme.toLowerCase(Locale.US); + if ("http".equals(scheme) || "https".equals(scheme)) { + String host = uri.getHost(); + if (host == null) + return null; + else + host = host.toLowerCase(Locale.US); - final String schemeSpecific = data.getSchemeSpecificPart(); - - if (schemeSpecific == null) { + final String schemeSpecific = uri.getSchemeSpecificPart(); + if (schemeSpecific == null) return null; - } final String[] osmandNetSite = { "//download.osmand.net/go?" }; final String[] osmandNetPattern = { "lat=([+-]?\\d+(?:\\.\\d+)?)&lon=([+-]?\\d+(?:\\.\\d+)?)&?(z=\\d{1,2})" }; - final String[] openstreetmapOrgSite = { "//openstreetmap.org/", "//www.openstreetmap.org/" }; - - final String[] openstreetmapOrgPattern = { "(?:.*)(?:map=)(\\d{1,2})/([+-]?\\d+(?:\\.\\d+)?)/([+-]?\\d+(?:\\.\\d+)?)(?:.*)" }; - final String[] openstreetmapDeSite = { "//openstreetmap.de/", "//www.openstreetmap.de/" }; final String[] openstreetmapDePattern = { @@ -390,11 +524,69 @@ public class GeoPointParserUtil { final String[] yandexRuPattern = { "(?:.*)ll=([+-]?\\d+(?:\\.\\d+)?),([+-]?\\d+(?:\\.\\d+)?)(?:.+)(z=\\d{1,2})(?:.*)" }; - final String sites[][] = { osmandNetSite, openstreetmapOrgSite, openstreetmapDeSite, googleComSite, - yandexRuSite }; + final String sites[][] = { osmandNetSite, openstreetmapDeSite, + googleComSite, yandexRuSite }; + + final String patterns[][] = { osmandNetPattern, + openstreetmapDePattern, googleComPattern, yandexRuPattern }; + + try { + if (host.equals("osm.org") || host.endsWith("openstreetmap.org")) { + Pattern p; + Matcher matcher; + String path = uri.getPath(); + if (path != null && path.startsWith("/go/")) { // short URL form + p = Pattern.compile("^/go/([A-Za-z0-9_@~]+-*)(?:.*)"); + matcher = p.matcher(uri.getPath()); + if (matcher.matches()) { + return MapUtils.decodeShortLinkString(matcher.group(1)); + } + } else { // data in the query and/or feature strings + String lat = "0"; + String lon = "0"; + String zoom = String.valueOf(GeoParsedPoint.NO_ZOOM); + String fragment = uri.getFragment(); + if (fragment != null) { + p = Pattern.compile("(?:map=)?(\\d{1,2})/([+-]?\\d+(?:\\.\\d+)?)/([+-]?\\d+(?:\\.\\d+)?)(?:.*)"); + matcher = p.matcher(fragment); + if (matcher.matches()) { + zoom = matcher.group(1); + lat = matcher.group(2); + lon = matcher.group(3); + } + } + String query = uri.getQuery(); + if (query != null) { + // the query string sometimes has higher resolution values + p = Pattern.compile("(?:.*)mlat=([+-]?\\d+(?:\\.\\d+)?)(?:.*)&mlon=([+-]?\\d+(?:\\.\\d+)?)(?:.*)?"); + matcher = p.matcher(query); + if (matcher.matches()) { + lat = matcher.group(1); + lon = matcher.group(2); + } + } + return new GeoParsedPoint(lat, lon, zoom); + } + } else if (schemeSpecific.startsWith("//map.baidu.")) { // .com and .cn both work + /* Baidu Map uses a custom format for lat/lon., it is basically standard lat/lon + * multiplied by 100,000, then rounded to an integer */ + Pattern p = Pattern.compile(".*[/?&]l=(\\d{1,2}).*&c=([+-]?\\d+),([+-]?\\d+).*"); + Matcher matcher = p.matcher(schemeSpecific); + if (matcher.matches()) { + double lat = Integer.valueOf(matcher.group(2)) / 100000.; + double lon = Integer.valueOf(matcher.group(3)) / 100000.; + int zoom = parseZoom(matcher.group(1)); + return new GeoParsedPoint(lat, lon, zoom); + } + } + } catch (IllegalStateException e) { + e.printStackTrace(); + return null; + } catch (NumberFormatException e) { + e.printStackTrace(); + return null; + } - final String patterns[][] = { osmandNetPattern, openstreetmapOrgPattern, openstreetmapDePattern, - googleComPattern, yandexRuPattern }; // search by geo coordinates for (int s = 0; s < sites.length; s++) { for (int si = 0; si < sites[s].length; si++) { @@ -403,7 +595,7 @@ public class GeoPointParserUtil { String subString = schemeSpecific.substring(sites[s][si].length()); if (subString.equals("")) { - subString = data.getFragment(); + subString = uri.getFragment(); } final Matcher matcher = Pattern.compile(patterns[s][p]).matcher(subString); @@ -461,9 +653,8 @@ public class GeoPointParserUtil { } } return null; - } - if ("geo".equals(scheme) || "osmand.geo".equals(scheme)) { - String schemeSpecific = data.getSchemeSpecificPart(); + } else if ("geo".equals(scheme) || "osmand.geo".equals(scheme)) { + String schemeSpecific = uri.getSchemeSpecificPart(); if (schemeSpecific == null) { return null; } @@ -540,6 +731,14 @@ public class GeoPointParserUtil { return null; } + private static int parseZoom(String zoom) { + try { + return Integer.valueOf(zoom); + } catch (NumberFormatException e) { + return GeoParsedPoint.NO_ZOOM; + } + } + public static class GeoParsedPoint { private static final int NO_ZOOM = -1; @@ -574,17 +773,27 @@ public class GeoPointParserUtil { this.zoom = zoom; } + public GeoParsedPoint(String latString, String lonString, String zoomString) throws NumberFormatException { + this(Double.valueOf(latString), Double.valueOf(lonString)); + this.zoom = parseZoom(zoomString); + } + + public GeoParsedPoint(String latString, String lonString) throws NumberFormatException { + this(Double.valueOf(latString), Double.valueOf(lonString)); + this.zoom = NO_ZOOM; + } + public GeoParsedPoint(String query) { super(); this.query = query; this.geoAddress = true; } - public double getLat() { + public double getLatitude() { return lat; } - public double getLon() { + public double getLongitude() { return lon; } diff --git a/OsmAnd-java/src/net/osmand/util/MapUtils.java b/OsmAnd-java/src/net/osmand/util/MapUtils.java index d31519be60..f9855eebd3 100644 --- a/OsmAnd-java/src/net/osmand/util/MapUtils.java +++ b/OsmAnd-java/src/net/osmand/util/MapUtils.java @@ -8,6 +8,7 @@ import java.util.List; import net.osmand.data.LatLon; import net.osmand.data.MapObject; import net.osmand.data.QuadPoint; +import net.osmand.util.GeoPointParserUtil.GeoParsedPoint; /** @@ -20,7 +21,9 @@ import net.osmand.data.QuadPoint; */ public class MapUtils { - private static final String BASE_SHORT_OSM_URL = "http://osm.org/go/"; + // TODO change the hostname back to osm.org once HTTPS works for it + // https://github.com/openstreetmap/operations/issues/2 + private static final String BASE_SHORT_OSM_URL = "https://openstreetmap.org/go/"; /** * This array is a lookup table that translates 6-bit positive integer @@ -32,7 +35,7 @@ public class MapUtils { 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_', '@' + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_', '~' }; public static double getDistance(LatLon l, double latitude, double longitude){ @@ -275,16 +278,19 @@ public class MapUtils { }); } + public static String buildGeoUrl(double latitude, double longitude, int zoom) { + return "geo:" + ((float) latitude) + "," + ((float)longitude) + "?z=" + zoom; + } // Examples // System.out.println(buildShortOsmUrl(51.51829d, 0.07347d, 16)); // http://osm.org/go/0EEQsyfu // System.out.println(buildShortOsmUrl(52.30103d, 4.862927d, 18)); // http://osm.org/go/0E4_JiVhs // System.out.println(buildShortOsmUrl(40.59d, -115.213d, 9)); // http://osm.org/go/TelHTB-- public static String buildShortOsmUrl(double latitude, double longitude, int zoom){ - return BASE_SHORT_OSM_URL + createShortLocString(latitude, longitude, zoom) + "?m"; + return BASE_SHORT_OSM_URL + createShortLinkString(latitude, longitude, zoom) + "?m"; } - public static String createShortLocString(double latitude, double longitude, int zoom) { + public static String createShortLinkString(double latitude, double longitude, int zoom) { long lat = (long) (((latitude + 90d)/180d)*(1L << 32)); long lon = (long) (((longitude + 180d)/360d)*(1L << 32)); long code = interleaveBits(lon, lat); @@ -301,44 +307,44 @@ public class MapUtils { return str; } - @SuppressWarnings("unused") - public static LatLon decodeShortLocString(String s) { + public static GeoParsedPoint decodeShortLinkString(String s) { + // convert old shortlink format to current one + s = s.replaceAll("@", "~"); + int i = 0; long x = 0; long y = 0; - int z = 0; - int z_offset = 0; + int z = -8; - for (int i = 0; i < s.length(); i++) { - if (s.charAt(i) == '-') { - z_offset--; - continue; - } + for (i = 0; i < s.length(); i++) { + int digit = -1; char c = s.charAt(i); - for (int j = 0; j < intToBase64.length; j++) { + for (int j = 0; j < intToBase64.length; j++) if (c == intToBase64[j]) { - for (int k = 0; k < 3; k++) { - x <<= 1; - if ((j & 32) != 0) { - x = x | 1; - } - j <<= 1; - y <<= 1; - if ((j & 32) != 0) { - y = y | 1; - } - j <<= 1; - } - z += 3; + digit = j; break; } + if (digit < 0) + break; + if (digit < 0) + break; + // distribute 6 bits into x and y + x <<= 3; + y <<= 3; + for (int j = 2; j >= 0; j--) { + x |= ((digit & (1 << (j+j+1))) == 0 ? 0 : (1 << j)); + y |= ((digit & (1 << (j+j))) == 0 ? 0 : (1 << j)); } + z += 3; } - x <<= (32 - z); - y <<= (32 - z); -// int zoom = z - 8 - ((3 + z_offset) % 3); - double dlat = (180d * (y) / ((double)(1L << 32))) - 90d; - double dlon = (360d * (x)/ ((double)(1L << 32))) - 180d; - return new LatLon(dlat, dlon); + double lon = x * Math.pow(2, 2 - 3 * i) * 90. - 180; + double lat = y * Math.pow(2, 2 - 3 * i) * 45. - 90; + // adjust z + if(i < s.length() && s.charAt(i) == '-') { + z -= 2; + if(i + 1 < s.length() && s.charAt(i + 1) == '-') + z++; + } + return new GeoParsedPoint(lat, lon, z); } /** diff --git a/OsmAnd/AndroidManifest.xml b/OsmAnd/AndroidManifest.xml index 93460e56de..b9e6420487 100644 --- a/OsmAnd/AndroidManifest.xml +++ b/OsmAnd/AndroidManifest.xml @@ -79,7 +79,11 @@ - + + + + + @@ -177,10 +181,16 @@ - - - - + + + + + + + + + + @@ -192,13 +202,6 @@ - - - - - - - diff --git a/OsmAnd/old-ndk-build.sh b/OsmAnd/old-ndk-build.sh index 8056be82fa..5d1b067aba 100755 --- a/OsmAnd/old-ndk-build.sh +++ b/OsmAnd/old-ndk-build.sh @@ -4,15 +4,23 @@ SCRIPT_LOC="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" NAME=$(basename $(dirname "${BASH_SOURCE[0]}") ) -if [ ! -d "$ANDROID_SDK" ]; then - echo "ANDROID_SDK is not set" - exit +if [ -d "$ANDROID_HOME" ]; then + # for backwards compatbility + export ANDROID_SDK=$ANDROID_HOME +else + echo "ANDROID_HOME is not set, trying ANDROID_SDK:" + if [ -d "$ANDROID_SDK" ]; then + export ANDROID_HOME=$ANDROID_SDK + else + echo "ANDROID_SDK is also not set" + exit + fi fi if [ ! -d "$ANDROID_NDK" ]; then echo "ANDROID_NDK is not set" exit fi -export ANDROID_SDK_ROOT=$ANDROID_SDK +export ANDROID_SDK_ROOT=$ANDROID_HOME export ANDROID_NDK_ROOT=$ANDROID_NDK export ANDROID_NDK_TOOLCHAIN_VERSION=4.7 diff --git a/OsmAnd/src/net/osmand/plus/activities/actions/ShareLocation.java b/OsmAnd/src/net/osmand/plus/activities/actions/ShareLocation.java index 27732c5056..303d589eb7 100644 --- a/OsmAnd/src/net/osmand/plus/activities/actions/ShareLocation.java +++ b/OsmAnd/src/net/osmand/plus/activities/actions/ShareLocation.java @@ -43,17 +43,18 @@ public class ShareLocation extends OsmAndAction { final double longitude = args.getDouble(MapActivityActions.KEY_LONGITUDE); final int zoom = args.getInt(MapActivityActions.KEY_ZOOM); try { - final String shortOsmUrl = MapUtils.buildShortOsmUrl(latitude, longitude, zoom); - final String appLink = "http://download.osmand.net/go?lat=" + ((float) latitude) + "&lon=" + ((float) longitude) + "&z=" + zoom; - String sms = mapActivity.getString(R.string.send_location_sms_pattern, shortOsmUrl, appLink); + final String geoUrl = MapUtils.buildGeoUrl(latitude, longitude, zoom); + // TODO change this to HTTPS once it is setup! + final String httpUrl = "http://osmand.net/go?lat=" + ((float) latitude) + "&lon=" + ((float) longitude) + "&z=" + zoom; + String sms = mapActivity.getString(R.string.send_location_sms_pattern, geoUrl, httpUrl); if (which == 0) { - sendEmail(shortOsmUrl, appLink); + sendEmail(httpUrl, geoUrl); } else if (which == 1) { sendSms(sms); } else if (which == 2) { sendToClipboard(sms); } else if (which == 3) { - sendGeoActivity(latitude, longitude, zoom); + sendGeoActivity(geoUrl); } else if (which == 4) { sendQRCode(latitude, longitude); } @@ -69,8 +70,8 @@ public class ShareLocation extends OsmAndAction { - private void sendEmail(final String shortOsmUrl, final String appLink) { - String email = mapActivity.getString(R.string.send_location_email_pattern, shortOsmUrl, appLink); + private void sendEmail(final String httpUrl, final String geoUrl) { + String email = mapActivity.getString(R.string.send_location_email_pattern, httpUrl, geoUrl); ShareDialog.sendEmail(mapActivity, email, getString(R.string.send_location)); } @@ -83,10 +84,8 @@ public class ShareLocation extends OsmAndAction { } - private void sendGeoActivity(final double latitude, final double longitude, final int zoom) { - final String simpleGeo = "geo:"+((float) latitude)+","+((float)longitude) +"?z="+zoom; - Uri location = Uri.parse(simpleGeo); - Intent mapIntent = new Intent(Intent.ACTION_VIEW, location); + private void sendGeoActivity(final String geoUrl) { + Intent mapIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(geoUrl)); mapActivity.startActivity(mapIntent); } diff --git a/OsmAnd/src/net/osmand/plus/activities/search/GeoIntentActivity.java b/OsmAnd/src/net/osmand/plus/activities/search/GeoIntentActivity.java index c1928af9dc..f9dd96b7f5 100644 --- a/OsmAnd/src/net/osmand/plus/activities/search/GeoIntentActivity.java +++ b/OsmAnd/src/net/osmand/plus/activities/search/GeoIntentActivity.java @@ -101,7 +101,7 @@ public class GeoIntentActivity extends OsmandListActivity { while (getMyApplication().isApplicationInitializing()) { Thread.sleep(200); } - return extract(intent.getScheme(), intent.getData()).execute(); + return extract(intent.getData()).execute(); } catch (Exception e) { return null; } @@ -126,6 +126,7 @@ public class GeoIntentActivity extends OsmandListActivity { .getItemId(0)); } } + finish(); } else { AccessibleToast.makeText(GeoIntentActivity.this, getString(R.string.search_offline_geo_error, intent.getData()), Toast.LENGTH_LONG).show(); @@ -202,19 +203,17 @@ public class GeoIntentActivity extends OsmandListActivity { * geo:0,0?q=34.99,-106.61(Treasure)
* geo:0,0?q=1600+Amphitheatre+Parkway%2C+CA
* - * @param scheme - * The intent scheme * @param data * The intent uri * @return */ - private MyService extract(final String scheme, final Uri data) { - GeoPointParserUtil.GeoParsedPoint p = GeoPointParserUtil.parse(scheme, data.toString()); + private MyService extract(final Uri uri) { + GeoPointParserUtil.GeoParsedPoint p = GeoPointParserUtil.parse(uri.toString()); if (p.isGeoPoint()) { if (p.getName() != null) { - return new GeoPointSearch(p.getLat(), p.getLon(), p.getName(), p.getZoom()); + return new GeoPointSearch(p.getLatitude(), p.getLongitude(), p.getName(), p.getZoom()); } - return new GeoPointSearch(p.getLat(), p.getLon(), p.getZoom()); + return new GeoPointSearch(p.getLatitude(), p.getLongitude(), p.getZoom()); } else { return new GeoAddressSearch(p.getQuery()); } diff --git a/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNotesPlugin.java b/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNotesPlugin.java index faf695f197..1eb89cd04b 100644 --- a/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNotesPlugin.java +++ b/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNotesPlugin.java @@ -22,7 +22,6 @@ import net.osmand.PlatformUtil; import net.osmand.access.AccessibleAlertBuilder; import net.osmand.access.AccessibleToast; import net.osmand.data.DataTileManager; -import net.osmand.data.LatLon; import net.osmand.plus.ApplicationMode; import net.osmand.plus.ContextMenuAdapter; import net.osmand.plus.ContextMenuAdapter.OnContextMenuClick; @@ -45,6 +44,7 @@ import net.osmand.plus.views.OsmandMapTileView; import net.osmand.plus.views.mapwidgets.StackWidgetView; import net.osmand.plus.views.mapwidgets.TextInfoWidget; import net.osmand.util.Algorithms; +import net.osmand.util.GeoPointParserUtil.GeoParsedPoint; import net.osmand.util.MapUtils; import org.apache.commons.logging.Log; @@ -553,7 +553,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { } private File getBaseFileName(double lat, double lon, OsmandApplication app, String ext) { - String basename = MapUtils.createShortLocString(lat, lon, 15); + String basename = MapUtils.createShortLinkString(lat, lon, 15); int k = 1; File f = app.getAppPath(IndexConstants.AV_INDEX_DIR); f.mkdirs(); @@ -943,9 +943,9 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { encodeName = encodeName.substring(0, i); } r.file = f; - LatLon l = MapUtils.decodeShortLocString(encodeName); - r.lat = l.getLatitude(); - r.lon = l.getLongitude(); + GeoParsedPoint geo = MapUtils.decodeShortLinkString(encodeName); + r.lat = geo.getLatitude(); + r.lon = geo.getLongitude(); Float heading = app.getLocationProvider().getHeading(); Location loc = app.getLocationProvider().getLastKnownLocation(); if (lastTakingPhoto != null && lastTakingPhoto.getName().equals(f.getName()) && heading != null) {