From 3d106d00b733e7e7f351261f8acde3042e60851a Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 13 Jan 2015 11:57:15 +0100 Subject: [PATCH 01/13] support parsing amap.com URLs amap.com aka autonavi is a popular mapping service in China. --- .../net/osmand/util/GeoPointParserUtil.java | 57 ++++++++++++++++++- OsmAnd/AndroidManifest.xml | 2 + 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java index 3bffa034fb..6c8e9cff02 100644 --- a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java +++ b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java @@ -395,6 +395,19 @@ public class GeoPointParserUtil { actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + // http://www.amap.com/#!poi!!q=38.174596,114.995033|2|%E5%AE%BE%E9%A6%86&radius=1000 + z = 13; // amap uses radius, so 1000m is roughly zoom level 13 + url = "http://www.amap.com/#!poi!!q=" + dlat + "," + dlon + "|2|%E5%AE%BE%E9%A6%86&radius=1000"; + System.out.println("\nurl: " + url); + actual = GeoPointParserUtil.parse(url); + assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + + z = GeoParsedPoint.NO_ZOOM; + url = "http://www.amap.com/?q=" + dlat + "," + dlon + ",%E4%B8%8A%E6%B5v%B7%E5%B8%82%E6%B5%A6%E4%B8%9C%E6%96%B0%E5%8C%BA%E4%BA%91%E5%8F%B0%E8%B7%AF8086"; + System.out.println("\nurl: " + url); + actual = GeoPointParserUtil.parse(url); + assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + /* URLs straight from various services, instead of generated here */ String urls[] = { @@ -412,13 +425,18 @@ public class GeoPointParserUtil { "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", + "http://www.amap.com/#!poi!!q=38.174596,114.995033,%E6%B2%B3%E5%8C%97%E7%9C%81%E7%9F%B3%E5%AE%B6%E5%BA%84%E5%B8%82%E6%97%A0%E6%9E%81%E5%8E%BF", + "http://wb.amap.com/?p=B013706PJN,38.179456,114.98577,%E6%96%B0%E4%B8%9C%E6%96%B9%E5%A4%A7%E9%85%92%E5%BA%97(%E4%BF%9D%E9%99%A9%E8%8A%B1...,%E5%BB%BA%E8%AE%BE%E8%B7%AF67%E5%8F%B7", + "http://www.amap.com/#!poi!!q=38.179456,114.98577|3|B013706PJN", + "http://www.amap.com/#!poi!!q=38.174596,114.995033|2|%E5%AE%BE%E9%A6%86&radius=1000", + "http://www.amap.com/?p=B013704EJT,38.17914,114.976337,%E6%97%A0%E6%9E%81%E5%8E%BF%E4%BA%BA%E6%B0%91%E6%94%BF%E5%BA%9C,%E5%BB%BA%E8%AE%BE%E4%B8%9C%E8%B7%AF12%E5%8F%B7", }; for (String u : urls) { System.out.println("url: " + u); actual = GeoPointParserUtil.parse(u); assert(actual != null); - System.out.println("Passed!"); + System.out.println("Properly parsed!"); } } @@ -509,7 +527,16 @@ public class GeoPointParserUtil { * @return {@link GeoParsedPoint} */ public static GeoParsedPoint parse(final String uriString) { - final URI uri = URI.create(uriString.replaceAll("\\s+", "+").replaceAll("%20", "+").replaceAll("%2C", ",")); + URI uri; + try { + // amap.com uses | in their URLs, which is an illegal character for a URL + uri = URI.create(uriString.replaceAll("\\s+", "+") + .replaceAll("%20", "+") + .replaceAll("%2C", ",") + .replaceAll("\\|", ";")); + } catch (IllegalArgumentException e) { + return null; + } String scheme = uri.getScheme(); if (scheme == null) @@ -640,6 +667,32 @@ public class GeoPointParserUtil { return parseGoogleMapsPath(path, params); } } + } else if (host.endsWith(".amap.com")) { + /* amap (mis)uses the Fragment, which is not included in the Scheme Specific Part, + * so instead we make a custom "everything but the Authority subString */ + // +4 for the :// and the / + final String subString = uri.toString().substring(scheme.length() + host.length() + 4); + Pattern p; + Matcher matcher; + final String[] patterns = { + /* though this looks like Query String, it is also used as part of the Fragment */ + ".*q=([+-]?\\d+(?:\\.\\d+)?),([+-]?\\d+(?:\\.\\d+)?).*&radius=(\\d+).*", + ".*q=([+-]?\\d+(?:\\.\\d+)?),([+-]?\\d+(?:\\.\\d+)?).*", + ".*p=(?:[A-Z0-9]+),([+-]?\\d+(?:\\.\\d+)?),([+-]?\\d+(?:\\.\\d+)?).*", }; + for (int i = 0; i < patterns.length; i++) { + p = Pattern.compile(patterns[i]); + matcher = p.matcher(subString); + if (matcher.matches()) { + if (matcher.groupCount() == 3) { + // amap uses radius in meters, so do rough conversion into zoom level + float radius = Float.valueOf(matcher.group(3)); + long zoom = Math.round(23. - Math.log(radius)/Math.log(2.0)); + return new GeoParsedPoint(matcher.group(1), matcher.group(2), String.valueOf(zoom)); + } else if (matcher.groupCount() == 2) { + return new GeoParsedPoint(matcher.group(1), matcher.group(2)); + } + } + } } } catch (RuntimeException e) { diff --git a/OsmAnd/AndroidManifest.xml b/OsmAnd/AndroidManifest.xml index 513729cf26..ce93a0224a 100644 --- a/OsmAnd/AndroidManifest.xml +++ b/OsmAnd/AndroidManifest.xml @@ -191,6 +191,8 @@ + + From 2771da35deae1bd369d05837730d7fa92b0b9565 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 16 Jan 2015 10:22:52 +0100 Subject: [PATCH 02/13] GeoPointParserUtil.getQueryParameters() to return Map of all parameters This parses out all of the parameters in the query string for both http: and geo: URIs. This will only work on URIs with valid syntax, so it will not work on URIs that do odd things like have a query string in the fragment, like this one: http://www.amap.com/#!poi!!q=38.174596,114.995033|2|%E5%AE%BE%E9%A6%86&radius=1000 --- .../net/osmand/util/GeoPointParserUtil.java | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java index 6c8e9cff02..afcfa340f3 100644 --- a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java +++ b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java @@ -22,6 +22,58 @@ public class GeoPointParserUtil { int z = GeoParsedPoint.NO_ZOOM; String url; + String noQueryParameters[] = { + "geo:0,0", + "geo:0,0?", + "http://download.osmand.net/go", + "http://download.osmand.net/go?", + }; + for (String s: noQueryParameters) { + URI uri = URI.create(s); + Map map = getQueryParameters(uri); + System.out.print(s + " map: " + map.size() + "..."); + if (map.size() != 0) { + System.out.println(""); + throw new RuntimeException("Map should be 0 but is " + map.size()); + } + System.out.println(" Passed!"); + } + + String oneQueryParameter[] = { + "geo:0,0?m", + "geo:0,0?m=", + "geo:0,0?m=foo", + "http://download.osmand.net/go?lat", + "http://download.osmand.net/go?lat=", + "http://download.osmand.net/go?lat=34.99393", + }; + for (String s: oneQueryParameter) { + URI uri = URI.create(s); + Map map = getQueryParameters(uri); + System.out.print(s + " map: " + map.size() + "..."); + if (map.size() != 1) { + System.out.println(""); + throw new RuntimeException("Map should be 1 but is " + map.size()); + } + System.out.println(" Passed!"); + } + + String twoQueryParameters[] = { + "geo:0,0?z=11&q=Lots+Of+Stuff", + "http://download.osmand.net/go?lat=34.99393&lon=-110.12345", + "http://download.osmand.net/go?lat=34.99393&lon=-110.12345#this+should+be+ignored", + }; + for (String s: twoQueryParameters) { + URI uri = URI.create(s); + Map map = getQueryParameters(uri); + System.out.print(s + " map: " + map.size() + "..."); + if (map.size() != 2) { + System.out.println(""); + throw new RuntimeException("Map should be 2 but is " + map.size()); + } + System.out.println(" Passed!"); + } + // geo:34,-106 url = "geo:" + ilat + "," + ilon; System.out.println("url: " + url); @@ -520,6 +572,43 @@ public class GeoPointParserUtil { return value; } + /** + * This parses out all of the parameters in the query string for both + * http: and geo: URIs. This will only work on URIs with valid syntax, so + * it will not work on URIs that do odd things like have a query string in + * the fragment, like this one: + * http://www.amap.com/#!poi!!q=38.174596,114.995033|2|%E5%AE%BE%E9%A6%86&radius=1000 + * + * @param uri + * @return {@link Map} a Map of the query parameters + */ + private static Map getQueryParameters(URI uri) { + final LinkedHashMap map = new LinkedHashMap(); + String query = null; + if (uri.isOpaque()) { + String schemeSpecificPart = uri.getSchemeSpecificPart(); + int pos = schemeSpecificPart.indexOf("?"); + if (pos == schemeSpecificPart.length()) { + query = ""; + } else if (pos > -1) { + query = schemeSpecificPart.substring(pos + 1); + } + } else { + query = uri.getQuery(); + } + if (query != null && !query.equals("")) { + String[] params = query.split("&"); + for (String p : params) { + String[] keyValue = p.split("="); + if (keyValue.length == 1) + map.put(keyValue[0], ""); + else if (keyValue.length > 1) + map.put(keyValue[0], keyValue[1]); + } + } + return map; + } + /** * Parses geo and map intents: * From d34d341d65321f5b60bde1a32ccf720ea699a23e Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 16 Jan 2015 10:22:52 +0100 Subject: [PATCH 03/13] keep Uri "path" intact during parsing for consistant regexes By not modifying "path" from what Uri.getPath() returns, it keeps the pattern matching consistent since the contents of "path" will always be the same as Uri.getPath(), and what is visible in the URI itself. --- .../src/net/osmand/util/GeoPointParserUtil.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java index afcfa340f3..fcce861b66 100644 --- a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java +++ b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java @@ -642,14 +642,16 @@ public class GeoPointParserUtil { String path = uri.getPath(); if (path == null) { path = ""; - } else if (path.startsWith("/")) { - path = path.substring(1); } String fragment = uri.getFragment(); String query = uri.getQuery(); if(query == null) { // DOUBLE check this may be wrong test of openstreetmap.de (looks very weird url and server doesn't respond) - query = path; + if (path.startsWith("/")) { + query = path.substring(1); + } else { + query = path; + } } Map params = new HashMap(); @@ -672,9 +674,9 @@ public class GeoPointParserUtil { if (host.equals("osm.org") || host.endsWith("openstreetmap.org")) { Pattern p; Matcher matcher; - if (path.startsWith("go/")) { // short URL form + if (path.startsWith("/go/")) { // short URL form p = Pattern.compile("^/go/([A-Za-z0-9_@~]+-*)(?:.*)"); - matcher = p.matcher(uri.getPath()); + matcher = p.matcher(path); if (matcher.matches()) { return MapUtils.decodeShortLinkString(matcher.group(1)); } From 9b77f6fa9025067d1919805b4bee6a4903853e0f Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 20 Jan 2015 20:48:28 +0100 Subject: [PATCH 04/13] claim location URLs from Nokia HERE closes https://dev.guardianproject.info/issues/4399 --- .../net/osmand/util/GeoPointParserUtil.java | 53 +++++++++++++++++++ OsmAnd/AndroidManifest.xml | 3 ++ 2 files changed, 56 insertions(+) diff --git a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java index fcce861b66..89b70ee2c6 100644 --- a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java +++ b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java @@ -460,6 +460,26 @@ public class GeoPointParserUtil { actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + // http://share.here.com/l/52.5134272,13.3778416,Hannah-Arendt-Stra%C3%9Fe?z=16.0&t=normal + url = "http://share.here.com/l/" + dlat + "," + dlon + ",Hannah-Arendt-Stra%C3%9Fe?z=" + z + "&t=normal"; + System.out.println("url: " + url); + actual = GeoPointParserUtil.parse(url); + assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + + // https://www.here.com/location?map=52.5134272,13.3778416,16,normal&msg=Hannah-Arendt-Stra%C3%9Fe + z = 16; + url = "https://www.here.com/location?map=" + dlat + "," + dlon + "," + z + ",normal&msg=Hannah-Arendt-Stra%C3%9Fe"; + System.out.println("url: " + url); + actual = GeoPointParserUtil.parse(url); + assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + + // https://www.here.com/?map=48.23145,16.38454,15,normal + z = 16; + url = "https://www.here.com/?map=" + dlat + "," + dlon + "," + z + ",normal"; + 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[] = { @@ -482,6 +502,9 @@ public class GeoPointParserUtil { "http://www.amap.com/#!poi!!q=38.179456,114.98577|3|B013706PJN", "http://www.amap.com/#!poi!!q=38.174596,114.995033|2|%E5%AE%BE%E9%A6%86&radius=1000", "http://www.amap.com/?p=B013704EJT,38.17914,114.976337,%E6%97%A0%E6%9E%81%E5%8E%BF%E4%BA%BA%E6%B0%91%E6%94%BF%E5%BA%9C,%E5%BB%BA%E8%AE%BE%E4%B8%9C%E8%B7%AF12%E5%8F%B7", + "http://share.here.com/l/52.5134272,13.3778416,Hannah-Arendt-Stra%C3%9Fe?z=16.0&t=normal", + "https://www.here.com/location?map=52.5134272,13.3778416,16,normal&msg=Hannah-Arendt-Stra%C3%9Fe", + "https://www.here.com/?map=48.23145,16.38454,15,normal", }; for (String u : urls) { @@ -784,6 +807,31 @@ public class GeoPointParserUtil { } } } + } else if (host.equals("here.com") || host.endsWith(".here.com")) { // www.here.com, share.here.com, here.com + Map queryMap = getQueryParameters(uri); + String z = String.valueOf(GeoParsedPoint.NO_ZOOM); + String label = null; + if (queryMap.containsKey("msg")) { + label = queryMap.get("msg"); + } + if (queryMap.containsKey("z")) { + z = queryMap.get("z"); + } + if (queryMap.containsKey("map")) { + String[] mapArray = queryMap.get("map").split(","); + if (mapArray.length > 2) { + return new GeoParsedPoint(mapArray[0], mapArray[1], mapArray[2], label); + } else if (mapArray.length > 1) { + return new GeoParsedPoint(mapArray[0], mapArray[1], z, label); + } + } + if (path.startsWith("/l/")) { + Pattern p = Pattern.compile("^/l/([+-]?\\d+(?:\\.\\d+)),([+-]?\\d+(?:\\.\\d+)),(.*)"); + Matcher matcher = p.matcher(path); + if (matcher.matches()) { + return new GeoParsedPoint(matcher.group(1), matcher.group(2), z, matcher.group(3)); + } + } } } catch (RuntimeException e) { @@ -986,6 +1034,11 @@ public class GeoPointParserUtil { this.zoom = zoom; } + public GeoParsedPoint(String latString, String lonString, String zoomString, String label) throws NumberFormatException { + this(latString, lonString, zoomString); + this.label = label; + } + public GeoParsedPoint(String latString, String lonString, String zoomString) throws NumberFormatException { this(Double.valueOf(latString), Double.valueOf(lonString)); this.zoom = parseZoom(zoomString); diff --git a/OsmAnd/AndroidManifest.xml b/OsmAnd/AndroidManifest.xml index ce93a0224a..ebf06daa71 100644 --- a/OsmAnd/AndroidManifest.xml +++ b/OsmAnd/AndroidManifest.xml @@ -193,6 +193,9 @@ + + + From 4e5fa43f9822e807a3e00d4f9d2cd78bab59ce48 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 20 Jan 2015 22:09:27 +0100 Subject: [PATCH 05/13] claim location URLs from QQ Map by Tencent closes https://dev.guardianproject.info/issues/4394 --- .../net/osmand/util/GeoPointParserUtil.java | 75 ++++++++++++++++++- OsmAnd/AndroidManifest.xml | 2 + 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java index 89b70ee2c6..60d606e71b 100644 --- a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java +++ b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java @@ -480,6 +480,20 @@ public class GeoPointParserUtil { actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + // http://map.wap.qq.com/loc/detail.jsp?sid=AU8f3ck87L6XDmytunBm4iWg&g_ut=2&city=%E5%8C%97%E4%BA%AC&key=NOBU%20Beijing&x=116.48177&y=39.91082&md=10461366113386140862 + z = GeoParsedPoint.NO_ZOOM; + url = "http://map.wap.qq.com/loc/detail.jsp?sid=AU8f3ck87L6XDmytunBm4iWg&g_ut=2&city=%E5%8C%97%E4%BA%AC&key=NOBU%20Beijing&x=" + dlon + "&y=" + dlat + "&md=10461366113386140862"; + System.out.println("url: " + url); + actual = GeoPointParserUtil.parse(url); + assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + + // http://map.qq.com/AppBox/print/?t=&c=%7B%22base%22%3A%7B%22l%22%3A11%2C%22lat%22%3A39.90403%2C%22lng%22%3A116.407526%7D%7D + z = 11; + url = "http://map.qq.com/AppBox/print/?t=&c=%7B%22base%22%3A%7B%22l%22%3A11%2C%22lat%22%3A" + dlat + "%2C%22lng%22%3A" + dlon + "%7D%7D"; + 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[] = { @@ -505,6 +519,10 @@ public class GeoPointParserUtil { "http://share.here.com/l/52.5134272,13.3778416,Hannah-Arendt-Stra%C3%9Fe?z=16.0&t=normal", "https://www.here.com/location?map=52.5134272,13.3778416,16,normal&msg=Hannah-Arendt-Stra%C3%9Fe", "https://www.here.com/?map=48.23145,16.38454,15,normal", + "http://map.wap.qq.com/loc/detail.jsp?sid=AU8f3ck87L6XDmytunBm4iWg&g_ut=2&city=%E5%8C%97%E4%BA%AC&key=NOBU%20Beijing&x=116.48177&y=39.91082&md=10461366113386140862", + "http://map.wap.qq.com/loc/d.jsp?c=113.275020,39.188380&m=113.275020,39.188380&n=%E9%BC%93%E6%A5%BC&a=%E5%B1%B1%E8%A5%BF%E7%9C%81%E5%BF%BB%E5%B7%9E%E5%B8%82%E7%B9%81%E5%B3%99%E5%8E%BF+&p=+&i=16959367104973338386&z=0", + "http://map.wap.qq.com/loc/d.jsp?c=113.275020,39.188380&m=113.275020,39.188380&n=%E9%BC%93%E6%A5%BC&a=%E5%B1%B1%E8%A5%BF%E7%9C%81%E5%BF%BB%E5%B7%9E%E5%B8%82%E7%B9%81%E5%B3%99%E5%8E%BF+&p=+&i=16959367104973338386&z=0&m", + "http://map.qq.com/AppBox/print/?t=&c=%7B%22base%22%3A%7B%22l%22%3A11%2C%22lat%22%3A39.90403%2C%22lng%22%3A116.407526%7D%7D", }; for (String u : urls) { @@ -545,7 +563,7 @@ public class GeoPointParserUtil { throw new RuntimeException("Zoom is not equal; actual=" + aZoom + ", expected=" + eZoom); } } - System.out.println("Passed!"); + System.out.println("Passed: " + actual); } private static void assertApproximateGeoPoint(GeoParsedPoint actual, GeoParsedPoint expected) { @@ -693,6 +711,8 @@ public class GeoPointParserUtil { simpleDomains.add("www.openstreetmap.de"); + final Pattern commaSeparatedPairPattern = Pattern.compile("([+-]?\\d+(?:\\.\\d+)?),([+-]?\\d+(?:\\.\\d+)?)"); + try { if (host.equals("osm.org") || host.endsWith("openstreetmap.org")) { Pattern p; @@ -832,6 +852,59 @@ public class GeoPointParserUtil { return new GeoParsedPoint(matcher.group(1), matcher.group(2), z, matcher.group(3)); } } + } else if (host.endsWith(".qq.com")) { + Map queryMap = getQueryParameters(uri); + String x = null; + String y = null; + String z = String.valueOf(GeoParsedPoint.NO_ZOOM); + String label = null; + if (queryMap.containsKey("city")) { + label = queryMap.get("city"); + } else if (queryMap.containsKey("key")) { + label = queryMap.get("key"); + } else if (queryMap.containsKey("a")) { + label = queryMap.get("a"); + } else if (queryMap.containsKey("n")) { + label = queryMap.get("n"); + } + String m = queryMap.get("m"); + if (m != null) { + Matcher matcher = commaSeparatedPairPattern.matcher(m); + if (matcher.matches()) { + x = matcher.group(2); + y = matcher.group(1); + } + } + String c = queryMap.get("c"); + if (c != null) { + // there are two different patterns of data that can be in ?c= + Matcher matcher = commaSeparatedPairPattern.matcher(c); + if (matcher.matches()) { + x = matcher.group(2); + y = matcher.group(1); + } else { + x = c.replaceAll(".*\"lng\":\\s*([+\\-]?[0-9.]+).*", "$1"); + if (x == null) // try 'lon' for the second time + x = c.replaceAll(".*\"lon\":\\s*([+\\-]?[0-9.]+).*", "$1"); + y = c.replaceAll(".*\"lat\":\\s*([+\\-]?[0-9.]+).*", "$1"); + z = c.replaceAll(".*\"l\":\\s*([+-]?[0-9.]+).*", "$1"); + return new GeoParsedPoint(y, x, z, label); + } + } + for (String key : new String[]{"centerX", "x", "x1", "x2"}) { + if (queryMap.containsKey(key)) { + x = queryMap.get(key); + break; + } + } + for (String key : new String[]{"centerY", "y", "y1", "y2"}) { + if (queryMap.containsKey(key)) { + y = queryMap.get(key); + break; + } + } + if (x != null && y != null) + return new GeoParsedPoint(y, x, z, label); } } catch (RuntimeException e) { diff --git a/OsmAnd/AndroidManifest.xml b/OsmAnd/AndroidManifest.xml index ebf06daa71..a6e38725fb 100644 --- a/OsmAnd/AndroidManifest.xml +++ b/OsmAnd/AndroidManifest.xml @@ -196,6 +196,8 @@ + + From 90c1b8a8e07a9fd7e6f279feed40819e9e88ecda Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 2 Feb 2015 21:37:45 +0100 Subject: [PATCH 06/13] only parse query string if it is used Not all location URLs have useful information in the query string, so only parse it if it is used in the section for a given hostname. Also, rename queryMap to params for consistency. --- .../net/osmand/util/GeoPointParserUtil.java | 89 +++++++++---------- 1 file changed, 44 insertions(+), 45 deletions(-) diff --git a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java index 60d606e71b..78e647a510 100644 --- a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java +++ b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java @@ -624,7 +624,6 @@ public class GeoPointParserUtil { * @return {@link Map} a Map of the query parameters */ private static Map getQueryParameters(URI uri) { - final LinkedHashMap map = new LinkedHashMap(); String query = null; if (uri.isOpaque()) { String schemeSpecificPart = uri.getSchemeSpecificPart(); @@ -637,6 +636,11 @@ public class GeoPointParserUtil { } else { query = uri.getQuery(); } + return getQueryParameters(query); + } + + private static Map getQueryParameters(String query) { + final LinkedHashMap map = new LinkedHashMap(); if (query != null && !query.equals("")) { String[] params = query.split("&"); for (String p : params) { @@ -685,23 +689,7 @@ public class GeoPointParserUtil { path = ""; } String fragment = uri.getFragment(); - String query = uri.getQuery(); - if(query == null) { - // DOUBLE check this may be wrong test of openstreetmap.de (looks very weird url and server doesn't respond) - if (path.startsWith("/")) { - query = path.substring(1); - } else { - query = path; - } - } - - Map params = new HashMap(); - for(String vl : query.split("&")) { - int i = vl.indexOf('='); - if(i > 0) { - params.put(vl.substring(0, i), vl.substring(i + 1)); - } - } + // lat-double, lon - double, zoom or z - int Set simpleDomains = new HashSet(); simpleDomains.add("osmand.net"); @@ -738,17 +726,21 @@ public class GeoPointParserUtil { lon = parseSilentDouble(vls[2]); } } - // the query string sometimes has higher resolution - // values - if(params.containsKey("mlat") && params.containsKey("mlon")) { - lat = parseSilentDouble(params.get("mlat")); - lon = parseSilentDouble(params.get("mlon")); + // the query string sometimes has higher resolution values + String mlat = getQueryParameter("mlat", uri); + if(mlat != null) { + lat = parseSilentDouble(mlat); + } + String mlon = getQueryParameter("mlon", uri); + if(mlon != null) { + lon = parseSilentDouble(mlon); } return new GeoParsedPoint(lat, lon, zoom); } } else if (host.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 */ + Map params = getQueryParameters(uri); String zm = params.get("l"); String[] vls = silentSplit(params.get("c"),","); if ( vls != null && vls.length >= 2) { @@ -758,6 +750,11 @@ public class GeoPointParserUtil { return new GeoParsedPoint(lat, lon, zoom); } } else if (simpleDomains.contains(host)) { + Map params = getQueryParameters(uri); + if(uri.getQuery() == null && params.size() == 0) { + // DOUBLE check this may be wrong test of openstreetmap.de (looks very weird url and server doesn't respond) + params = getQueryParameters(path.substring(1)); + } if (params.containsKey("lat") && params.containsKey("lon")) { final double lat = parseSilentDouble(params.get("lat")); final double lon = parseSilentDouble(params.get("lon")); @@ -772,6 +769,7 @@ public class GeoPointParserUtil { } else if (host.equals("maps.yandex.ru") || host.equals("yandex.ru") || host.equals("www.yandex.ru")) { + Map params = getQueryParameters(uri); String zm = params.get("z"); String[] vls = silentSplit(params.get("ll"),","); if ( vls != null && vls.length >= 2) { @@ -784,6 +782,7 @@ public class GeoPointParserUtil { } else if (host.equals("maps.google.com") || host.equals("google.com") || host.equals("www.google.com")) { + Map params = getQueryParameters(uri); if(params.containsKey("daddr")){ return parseGoogleMapsPath(params.get("daddr"), params); } else if(params.containsKey("saddr")){ @@ -828,17 +827,17 @@ public class GeoPointParserUtil { } } } else if (host.equals("here.com") || host.endsWith(".here.com")) { // www.here.com, share.here.com, here.com - Map queryMap = getQueryParameters(uri); + Map params = getQueryParameters(uri); String z = String.valueOf(GeoParsedPoint.NO_ZOOM); String label = null; - if (queryMap.containsKey("msg")) { - label = queryMap.get("msg"); + if (params.containsKey("msg")) { + label = params.get("msg"); } - if (queryMap.containsKey("z")) { - z = queryMap.get("z"); + if (params.containsKey("z")) { + z = params.get("z"); } - if (queryMap.containsKey("map")) { - String[] mapArray = queryMap.get("map").split(","); + if (params.containsKey("map")) { + String[] mapArray = params.get("map").split(","); if (mapArray.length > 2) { return new GeoParsedPoint(mapArray[0], mapArray[1], mapArray[2], label); } else if (mapArray.length > 1) { @@ -853,21 +852,21 @@ public class GeoPointParserUtil { } } } else if (host.endsWith(".qq.com")) { - Map queryMap = getQueryParameters(uri); + Map params = getQueryParameters(uri); String x = null; String y = null; String z = String.valueOf(GeoParsedPoint.NO_ZOOM); String label = null; - if (queryMap.containsKey("city")) { - label = queryMap.get("city"); - } else if (queryMap.containsKey("key")) { - label = queryMap.get("key"); - } else if (queryMap.containsKey("a")) { - label = queryMap.get("a"); - } else if (queryMap.containsKey("n")) { - label = queryMap.get("n"); + if (params.containsKey("city")) { + label = params.get("city"); + } else if (params.containsKey("key")) { + label = params.get("key"); + } else if (params.containsKey("a")) { + label = params.get("a"); + } else if (params.containsKey("n")) { + label = params.get("n"); } - String m = queryMap.get("m"); + String m = params.get("m"); if (m != null) { Matcher matcher = commaSeparatedPairPattern.matcher(m); if (matcher.matches()) { @@ -875,7 +874,7 @@ public class GeoPointParserUtil { y = matcher.group(1); } } - String c = queryMap.get("c"); + String c = params.get("c"); if (c != null) { // there are two different patterns of data that can be in ?c= Matcher matcher = commaSeparatedPairPattern.matcher(c); @@ -892,14 +891,14 @@ public class GeoPointParserUtil { } } for (String key : new String[]{"centerX", "x", "x1", "x2"}) { - if (queryMap.containsKey(key)) { - x = queryMap.get(key); + if (params.containsKey(key)) { + x = params.get(key); break; } } for (String key : new String[]{"centerY", "y", "y1", "y2"}) { - if (queryMap.containsKey(key)) { - y = queryMap.get(key); + if (params.containsKey(key)) { + y = params.get(key); break; } } From 897d6ba387628337f3ee3bb983c358906553fe9f Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 2 Feb 2015 21:39:53 +0100 Subject: [PATCH 07/13] only output coords from Yandex URL if the full ll= string matches This just makes sure that there is a full lat/lon match before outputing. --- .../src/net/osmand/util/GeoPointParserUtil.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java index 78e647a510..48d7e2e4b3 100644 --- a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java +++ b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java @@ -770,15 +770,14 @@ public class GeoPointParserUtil { || host.equals("yandex.ru") || host.equals("www.yandex.ru")) { Map params = getQueryParameters(uri); - String zm = params.get("z"); - String[] vls = silentSplit(params.get("ll"),","); - if ( vls != null && vls.length >= 2) { - double lat = parseSilentDouble(vls[0]); - double lon = parseSilentDouble(vls[1]) ; - int zoom = parseZoom(zm); - return new GeoParsedPoint(lat, lon, zoom); - } - + String ll = params.get("ll"); + if (ll != null) { + Matcher matcher = commaSeparatedPairPattern.matcher(ll); + if (matcher.matches()) { + String z = String.valueOf(parseZoom(params.get("z"))); + return new GeoParsedPoint(matcher.group(1), matcher.group(2), z); + } + } } else if (host.equals("maps.google.com") || host.equals("google.com") || host.equals("www.google.com")) { From 59c34b350ad2dd6b8d92eb6ff65ca91c287f1daf Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 2 Feb 2015 21:56:52 +0100 Subject: [PATCH 08/13] improve Yandex link parsing * also handle maps.yandex.com URLs * properly handle unparsable short links (i.e. don't crash or return results) * include text= as Label --- .../net/osmand/util/GeoPointParserUtil.java | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java index 48d7e2e4b3..0edc5dee53 100644 --- a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java +++ b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java @@ -523,14 +523,30 @@ public class GeoPointParserUtil { "http://map.wap.qq.com/loc/d.jsp?c=113.275020,39.188380&m=113.275020,39.188380&n=%E9%BC%93%E6%A5%BC&a=%E5%B1%B1%E8%A5%BF%E7%9C%81%E5%BF%BB%E5%B7%9E%E5%B8%82%E7%B9%81%E5%B3%99%E5%8E%BF+&p=+&i=16959367104973338386&z=0", "http://map.wap.qq.com/loc/d.jsp?c=113.275020,39.188380&m=113.275020,39.188380&n=%E9%BC%93%E6%A5%BC&a=%E5%B1%B1%E8%A5%BF%E7%9C%81%E5%BF%BB%E5%B7%9E%E5%B8%82%E7%B9%81%E5%B3%99%E5%8E%BF+&p=+&i=16959367104973338386&z=0&m", "http://map.qq.com/AppBox/print/?t=&c=%7B%22base%22%3A%7B%22l%22%3A11%2C%22lat%22%3A39.90403%2C%22lng%22%3A116.407526%7D%7D", + "http://maps.yandex.com/?text=Australia%2C%20Victoria%2C%20Christmas%20Hills&sll=145.319026%2C-37.650344&ll=145.319026%2C-37.650344&spn=0.352249%2C0.151501&z=12&l=map", }; - for (String u : urls) { - System.out.println("url: " + u); - actual = GeoPointParserUtil.parse(u); - assert(actual != null); - System.out.println("Properly parsed!"); - } + for (String u : urls) { + System.out.println("url: " + u); + actual = GeoPointParserUtil.parse(u); + if (actual == null) + throw new RuntimeException(u + " not parsable!"); + System.out.println("Properly parsed as: " + actual); + } + + // these URLs are not parsable, but should not crash or cause problems + String[] unparsableUrls = { + "http://maps.yandex.ru/-/CVCw6M9g", + "http://maps.yandex.com/-/CVCXEKYW", + }; + + for (String u : unparsableUrls) { + System.out.println("url: " + u); + actual = GeoPointParserUtil.parse(u); + if (actual != null) + throw new RuntimeException(u + " not parsable, but parse did not return null!"); + System.out.println("Handled URL"); + } } private static boolean areCloseEnough(double a, double b, long howClose) { @@ -766,16 +782,14 @@ public class GeoPointParserUtil { } return new GeoParsedPoint(lat, lon, zoom); } - } else if (host.equals("maps.yandex.ru") - || host.equals("yandex.ru") - || host.equals("www.yandex.ru")) { + } else if (host.matches("(?:www\\.)?(?:maps\\.)?yandex\\.[a-z]+")) { Map params = getQueryParameters(uri); String ll = params.get("ll"); if (ll != null) { Matcher matcher = commaSeparatedPairPattern.matcher(ll); if (matcher.matches()) { String z = String.valueOf(parseZoom(params.get("z"))); - return new GeoParsedPoint(matcher.group(1), matcher.group(2), z); + return new GeoParsedPoint(matcher.group(1), matcher.group(2), z, params.get("text")); } } } else if (host.equals("maps.google.com") From 1c4ad908da9d5a807cb498347147be0436a79eb5 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 2 Feb 2015 22:03:38 +0100 Subject: [PATCH 09/13] handle all Google country-specific domains, i.e. google.at, google.ru, etc. https://en.wikipedia.org/wiki/List_of_Google_domains --- OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java index 0edc5dee53..1804ca477c 100644 --- a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java +++ b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java @@ -511,6 +511,7 @@ public class GeoPointParserUtil { "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", + "https://www.google.at/maps/place/Bargou,+Tunesien/@36.0922506,9.5676327,15z/data=!3m1!4b1!4m2!3m1!1s0x12fc5d0b4dc5e66f:0xbd3618c6193d14cd", "http://www.amap.com/#!poi!!q=38.174596,114.995033,%E6%B2%B3%E5%8C%97%E7%9C%81%E7%9F%B3%E5%AE%B6%E5%BA%84%E5%B8%82%E6%97%A0%E6%9E%81%E5%8E%BF", "http://wb.amap.com/?p=B013706PJN,38.179456,114.98577,%E6%96%B0%E4%B8%9C%E6%96%B9%E5%A4%A7%E9%85%92%E5%BA%97(%E4%BF%9D%E9%99%A9%E8%8A%B1...,%E5%BB%BA%E8%AE%BE%E8%B7%AF67%E5%8F%B7", "http://www.amap.com/#!poi!!q=38.179456,114.98577|3|B013706PJN", @@ -792,9 +793,7 @@ public class GeoPointParserUtil { return new GeoParsedPoint(matcher.group(1), matcher.group(2), z, params.get("text")); } } - } else if (host.equals("maps.google.com") - || host.equals("google.com") - || host.equals("www.google.com")) { + } else if (host.matches("(?:www\\.)?(?:maps\\.)?google\\.[a-z]+")) { Map params = getQueryParameters(uri); if(params.containsKey("daddr")){ return parseGoogleMapsPath(params.get("daddr"), params); From 7cb58ec54073831fb72d2aec12e8db38ecedf0ac Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 13 Jan 2015 19:37:28 +0100 Subject: [PATCH 10/13] also parse maps.apple.com links, the query string includes lat/long/zoom/etc https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/MapLinks/MapLinks.html --- .../net/osmand/util/GeoPointParserUtil.java | 53 ++++++++++++++++++- OsmAnd/AndroidManifest.xml | 1 + 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java index 1804ca477c..56e4313d3c 100644 --- a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java +++ b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java @@ -494,6 +494,15 @@ public class GeoPointParserUtil { actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + // https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/MapLinks/MapLinks.html + + // http://maps.apple.com/?ll= + z = 11; + url = "http://maps.apple.com/?ll=" + dlat + "," + dlon + "&z=" + z; + System.out.println("\nurl: " + url); + actual = GeoPointParserUtil.parse(url); + assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + /* URLs straight from various services, instead of generated here */ String urls[] = { @@ -525,6 +534,8 @@ public class GeoPointParserUtil { "http://map.wap.qq.com/loc/d.jsp?c=113.275020,39.188380&m=113.275020,39.188380&n=%E9%BC%93%E6%A5%BC&a=%E5%B1%B1%E8%A5%BF%E7%9C%81%E5%BF%BB%E5%B7%9E%E5%B8%82%E7%B9%81%E5%B3%99%E5%8E%BF+&p=+&i=16959367104973338386&z=0&m", "http://map.qq.com/AppBox/print/?t=&c=%7B%22base%22%3A%7B%22l%22%3A11%2C%22lat%22%3A39.90403%2C%22lng%22%3A116.407526%7D%7D", "http://maps.yandex.com/?text=Australia%2C%20Victoria%2C%20Christmas%20Hills&sll=145.319026%2C-37.650344&ll=145.319026%2C-37.650344&spn=0.352249%2C0.151501&z=12&l=map", + "http://maps.apple.com/?q=Bargou,+Tunisien", + "http://maps.apple.com/?daddr=Bargou,+Tunisien", }; for (String u : urls) { @@ -532,7 +543,7 @@ public class GeoPointParserUtil { actual = GeoPointParserUtil.parse(u); if (actual == null) throw new RuntimeException(u + " not parsable!"); - System.out.println("Properly parsed as: " + actual); + System.out.println("Properly parsed as: " + actual.getGeoUriString()); } // these URLs are not parsable, but should not crash or cause problems @@ -916,6 +927,46 @@ public class GeoPointParserUtil { } if (x != null && y != null) return new GeoParsedPoint(y, x, z, label); + } else if (host.equals("maps.apple.com")) { + // https://developer.apple.com/library/iad/featuredarticles/iPhoneURLScheme_Reference/MapLinks/MapLinks.html + Map params = getQueryParameters(uri); + String z = String.valueOf(GeoParsedPoint.NO_ZOOM); + String label = null; + if (params.containsKey("q")) { + label = params.get("q"); + } + if (params.containsKey("near")) { + label = params.get("near"); + } + if (params.containsKey("z")) { + z = params.get("z"); + } + String ll = params.get("ll"); + if (ll != null) { + Matcher matcher = commaSeparatedPairPattern.matcher(ll); + if (matcher.matches()) { + return new GeoParsedPoint(matcher.group(1), matcher.group(2), z, label); + } + } + String sll = params.get("sll"); + if (sll != null) { + Matcher matcher = commaSeparatedPairPattern.matcher(sll); + if (matcher.matches()) { + return new GeoParsedPoint(matcher.group(1), matcher.group(2), z, label); + } + } + // if no ll= or sll=, then just use the q string + if (params.containsKey("q")) { + return new GeoParsedPoint(params.get("q")); + } + // if no q=, then just use the destination address + if (params.containsKey("daddr")) { + return new GeoParsedPoint(params.get("daddr")); + } + // if no daddr=, then just use the source address + if (params.containsKey("saddr")) { + return new GeoParsedPoint(params.get("saddr")); + } } } catch (RuntimeException e) { diff --git a/OsmAnd/AndroidManifest.xml b/OsmAnd/AndroidManifest.xml index a6e38725fb..d1d9c92c6a 100644 --- a/OsmAnd/AndroidManifest.xml +++ b/OsmAnd/AndroidManifest.xml @@ -198,6 +198,7 @@ + From 124d48cd6ee7f05358e4ebbb7c56170b803fead6 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 2 Feb 2015 22:33:54 +0100 Subject: [PATCH 11/13] add various unparsable short links as tests --- OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java index 56e4313d3c..73bc6d29c9 100644 --- a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java +++ b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java @@ -550,6 +550,12 @@ public class GeoPointParserUtil { String[] unparsableUrls = { "http://maps.yandex.ru/-/CVCw6M9g", "http://maps.yandex.com/-/CVCXEKYW", + "http://goo.gl/maps/Cji0V", + "http://amap.com/0F0i02", + "http://j.map.baidu.com/oXrVz", + "http://l.map.qq.com/9741483212?m", + "http://map.qq.com/?l=261496722", + "http://her.is/vLCEXE", }; for (String u : unparsableUrls) { From 34ecdafc5d0698f1551ced5f67516a350e90e44f Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 3 Feb 2015 00:28:45 +0100 Subject: [PATCH 12/13] GeoParsedPoint normalize query string format as plain, not URL-encoded There were parts of this code that were sticking in a URL-encoded query string into GeoParsedPoint, and other parts that were putting in a regular non-URL-encoded String. This meant that URLs with an & in the query string encoded as %26 were not being properly parsed, since & is used to split up the query string. That also makes it impossible to output a properly encoded URI from getGeoUriString(). --- .../net/osmand/util/GeoPointParserUtil.java | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java index 73bc6d29c9..9ff98d3ede 100644 --- a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java +++ b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java @@ -397,29 +397,29 @@ public class GeoPointParserUtil { 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; + qstr = "760 West Genesee Street Syracuse NY 13204"; + url = "http://www.google.com/maps/place/" + URLEncoder.encode(qstr); System.out.println("url: " + 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; + qstr = "760 West Genesee Street Syracuse NY 13204"; + url = "http://www.google.com/maps?q=" + URLEncoder.encode(qstr); System.out.println("url: " + 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; + qstr = "760 West Genesee Street Syracuse NY 13204"; + url = "http://www.google.com/maps?daddr=" + URLEncoder.encode(qstr); System.out.println("url: " + 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; + qstr = "760 West Genesee Street Syracuse NY 13204"; + url = "http://www.google.com/maps/dir/Current+Location/" + URLEncoder.encode(qstr); System.out.println("url: " + url); actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(qstr)); @@ -536,6 +536,8 @@ public class GeoPointParserUtil { "http://maps.yandex.com/?text=Australia%2C%20Victoria%2C%20Christmas%20Hills&sll=145.319026%2C-37.650344&ll=145.319026%2C-37.650344&spn=0.352249%2C0.151501&z=12&l=map", "http://maps.apple.com/?q=Bargou,+Tunisien", "http://maps.apple.com/?daddr=Bargou,+Tunisien", + "http://maps.apple.com/?lsp=7618&q=40.738065,-73.988898&sll=40.738065,-73.988898", + "http://maps.apple.com/?lsp=9902&auid=13787349062281695774&sll=40.694576,-73.982992&q=Garden%20Nail%20%26%20Spa&hnear=325%20Gold%20St%2C%20Brooklyn%2C%20NY%20%2011201-3054%2C%20United%20States", }; for (String u : urls) { @@ -576,7 +578,8 @@ public class GeoPointParserUtil { private static void assertGeoPoint(GeoParsedPoint actual, GeoParsedPoint expected) { if (expected.getQuery() != null) { if (!expected.getQuery().equals(actual.getQuery())) - throw new RuntimeException("Query param not equal"); + throw new RuntimeException("Query param not equal:\n'" + + actual.getQuery() + "' != '" + expected.getQuery()); } else { double aLat = actual.getLatitude(), eLat = expected.getLatitude(), aLon = actual.getLongitude(), eLon = expected.getLongitude(); int aZoom = actual.getZoom(), eZoom = expected.getZoom(); @@ -668,7 +671,7 @@ public class GeoPointParserUtil { query = schemeSpecificPart.substring(pos + 1); } } else { - query = uri.getQuery(); + query = uri.getRawQuery(); } return getQueryParameters(query); } @@ -682,7 +685,7 @@ public class GeoPointParserUtil { if (keyValue.length == 1) map.put(keyValue[0], ""); else if (keyValue.length > 1) - map.put(keyValue[0], keyValue[1]); + map.put(keyValue[0], URLDecoder.decode(keyValue[1])); } } return map; @@ -1101,7 +1104,7 @@ public class GeoPointParserUtil { } return new GeoParsedPoint(lat, lon, zoom); } - return new GeoParsedPoint(opath); + return new GeoParsedPoint(URLDecoder.decode(opath)); } private static String[] silentSplit(String vl, String split) { @@ -1190,6 +1193,9 @@ public class GeoPointParserUtil { this.zoom = NO_ZOOM; } + /** + * Accepts a plain {@code String}, not URL-encoded + */ public GeoParsedPoint(String query) { super(); this.query = query; From 859595267e51ddd9b1c0b8d9e85de3d9f29450d5 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 2 Feb 2015 22:57:38 +0100 Subject: [PATCH 13/13] add more kinds of Google URLs for testing This includes some valid Google Maps links that cause problems with the new `parseGoogleMapsPath()` method. --- .../src/net/osmand/util/GeoPointParserUtil.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java index 9ff98d3ede..0a04e42028 100644 --- a/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java +++ b/OsmAnd-java/src/net/osmand/util/GeoPointParserUtil.java @@ -326,6 +326,18 @@ public class GeoPointParserUtil { actual = GeoPointParserUtil.parse(url); assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + // http://www.google.com/maps/?q=loc:34,-106&z=11 + url = "http://www.google.com/maps/?q=loc:" + ilat + "," + ilon + "&z=" + z; + System.out.println("url: " + url); + actual = GeoPointParserUtil.parse(url); + assertGeoPoint(actual, new GeoParsedPoint(ilat, ilon, z)); + + // http://www.google.com/maps/?q=loc:34.99393,-106.61568&z=11 + url = "http://www.google.com/maps/?q=loc:" + dlat + "," + dlon + "&z=" + z; + System.out.println("url: " + url); + actual = GeoPointParserUtil.parse(url); + assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z)); + // whatsapp // http://maps.google.com/maps/q=loc:34,-106 (You) z = GeoParsedPoint.NO_ZOOM; @@ -538,6 +550,9 @@ public class GeoPointParserUtil { "http://maps.apple.com/?daddr=Bargou,+Tunisien", "http://maps.apple.com/?lsp=7618&q=40.738065,-73.988898&sll=40.738065,-73.988898", "http://maps.apple.com/?lsp=9902&auid=13787349062281695774&sll=40.694576,-73.982992&q=Garden%20Nail%20%26%20Spa&hnear=325%20Gold%20St%2C%20Brooklyn%2C%20NY%20%2011201-3054%2C%20United%20States", + "https://www.google.com/maps/place/Wild+Herb+Market/@33.32787,-105.66291,14z/data=!4m5!1m2!2m1!1sfood!3m1!1s0x86e1ce2079e1f94b:0x1d7460465dcaf3ed", + "http://www.google.com/maps/search/food/@34,-106,14z", + "http://www.google.com/maps/search/food/@34.99393,-106.61568,14z", }; for (String u : urls) {