diff options
author | blafoo <github@blafoo.de> | 2012-02-17 23:24:13 +0100 |
---|---|---|
committer | blafoo <github@blafoo.de> | 2012-02-23 23:19:49 +0100 |
commit | 98f3bd4d23f9a095f34b5b18cd08273e601f3981 (patch) | |
tree | 2ad830c5d28f974b2636c897f0642b8dc2711d72 | |
parent | 039e877c27688ae67da949480df66108dac7c4c6 (diff) | |
download | cgeo-98f3bd4d23f9a095f34b5b18cd08273e601f3981.zip cgeo-98f3bd4d23f9a095f34b5b18cd08273e601f3981.tar.gz cgeo-98f3bd4d23f9a095f34b5b18cd08273e601f3981.tar.bz2 |
JSON (new format) parsing
-rw-r--r-- | main/src/cgeo/geocaching/SearchResult.java | 5 | ||||
-rw-r--r-- | main/src/cgeo/geocaching/cgBase.java | 20 | ||||
-rw-r--r-- | main/src/cgeo/geocaching/connector/GCConnectorImpl.java | 195 | ||||
-rw-r--r-- | main/src/cgeo/geocaching/enumerations/CacheType.java | 2 | ||||
-rw-r--r-- | tests/src/cgeo/geocaching/connector/GCConnectorTest.java | 20 |
5 files changed, 239 insertions, 3 deletions
diff --git a/main/src/cgeo/geocaching/SearchResult.java b/main/src/cgeo/geocaching/SearchResult.java index 25738ef..74602d4 100644 --- a/main/src/cgeo/geocaching/SearchResult.java +++ b/main/src/cgeo/geocaching/SearchResult.java @@ -178,6 +178,11 @@ public class SearchResult implements Parcelable { return geocodes.add(geocode); } + /** Add the geocodes to the search. No caches are loaded into the CacheCache */ + public boolean addGeocodes(Set<String> geocodes) { + return this.geocodes.addAll(geocodes); + } + /** Add the cache geocode to the search and store the cache in the CacheCache */ public boolean addCache(final cgCache cache) { addGeocode(cache.getGeocode()); diff --git a/main/src/cgeo/geocaching/cgBase.java b/main/src/cgeo/geocaching/cgBase.java index c88739c..5481da6 100644 --- a/main/src/cgeo/geocaching/cgBase.java +++ b/main/src/cgeo/geocaching/cgBase.java @@ -686,6 +686,8 @@ public class cgBase { return searchResult; } + // TODO Valentine Remove with merge + @Deprecated public static SearchResult parseMapJSON(final String uri, final String data) { if (StringUtils.isEmpty(data)) { Log.e(Settings.tag, "cgeoBase.parseMapJSON: No page given"); @@ -1869,6 +1871,8 @@ public class cgBase { return searchByAny(thread, cacheType, false, listId, showCaptcha, params); } + // TODO Valentine Remove with merge + @Deprecated public static SearchResult searchByViewport(final String userToken, final Viewport viewport) { String page = null; @@ -1896,8 +1900,18 @@ public class cgBase { return search; } - private static String requestJSONgc(final String uri, final String params) { - String page; + public static String requestJSON(final String url, final String referer) { + final HttpGet request = new HttpGet(url); + request.addHeader("Content-Type", "application/json; charset=UTF-8"); + request.addHeader("X-Requested-With", "XMLHttpRequest"); + request.addHeader("Accept", "application/json, text/javascript, */*; q=0.01"); + request.addHeader("Referer", referer); + return getResponseData(request(request)); + } + + // TODO Valentine Remove with merge + @Deprecated + public static String requestJSONgc(final String uri, final String params) { final HttpPost request = new HttpPost("http://www.geocaching.com/map/default.aspx/MapAction"); try { request.setEntity(new StringEntity(params, HTTP.UTF_8)); @@ -1909,7 +1923,7 @@ public class cgBase { request.addHeader("X-Requested-With", "XMLHttpRequest"); request.addHeader("Accept", "application/json, text/javascript, */*; q=0.01"); request.addHeader("Referer", uri); - page = getResponseData(request(request)); + String page = getResponseData(request(request)); return page; } diff --git a/main/src/cgeo/geocaching/connector/GCConnectorImpl.java b/main/src/cgeo/geocaching/connector/GCConnectorImpl.java new file mode 100644 index 0000000..439ff7a --- /dev/null +++ b/main/src/cgeo/geocaching/connector/GCConnectorImpl.java @@ -0,0 +1,195 @@ +package cgeo.geocaching.connector; + +import cgeo.geocaching.SearchResult; +import cgeo.geocaching.Settings; +import cgeo.geocaching.StoredList; +import cgeo.geocaching.cgBase; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.enumerations.CacheType; +import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.geopoint.Viewport; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author blafoo + * + */ +public class GCConnectorImpl { + + // TODO Valentine remove before merge + /** go online or use mocked data ? */ + public static final boolean IS_ONLINE = false; + + + // TODO Valentine move to connector before merge + @SuppressWarnings("null") + public static SearchResult searchByViewport(final Viewport viewport) { + + final SearchResult searchResult = new SearchResult(); + + List<ImmutablePair<Integer, Integer>> tiles = getTilesForViewport(viewport); + // TODO Valentine Use the coords from the viewport for the referer + final String referer = "http://www.geocaching.com/map/default.aspx?ll=52.4162,9.59412"; + for (ImmutablePair<Integer, Integer> tile : tiles) { + /* + * http://www.geocaching.com/map/ --- map-url + * map.info? --- request for JSON + * x=8634 --- x-tile + * y=5381 --- y-tile + * z=14 --- zoom + * _=1329484185663 --- token/filter, not required + */ + final String url = "http://www.geocaching.com/map/map.info?x=" + tile.left + "&y=" + tile.right + "&z=14"; + String page = ""; + if (IS_ONLINE) { + page = cgBase.requestJSON(url, referer); + } else { + page = "{\"grid\":[\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" 04$ \",\" /5' \",\" .6& \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" %:( \",\" #;, \",\" !<) \",\" \",\" \",\" \",\" \",\" 8-1 \",\" 9+2 \",\" 7*3 \",\" \"],\"keys\":[\"\",\"55_55\",\"55_54\",\"17_25\",\"55_53\",\"17_27\",\"17_26\",\"57_53\",\"57_55\",\"3_62\",\"3_61\",\"57_54\",\"3_60\",\"15_27\",\"15_26\",\"15_25\",\"4_60\",\"4_61\",\"4_62\",\"16_25\",\"16_26\",\"16_27\",\"2_62\",\"2_60\",\"2_61\",\"56_53\",\"56_54\",\"56_55\"],\"data\":{\"55_55\":[{\"i\":\"gEaR\",\"n\":\"Spiel & Sport\"}],\"" + + "55_54\":[{\"i\":\"gEaR\",\"n\":\"Spiel & Sport\"}],\"17_25\":[{\"i\":\"Rkzt\",\"n\":\"EDSSW: Rathaus \"}],\"55_53\":[{\"i\":\"gEaR\",\"n\":\"Spiel & Sport\"}],\"17_27\":[{\"i\":\"Rkzt\",\"n\":\"EDSSW: Rathaus \"}],\"17_26\":[{\"i\":\"Rkzt\",\"n\":\"EDSSW: Rathaus \"}],\"57_53\":[{\"i\":\"gEaR\",\"n\":\"Spiel & Sport\"}],\"57_55\":[{\"i\":\"gEaR\",\"n\":\"Spiel & Sport\"}],\"3_62\":[{\"i\":\"gOWz\",\"n\":\"Baumarktserie - Wer Wo Was -\"}],\"3_61\":[{\"i\":\"gOWz\",\"n\":\"Baumarktserie - Wer Wo Was -\"}],\"57_54\":[{\"i\":\"gEaR\",\"n\":\"Spiel & Sport\"}],\"3_60\":[{\"i\":\"gOWz\",\"n\":\"Baumarktserie - Wer Wo Was -\"}],\"15_27\":[{\"i\":\"Rkzt\",\"n\":\"EDSSW: Rathaus \"}],\"15_26\":[{\"i\":\"Rkzt\",\"n\":\"EDSSW: Rathaus \"}],\"15_25\":[{\"i\":\"Rkzt\",\"n\":\"EDSSW: Rathaus \"}],\"4_60\":[{\"i\":\"gOWz\",\"n\":\"Baumarktserie - Wer Wo Was -\"}],\"4_61\":[{\"i\":\"gOWz\",\"n\":\"Baumarktserie - Wer Wo Was -\"}],\"4_62\":[{\"i\":\"gOWz\",\"n\":\"Baumarktserie - Wer Wo Was -\"}],\"16_25\":[{\"i\":\"Rkzt\",\"n\":\"EDSSW: Rathaus \"}],\"16_26\":[{\"i\":\"Rkzt\",\"n\":\"EDSSW: Rathaus \"}],\"16_27\":[{\"i\":\"Rkzt\",\"n\":\"EDSSW: Rathaus \"}],\"2_62\":[{\"i\":\"gOWz\",\"n\":\"Baumarktserie - Wer Wo Was -\"}],\"2_60\":[{\"i\":\"gOWz\",\"n\":\"Baumarktserie - Wer Wo Was -\"}],\"2_61\":[{\"i\":\"gOWz\",\"n\":\"Baumarktserie - Wer Wo Was -\"}],\"56_53\":[{\"i\":\"gEaR\",\"n\":\"Spiel & Sport\"}],\"56_54\":[{\"i\":\"gEaR\",\"n\":\"Spiel & Sport\"}],\"56_55\":[{\"i\":\"gEaR\",\"n\":\"Spiel & Sport\"}]}}"; + } + if (StringUtils.isBlank(page)) { + Log.e(Settings.tag, "GCConnectImpl.searchByViewport: No data from server for tile (" + tile.left + "/" + tile.right + ")"); + } + final SearchResult search = parseMapJSON(url, page); + if (search == null || CollectionUtils.isEmpty(search.getGeocodes())) { + Log.e(Settings.tag, "GCConnectImpl.searchByViewport: No cache parsed for viewport " + viewport); + } + searchResult.addGeocodes(search.getGeocodes()); + } + + final SearchResult search = searchResult.filterSearchResults(Settings.isExcludeDisabledCaches(), Settings.isExcludeMyCaches(), Settings.getCacheType(), StoredList.TEMPORARY_LIST_ID); + return search; + } + + /** + * @param url + * URL used to retrieve data. + * @param page + * Retrieved data. + * @return SearchResult. Never null. + */ + public static SearchResult parseMapJSON(final String url, final String page) { + + final SearchResult searchResult = new SearchResult(); + searchResult.setUrl(url); + + try { + + if (StringUtils.isEmpty(page)) { + throw new JSONException("No page given"); + } + + // Example JSON information + // {"grid":[....], + // "keys":["","55_55","55_54","17_25","55_53","17_27","17_26","57_53","57_55","3_62","3_61","57_54","3_60","15_27","15_26","15_25","4_60","4_61","4_62","16_25","16_26","16_27","2_62","2_60","2_61","56_53","56_54","56_55"], + // "data":{"55_55":[{"i":"gEaR","n":"Spiel & Sport"}],"55_54":[{"i":"gEaR","n":"Spiel & Sport"}],"17_25":[{"i":"Rkzt","n":"EDSSW: Rathaus "}],"55_53":[{"i":"gEaR","n":"Spiel & Sport"}],"17_27":[{"i":"Rkzt","n":"EDSSW: Rathaus "}],"17_26":[{"i":"Rkzt","n":"EDSSW: Rathaus "}],"57_53":[{"i":"gEaR","n":"Spiel & Sport"}],"57_55":[{"i":"gEaR","n":"Spiel & Sport"}],"3_62":[{"i":"gOWz","n":"Baumarktserie - Wer Wo Was -"}],"3_61":[{"i":"gOWz","n":"Baumarktserie - Wer Wo Was -"}],"57_54":[{"i":"gEaR","n":"Spiel & Sport"}],"3_60":[{"i":"gOWz","n":"Baumarktserie - Wer Wo Was -"}],"15_27":[{"i":"Rkzt","n":"EDSSW: Rathaus "}],"15_26":[{"i":"Rkzt","n":"EDSSW: Rathaus "}],"15_25":[{"i":"Rkzt","n":"EDSSW: Rathaus "}],"4_60":[{"i":"gOWz","n":"Baumarktserie - Wer Wo Was -"}],"4_61":[{"i":"gOWz","n":"Baumarktserie - Wer Wo Was -"}],"4_62":[{"i":"gOWz","n":"Baumarktserie - Wer Wo Was -"}],"16_25":[{"i":"Rkzt","n":"EDSSW: Rathaus "}],"16_26":[{"i":"Rkzt","n":"EDSSW: Rathaus "}],"16_27":[{"i":"Rkzt","n":"EDSSW: Rathaus "}],"2_62":[{"i":"gOWz","n":"Baumarktserie - Wer Wo Was -"}],"2_60":[{"i":"gOWz","n":"Baumarktserie - Wer Wo Was -"}],"2_61":[{"i":"gOWz","n":"Baumarktserie - Wer Wo Was -"}],"56_53":[{"i":"gEaR","n":"Spiel & Sport"}],"56_54":[{"i":"gEaR","n":"Spiel & Sport"}],"56_55":[{"i":"gEaR","n":"Spiel & Sport"}]} + // } + + final JSONObject json = new JSONObject(page); + + final JSONArray grid = json.getJSONArray("grid"); + if (grid == null || grid.length() != 64) { + throw new JSONException("No grid inside JSON"); + } + final JSONArray keys = json.getJSONArray("keys"); + if (keys == null) { + throw new JSONException("No keys inside JSON"); + } + final JSONObject dataObject = json.getJSONObject("data"); + if (dataObject == null) { + throw new JSONException("No data inside JSON"); + } + + for (int y = 0; y < grid.length(); y++) { + byte[] row = grid.getString(y).getBytes(); + for (int x = 0; x < row.length; x++) { + byte id = getUTFGridId(row[x]); + if (id > 0) { + Log.d(Settings.tag, "(" + x + "/" + y + ") =" + String.valueOf(id)); + } + } + } + + //Map<String, Integer> keyIds = new HashMap<String, Integer>(); // key (55_55), index + //Map<String, cgCache> caches = new HashMap<String, cgCache>(); // name, cache + //Map<String, List<String>> positions = new HashMap<String, List<String>>(); // name, keys + + for (int i = 0; i < keys.length(); i++) { + String key = keys.getString(i); + Log.d(Settings.tag, "Key #" + i + "=" + key); + if (StringUtils.isNotBlank(key)) { + JSONArray dataForKey = dataObject.getJSONArray(key); + for (int j = 0; j < dataForKey.length(); j++) { + JSONObject cacheInfo = dataForKey.getJSONObject(j); + // TODO Valentine How to convert to a geocode ? Or is an extra request needed ? + String id = cacheInfo.getString("i"); + String name = cacheInfo.getString("n"); + + final cgCache cacheToAdd = new cgCache(); + cacheToAdd.setDetailed(false); + cacheToAdd.setReliableLatLon(false); + cacheToAdd.setGeocode(id); + cacheToAdd.setCoords(getCoordsForUTFGrid(key)); + cacheToAdd.setName(name); + cacheToAdd.setType(CacheType.GC_LIVE_MAP); + + Log.d(Settings.tag, "key=" + key + " id=" + id + " name=" + name); + + //caches.put(id, cacheToAdd); + searchResult.addCache(cacheToAdd); + } + } + } + + } catch (Exception e) { + Log.e(Settings.tag, "cgBase.parseMapJSON", e); + } + + return searchResult; + } + + /** + * Calculate tiles for the given viewport + * + * @param viewport + * @return + */ + protected static List<ImmutablePair<Integer, Integer>> getTilesForViewport(Viewport viewport) { + // TODO Valentine Calculate tile number + ImmutablePair<Integer, Integer> tile = new ImmutablePair<Integer, Integer>(8633, 5381); // = N 52° 24,516 E 009° 42,592 + List<ImmutablePair<Integer, Integer>> tiles = new ArrayList<ImmutablePair<Integer, Integer>>(); + tiles.add(tile); + return tiles; + + } + + protected static Geopoint getCoordsForUTFGrid(String key) { + // TODO Valentine Calculate coords + return new Geopoint("N 52° 24,516 E 009° 42,592"); + } + + /** @see https://github.com/mapbox/mbtiles-spec/blob/master/1.1/utfgrid.md */ + protected static byte getUTFGridId(final byte value) { + byte result = value; + if (result >= 93) { + result--; + } + if (result >= 35) { + result--; + } + return (byte) (result - 32); + } + +} diff --git a/main/src/cgeo/geocaching/enumerations/CacheType.java b/main/src/cgeo/geocaching/enumerations/CacheType.java index ca4e999..fd1b926 100644 --- a/main/src/cgeo/geocaching/enumerations/CacheType.java +++ b/main/src/cgeo/geocaching/enumerations/CacheType.java @@ -29,6 +29,8 @@ public enum CacheType { PROJECT_APE("ape", "project ape cache", "2555690d-b2bc-4b55-b5ac-0cb704c0b768", R.string.ape, R.drawable.type_ape), GCHQ("gchq", "groundspeak hq", "416f2494-dc17-4b6a-9bab-1a29dd292d8c", R.string.gchq, R.drawable.type_hq), GPS_EXHIBIT("gps", "gps cache exhibit", "72e69af2-7986-4990-afd9-bc16cbbb4ce3", R.string.gps, R.drawable.type_traditional), // icon missing + // TODO Valentine create new drawable + GC_LIVE_MAP("live map", "live map", "", R.string.unknown, R.drawable.type_mystery), UNKNOWN("unknown", "unknown", "", R.string.unknown, R.drawable.type_mystery), // icon missing /** No real cache type -> filter */ ALL("all", "display all caches", "9a79e6ce-3344-409c-bbe9-496530baf758", R.string.all_types, R.drawable.type_mystery); diff --git a/tests/src/cgeo/geocaching/connector/GCConnectorTest.java b/tests/src/cgeo/geocaching/connector/GCConnectorTest.java new file mode 100644 index 0000000..10f2653 --- /dev/null +++ b/tests/src/cgeo/geocaching/connector/GCConnectorTest.java @@ -0,0 +1,20 @@ +package cgeo.geocaching.connector; + +import cgeo.geocaching.SearchResult; +import cgeo.geocaching.geopoint.Viewport; +import cgeo.geocaching.test.mock.GC2JVEH; + +import android.test.AndroidTestCase; + +public class GCConnectorTest extends AndroidTestCase { + + @SuppressWarnings("null") + public static void testGetViewport() { + GC2JVEH cache = new GC2JVEH(); + final Viewport viewport = new Viewport(cache.getCoords(), 1.0, 1.0); + SearchResult searchResult = GCConnectorImpl.searchByViewport(viewport); + assertTrue(searchResult != null); + assertTrue(searchResult.getGeocodes().contains(cache.getGeocode())); + } + +} |