aboutsummaryrefslogtreecommitdiffstats
path: root/main/src
diff options
context:
space:
mode:
Diffstat (limited to 'main/src')
-rw-r--r--main/src/cgeo/geocaching/Settings.java38
-rw-r--r--main/src/cgeo/geocaching/SettingsActivity.java19
-rw-r--r--main/src/cgeo/geocaching/cgCache.java5
-rw-r--r--main/src/cgeo/geocaching/cgeocaches.java12
-rw-r--r--main/src/cgeo/geocaching/connector/AbstractConnector.java26
-rw-r--r--main/src/cgeo/geocaching/connector/ConnectorFactory.java53
-rw-r--r--main/src/cgeo/geocaching/connector/IConnector.java28
-rw-r--r--main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java1
-rw-r--r--main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java2
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCConnector.java14
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java514
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCApiConnector.java6
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCConnector.java6
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCXMLApiConnector.java52
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCXMLClient.java110
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheRealm.java22
-rw-r--r--main/src/cgeo/geocaching/geopoint/Geopoint.java2
-rw-r--r--main/src/cgeo/geocaching/maps/CGeoMap.java3
18 files changed, 884 insertions, 29 deletions
diff --git a/main/src/cgeo/geocaching/Settings.java b/main/src/cgeo/geocaching/Settings.java
index a766470..5898bf7 100644
--- a/main/src/cgeo/geocaching/Settings.java
+++ b/main/src/cgeo/geocaching/Settings.java
@@ -109,6 +109,8 @@ public final class Settings {
private static final String KEY_PLAIN_LOGS = "plainLogs";
private static final String KEY_NATIVE_UA = "nativeUa";
private static final String KEY_MAP_DIRECTORY = "mapDirectory";
+ private static final String KEY_CONNECTOR_OC_ACTIVE = "connectorOCActive";
+ private static final String KEY_CONNECTOR_OC_USER = "connectorOCUser";
private final static int unitsMetric = 1;
@@ -305,6 +307,42 @@ public final class Settings {
});
}
+ public static boolean isOCConnectorActive() {
+ return sharedPrefs.getBoolean(KEY_CONNECTOR_OC_ACTIVE, false);
+ }
+
+ public static boolean setOCConnectorActive(final boolean isActive) {
+ return editSharedSettings(new PrefRunnable() {
+
+ @Override
+ public void edit(Editor edit) {
+ edit.putBoolean(KEY_CONNECTOR_OC_ACTIVE, isActive);
+ }
+ });
+ }
+
+ public static String getOCConnectorUserName() {
+ String ocConnectorUser = sharedPrefs.getString(KEY_CONNECTOR_OC_USER, null);
+ if (StringUtils.isBlank(ocConnectorUser)) {
+ return StringUtils.EMPTY;
+ }
+ return ocConnectorUser;
+ }
+
+ public static boolean setOCConnectorUserName(final String userName) {
+ return editSharedSettings(new PrefRunnable() {
+
+ @Override
+ public void edit(Editor edit) {
+ if (StringUtils.isBlank(userName)) {
+ edit.remove(KEY_CONNECTOR_OC_USER);
+ } else {
+ edit.putString(KEY_CONNECTOR_OC_USER, userName);
+ }
+ }
+ });
+ }
+
public static boolean isGCvoteLogin() {
final String preUsername = sharedPrefs.getString(KEY_USERNAME, null);
final String prePassword = sharedPrefs.getString(KEY_GCVOTE_PASSWORD, null);
diff --git a/main/src/cgeo/geocaching/SettingsActivity.java b/main/src/cgeo/geocaching/SettingsActivity.java
index 199e083..0a41942 100644
--- a/main/src/cgeo/geocaching/SettingsActivity.java
+++ b/main/src/cgeo/geocaching/SettingsActivity.java
@@ -242,6 +242,21 @@ public class SettingsActivity extends AbstractActivity {
}
});
+ // opencaching.de settings
+ final CheckBox ocCheck = (CheckBox) findViewById(R.id.oc_option);
+ ocCheck.setChecked(Settings.isOCConnectorActive());
+ ocCheck.setOnClickListener(new View.OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ Settings.setOCConnectorActive(ocCheck.isChecked());
+ }
+ });
+ EditText ocUserEdit = (EditText) findViewById(R.id.oc_username);
+ if (ocUserEdit.getText().length() == 0) {
+ ocUserEdit.setText(Settings.getOCConnectorUserName());
+ }
+
// gcvote settings
final ImmutablePair<String, String> gcvoteLogin = Settings.getGCvoteLogin();
if (null != gcvoteLogin && null != gcvoteLogin.right) {
@@ -813,6 +828,7 @@ public class SettingsActivity extends AbstractActivity {
String signatureNew = ((EditText) findViewById(R.id.signature)).getText().toString();
String mapDirectoryNew = StringUtils.trimToEmpty(((EditText) findViewById(R.id.map_directory)).getText().toString());
String themesDirectoryNew = StringUtils.trimToEmpty(((EditText) findViewById(R.id.themefolder)).getText().toString());
+ String ocUserName = StringUtils.trimToEmpty(((EditText) findViewById(R.id.oc_username)).getText().toString());
String altitudeNew = StringUtils.trimToNull(((EditText) findViewById(R.id.altitude)).getText().toString());
int altitudeNewInt = parseNumber(altitudeNew, 0);
@@ -826,6 +842,7 @@ public class SettingsActivity extends AbstractActivity {
final boolean status4 = Settings.setAltCorrection(altitudeNewInt);
final boolean status5 = Settings.setMapFileDirectory(mapDirectoryNew);
final boolean status6 = Settings.setCustomRenderThemeBaseFolder(themesDirectoryNew);
+ final boolean status7 = Settings.setOCConnectorUserName(ocUserName);
Settings.setShowWaypointsThreshold(waypointThreshold);
String importNew = StringUtils.trimToEmpty(((EditText) findViewById(R.id.gpx_importdir)).getText().toString());
@@ -833,7 +850,7 @@ public class SettingsActivity extends AbstractActivity {
Settings.setGpxImportDir(importNew);
Settings.setGpxExportDir(exportNew);
- return status1 && status2 && status3 && status4 && status5 && status6;
+ return status1 && status2 && status3 && status4 && status5 && status6 && status7;
}
/**
diff --git a/main/src/cgeo/geocaching/cgCache.java b/main/src/cgeo/geocaching/cgCache.java
index 7fbbf0c..b486142 100644
--- a/main/src/cgeo/geocaching/cgCache.java
+++ b/main/src/cgeo/geocaching/cgCache.java
@@ -11,6 +11,7 @@ import cgeo.geocaching.connector.gc.GCConnector;
import cgeo.geocaching.connector.gc.GCConstants;
import cgeo.geocaching.connector.gc.Tile;
import cgeo.geocaching.enumerations.CacheAttribute;
+import cgeo.geocaching.enumerations.CacheRealm;
import cgeo.geocaching.enumerations.CacheSize;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LoadFlags;
@@ -545,6 +546,10 @@ public class cgCache implements ICache, IWaypoint {
return getConnector().supportsOwnCoordinates();
}
+ public CacheRealm getCacheRealm() {
+ return getConnector().getCacheRealm();
+ }
+
@Override
public float getDifficulty() {
return difficulty;
diff --git a/main/src/cgeo/geocaching/cgeocaches.java b/main/src/cgeo/geocaching/cgeocaches.java
index 901743c..1210dd4 100644
--- a/main/src/cgeo/geocaching/cgeocaches.java
+++ b/main/src/cgeo/geocaching/cgeocaches.java
@@ -7,6 +7,8 @@ import cgeo.geocaching.activity.FilteredActivity;
import cgeo.geocaching.activity.Progress;
import cgeo.geocaching.apps.cache.navi.NavigationAppFactory;
import cgeo.geocaching.apps.cachelist.CacheListAppFactory;
+import cgeo.geocaching.connector.ConnectorFactory;
+import cgeo.geocaching.connector.capability.ISearchByCenter;
import cgeo.geocaching.connector.gc.AbstractSearchThread;
import cgeo.geocaching.connector.gc.GCParser;
import cgeo.geocaching.connector.gc.SearchHandler;
@@ -1376,7 +1378,17 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
@Override
public void runSearch() {
+
search = GCParser.searchByCoords(coords, Settings.getCacheType(), Settings.isShowCaptcha());
+
+ for (ISearchByCenter centerConn : ConnectorFactory.getSearchByCenterConnectors()) {
+ if (centerConn.isActivated()) {
+ SearchResult temp = centerConn.searchByCenter(coords);
+ if (temp != null) {
+ search.addGeocodes(temp.getGeocodes());
+ }
+ }
+ }
replaceCacheListFromSearch();
}
}
diff --git a/main/src/cgeo/geocaching/connector/AbstractConnector.java b/main/src/cgeo/geocaching/connector/AbstractConnector.java
index 0308ae7..9604b5f 100644
--- a/main/src/cgeo/geocaching/connector/AbstractConnector.java
+++ b/main/src/cgeo/geocaching/connector/AbstractConnector.java
@@ -1,9 +1,8 @@
package cgeo.geocaching.connector;
-import cgeo.geocaching.SearchResult;
import cgeo.geocaching.cgCache;
+import cgeo.geocaching.enumerations.CacheRealm;
import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.Viewport;
import org.apache.commons.lang3.StringUtils;
@@ -26,7 +25,7 @@ public abstract class AbstractConnector implements IConnector {
/**
* Uploading modified coordinates to website
- *
+ *
* @param cache
* @param wpt
* @return success
@@ -64,11 +63,6 @@ public abstract class AbstractConnector implements IConnector {
return false;
}
- @Override
- public SearchResult searchByViewport(Viewport viewport, String[] tokens) {
- return null;
- }
-
protected static boolean isNumericId(final String string) {
try {
return Integer.parseInt(string) > 0;
@@ -107,4 +101,20 @@ public abstract class AbstractConnector implements IConnector {
}
abstract protected String getCacheUrlPrefix();
+
+ /**
+ * {@link IConnector}
+ */
+ @Override
+ public CacheRealm getCacheRealm() {
+ return CacheRealm.OTHER;
+ }
+
+ /**
+ * {@link IConnector}
+ */
+ @Override
+ public boolean isActivated() {
+ return false;
+ }
}
diff --git a/main/src/cgeo/geocaching/connector/ConnectorFactory.java b/main/src/cgeo/geocaching/connector/ConnectorFactory.java
index bc4dcc0..4802c3e 100644
--- a/main/src/cgeo/geocaching/connector/ConnectorFactory.java
+++ b/main/src/cgeo/geocaching/connector/ConnectorFactory.java
@@ -3,25 +3,31 @@ package cgeo.geocaching.connector;
import cgeo.geocaching.ICache;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.cgTrackable;
+import cgeo.geocaching.connector.capability.ISearchByCenter;
+import cgeo.geocaching.connector.capability.ISearchByViewPort;
import cgeo.geocaching.connector.gc.GCConnector;
import cgeo.geocaching.connector.oc.OCApiConnector;
import cgeo.geocaching.connector.oc.OCConnector;
+import cgeo.geocaching.connector.oc.OCXMLApiConnector;
import cgeo.geocaching.connector.ox.OXConnector;
import cgeo.geocaching.geopoint.Viewport;
import org.apache.commons.lang3.StringUtils;
+import java.util.ArrayList;
+import java.util.List;
+
public final class ConnectorFactory {
private static final UnknownConnector UNKNOWN_CONNECTOR = new UnknownConnector();
private static final IConnector[] connectors = new IConnector[] {
GCConnector.getInstance(),
- new OCConnector("OpenCaching.DE", "www.opencaching.de", "OC"),
+ new OCXMLApiConnector("OpenCaching.DE", "www.opencaching.de", "OC"),
new OCConnector("OpenCaching.CZ", "www.opencaching.cz", "OZ"),
new OCApiConnector("OpenCaching.CO.UK", "www.opencaching.org.uk", "OK", "arU4okouc4GEjMniE2fq"),
new OCConnector("OpenCaching.ES", "www.opencachingspain.es", "OC"),
new OCConnector("OpenCaching.IT", "www.opencaching.it", "OC"),
new OCConnector("OpenCaching.JP", "www.opencaching.jp", "OJ"),
- new OCConnector("OpenCaching.NO/SE", "www.opencaching.no", "OS"),
+ new OCConnector("OpenCaching.NO/SE", "www.opencaching.se", "OS"),
new OCApiConnector("OpenCaching.NL", "www.opencaching.nl", "OB", "PdzU8jzIlcfMADXaYN8j"),
new OCApiConnector("OpenCaching.PL", "www.opencaching.pl", "OP", "GkxM47WkUkLQXXsZ9qSh"),
new OCApiConnector("OpenCaching.US", "www.opencaching.us", "OU", "pTsYAYSXFcfcRQnYE6uA"),
@@ -31,10 +37,37 @@ public final class ConnectorFactory {
UNKNOWN_CONNECTOR // the unknown connector MUST be the last one
};
+ private static final ISearchByViewPort[] searchByViewPortConns;
+
+ private static final ISearchByCenter[] searchByCenterConns;
+
+ static {
+ List<ISearchByViewPort> vpConns = new ArrayList<ISearchByViewPort>();
+ for (IConnector conn : connectors) {
+ if (conn instanceof ISearchByViewPort) {
+ vpConns.add((ISearchByViewPort) conn);
+ }
+ }
+ searchByViewPortConns = vpConns.toArray(new ISearchByViewPort[] {});
+
+ List<ISearchByCenter> centerConns = new ArrayList<ISearchByCenter>();
+ for (IConnector conn : connectors) {
+ // GCConnector is handled specially, omit it here!
+ if (conn instanceof ISearchByCenter && !(conn instanceof GCConnector)) {
+ centerConns.add((ISearchByCenter) conn);
+ }
+ }
+ searchByCenterConns = centerConns.toArray(new ISearchByCenter[] {});
+ }
+
public static IConnector[] getConnectors() {
return connectors;
}
+ public static ISearchByCenter[] getSearchByCenterConnectors() {
+ return searchByCenterConns;
+ }
+
public static boolean canHandle(final String geocode) {
if (isInvalidGeocode(geocode)) {
return false;
@@ -74,11 +107,19 @@ public final class ConnectorFactory {
return StringUtils.isBlank(geocode) || !Character.isLetterOrDigit(geocode.charAt(0));
}
- /** @see IConnector#searchByViewport */
+ /** @see ISearchByViewPort#searchByViewport */
public static SearchResult searchByViewport(final Viewport viewport, final String[] tokens) {
- // We have only connector capable of doing a 'searchByViewport()'
- // If there is a second connector the information has to be collected from all collectors
- return GCConnector.getInstance().searchByViewport(viewport, tokens);
+
+ SearchResult result = new SearchResult();
+ for (ISearchByViewPort vpconn : searchByViewPortConns) {
+ if (vpconn.isActivated()) {
+ SearchResult temp = vpconn.searchByViewport(viewport, tokens);
+ if (temp != null) {
+ result.addGeocodes(temp.getGeocodes());
+ }
+ }
+ }
+ return result;
}
public static String getGeocodeFromURL(final String url) {
diff --git a/main/src/cgeo/geocaching/connector/IConnector.java b/main/src/cgeo/geocaching/connector/IConnector.java
index 69cc7d1..2944bed 100644
--- a/main/src/cgeo/geocaching/connector/IConnector.java
+++ b/main/src/cgeo/geocaching/connector/IConnector.java
@@ -1,9 +1,8 @@
package cgeo.geocaching.connector;
-import cgeo.geocaching.SearchResult;
import cgeo.geocaching.cgCache;
+import cgeo.geocaching.enumerations.CacheRealm;
import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.Viewport;
public interface IConnector {
/**
@@ -73,15 +72,6 @@ public interface IConnector {
public boolean supportsUserActions();
/**
- * Search caches by viewport.
- *
- * @param viewport
- * @param tokens
- * @return
- */
- public SearchResult searchByViewport(final Viewport viewport, final String[] tokens);
-
- /**
* return true if this is a ZIP file containing a GPX file
*
* @param fileName
@@ -115,7 +105,7 @@ public interface IConnector {
/**
* enable/disable uploading modified coordinates to website
- *
+ *
* @return true, when uploading is possible
*/
public boolean supportsOwnCoordinates();
@@ -137,4 +127,18 @@ public interface IConnector {
*/
public boolean deleteModifiedCoordinates(cgCache cache);
+ /**
+ * The CacheRealm this cache belongs to
+ *
+ * @return
+ */
+ public CacheRealm getCacheRealm();
+
+ /**
+ * Return true if this connector is activated for online
+ * interaction (download details, do searches, ...)
+ *
+ * @return
+ */
+ public boolean isActivated();
}
diff --git a/main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java b/main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java
index 62645c2..3fdd61f 100644
--- a/main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java
+++ b/main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java
@@ -10,4 +10,5 @@ import cgeo.geocaching.geopoint.Geopoint;
public interface ISearchByCenter {
public SearchResult searchByCenter(final Geopoint center);
+ public boolean isActivated();
}
diff --git a/main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java b/main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java
index 316cf00..f1bd2ce 100644
--- a/main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java
+++ b/main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java
@@ -5,4 +5,6 @@ import cgeo.geocaching.geopoint.Viewport;
public interface ISearchByViewPort {
public SearchResult searchByViewport(final Viewport viewport, final String[] tokens);
+
+ public boolean isActivated();
}
diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
index b196504..8943835 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
@@ -7,6 +7,8 @@ import cgeo.geocaching.cgData;
import cgeo.geocaching.connector.AbstractConnector;
import cgeo.geocaching.connector.capability.ISearchByCenter;
import cgeo.geocaching.connector.capability.ISearchByGeocode;
+import cgeo.geocaching.connector.capability.ISearchByViewPort;
+import cgeo.geocaching.enumerations.CacheRealm;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.Viewport;
@@ -18,7 +20,7 @@ import org.apache.commons.lang3.StringUtils;
import java.util.regex.Pattern;
-public class GCConnector extends AbstractConnector implements ISearchByGeocode, ISearchByCenter {
+public class GCConnector extends AbstractConnector implements ISearchByGeocode, ISearchByCenter, ISearchByViewPort {
private static final String HTTP_COORD_INFO = "http://coord.info/";
private static final Pattern gpxZipFilePattern = Pattern.compile("\\d{7,}(_.+)?\\.zip", Pattern.CASE_INSENSITIVE);
@@ -216,4 +218,14 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
protected String getCacheUrlPrefix() {
return HTTP_COORD_INFO;
}
+
+ @Override
+ public CacheRealm getCacheRealm() {
+ return CacheRealm.GC;
+ }
+
+ @Override
+ public boolean isActivated() {
+ return true;
+ }
}
diff --git a/main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java b/main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java
new file mode 100644
index 0000000..d0c0e16
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java
@@ -0,0 +1,514 @@
+package cgeo.geocaching.connector.oc;
+
+import cgeo.geocaching.LogEntry;
+import cgeo.geocaching.Settings;
+import cgeo.geocaching.cgCache;
+import cgeo.geocaching.enumerations.CacheSize;
+import cgeo.geocaching.enumerations.CacheType;
+import cgeo.geocaching.enumerations.LogType;
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.utils.Log;
+
+import org.apache.commons.lang3.StringUtils;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+import android.sax.Element;
+import android.sax.EndElementListener;
+import android.sax.EndTextElementListener;
+import android.sax.RootElement;
+import android.sax.StartElementListener;
+import android.util.Xml;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.regex.Pattern;
+
+public class OC11XMLParser {
+
+ private static Pattern STRIP_DATE = Pattern.compile("\\+0([0-9]){1}\\:00");
+
+ private static class CacheHolder {
+ public cgCache cache;
+ public String latitude;
+ public String longitude;
+ }
+
+ private static class CacheLog {
+ public String cacheId;
+ public LogEntry logEntry;
+ }
+
+ private static class CacheDescription {
+ public String cacheId;
+ public String shortDesc;
+ public String desc;
+ public String hint;
+ }
+
+ private static Date parseFullDate(final String date) {
+ final SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
+ ISO8601DATEFORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
+ final String strippedDate = STRIP_DATE.matcher(date).replaceAll("+0$100");
+ try {
+ return ISO8601DATEFORMAT.parse(strippedDate);
+ } catch (ParseException e) {
+ Log.e("OC11XMLParser.parseFullDate", e);
+ }
+ return null;
+ }
+
+ private static Date parseDayDate(final String date) {
+ final SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
+ ISO8601DATEFORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
+ final String strippedDate = STRIP_DATE.matcher(date).replaceAll("+0$100");
+ try {
+ return ISO8601DATEFORMAT.parse(strippedDate);
+ } catch (ParseException e) {
+ Log.e("OC11XMLParser.parseDayDate", e);
+ }
+ return null;
+ }
+
+ private static CacheSize getCacheSize(final String sizeId) {
+ int size = Integer.parseInt(sizeId);
+
+ switch (size) {
+ case 1:
+ return CacheSize.OTHER;
+ case 2:
+ return CacheSize.MICRO;
+ case 3:
+ return CacheSize.SMALL;
+ case 4:
+ return CacheSize.REGULAR;
+ case 5:
+ case 6:
+ return CacheSize.LARGE;
+ case 8:
+ return CacheSize.VIRTUAL;
+ default:
+ break;
+ }
+ return CacheSize.NOT_CHOSEN;
+ }
+
+ private static CacheType getCacheType(final String typeId) {
+ int type = Integer.parseInt(typeId);
+ switch (type) {
+ case 1: // Other/unbekannter Cachetyp
+ return CacheType.UNKNOWN;
+ case 2: // Trad./normaler Cache
+ return CacheType.TRADITIONAL;
+ case 3: // Multi/Multicache
+ return CacheType.MULTI;
+ case 4: // Virt./virtueller Cache
+ return CacheType.VIRTUAL;
+ case 5: // ICam./Webcam-Cache
+ return CacheType.WEBCAM;
+ case 6: // Event/Event-Cache
+ return CacheType.EVENT;
+ case 7: // Quiz/Rätselcache
+ return CacheType.MYSTERY;
+ case 8: // Math/Mathe-/Physikcache
+ return CacheType.MYSTERY;
+ case 9: // Moving/beweglicher Cache
+ return CacheType.UNKNOWN;
+ case 10: // Driv./Drive-In
+ return CacheType.TRADITIONAL;
+ }
+ return CacheType.UNKNOWN;
+ }
+
+ private static LogType getLogType(final int typeId) {
+ switch (typeId) {
+ case 1:
+ return LogType.FOUND_IT;
+ case 2:
+ return LogType.DIDNT_FIND_IT;
+ case 3:
+ return LogType.NOTE;
+ case 7:
+ return LogType.ATTENDED;
+ case 8:
+ return LogType.WILL_ATTEND;
+ }
+ return LogType.UNKNOWN;
+ }
+
+ private static void setCacheStatus(final int statusId, final cgCache cache) {
+
+ switch (statusId) {
+ case 1:
+ cache.setArchived(false);
+ cache.setDisabled(false);
+ break;
+ case 2:
+ cache.setArchived(false);
+ cache.setDisabled(true);
+ break;
+ default:
+ cache.setArchived(true);
+ cache.setDisabled(false);
+ break;
+ }
+ }
+
+ private static void resetCache(final CacheHolder cacheHolder) {
+ cacheHolder.cache = new cgCache(null);
+ cacheHolder.cache.setReliableLatLon(true);
+ cacheHolder.cache.setDescription(StringUtils.EMPTY);
+ cacheHolder.latitude = "0.0";
+ cacheHolder.longitude = "0.0";
+ }
+
+ private static void resetLog(final CacheLog log) {
+ log.cacheId = StringUtils.EMPTY;
+ log.logEntry = new LogEntry("", 0, LogType.UNKNOWN, "");
+ }
+
+ private static void resetDesc(final CacheDescription desc) {
+ desc.cacheId = StringUtils.EMPTY;
+ desc.shortDesc = StringUtils.EMPTY;
+ desc.desc = StringUtils.EMPTY;
+ desc.hint = StringUtils.EMPTY;
+ }
+
+ public static Collection<cgCache> parseCaches(final InputStream stream) throws IOException {
+
+ final int CACHE_PARSE_LIMIT = 250;
+
+ final Map<String, cgCache> caches = new HashMap<String, cgCache>();
+
+ final CacheHolder cacheHolder = new CacheHolder();
+ final CacheLog logHolder = new CacheLog();
+ final CacheDescription descHolder = new CacheDescription();
+
+ final RootElement root = new RootElement("oc11xml");
+ final Element cacheNode = root.getChild("cache");
+
+ // cache
+ cacheNode.setStartElementListener(new StartElementListener() {
+
+ @Override
+ public void start(Attributes attributes) {
+ resetCache(cacheHolder);
+ }
+
+ });
+
+ cacheNode.setEndElementListener(new EndElementListener() {
+
+ @Override
+ public void end() {
+ cgCache cache = cacheHolder.cache;
+ Geopoint coords = new Geopoint(cacheHolder.latitude, cacheHolder.longitude);
+ if (StringUtils.isNotBlank(cache.getGeocode())
+ && !coords.equals(Geopoint.ZERO)
+ && !cache.isArchived()
+ && caches.size() < CACHE_PARSE_LIMIT) {
+ cache.setCoords(coords);
+ caches.put(cache.getCacheId(), cache);
+ }
+ }
+ });
+
+ // cache.id
+ cacheNode.getChild("id").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String body) {
+ cacheHolder.cache.setCacheId(body);
+ }
+ });
+
+ // cache.longitude
+ cacheNode.getChild("longitude").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String body) {
+ String longitude = body.trim();
+ if (StringUtils.isNotBlank(longitude)) {
+ cacheHolder.longitude = longitude;
+ }
+ }
+ });
+
+ // cache.latitude
+ cacheNode.getChild("latitude").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String body) {
+ String latitude = body.trim();
+ if (StringUtils.isNotBlank(latitude)) {
+ cacheHolder.latitude = latitude;
+ }
+ }
+ });
+
+ // cache.name
+ cacheNode.getChild("name").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String body) {
+ final String content = body.trim();
+ cacheHolder.cache.setName(content);
+ }
+ });
+
+ // cache.waypoints[oc]
+ cacheNode.getChild("waypoints").setStartElementListener(new StartElementListener() {
+
+ @Override
+ public void start(Attributes attrs) {
+ if (attrs.getIndex("oc") > -1) {
+ cacheHolder.cache.setGeocode(attrs.getValue("oc"));
+ }
+ if (attrs.getIndex("gccom") > -1) {
+ String gccode = attrs.getValue("gccom");
+ if (!StringUtils.isBlank(gccode)) {
+ cacheHolder.cache.setDescription(String.format("Listed on geocaching com: <a href=\"http://coord.info/%s\">%s</a><br /><br />", gccode, gccode));
+ }
+ }
+ }
+ });
+
+ // cache.type[id]
+ cacheNode.getChild("type").setStartElementListener(new StartElementListener() {
+
+ @Override
+ public void start(Attributes attrs) {
+ if (attrs.getIndex("id") > -1) {
+ final String typeId = attrs.getValue("id");
+ cacheHolder.cache.setType(getCacheType(typeId));
+ }
+ }
+ });
+
+ // cache.status[id]
+ cacheNode.getChild("status").setStartElementListener(new StartElementListener() {
+
+ @Override
+ public void start(Attributes attrs) {
+ if (attrs.getIndex("id") > -1) {
+ try {
+ final int statusId = Integer.parseInt(attrs.getValue("id"));
+ setCacheStatus(statusId, cacheHolder.cache);
+ } catch (NumberFormatException e) {
+ Log.w(String.format("Failed to parse status of cache '%s'.", cacheHolder.cache.getGeocode()));
+ }
+ }
+ }
+ });
+
+ // cache.size[id]
+ cacheNode.getChild("size").setStartElementListener(new StartElementListener() {
+
+ @Override
+ public void start(Attributes attrs) {
+ if (attrs.getIndex("id") > -1) {
+ final String typeId = attrs.getValue("id");
+ cacheHolder.cache.setSize(getCacheSize(typeId));
+ }
+ }
+ });
+
+ // cache.difficulty
+ cacheNode.getChild("difficulty").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String body) {
+ final String content = body.trim();
+ cacheHolder.cache.setDifficulty(Float.valueOf(content));
+ }
+ });
+
+ // cache.terrain
+ cacheNode.getChild("terrain").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String body) {
+ final String content = body.trim();
+ cacheHolder.cache.setTerrain(Float.valueOf(content));
+ }
+ });
+
+ // cache.terrain
+ cacheNode.getChild("datehidden").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String body) {
+ final String content = body.trim();
+ cacheHolder.cache.setHidden(parseFullDate(content));
+ }
+ });
+
+ // cache.attributes.attribute
+ cacheNode.getChild("attributes").getChild("attribute").setEndTextElementListener(new EndTextElementListener() {
+ @Override
+ public void end(String body) {
+ if (StringUtils.isNotBlank(body)) {
+ cacheHolder.cache.getAttributes().add(body.trim());
+ }
+ }
+ });
+
+ // cachedesc
+ final Element cacheDesc = root.getChild("cachedesc");
+
+ cacheDesc.setStartElementListener(new StartElementListener() {
+
+ @Override
+ public void start(Attributes attributes) {
+ resetDesc(descHolder);
+ }
+ });
+
+ cacheDesc.setEndElementListener(new EndElementListener() {
+
+ @Override
+ public void end() {
+ final cgCache cache = caches.get(descHolder.cacheId);
+ if (cache != null) {
+ cache.setShortdesc(descHolder.shortDesc);
+ cache.setDescription(cache.getDescription() + descHolder.desc);
+ cache.setHint(descHolder.hint);
+ }
+ }
+ });
+
+ // cachedesc.cacheid
+ cacheDesc.getChild("cacheid").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String body) {
+ descHolder.cacheId = body;
+ }
+ });
+
+ // cachedesc.desc
+ cacheDesc.getChild("shortdesc").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String body) {
+ final String content = body.trim();
+ descHolder.shortDesc = content;
+ }
+ });
+
+ // cachedesc.desc
+ cacheDesc.getChild("desc").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String body) {
+ final String content = body.trim();
+ descHolder.desc = content;
+ }
+ });
+
+ // cachedesc.hint
+ cacheDesc.getChild("hint").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String body) {
+ final String content = body.trim();
+ descHolder.hint = content;
+ }
+ });
+
+ // cachelog
+ final Element cacheLog = root.getChild("cachelog");
+
+ cacheLog.setStartElementListener(new StartElementListener() {
+
+ @Override
+ public void start(Attributes attrs) {
+ resetLog(logHolder);
+ }
+ });
+
+ cacheLog.setEndElementListener(new EndElementListener() {
+
+ @Override
+ public void end() {
+ final cgCache cache = caches.get(logHolder.cacheId);
+ if (cache != null && logHolder.logEntry.type != LogType.UNKNOWN) {
+ cache.getLogs().prepend(logHolder.logEntry);
+ if (logHolder.logEntry.type == LogType.FOUND_IT
+ && StringUtils.equals(logHolder.logEntry.author, Settings.getOCConnectorUserName())) {
+ cache.setFound(true);
+ cache.setVisitedDate(logHolder.logEntry.date);
+ }
+ }
+ }
+ });
+
+ // cachelog.cacheid
+ cacheLog.getChild("cacheid").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String body) {
+ logHolder.cacheId = body;
+ }
+ });
+
+ // cachelog.date
+ cacheLog.getChild("date").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String body) {
+ try {
+ logHolder.logEntry.date = parseDayDate(body).getTime();
+ } catch (Exception e) {
+ Log.w("Failed to parse log date: " + e.toString());
+ }
+ }
+ });
+
+ // cachelog.logtype
+ cacheLog.getChild("logtype").setStartElementListener(new StartElementListener() {
+
+ @Override
+ public void start(Attributes attrs) {
+ if (attrs.getIndex("id") > -1) {
+ final int typeId = Integer.parseInt(attrs.getValue("id"));
+ logHolder.logEntry.type = getLogType(typeId);
+ }
+ }
+ });
+
+ // cachelog.userid
+ cacheLog.getChild("userid").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String finderName) {
+ logHolder.logEntry.author = finderName;
+ }
+ });
+
+ // cachelog.text
+ cacheLog.getChild("text").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String logText) {
+ logHolder.logEntry.log = logText;
+ }
+ });
+
+ try {
+ Xml.parse(stream, Xml.Encoding.UTF_8, root.getContentHandler());
+ return caches.values();
+ } catch (SAXException e) {
+ Log.e("Cannot parse .gpx file as oc11xml: could not parse XML - " + e.toString());
+ return null;
+ }
+ }
+}
diff --git a/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java b/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java
index 17c961a..74968e7 100644
--- a/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java
+++ b/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java
@@ -34,4 +34,10 @@ public class OCApiConnector extends OCConnector implements ISearchByGeocode {
}
return new SearchResult(cache);
}
+
+ @Override
+ public boolean isActivated() {
+ // currently always active, but only for details download
+ return true;
+ }
}
diff --git a/main/src/cgeo/geocaching/connector/oc/OCConnector.java b/main/src/cgeo/geocaching/connector/oc/OCConnector.java
index c098d12..24fd7d6 100644
--- a/main/src/cgeo/geocaching/connector/oc/OCConnector.java
+++ b/main/src/cgeo/geocaching/connector/oc/OCConnector.java
@@ -2,6 +2,7 @@ package cgeo.geocaching.connector.oc;
import cgeo.geocaching.cgCache;
import cgeo.geocaching.connector.AbstractConnector;
+import cgeo.geocaching.enumerations.CacheRealm;
import java.util.regex.Pattern;
@@ -51,4 +52,9 @@ public class OCConnector extends AbstractConnector {
return "http://" + host + "/viewcache.php?wp=";
}
+ @Override
+ public CacheRealm getCacheRealm() {
+ return CacheRealm.OC;
+ }
+
}
diff --git a/main/src/cgeo/geocaching/connector/oc/OCXMLApiConnector.java b/main/src/cgeo/geocaching/connector/oc/OCXMLApiConnector.java
new file mode 100644
index 0000000..3a2f42e
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/oc/OCXMLApiConnector.java
@@ -0,0 +1,52 @@
+package cgeo.geocaching.connector.oc;
+
+import cgeo.geocaching.SearchResult;
+import cgeo.geocaching.Settings;
+import cgeo.geocaching.cgCache;
+import cgeo.geocaching.connector.capability.ISearchByCenter;
+import cgeo.geocaching.connector.capability.ISearchByGeocode;
+import cgeo.geocaching.connector.capability.ISearchByViewPort;
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.utils.CancellableHandler;
+
+public class OCXMLApiConnector extends OCConnector implements ISearchByGeocode, ISearchByCenter, ISearchByViewPort {
+
+ private final static double SEARCH_DISTANCE_LIMIT = 15.0;
+ private final static double NEARBY_SEARCH_DISTANCE = 5.0;
+
+ public OCXMLApiConnector(String name, String host, String prefix) {
+ super(name, host, prefix);
+ }
+
+ @Override
+ public SearchResult searchByGeocode(final String geocode, final String guid, CancellableHandler handler) {
+ final cgCache cache = OCXMLClient.getCache(geocode);
+ if (cache == null) {
+ return null;
+ }
+ return new SearchResult(cache);
+ }
+
+ @Override
+ public SearchResult searchByCenter(final Geopoint center) {
+ return new SearchResult(OCXMLClient.getCachesAround(center, NEARBY_SEARCH_DISTANCE));
+ }
+
+ @Override
+ public SearchResult searchByViewport(final Viewport viewport, final String[] tokens) {
+ final Geopoint center = viewport.getCenter();
+ double distance = center.distanceTo(viewport.bottomLeft) * 1.15;
+ if (distance > SEARCH_DISTANCE_LIMIT) {
+ distance = SEARCH_DISTANCE_LIMIT;
+ }
+ return new SearchResult(OCXMLClient.getCachesAround(center, distance));
+ }
+
+ @Override
+ public boolean isActivated() {
+ // currently only tested and working with oc.de
+ return Settings.isOCConnectorActive();
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/oc/OCXMLClient.java b/main/src/cgeo/geocaching/connector/oc/OCXMLClient.java
new file mode 100644
index 0000000..26b42e3
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/oc/OCXMLClient.java
@@ -0,0 +1,110 @@
+package cgeo.geocaching.connector.oc;
+
+import cgeo.geocaching.cgCache;
+import cgeo.geocaching.cgData;
+import cgeo.geocaching.connector.ConnectorFactory;
+import cgeo.geocaching.connector.IConnector;
+import cgeo.geocaching.enumerations.LoadFlags;
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.geopoint.GeopointFormatter;
+import cgeo.geocaching.network.Network;
+import cgeo.geocaching.network.Parameters;
+import cgeo.geocaching.utils.Log;
+
+import ch.boye.httpclientandroidlib.HttpResponse;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Locale;
+import java.util.zip.GZIPInputStream;
+
+public class OCXMLClient {
+
+ private static final String SERVICE_CACHE = "/xml/ocxml11.php";
+
+ // Url for single cache requests
+ // http://www.opencaching.de/xml/ocxml11.php?modifiedsince=20060320000000&user=0&cache=1&cachedesc=1&cachelog=1&picture=1&removedobject=0&session=0&doctype=0&charset=utf-8&wp=OCC9BE
+
+ public static cgCache getCache(final String geoCode) {
+ try {
+ final Parameters params = getOCXmlQueryParameters(true, true);
+ params.put("wp", geoCode);
+ final InputStream data = request(ConnectorFactory.getConnector(geoCode), SERVICE_CACHE, params);
+
+ if (data == null) {
+ return null;
+ }
+
+ Collection<cgCache> caches = OC11XMLParser.parseCaches(new GZIPInputStream(data));
+ if (caches.iterator().hasNext()) {
+ cgCache cache = caches.iterator().next();
+ cache.setDetailed(true);
+ cgData.saveCache(cache, LoadFlags.SAVE_ALL);
+ return cache;
+ }
+ return null;
+ } catch (IOException e) {
+ Log.e("Error parsing cache '" + geoCode + "': " + e.toString());
+ return null;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Collection<cgCache> getCachesAround(final Geopoint center, final double distance) {
+ try {
+ final Parameters params = getOCXmlQueryParameters(false, false);
+ params.put("lat", GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, center));
+ params.put("lon", GeopointFormatter.format(GeopointFormatter.Format.LON_DECDEGREE_RAW, center));
+ params.put("distance", String.format(Locale.US, "%f", distance));
+ final InputStream data = request(ConnectorFactory.getConnector("OCXXX"), SERVICE_CACHE, params);
+
+ if (data == null) {
+ return CollectionUtils.EMPTY_COLLECTION;
+ }
+
+ return OC11XMLParser.parseCaches(new GZIPInputStream(data));
+ } catch (IOException e) {
+ Log.e("Error parsing nearby search result: " + e.toString());
+ return CollectionUtils.EMPTY_COLLECTION;
+ }
+ }
+
+ private static InputStream request(final IConnector connector, final String service, final Parameters params) {
+ if (connector == null) {
+ return null;
+ }
+ if (!(connector instanceof OCXMLApiConnector)) {
+ return null;
+ }
+
+ final String host = connector.getHost();
+ if (StringUtils.isBlank(host)) {
+ return null;
+ }
+
+ final String uri = "http://" + host + service;
+ HttpResponse resp = Network.getRequest(uri, params);
+ if (resp != null) {
+ try {
+ return resp.getEntity().getContent();
+ } catch (IllegalStateException e) {
+ // fall through and return null
+ } catch (IOException e) {
+ // fall through and return null
+ }
+ }
+ return null;
+ }
+
+ private static Parameters getOCXmlQueryParameters(final boolean withDescription, final boolean withLogs) {
+ final Parameters params = new Parameters("modifiedsince", "20060320000000",
+ "user", "0", "cache", "1", "cachedesc", withDescription ? "1" : "0",
+ "cachelog", withLogs ? "1" : "0", "picture", "0", "removedobject", "0",
+ "session", "0", "doctype", "0", "charset", "utf-8", "zip", "gzip");
+ return params;
+ }
+}
diff --git a/main/src/cgeo/geocaching/enumerations/CacheRealm.java b/main/src/cgeo/geocaching/enumerations/CacheRealm.java
new file mode 100644
index 0000000..5a203ab
--- /dev/null
+++ b/main/src/cgeo/geocaching/enumerations/CacheRealm.java
@@ -0,0 +1,22 @@
+package cgeo.geocaching.enumerations;
+
+import cgeo.geocaching.R;
+
+public enum CacheRealm {
+
+ GC("gc", "geocaching.com", R.drawable.marker, R.drawable.marker_disabled),
+ OC("oc", "OpenCaching Network", R.drawable.marker_oc, R.drawable.marker_disabled_oc),
+ OTHER("other", "Other", R.drawable.marker_other, R.drawable.marker_disabled_other);
+
+ public final String id;
+ public final String name;
+ public final int markerId;
+ public final int markerDisabledId;
+
+ CacheRealm(String id, String name, int markerId, int markerDisabledId) {
+ this.id = id;
+ this.name = name;
+ this.markerId = markerId;
+ this.markerDisabledId = markerDisabledId;
+ }
+}
diff --git a/main/src/cgeo/geocaching/geopoint/Geopoint.java b/main/src/cgeo/geocaching/geopoint/Geopoint.java
index 0dfdbcb..428ebbd 100644
--- a/main/src/cgeo/geocaching/geopoint/Geopoint.java
+++ b/main/src/cgeo/geocaching/geopoint/Geopoint.java
@@ -23,6 +23,8 @@ public final class Geopoint implements ICoordinates, Parcelable {
public static final double rad2deg = 180 / Math.PI;
public static final float erad = 6371.0f;
+ public static final Geopoint ZERO = new Geopoint(0.0, 0.0);
+
private final double latitude;
private final double longitude;
diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java
index 32814c4..356f763 100644
--- a/main/src/cgeo/geocaching/maps/CGeoMap.java
+++ b/main/src/cgeo/geocaching/maps/CGeoMap.java
@@ -1634,6 +1634,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
.append(cache.isReliableLatLon())
.append(cache.getType().id)
.append(cache.isDisabled() || cache.isArchived())
+ .append(cache.getCacheRealm().id)
.append(cache.isOwn())
.append(cache.isFound())
.append(cache.hasUserModifiedCoords())
@@ -1653,7 +1654,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
final ArrayList<int[]> insets = new ArrayList<int[]>(8);
// background: disabled or not
- final Drawable marker = getResources().getDrawable(cache.isDisabled() || cache.isArchived() ? R.drawable.marker_disabled : R.drawable.marker);
+ final Drawable marker = getResources().getDrawable(cache.isDisabled() || cache.isArchived() ? cache.getCacheRealm().markerDisabledId : cache.getCacheRealm().markerId);
layers.add(marker);
final int resolution = marker.getIntrinsicWidth() > 40 ? 1 : 0;
// reliable or not