aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorblafoo <github@blafoo.de>2012-02-17 23:24:13 +0100
committerblafoo <github@blafoo.de>2012-02-23 23:19:49 +0100
commit98f3bd4d23f9a095f34b5b18cd08273e601f3981 (patch)
tree2ad830c5d28f974b2636c897f0642b8dc2711d72
parent039e877c27688ae67da949480df66108dac7c4c6 (diff)
downloadcgeo-98f3bd4d23f9a095f34b5b18cd08273e601f3981.zip
cgeo-98f3bd4d23f9a095f34b5b18cd08273e601f3981.tar.gz
cgeo-98f3bd4d23f9a095f34b5b18cd08273e601f3981.tar.bz2
JSON (new format) parsing
-rw-r--r--main/src/cgeo/geocaching/SearchResult.java5
-rw-r--r--main/src/cgeo/geocaching/cgBase.java20
-rw-r--r--main/src/cgeo/geocaching/connector/GCConnectorImpl.java195
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheType.java2
-rw-r--r--tests/src/cgeo/geocaching/connector/GCConnectorTest.java20
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()));
+ }
+
+}