aboutsummaryrefslogtreecommitdiffstats
path: root/src/cgeo/geocaching
diff options
context:
space:
mode:
Diffstat (limited to 'src/cgeo/geocaching')
-rw-r--r--src/cgeo/geocaching/cg8.java17
-rw-r--r--src/cgeo/geocaching/cg8wrap.java27
-rw-r--r--src/cgeo/geocaching/cgAddressImg.java60
-rw-r--r--src/cgeo/geocaching/cgBase.java5828
-rw-r--r--src/cgeo/geocaching/cgCache.java218
-rw-r--r--src/cgeo/geocaching/cgCacheDifficultyComparator.java26
-rw-r--r--src/cgeo/geocaching/cgCacheDistanceComparator.java51
-rw-r--r--src/cgeo/geocaching/cgCacheGeocodeComparator.java26
-rw-r--r--src/cgeo/geocaching/cgCacheInventoryComparator.java36
-rw-r--r--src/cgeo/geocaching/cgCacheListAdapter.java909
-rw-r--r--src/cgeo/geocaching/cgCacheNameComparator.java20
-rw-r--r--src/cgeo/geocaching/cgCachePopularityComparator.java26
-rw-r--r--src/cgeo/geocaching/cgCacheRatingComparator.java36
-rw-r--r--src/cgeo/geocaching/cgCacheSizeComparator.java47
-rw-r--r--src/cgeo/geocaching/cgCacheTerrainComparator.java26
-rw-r--r--src/cgeo/geocaching/cgCacheView.java29
-rw-r--r--src/cgeo/geocaching/cgCacheVisitComparator.java27
-rw-r--r--src/cgeo/geocaching/cgCacheVoteComparator.java38
-rw-r--r--src/cgeo/geocaching/cgCacheWrap.java12
-rw-r--r--src/cgeo/geocaching/cgCompass.java322
-rw-r--r--src/cgeo/geocaching/cgCompassMini.java176
-rw-r--r--src/cgeo/geocaching/cgCoord.java46
-rw-r--r--src/cgeo/geocaching/cgData.java3046
-rw-r--r--src/cgeo/geocaching/cgDirection.java102
-rw-r--r--src/cgeo/geocaching/cgDirectionImg.java96
-rw-r--r--src/cgeo/geocaching/cgDistanceView.java45
-rw-r--r--src/cgeo/geocaching/cgGPXListAdapter.java75
-rw-r--r--src/cgeo/geocaching/cgGPXParser.java547
-rw-r--r--src/cgeo/geocaching/cgGPXView.java9
-rw-r--r--src/cgeo/geocaching/cgGeo.java445
-rw-r--r--src/cgeo/geocaching/cgHtmlImg.java286
-rw-r--r--src/cgeo/geocaching/cgList.java20
-rw-r--r--src/cgeo/geocaching/cgLog.java12
-rw-r--r--src/cgeo/geocaching/cgLogForm.java10
-rw-r--r--src/cgeo/geocaching/cgMapImg.java114
-rw-r--r--src/cgeo/geocaching/cgOAuth.java53
-rw-r--r--src/cgeo/geocaching/cgRating.java7
-rw-r--r--src/cgeo/geocaching/cgResponse.java40
-rw-r--r--src/cgeo/geocaching/cgSearch.java39
-rw-r--r--src/cgeo/geocaching/cgSearchHandler.java104
-rw-r--r--src/cgeo/geocaching/cgSearchThread.java46
-rw-r--r--src/cgeo/geocaching/cgSettings.java513
-rw-r--r--src/cgeo/geocaching/cgSpoiler.java7
-rw-r--r--src/cgeo/geocaching/cgTrackable.java35
-rw-r--r--src/cgeo/geocaching/cgTrackableLog.java9
-rw-r--r--src/cgeo/geocaching/cgUpdateDir.java7
-rw-r--r--src/cgeo/geocaching/cgUpdateLoc.java7
-rw-r--r--src/cgeo/geocaching/cgUser.java12
-rw-r--r--src/cgeo/geocaching/cgWarning.java52
-rw-r--r--src/cgeo/geocaching/cgWaypoint.java16
-rw-r--r--src/cgeo/geocaching/cgeo.java669
-rw-r--r--src/cgeo/geocaching/cgeoabout.java110
-rw-r--r--src/cgeo/geocaching/cgeoaddresses.java201
-rw-r--r--src/cgeo/geocaching/cgeoadvsearch.java552
-rw-r--r--src/cgeo/geocaching/cgeoapplication.java828
-rw-r--r--src/cgeo/geocaching/cgeoauth.java413
-rw-r--r--src/cgeo/geocaching/cgeocaches.java2193
-rw-r--r--src/cgeo/geocaching/cgeodate.java62
-rw-r--r--src/cgeo/geocaching/cgeodetail.java1902
-rw-r--r--src/cgeo/geocaching/cgeogpxes.java292
-rw-r--r--src/cgeo/geocaching/cgeohelpers.java107
-rw-r--r--src/cgeo/geocaching/cgeoinit.java965
-rw-r--r--src/cgeo/geocaching/cgeonavigate.java503
-rw-r--r--src/cgeo/geocaching/cgeopoint.java535
-rw-r--r--src/cgeo/geocaching/cgeopopup.java834
-rw-r--r--src/cgeo/geocaching/cgeosmaps.java172
-rw-r--r--src/cgeo/geocaching/cgeospoilers.java231
-rw-r--r--src/cgeo/geocaching/cgeotouch.java487
-rw-r--r--src/cgeo/geocaching/cgeotrackable.java671
-rw-r--r--src/cgeo/geocaching/cgeotrackables.java186
-rw-r--r--src/cgeo/geocaching/cgeovisit.java912
-rw-r--r--src/cgeo/geocaching/cgeowaypoint.java465
-rw-r--r--src/cgeo/geocaching/cgeowaypointadd.java434
-rw-r--r--src/cgeo/geocaching/filter/cgFilter.java20
-rw-r--r--src/cgeo/geocaching/filter/cgFilterBySize.java17
-rw-r--r--src/cgeo/geocaching/filter/cgFilterByTrackables.java12
-rw-r--r--src/cgeo/geocaching/filter/cgFilterByType.java17
-rw-r--r--src/cgeo/geocaching/googlemaps/googleCacheOverlay.java101
-rw-r--r--src/cgeo/geocaching/googlemaps/googleCacheOverlayItem.java28
-rw-r--r--src/cgeo/geocaching/googlemaps/googleGeoPoint.java13
-rw-r--r--src/cgeo/geocaching/googlemaps/googleMapActivity.java101
-rw-r--r--src/cgeo/geocaching/googlemaps/googleMapController.java37
-rw-r--r--src/cgeo/geocaching/googlemaps/googleMapFactory.java54
-rw-r--r--src/cgeo/geocaching/googlemaps/googleMapProjection.java28
-rw-r--r--src/cgeo/geocaching/googlemaps/googleMapView.java118
-rw-r--r--src/cgeo/geocaching/googlemaps/googleOverlay.java26
-rw-r--r--src/cgeo/geocaching/googlemaps/googleUsersOverlay.java94
-rw-r--r--src/cgeo/geocaching/googlemaps/googleUsersOverlayItem.java43
-rw-r--r--src/cgeo/geocaching/mapcommon/ItemizedOverlayBase.java57
-rw-r--r--src/cgeo/geocaching/mapcommon/MapBase.java64
-rw-r--r--src/cgeo/geocaching/mapcommon/cgMapMyOverlay.java198
-rw-r--r--src/cgeo/geocaching/mapcommon/cgMapOverlay.java322
-rw-r--r--src/cgeo/geocaching/mapcommon/cgOverlayScale.java140
-rw-r--r--src/cgeo/geocaching/mapcommon/cgUsersOverlay.java185
-rw-r--r--src/cgeo/geocaching/mapcommon/cgeomap.java1686
-rw-r--r--src/cgeo/geocaching/mapinterfaces/ActivityImpl.java33
-rw-r--r--src/cgeo/geocaching/mapinterfaces/CacheOverlayItemImpl.java17
-rw-r--r--src/cgeo/geocaching/mapinterfaces/GeoPointImpl.java15
-rw-r--r--src/cgeo/geocaching/mapinterfaces/ItemizedOverlayImpl.java33
-rw-r--r--src/cgeo/geocaching/mapinterfaces/MapControllerImpl.java19
-rw-r--r--src/cgeo/geocaching/mapinterfaces/MapFactory.java30
-rw-r--r--src/cgeo/geocaching/mapinterfaces/MapProjectionImpl.java17
-rw-r--r--src/cgeo/geocaching/mapinterfaces/MapViewImpl.java64
-rw-r--r--src/cgeo/geocaching/mapinterfaces/OverlayBase.java19
-rw-r--r--src/cgeo/geocaching/mapinterfaces/OverlayImpl.java11
-rw-r--r--src/cgeo/geocaching/mapinterfaces/OverlayItemImpl.java18
-rw-r--r--src/cgeo/geocaching/mapinterfaces/UserOverlayItemImpl.java14
-rw-r--r--src/cgeo/geocaching/mapsforge/mfCacheOverlay.java99
-rw-r--r--src/cgeo/geocaching/mapsforge/mfCacheOverlayItem.java35
-rw-r--r--src/cgeo/geocaching/mapsforge/mfGeoPoint.java12
-rw-r--r--src/cgeo/geocaching/mapsforge/mfMapActivity.java96
-rw-r--r--src/cgeo/geocaching/mapsforge/mfMapController.java43
-rw-r--r--src/cgeo/geocaching/mapsforge/mfMapFactory.java54
-rw-r--r--src/cgeo/geocaching/mapsforge/mfMapProjection.java28
-rw-r--r--src/cgeo/geocaching/mapsforge/mfMapView.java159
-rw-r--r--src/cgeo/geocaching/mapsforge/mfOverlay.java26
-rw-r--r--src/cgeo/geocaching/mapsforge/mfUsersOverlay.java98
-rw-r--r--src/cgeo/geocaching/mapsforge/mfUsersOverlayItem.java43
118 files changed, 31825 insertions, 0 deletions
diff --git a/src/cgeo/geocaching/cg8.java b/src/cgeo/geocaching/cg8.java
new file mode 100644
index 0000000..698988e
--- /dev/null
+++ b/src/cgeo/geocaching/cg8.java
@@ -0,0 +1,17 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import android.view.Display;
+
+public class cg8 {
+ private Activity activity = null;
+
+ public cg8(Activity activityIn) {
+ activity = activityIn;
+ }
+
+ public int getRotation() {
+ Display display = activity.getWindowManager().getDefaultDisplay();
+ return display.getRotation();
+ }
+}
diff --git a/src/cgeo/geocaching/cg8wrap.java b/src/cgeo/geocaching/cg8wrap.java
new file mode 100644
index 0000000..2903c8d
--- /dev/null
+++ b/src/cgeo/geocaching/cg8wrap.java
@@ -0,0 +1,27 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+
+public class cg8wrap {
+ static {
+ try {
+ Class.forName("cgeo.geocaching.cg8");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private cg8 cg8;
+
+ public static void check() {
+ // nothing
+ }
+
+ public cg8wrap(Activity activityIn) {
+ cg8 = new cg8(activityIn);
+ }
+
+ public int getRotation() {
+ return cg8.getRotation();
+ }
+}
diff --git a/src/cgeo/geocaching/cgAddressImg.java b/src/cgeo/geocaching/cgAddressImg.java
new file mode 100644
index 0000000..bdc0ccf
--- /dev/null
+++ b/src/cgeo/geocaching/cgAddressImg.java
@@ -0,0 +1,60 @@
+package cgeo.geocaching;
+
+import android.util.Log;
+import android.graphics.Rect;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.entity.BufferedHttpEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+
+public class cgAddressImg {
+ public static BitmapDrawable getDrawable(String url) {
+ Bitmap imagePre = null;
+
+ if (url == null || url.length() == 0) return null;
+
+ HttpClient client = null;
+ HttpGet getMethod = null;
+ HttpResponse httpResponse = null;
+ HttpEntity entity = null;
+ BufferedHttpEntity bufferedEntity = null;
+
+ for (int i = 0; i < 2; i ++) {
+ if (i > 0) Log.w(cgSettings.tag, "cgAddressImg.getDrawable: Failed to download data, retrying. Attempt #" + (i + 1));
+
+ try {
+ client = new DefaultHttpClient();
+ getMethod = new HttpGet(url);
+ httpResponse = client.execute(getMethod);
+ entity = httpResponse.getEntity();
+ bufferedEntity = new BufferedHttpEntity(entity);
+
+ Log.i(cgSettings.tag, "[" + entity.getContentLength() + "B] Downloading address map " + url);
+
+ if (bufferedEntity != null) imagePre = BitmapFactory.decodeStream(bufferedEntity.getContent(), null, null);
+ if (imagePre != null) break;
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgAddressImg.getDrawable (downloading from web): " + e.toString());
+ }
+ }
+
+ if (imagePre == null) {
+ Log.d(cgSettings.tag, "cgAddressImg.getDrawable: Failed to obtain image");
+
+ return null;
+ }
+
+ final BitmapDrawable image = new BitmapDrawable(imagePre);
+ image.setBounds(new Rect(0, 0, imagePre.getWidth(), imagePre.getHeight()));
+
+ // imagePre.recycle();
+ imagePre = null;
+
+ return image;
+ }
+}
diff --git a/src/cgeo/geocaching/cgBase.java b/src/cgeo/geocaching/cgBase.java
new file mode 100644
index 0000000..9a13bda
--- /dev/null
+++ b/src/cgeo/geocaching/cgBase.java
@@ -0,0 +1,5828 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import java.io.InputStreamReader;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.net.URLConnection;
+import java.net.HttpURLConnection;
+import java.util.Map;
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import android.util.Log;
+import android.content.SharedPreferences;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Message;
+import android.text.Html;
+import android.text.Spannable;
+import android.text.style.StrikethroughSpan;
+import android.view.Display;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import com.google.android.apps.analytics.GoogleAnalyticsTracker;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.URLDecoder;
+import java.security.MessageDigest;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Set;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.Inflater;
+import java.util.zip.InflaterInputStream;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+public class cgBase {
+
+ public static HashMap<String, String> cacheTypes = new HashMap<String, String>();
+ public static HashMap<String, String> cacheTypesInv = new HashMap<String, String>();
+ public static HashMap<String, String> cacheIDs = new HashMap<String, String>();
+ public static HashMap<String, String> cacheIDsChoices = new HashMap<String, String>();
+ public static HashMap<String, String> waypointTypes = new HashMap<String, String>();
+ public static HashMap<String, Integer> logTypes = new HashMap<String, Integer>();
+ public static HashMap<String, Integer> logTypes0 = new HashMap<String, Integer>();
+ public static HashMap<Integer, String> logTypes1 = new HashMap<Integer, String>();
+ public static HashMap<Integer, String> logTypes2 = new HashMap<Integer, String>();
+ public static HashMap<Integer, String> logTypesTrackable = new HashMap<Integer, String>();
+ public static HashMap<Integer, String> logTypesTrackableAction = new HashMap<Integer, String>();
+ public static HashMap<Integer, String> errorRetrieve = new HashMap<Integer, String>();
+ public static SimpleDateFormat dateIn = new SimpleDateFormat("MM/dd/yyyy");
+ public static SimpleDateFormat dateEvIn = new SimpleDateFormat("dd MMMMM yyyy", Locale.ENGLISH); // 28 March 2009
+ public static SimpleDateFormat dateTbIn1 = new SimpleDateFormat("EEEEE, dd MMMMM yyyy", Locale.ENGLISH); // Saturday, 28 March 2009
+ public static SimpleDateFormat dateTbIn2 = new SimpleDateFormat("EEEEE, MMMMM dd, yyyy", Locale.ENGLISH); // Saturday, March 28, 2009
+ public static SimpleDateFormat dateSqlIn = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 2010-07-25 14:44:01
+ public static SimpleDateFormat dateGPXIn = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); // 2010-04-20T07:00:00Z
+ public static DateFormat dateOut = DateFormat.getDateInstance(DateFormat.LONG, Locale.getDefault());
+ public static DateFormat timeOut = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault());
+ public static DateFormat dateOutShort = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
+ private Resources res = null;
+ private HashMap<String, String> cookies = new HashMap<String, String>();
+ private final String passMatch = "[/\\?&]*[Pp]ass(word)?=[^&^#^$]+";
+ private final Pattern patternLoggedIn = Pattern.compile("<span class=\"Success\">You are logged in as[^<]*<strong[^>]*>([^<]+)</strong>[^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ private final Pattern patternLogged2In = Pattern.compile("<strong>[^\\w]*Hello,[^<]*<a[^>]+>([^<]+)</a>[^<]*</strong>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ private final Pattern patternViewstate = Pattern.compile("id=\"__VIEWSTATE\"[^(value)]+value=\"([^\"]+)\"[^>]+>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ private final Pattern patternViewstate1 = Pattern.compile("id=\"__VIEWSTATE1\"[^(value)]+value=\"([^\"]+)\"[^>]+>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ public static final double kmInMiles = 1 / 1.609344;
+ public static final double deg2rad = Math.PI / 180;
+ public static final double rad2deg = 180 / Math.PI;
+ public static final float erad = 6371.0f;
+ public static final int mapAppAny = 0;
+ public static final int mapAppLocus = 1;
+ public static final int mapAppRmaps = 2;
+ private cgeoapplication app = null;
+ private cgSettings settings = null;
+ private SharedPreferences prefs = null;
+ public String version = null;
+ private String idBrowser = "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.86 Safari/533.4";
+ Context context = null;
+ final private static HashMap<String, Integer> gcIcons = new HashMap<String, Integer>();
+ final private static HashMap<String, Integer> wpIcons = new HashMap<String, Integer>();
+
+ public static final int LOG_FOUND_IT = 2;
+ public static final int LOG_DIDNT_FIND_IT = 3;
+ public static final int LOG_NOTE = 4;
+ public static final int LOG_PUBLISH_LISTING = 1003; // unknown ID; used number doesn't match any GC.com's ID
+ public static final int LOG_ENABLE_LISTING = 23;
+ public static final int LOG_ARCHIVE = 5;
+ public static final int LOG_TEMP_DISABLE_LISTING = 22;
+ public static final int LOG_NEEDS_ARCHIVE = 7;
+ public static final int LOG_WILL_ATTEND = 9;
+ public static final int LOG_ATTENDED = 10;
+ public static final int LOG_RETRIEVED_IT = 13;
+ public static final int LOG_PLACED_IT = 14;
+ public static final int LOG_GRABBED_IT = 19;
+ public static final int LOG_NEEDS_MAINTENANCE = 45;
+ public static final int LOG_OWNER_MAINTENANCE = 46;
+ public static final int LOG_UPDATE_COORDINATES = 47;
+ public static final int LOG_DISCOVERED_IT = 48;
+ public static final int LOG_POST_REVIEWER_NOTE = 18;
+ public static final int LOG_VISIT = 1001; // unknown ID; used number doesn't match any GC.com's ID
+ public static final int LOG_WEBCAM_PHOTO_TAKEN = 11;
+ public static final int LOG_ANNOUNCEMENT = 74;
+
+ public cgBase(cgeoapplication appIn, cgSettings settingsIn, SharedPreferences prefsIn) {
+ context = appIn.getBaseContext();
+ res = appIn.getBaseContext().getResources();
+
+ // cache types
+ cacheTypes.put("traditional cache", "traditional");
+ cacheTypes.put("multi-cache", "multi");
+ cacheTypes.put("unknown cache", "mystery");
+ cacheTypes.put("letterbox hybrid", "letterbox");
+ cacheTypes.put("event cache", "event");
+ cacheTypes.put("mega-event cache", "mega");
+ cacheTypes.put("earthcache", "earth");
+ cacheTypes.put("cache in trash out event", "cito");
+ cacheTypes.put("webcam cache", "webcam");
+ cacheTypes.put("virtual cache", "virtual");
+ cacheTypes.put("wherigo cache", "wherigo");
+ cacheTypes.put("lost & found", "lostfound");
+ cacheTypes.put("project ape cache", "ape");
+ cacheTypes.put("groundspeak hq", "gchq");
+ cacheTypes.put("gps cache exhibit", "gps");
+
+ // cache types inverted
+ cacheTypesInv.put("traditional", res.getString(R.string.traditional));
+ cacheTypesInv.put("multi", res.getString(R.string.multi));
+ cacheTypesInv.put("mystery", res.getString(R.string.mystery));
+ cacheTypesInv.put("letterbox", res.getString(R.string.letterbox));
+ cacheTypesInv.put("event", res.getString(R.string.event));
+ cacheTypesInv.put("mega", res.getString(R.string.mega));
+ cacheTypesInv.put("earth", res.getString(R.string.earth));
+ cacheTypesInv.put("cito", res.getString(R.string.cito));
+ cacheTypesInv.put("webcam", res.getString(R.string.webcam));
+ cacheTypesInv.put("virtual", res.getString(R.string.virtual));
+ cacheTypesInv.put("wherigo", res.getString(R.string.wherigo));
+ cacheTypesInv.put("lostfound", res.getString(R.string.lostfound));
+ cacheTypesInv.put("ape", res.getString(R.string.ape));
+ cacheTypesInv.put("gchq", res.getString(R.string.gchq));
+ cacheTypesInv.put("gps", res.getString(R.string.gps));
+
+ // cache ids
+ cacheIDs.put("all", "9a79e6ce-3344-409c-bbe9-496530baf758"); // hard-coded also in cgSettings
+ cacheIDs.put("traditional", "32bc9333-5e52-4957-b0f6-5a2c8fc7b257");
+ cacheIDs.put("multi", "a5f6d0ad-d2f2-4011-8c14-940a9ebf3c74");
+ cacheIDs.put("mystery", "40861821-1835-4e11-b666-8d41064d03fe");
+ cacheIDs.put("letterbox", "4bdd8fb2-d7bc-453f-a9c5-968563b15d24");
+ cacheIDs.put("event", "69eb8534-b718-4b35-ae3c-a856a55b0874");
+ cacheIDs.put("mega-event", "69eb8535-b718-4b35-ae3c-a856a55b0874");
+ cacheIDs.put("earth", "c66f5cf3-9523-4549-b8dd-759cd2f18db8");
+ cacheIDs.put("cito", "57150806-bc1a-42d6-9cf0-538d171a2d22");
+ cacheIDs.put("webcam", "31d2ae3c-c358-4b5f-8dcd-2185bf472d3d");
+ cacheIDs.put("virtual", "294d4360-ac86-4c83-84dd-8113ef678d7e");
+ cacheIDs.put("wherigo", "0544fa55-772d-4e5c-96a9-36a51ebcf5c9");
+ cacheIDs.put("lostfound", "3ea6533d-bb52-42fe-b2d2-79a3424d4728");
+ cacheIDs.put("ape", "2555690d-b2bc-4b55-b5ac-0cb704c0b768");
+ cacheIDs.put("gchq", "416f2494-dc17-4b6a-9bab-1a29dd292d8c");
+ cacheIDs.put("gps", "72e69af2-7986-4990-afd9-bc16cbbb4ce3");
+
+ // cache choices
+ cacheIDsChoices.put(res.getString(R.string.all), cacheIDs.get("all"));
+ cacheIDsChoices.put(res.getString(R.string.traditional), cacheIDs.get("traditional"));
+ cacheIDsChoices.put(res.getString(R.string.multi), cacheIDs.get("multi"));
+ cacheIDsChoices.put(res.getString(R.string.mystery), cacheIDs.get("mystery"));
+ cacheIDsChoices.put(res.getString(R.string.letterbox), cacheIDs.get("letterbox"));
+ cacheIDsChoices.put(res.getString(R.string.event), cacheIDs.get("event"));
+ cacheIDsChoices.put(res.getString(R.string.mega), cacheIDs.get("mega"));
+ cacheIDsChoices.put(res.getString(R.string.earth), cacheIDs.get("earth"));
+ cacheIDsChoices.put(res.getString(R.string.cito), cacheIDs.get("cito"));
+ cacheIDsChoices.put(res.getString(R.string.webcam), cacheIDs.get("webcam"));
+ cacheIDsChoices.put(res.getString(R.string.virtual), cacheIDs.get("virtual"));
+ cacheIDsChoices.put(res.getString(R.string.wherigo), cacheIDs.get("whereigo"));
+ cacheIDsChoices.put(res.getString(R.string.lostfound), cacheIDs.get("lostfound"));
+ cacheIDsChoices.put(res.getString(R.string.ape), cacheIDs.get("ape"));
+ cacheIDsChoices.put(res.getString(R.string.gchq), cacheIDs.get("gchq"));
+ cacheIDsChoices.put(res.getString(R.string.gps), cacheIDs.get("gps"));
+
+ // waypoint types
+ waypointTypes.put("flag", res.getString(R.string.wp_final));
+ waypointTypes.put("stage", res.getString(R.string.wp_stage));
+ waypointTypes.put("puzzle", res.getString(R.string.wp_puzzle));
+ waypointTypes.put("pkg", res.getString(R.string.wp_pkg));
+ waypointTypes.put("trailhead", res.getString(R.string.wp_trailhead));
+ waypointTypes.put("waypoint", res.getString(R.string.wp_waypoint));
+
+ // log types
+ logTypes.put("icon_smile", LOG_FOUND_IT);
+ logTypes.put("icon_sad", LOG_DIDNT_FIND_IT);
+ logTypes.put("icon_note", LOG_NOTE);
+ logTypes.put("icon_greenlight", LOG_PUBLISH_LISTING);
+ logTypes.put("icon_enabled", LOG_ENABLE_LISTING);
+ logTypes.put("traffic_cone", LOG_ARCHIVE);
+ logTypes.put("icon_disabled", LOG_TEMP_DISABLE_LISTING);
+ logTypes.put("icon_remove", LOG_NEEDS_ARCHIVE);
+ logTypes.put("icon_rsvp", LOG_WILL_ATTEND);
+ logTypes.put("icon_attended", LOG_ATTENDED);
+ logTypes.put("picked_up", LOG_RETRIEVED_IT);
+ logTypes.put("dropped_off", LOG_PLACED_IT);
+ logTypes.put("transfer", LOG_GRABBED_IT);
+ logTypes.put("icon_needsmaint", LOG_NEEDS_MAINTENANCE);
+ logTypes.put("icon_maint", LOG_OWNER_MAINTENANCE);
+ logTypes.put("coord_update", LOG_UPDATE_COORDINATES);
+ logTypes.put("icon_discovered", LOG_DISCOVERED_IT);
+ logTypes.put("big_smile", LOG_POST_REVIEWER_NOTE);
+ logTypes.put("icon_visited", LOG_VISIT); // unknown ID; used number doesn't match any GC.com's ID
+ logTypes.put("icon_camera", LOG_WEBCAM_PHOTO_TAKEN); // unknown ID; used number doesn't match any GC.com's ID
+ logTypes.put("icon_announcement", LOG_ANNOUNCEMENT); // unknown ID; used number doesn't match any GC.com's ID
+
+ logTypes0.put("found it", LOG_FOUND_IT);
+ logTypes0.put("didn't find it", LOG_DIDNT_FIND_IT);
+ logTypes0.put("write note", LOG_NOTE);
+ logTypes0.put("publish listing", LOG_PUBLISH_LISTING);
+ logTypes0.put("enable listing", LOG_ENABLE_LISTING);
+ logTypes0.put("archive", LOG_ARCHIVE);
+ logTypes0.put("temporarily disable listing", LOG_TEMP_DISABLE_LISTING);
+ logTypes0.put("needs archived", LOG_NEEDS_ARCHIVE);
+ logTypes0.put("will attend", LOG_WILL_ATTEND);
+ logTypes0.put("attended", LOG_ATTENDED);
+ logTypes0.put("retrieved it", LOG_RETRIEVED_IT);
+ logTypes0.put("placed it", LOG_PLACED_IT);
+ logTypes0.put("grabbed it", LOG_GRABBED_IT);
+ logTypes0.put("needs maintenance", LOG_NEEDS_MAINTENANCE);
+ logTypes0.put("owner maintenance", LOG_OWNER_MAINTENANCE);
+ logTypes0.put("update coordinates", LOG_UPDATE_COORDINATES);
+ logTypes0.put("discovered it", LOG_DISCOVERED_IT);
+ logTypes0.put("post reviewer note", LOG_POST_REVIEWER_NOTE);
+ logTypes0.put("visit", LOG_VISIT); // unknown ID; used number doesn't match any GC.com's ID
+ logTypes0.put("webcam photo taken", LOG_WEBCAM_PHOTO_TAKEN); // unknown ID; used number doesn't match any GC.com's ID
+ logTypes0.put("announcement", LOG_ANNOUNCEMENT); // unknown ID; used number doesn't match any GC.com's ID
+
+ logTypes1.put(LOG_FOUND_IT, res.getString(R.string.log_found));
+ logTypes1.put(LOG_DIDNT_FIND_IT, res.getString(R.string.log_dnf));
+ logTypes1.put(LOG_NOTE, res.getString(R.string.log_note));
+ logTypes1.put(LOG_PUBLISH_LISTING, res.getString(R.string.log_published));
+ logTypes1.put(LOG_ENABLE_LISTING, res.getString(R.string.log_enabled));
+ logTypes1.put(LOG_ARCHIVE, res.getString(R.string.log_archived));
+ logTypes1.put(LOG_TEMP_DISABLE_LISTING, res.getString(R.string.log_disabled));
+ logTypes1.put(LOG_NEEDS_ARCHIVE, res.getString(R.string.log_needs_archived));
+ logTypes1.put(LOG_WILL_ATTEND, res.getString(R.string.log_attend));
+ logTypes1.put(LOG_ATTENDED, res.getString(R.string.log_attended));
+ logTypes1.put(LOG_RETRIEVED_IT, res.getString(R.string.log_retrieved));
+ logTypes1.put(LOG_PLACED_IT, res.getString(R.string.log_placed));
+ logTypes1.put(LOG_GRABBED_IT, res.getString(R.string.log_grabbed));
+ logTypes1.put(LOG_NEEDS_MAINTENANCE, res.getString(R.string.log_maintenance_needed));
+ logTypes1.put(LOG_OWNER_MAINTENANCE, res.getString(R.string.log_maintained));
+ logTypes1.put(LOG_UPDATE_COORDINATES, res.getString(R.string.log_update));
+ logTypes1.put(LOG_DISCOVERED_IT, res.getString(R.string.log_discovered));
+ logTypes1.put(LOG_POST_REVIEWER_NOTE, res.getString(R.string.log_reviewed));
+ logTypes1.put(LOG_VISIT, res.getString(R.string.log_taken));
+ logTypes1.put(LOG_WEBCAM_PHOTO_TAKEN, res.getString(R.string.log_webcam));
+ logTypes1.put(LOG_ANNOUNCEMENT, res.getString(R.string.log_announcement));
+
+ logTypes2.put(LOG_FOUND_IT, res.getString(R.string.log_found)); // traditional, multi, unknown, earth, wherigo, virtual, letterbox
+ logTypes2.put(LOG_DIDNT_FIND_IT, res.getString(R.string.log_dnf)); // traditional, multi, unknown, earth, wherigo, virtual, letterbox, webcam
+ logTypes2.put(LOG_NOTE, res.getString(R.string.log_note)); // traditional, multi, unknown, earth, wherigo, virtual, event, letterbox, webcam, trackable
+ logTypes2.put(LOG_PUBLISH_LISTING, res.getString(R.string.log_published)); // X
+ logTypes2.put(LOG_ENABLE_LISTING, res.getString(R.string.log_enabled)); // owner
+ logTypes2.put(LOG_ARCHIVE, res.getString(R.string.log_archived)); // traditional, multi, unknown, earth, event, wherigo, virtual, letterbox, webcam
+ logTypes2.put(LOG_TEMP_DISABLE_LISTING, res.getString(R.string.log_disabled)); // owner
+ logTypes2.put(LOG_NEEDS_ARCHIVE, res.getString(R.string.log_needs_archived)); // traditional, multi, unknown, earth, event, wherigo, virtual, letterbox, webcam
+ logTypes2.put(LOG_WILL_ATTEND, res.getString(R.string.log_attend)); // event
+ logTypes2.put(LOG_ATTENDED, res.getString(R.string.log_attended)); // event
+ logTypes2.put(LOG_WEBCAM_PHOTO_TAKEN, res.getString(R.string.log_webcam)); // webcam
+ logTypes2.put(LOG_RETRIEVED_IT, res.getString(R.string.log_retrieved)); //trackable
+ logTypes2.put(LOG_GRABBED_IT, res.getString(R.string.log_grabbed)); //trackable
+ logTypes2.put(LOG_NEEDS_MAINTENANCE, res.getString(R.string.log_maintenance_needed)); // traditional, unknown, multi, wherigo, virtual, letterbox, webcam
+ logTypes2.put(LOG_OWNER_MAINTENANCE, res.getString(R.string.log_maintained)); // owner
+ logTypes2.put(LOG_DISCOVERED_IT, res.getString(R.string.log_discovered)); //trackable
+ logTypes2.put(LOG_POST_REVIEWER_NOTE, res.getString(R.string.log_reviewed)); // X
+ logTypes2.put(LOG_ANNOUNCEMENT, res.getString(R.string.log_announcement)); // X
+
+ // trackables for logs
+ logTypesTrackable.put(0, res.getString(R.string.log_tb_nothing)); // do nothing
+ logTypesTrackable.put(1, res.getString(R.string.log_tb_visit)); // visit cache
+ logTypesTrackable.put(2, res.getString(R.string.log_tb_drop)); // drop here
+ logTypesTrackableAction.put(0, ""); // do nothing
+ logTypesTrackableAction.put(1, "_Visited"); // visit cache
+ logTypesTrackableAction.put(2, "_DroppedOff"); // drop here
+
+ // retrieving errors (because of ____ )
+ errorRetrieve.put(1, res.getString(R.string.err_none));
+ errorRetrieve.put(0, res.getString(R.string.err_start));
+ errorRetrieve.put(-1, res.getString(R.string.err_parse));
+ errorRetrieve.put(-2, res.getString(R.string.err_server));
+ errorRetrieve.put(-3, res.getString(R.string.err_login));
+ errorRetrieve.put(-4, res.getString(R.string.err_unknown));
+ errorRetrieve.put(-5, res.getString(R.string.err_comm));
+ errorRetrieve.put(-6, res.getString(R.string.err_wrong));
+ errorRetrieve.put(-7, res.getString(R.string.err_license));
+
+ // init
+ app = appIn;
+ settings = settingsIn;
+ prefs = prefsIn;
+
+ try {
+ PackageManager manager = app.getPackageManager();
+ PackageInfo info = manager.getPackageInfo(app.getPackageName(), 0);
+ version = info.versionName;
+ } catch (Exception e) {
+ // nothing
+ }
+
+ if (settings.asBrowser == 1) {
+ final long rndBrowser = Math.round(Math.random() * 6);
+ if (rndBrowser == 0) {
+ idBrowser = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.1 (KHTML, like Gecko) Chrome/5.0.322.2 Safari/533.1";
+ } else if (rndBrowser == 1) {
+ idBrowser = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; MDDC)";
+ } else if (rndBrowser == 2) {
+ idBrowser = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3";
+ } else if (rndBrowser == 3) {
+ idBrowser = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-us) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10";
+ } else if (rndBrowser == 4) {
+ idBrowser = "Mozilla/5.0 (iPod; U; CPU iPhone OS 2_2_1 like Mac OS X; en-us) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5H11a Safari/525.20";
+ } else if (rndBrowser == 5) {
+ idBrowser = "Mozilla/5.0 (Linux; U; Android 1.1; en-gb; dream) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2";
+ } else if (rndBrowser == 6) {
+ idBrowser = "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.86 Safari/533.4";
+ } else {
+ idBrowser = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.307.11 Safari/532.9";
+ }
+ }
+ }
+
+ public String findViewstate(String page, int index) {
+ String viewstate = null;
+
+ if (index == 0) {
+ final Matcher matcherViewstate = patternViewstate.matcher(page);
+ while (matcherViewstate.find()) {
+ if (matcherViewstate.groupCount() > 0) {
+ viewstate = matcherViewstate.group(1);
+ }
+ }
+ } else if (index == 1) {
+ final Matcher matcherViewstate = patternViewstate1.matcher(page);
+ while (matcherViewstate.find()) {
+ if (matcherViewstate.groupCount() > 0) {
+ viewstate = matcherViewstate.group(1);
+ }
+ }
+ }
+
+ return viewstate;
+ }
+
+ public class loginThread extends Thread {
+
+ @Override
+ public void run() {
+ login();
+ }
+ }
+
+ public int login() {
+ final String host = "www.geocaching.com";
+ final String path = "/login/default.aspx";
+ cgResponse loginResponse = null;
+ String loginData = null;
+
+ String viewstate = null;
+ String viewstate1 = null;
+
+ final HashMap<String, String> loginStart = settings.getLogin();
+
+ if (loginStart == null) {
+ return -3; // no login information stored
+ }
+
+ loginResponse = request(true, host, path, "GET", new HashMap<String, String>(), false, false, false);
+ loginData = loginResponse.getData();
+ if (loginData != null && loginData.length() > 0) {
+ if (checkLogin(loginData) == true) {
+ Log.i(cgSettings.tag, "Already logged in Geocaching.com as " + loginStart.get("username"));
+
+ switchToEnglish(viewstate, viewstate1);
+
+ return 1; // logged in
+ }
+
+ viewstate = findViewstate(loginData, 0);
+ viewstate1 = findViewstate(loginData, 1);
+
+ if (viewstate == null || viewstate.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.login: Failed to find viewstate");
+ return -1; // no viewstate
+ }
+ } else {
+ Log.e(cgSettings.tag, "cgeoBase.login: Failed to retrieve login page (1st)");
+ return -2; // no loginpage
+ }
+
+ final HashMap<String, String> login = settings.getLogin();
+ final HashMap<String, String> params = new HashMap<String, String>();
+
+ if (login == null || login.get("username") == null || login.get("username").length() == 0 || login.get("password") == null || login.get("password").length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.login: No login information stored");
+ return -3;
+ }
+
+ settings.deleteCookies();
+
+ params.put("__EVENTTARGET", "");
+ params.put("__EVENTARGUMENT", "");
+ params.put("__VIEWSTATE", viewstate);
+ if (viewstate1 != null) {
+ params.put("__VIEWSTATE1", viewstate1);
+ params.put("__VIEWSTATEFIELDCOUNT", "2");
+ }
+ params.put("ctl00$SiteContent$tbUsername", login.get("username"));
+ params.put("ctl00$SiteContent$tbPassword", login.get("password"));
+ params.put("ctl00$SiteContent$cbRememberMe", "on");
+ params.put("ctl00$SiteContent$btnSignIn", "Login");
+
+ loginResponse = request(true, host, path, "POST", params, false, false, false);
+ loginData = loginResponse.getData();
+
+ if (loginData != null && loginData.length() > 0) {
+ if (checkLogin(loginData) == true) {
+ Log.i(cgSettings.tag, "Successfully logged in Geocaching.com as " + login.get("username"));
+
+ switchToEnglish(findViewstate(loginData, 0), findViewstate(loginData, 1));
+
+ return 1; // logged in
+ } else {
+ if (loginData.indexOf("Your username/password combination does not match.") != -1) {
+ Log.i(cgSettings.tag, "Failed to log in Geocaching.com as " + login.get("username") + " because of wrong username/password");
+
+ return -6; // wrong login
+ } else {
+ Log.i(cgSettings.tag, "Failed to log in Geocaching.com as " + login.get("username") + " for some unknown reason");
+
+ return -4; // can't login
+ }
+ }
+ } else {
+ Log.e(cgSettings.tag, "cgeoBase.login: Failed to retrieve login page (2nd)");
+
+ return -5; // no login page
+ }
+ }
+
+ public Boolean checkLogin(String page) {
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.checkLogin: No page given");
+ return false;
+ }
+
+ // on every page
+ final Matcher matcherLogged2In = patternLogged2In.matcher(page);
+ while (matcherLogged2In.find()) {
+ return true;
+ }
+
+ // after login
+ final Matcher matcherLoggedIn = patternLoggedIn.matcher(page);
+ while (matcherLoggedIn.find()) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public String switchToEnglish(String viewstate, String viewstate1) {
+ final String host = "www.geocaching.com";
+ final String path = "/default.aspx";
+ final HashMap<String, String> params = new HashMap<String, String>();
+
+ if (viewstate != null) {
+ params.put("__VIEWSTATE", viewstate);
+ }
+ if (viewstate1 != null) {
+ params.put("__VIEWSTATE1", viewstate1);
+ params.put("__VIEWSTATEFIELDCOUNT", "2");
+ }
+ params.put("__EVENTTARGET", "ctl00$uxLocaleList$uxLocaleList$ctl00$uxLocaleItem"); // switch to english
+ params.put("__EVENTARGUMENT", "");
+
+ return request(false, host, path, "POST", params, false, false, false).getData();
+ }
+
+ public cgCacheWrap parseSearch(cgSearchThread thread, String url, String page, boolean showCaptcha) {
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.parseSearch: No page given");
+ return null;
+ }
+
+ final cgCacheWrap caches = new cgCacheWrap();
+ final ArrayList<String> cids = new ArrayList<String>();
+ final ArrayList<String> guids = new ArrayList<String>();
+ String recaptchaChallenge = null;
+ String recaptchaText = null;
+
+ caches.url = url;
+
+ final Pattern patternCacheType = Pattern.compile("<td class=\"Merge\">[^<]*<a href=\"[^\"]*/seek/cache_details\\.aspx\\?guid=[^\"]+\"[^>]+>[^<]*<img src=\"[^\"]*/images/wpttypes/[^\\.]+\\.gif\" alt=\"([^\"]+)\" title=\"[^\"]+\"[^>]*>[^<]*</a>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternGuidAndDisabled = Pattern.compile("<img src=\"[^\"]*/images/wpttypes/[^>]*>[^<]*</a></td><td class=\"Merge\">[^<]*<a href=\"[^\"]*/seek/cache_details\\.aspx\\?guid=([a-z0-9\\-]+)\" class=\"lnk([^\"]*)\">([^<]*<span>)?([^<]*)(</span>[^<]*)?</a>[^<]+<br />([^<]*)<span[^>]+>([^<]*)</span>([^<]*<img[^>]+>)?[^<]*<br />[^<]*</td>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternTbs = Pattern.compile("<a id=\"ctl00_ContentBody_dlResults_ctl[0-9]+_uxTravelBugList\" class=\"tblist\" data-tbcount=\"([0-9]+)\" data-id=\"[^\"]*\"[^>]*>(.*)</a>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternTbsInside = Pattern.compile("(<img src=\"[^\"]+\" alt=\"([^\"]+)\" title=\"[^\"]*\" />[^<]*)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternDirection = Pattern.compile("<img id=\"ctl00_ContentBody_dlResults_ctl[0-9]+_uxDistanceAndHeading\" title=\"[^\"]*\" src=\"[^\"]*/seek/CacheDir\\.ashx\\?k=([^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternCode = Pattern.compile("\\|[^\\w]*(GC[a-z0-9]+)[^\\|]*\\|", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternId = Pattern.compile("name=\"CID\"[^v]*value=\"([0-9]+)\"", Pattern.CASE_INSENSITIVE);
+ final Pattern patternFavourite = Pattern.compile("<span id=\"ctl00_ContentBody_dlResults_ctl[0-9]+_uxFavoritesValue\" title=\"[^\"]*\" class=\"favorite-rank\">([0-9]+)</span>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternTotalCnt = Pattern.compile("<td class=\"PageBuilderWidget\"><span>Total Records[^<]*<b>(\\d+)<\\/b>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternRecaptcha = Pattern.compile("<script[^>]*src=\"[^\"]*/recaptcha/api/challenge\\?k=([^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternRecaptchaChallenge = Pattern.compile("challenge : '([^']+)'", Pattern.CASE_INSENSITIVE);
+
+ caches.viewstate = findViewstate(page, 0);
+ caches.viewstate1 = findViewstate(page, 1);
+
+ // recaptcha
+ if (showCaptcha == true) {
+ try {
+ String recaptchaJsParam = null;
+ final Matcher matcherRecaptcha = patternRecaptcha.matcher(page);
+ while (matcherRecaptcha.find()) {
+ if (matcherRecaptcha.groupCount() > 0) {
+ recaptchaJsParam = matcherRecaptcha.group(1);
+ }
+ }
+
+ if (recaptchaJsParam != null) {
+ final String recaptchaJs = request(false, "www.google.com", "/recaptcha/api/challenge", "GET", "k=" + urlencode_rfc3986(recaptchaJsParam.trim()), 0, true).getData();
+
+ if (recaptchaJs != null && recaptchaJs.length() > 0) {
+ final Matcher matcherRecaptchaChallenge = patternRecaptchaChallenge.matcher(recaptchaJs);
+ while (matcherRecaptchaChallenge.find()) {
+ if (matcherRecaptchaChallenge.groupCount() > 0) {
+ recaptchaChallenge = matcherRecaptchaChallenge.group(1).trim();
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse recaptcha challenge
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse recaptcha challenge");
+ }
+
+ if (thread != null && recaptchaChallenge != null && recaptchaChallenge.length() > 0) {
+ thread.setChallenge(recaptchaChallenge);
+ thread.notifyNeed();
+ }
+ }
+
+ int startPos = -1;
+ int endPos = -1;
+
+ startPos = page.indexOf("<div id=\"ctl00_ContentBody_ResultsPanel\"");
+ if (startPos == -1) {
+ Log.e(cgSettings.tag, "cgeoBase.parseSearch: ID \"ctl00_ContentBody_dlResults\" not found on page");
+ return null;
+ }
+
+ page = page.substring(startPos); // cut on <table
+
+ startPos = page.indexOf(">");
+ endPos = page.indexOf("ctl00_ContentBody_UnitTxt");
+ if (startPos == -1 || endPos == -1) {
+ Log.e(cgSettings.tag, "cgeoBase.parseSearch: ID \"ctl00_ContentBody_UnitTxt\" not found on page");
+ return null;
+ }
+
+ page = page.substring(startPos + 1, endPos - startPos + 1); // cut between <table> and </table>
+
+ final String[] rows = page.split("<tr class=");
+ final int rows_count = rows.length;
+
+ for (int z = 1; z < rows_count; z++) {
+ cgCache cache = new cgCache();
+ String row = rows[z];
+
+ // check for cache type presence
+ if (row.indexOf("images/wpttypes") == -1) {
+ continue;
+ }
+
+ try {
+ final Matcher matcherGuidAndDisabled = patternGuidAndDisabled.matcher(row);
+
+ while (matcherGuidAndDisabled.find()) {
+ if (matcherGuidAndDisabled.groupCount() > 0) {
+ guids.add(matcherGuidAndDisabled.group(1));
+
+ cache.guid = matcherGuidAndDisabled.group(1);
+ if (matcherGuidAndDisabled.group(4) != null) {
+ cache.name = Html.fromHtml(matcherGuidAndDisabled.group(4).trim()).toString();
+ }
+ if (matcherGuidAndDisabled.group(6) != null) {
+ cache.location = Html.fromHtml(matcherGuidAndDisabled.group(6).trim()).toString();
+ }
+
+ final String attr = matcherGuidAndDisabled.group(2);
+ if (attr != null) {
+ if (attr.contains("Strike") == true) {
+ cache.disabled = true;
+ } else {
+ cache.disabled = false;
+ }
+
+ if (attr.contains("OldWarning") == true) {
+ cache.archived = true;
+ } else {
+ cache.archived = false;
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse GUID and/or Disabled
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse GUID and/or Disabled data");
+ }
+
+ if (settings.excludeDisabled == 1 && (cache.disabled == true || cache.archived == true)) {
+ // skip disabled and archived caches
+ cache = null;
+ continue;
+ }
+
+ String inventoryPre = null;
+
+ // GC* code
+ try {
+ final Matcher matcherCode = patternCode.matcher(row);
+ while (matcherCode.find()) {
+ if (matcherCode.groupCount() > 0) {
+ cache.geocode = matcherCode.group(1).toUpperCase();
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse code
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache code");
+ }
+
+ // cache type
+ try {
+ final Matcher matcherCacheType = patternCacheType.matcher(row);
+ while (matcherCacheType.find()) {
+ if (matcherCacheType.groupCount() > 0) {
+ cache.type = cacheTypes.get(matcherCacheType.group(1).toLowerCase());
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse type
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache type");
+ }
+
+ // cache direction - image
+ try {
+ final Matcher matcherDirection = patternDirection.matcher(row);
+ while (matcherDirection.find()) {
+ if (matcherDirection.groupCount() > 0) {
+ cache.directionImg = matcherDirection.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse direction image
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache direction image");
+ }
+
+ // cache inventory
+ try {
+ final Matcher matcherTbs = patternTbs.matcher(row);
+ while (matcherTbs.find()) {
+ if (matcherTbs.groupCount() > 0) {
+ cache.inventoryItems = Integer.parseInt(matcherTbs.group(1));
+ inventoryPre = matcherTbs.group(2);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse inventory
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache inventory (1)");
+ }
+
+ if (inventoryPre != null && inventoryPre.trim().length() > 0) {
+ try {
+ final Matcher matcherTbsInside = patternTbsInside.matcher(inventoryPre);
+ while (matcherTbsInside.find()) {
+ if (matcherTbsInside.groupCount() == 2 && matcherTbsInside.group(2) != null) {
+ final String inventoryItem = matcherTbsInside.group(2).toLowerCase();
+ if (inventoryItem.equals("premium member only cache")) {
+ continue;
+ } else {
+ if (cache.inventoryItems <= 0) {
+ cache.inventoryItems = 1;
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache inventory info
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache inventory info");
+ }
+ }
+
+ // premium cache
+ if (row.indexOf("/images/small_profile.gif") != -1) {
+ cache.members = true;
+ } else {
+ cache.members = false;
+ }
+
+ // found it
+ if (row.indexOf("/images/icons/icon_smile") != -1) {
+ cache.found = true;
+ } else {
+ cache.found = false;
+ }
+
+ // own it
+ if (row.indexOf("/images/silk/star.png") != -1) {
+ cache.own = true;
+ } else {
+ cache.own = false;
+ }
+
+ // id
+ try {
+ final Matcher matcherId = patternId.matcher(row);
+ while (matcherId.find()) {
+ if (matcherId.groupCount() > 0) {
+ cache.cacheid = matcherId.group(1);
+ cids.add(cache.cacheid);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache id
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache id");
+ }
+
+ // favourite count
+ try {
+ final Matcher matcherFavourite = patternFavourite.matcher(row);
+ while (matcherFavourite.find()) {
+ if (matcherFavourite.groupCount() > 0) {
+ cache.favouriteCnt = Integer.parseInt(matcherFavourite.group(1));
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse favourite count
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse favourite count");
+ }
+
+ if (cache.nameSp == null) {
+ cache.nameSp = (new Spannable.Factory()).newSpannable(cache.name);
+ if (cache.disabled == true || cache.archived == true) { // strike
+ cache.nameSp.setSpan(new StrikethroughSpan(), 0, cache.nameSp.toString().length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+
+ caches.cacheList.add(cache);
+ }
+
+ // total caches found
+ try {
+ final Matcher matcherTotalCnt = patternTotalCnt.matcher(page);
+ while (matcherTotalCnt.find()) {
+ if (matcherTotalCnt.groupCount() > 0) {
+ if (matcherTotalCnt.group(1) != null) {
+ caches.totalCnt = new Integer(matcherTotalCnt.group(1));
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache count
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache count");
+ }
+
+ if (thread != null && recaptchaChallenge != null) {
+ if (thread.getText() == null) {
+ thread.waitForUser();
+ }
+
+ recaptchaText = thread.getText();
+ }
+
+ if (cids.size() > 0 && (recaptchaChallenge == null || (recaptchaChallenge != null && recaptchaText != null && recaptchaText.length() > 0))) {
+ Log.i(cgSettings.tag, "Trying to get .loc for " + cids.size() + " caches");
+
+ try {
+ // get coordinates for parsed caches
+ final String host = "www.geocaching.com";
+ final String path = "/seek/nearest.aspx";
+ final StringBuilder params = new StringBuilder();
+ params.append("__EVENTTARGET=");
+ params.append("&");
+ params.append("__EVENTARGUMENT=");
+ params.append("&");
+ params.append("__VIEWSTATE=");
+ params.append(urlencode_rfc3986(caches.viewstate));
+ if (caches.viewstate1 != null) {
+ params.append("&");
+ params.append("__VIEWSTATE1=");
+ params.append(urlencode_rfc3986(caches.viewstate1));
+ params.append("&");
+ params.append("__VIEWSTATEFIELDCOUNT=2");
+ }
+
+ for (String cid : cids) {
+ params.append("&");
+ params.append("CID=");
+ params.append(urlencode_rfc3986(cid));
+ }
+
+ if (recaptchaChallenge != null && recaptchaText != null && recaptchaText.length() > 0) {
+ params.append("&");
+ params.append("recaptcha_challenge_field=");
+ params.append(urlencode_rfc3986(recaptchaChallenge));
+ params.append("&");
+ params.append("recaptcha_response_field=");
+ params.append(urlencode_rfc3986(recaptchaText));
+ }
+ params.append("&");
+ params.append("ctl00%24ContentBody%24uxDownloadLoc=Download+Waypoints");
+
+ final String coordinates = request(false, host, path, "POST", params.toString(), 0, true).getData();
+
+ if (coordinates != null && coordinates.length() > 0) {
+ if (coordinates.indexOf("You have not agreed to the license agreement. The license agreement is required before you can start downloading GPX or LOC files from Geocaching.com") > -1) {
+ Log.i(cgSettings.tag, "User has not agreed to the license agreement. Can\'t download .loc file.");
+
+ caches.error = errorRetrieve.get(-7);
+
+ return caches;
+ }
+ }
+
+ if (coordinates != null && coordinates.length() > 0) {
+ final HashMap<String, cgCoord> cidCoords = new HashMap<String, cgCoord>();
+ final Pattern patternCidCode = Pattern.compile("name id=\"([^\"]+)\"");
+ final Pattern patternCidLat = Pattern.compile("lat=\"([^\"]+)\"");
+ final Pattern patternCidLon = Pattern.compile("lon=\"([^\"]+)\"");
+ // premium only >>
+ final Pattern patternCidDif = Pattern.compile("<difficulty>([^<]+)</difficulty>");
+ final Pattern patternCidTer = Pattern.compile("<terrain>([^<]+)</terrain>");
+ final Pattern patternCidCon = Pattern.compile("<container>([^<]+)</container>");
+ // >> premium only
+
+ final String[] points = coordinates.split("<waypoint>");
+
+ // parse coordinates
+ for (String point : points) {
+ final cgCoord pointCoord = new cgCoord();
+ final Matcher matcherCidCode = patternCidCode.matcher(point);
+ final Matcher matcherLatCode = patternCidLat.matcher(point);
+ final Matcher matcherLonCode = patternCidLon.matcher(point);
+ final Matcher matcherDifCode = patternCidDif.matcher(point);
+ final Matcher matcherTerCode = patternCidTer.matcher(point);
+ final Matcher matcherConCode = patternCidCon.matcher(point);
+ HashMap<String, Object> tmp = null;
+
+ if (matcherCidCode.find() == true) {
+ pointCoord.name = matcherCidCode.group(1).trim().toUpperCase();
+ }
+ if (matcherLatCode.find() == true) {
+ tmp = parseCoordinate(matcherLatCode.group(1), "lat");
+ pointCoord.latitude = (Double) tmp.get("coordinate");
+ }
+ if (matcherLonCode.find() == true) {
+ tmp = parseCoordinate(matcherLonCode.group(1), "lon");
+ pointCoord.longitude = (Double) tmp.get("coordinate");
+ }
+ if (matcherDifCode.find() == true) {
+ pointCoord.difficulty = new Float(matcherDifCode.group(1));
+ }
+ if (matcherTerCode.find() == true) {
+ pointCoord.terrain = new Float(matcherTerCode.group(1));
+ }
+ if (matcherConCode.find() == true) {
+ final int size = Integer.parseInt(matcherConCode.group(1));
+
+ if (size == 1) {
+ pointCoord.size = "not chosen";
+ } else if (size == 2) {
+ pointCoord.size = "micro";
+ } else if (size == 3) {
+ pointCoord.size = "regular";
+ } else if (size == 4) {
+ pointCoord.size = "large";
+ } else if (size == 5) {
+ pointCoord.size = "virtual";
+ } else if (size == 6) {
+ pointCoord.size = "other";
+ } else if (size == 8) {
+ pointCoord.size = "small";
+ } else {
+ pointCoord.size = "unknown";
+ }
+ }
+
+ cidCoords.put(pointCoord.name, pointCoord);
+ }
+
+ Log.i(cgSettings.tag, "Coordinates found in .loc file: " + cidCoords.size());
+
+ // save found cache coordinates
+ for (cgCache oneCache : caches.cacheList) {
+ if (cidCoords.containsKey(oneCache.geocode) == true) {
+ cgCoord thisCoords = cidCoords.get(oneCache.geocode);
+
+ oneCache.latitude = thisCoords.latitude;
+ oneCache.longitude = thisCoords.longitude;
+ oneCache.difficulty = thisCoords.difficulty;
+ oneCache.terrain = thisCoords.terrain;
+ oneCache.size = thisCoords.size;
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.parseSearch.CIDs: " + e.toString());
+ }
+ }
+
+ // get direction images
+ cgDirectionImg dirImgDownloader = new cgDirectionImg(settings);
+ for (cgCache oneCache : caches.cacheList) {
+ if (oneCache.latitude == null && oneCache.longitude == null && oneCache.direction == null && oneCache.directionImg != null) {
+ dirImgDownloader.getDrawable(oneCache.geocode, oneCache.directionImg);
+ }
+ }
+ dirImgDownloader = null;
+
+ // get ratings
+ if (guids.size() > 0) {
+ Log.i(cgSettings.tag, "Trying to get ratings for " + cids.size() + " caches");
+
+ try {
+ final HashMap<String, cgRating> ratings = getRating(guids, null);
+
+ if (ratings != null) {
+ // save found cache coordinates
+ for (cgCache oneCache : caches.cacheList) {
+ if (ratings.containsKey(oneCache.guid) == true) {
+ cgRating thisRating = ratings.get(oneCache.guid);
+
+ oneCache.rating = thisRating.rating;
+ oneCache.votes = thisRating.votes;
+ oneCache.myVote = thisRating.myVote;
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.parseSearch.GCvote: " + e.toString());
+ }
+ }
+
+ return caches;
+ }
+
+ public cgCacheWrap parseMapJSON(String url, String data) {
+ if (data == null || data.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.parseMapJSON: No page given");
+ return null;
+ }
+
+ final cgCacheWrap caches = new cgCacheWrap();
+ caches.url = url;
+
+ try {
+ final JSONObject yoDawg = new JSONObject(data);
+ final String json = yoDawg.getString("d");
+
+ if (json == null || json.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.parseMapJSON: No JSON inside JSON");
+ return null;
+ }
+
+ final JSONObject dataJSON = new JSONObject(json);
+ final JSONObject extra = dataJSON.getJSONObject("cs");
+ if (extra != null && extra.length() > 0) {
+ int count = extra.getInt("count");
+
+ if (count > 0 && extra.has("cc")) {
+ final JSONArray cachesData = extra.getJSONArray("cc");
+ if (cachesData != null && cachesData.length() > 0) {
+ JSONObject oneCache = null;
+ for (int i = 0; i < count; i++) {
+ oneCache = cachesData.getJSONObject(i);
+ if (oneCache == null) {
+ break;
+ }
+
+ final cgCache cacheToAdd = new cgCache();
+ cacheToAdd.reliableLatLon = false;
+ cacheToAdd.geocode = oneCache.getString("gc");
+ cacheToAdd.latitude = oneCache.getDouble("lat");
+ cacheToAdd.longitude = oneCache.getDouble("lon");
+ cacheToAdd.name = oneCache.getString("nn");
+ cacheToAdd.found = oneCache.getBoolean("f");
+ cacheToAdd.own = oneCache.getBoolean("o");
+ cacheToAdd.disabled = !oneCache.getBoolean("ia");
+ int ctid = oneCache.getInt("ctid");
+ if (ctid == 2) {
+ cacheToAdd.type = "traditional";
+ } else if (ctid == 3) {
+ cacheToAdd.type = "multi";
+ } else if (ctid == 4) {
+ cacheToAdd.type = "virtual";
+ } else if (ctid == 5) {
+ cacheToAdd.type = "letterbox";
+ } else if (ctid == 6) {
+ cacheToAdd.type = "event";
+ } else if (ctid == 8) {
+ cacheToAdd.type = "mystery";
+ } else if (ctid == 11) {
+ cacheToAdd.type = "webcam";
+ } else if (ctid == 13) {
+ cacheToAdd.type = "cito";
+ } else if (ctid == 137) {
+ cacheToAdd.type = "earth";
+ } else if (ctid == 453) {
+ cacheToAdd.type = "mega";
+ } else if (ctid == 1858) {
+ cacheToAdd.type = "wherigo";
+ } else if (ctid == 3653) {
+ cacheToAdd.type = "lost";
+ }
+
+ caches.cacheList.add(cacheToAdd);
+ }
+ }
+ } else {
+ Log.w(cgSettings.tag, "There are no caches in viewport");
+ }
+ caches.totalCnt = caches.cacheList.size();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.parseMapJSON: " + e.toString());
+ }
+
+ return caches;
+ }
+
+ public cgCacheWrap parseCache(String page, int reason) {
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.parseCache: No page given");
+ return null;
+ }
+
+ final Pattern patternGeocode = Pattern.compile("<meta name=\"og:url\" content=\"[^\"]+/(GC[0-9A-Z]+)\"[^>]*>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternCacheId = Pattern.compile("/seek/log\\.aspx\\?ID=(\\d+)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternCacheGuid = Pattern.compile("<link rel=\"alternate\" href=\"[^\"]*/datastore/rss_galleryimages\\.ashx\\?guid=([0-9a-z\\-]+)\"[^>]*>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternType = Pattern.compile("<img src=\"[^\"]*/WptTypes/\\d+\\.gif\" alt=\"([^\"]+)\" (title=\"[^\"]*\" )?width=\"32\" height=\"32\"[^>]*>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+
+ final Pattern patternName = Pattern.compile("<h2[^>]*>[^<]*<span id=\"ctl00_ContentBody_CacheName\">([^<]+)<\\/span>[^<]*<\\/h2>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternSize = Pattern.compile("<div class=\"CacheSize[^\"]*\">[^<]*<p[^>]*>[^S]*Size[^:]*:[^<]*<span[^>]*>[^<]*<img src=\"[^\"]*/icons/container/[a-z_]+\\.gif\" alt=\"Size: ([^\"]+)\"[^>]*>[^<]*<small>[^<]*</small>[^<]*</span>[^<]*</p>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternDifficulty = Pattern.compile("<span id=\"ctl00_ContentBody_uxLegendScale\"[^>]*>[^<]*<img src=\"[^\"]*/images/stars/stars([0-9_]+)\\.gif\" alt=\"[^\"]+\"[^>]*>[^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternTerrain = Pattern.compile("<span id=\"ctl00_ContentBody_Localize6\"[^>]*>[^<]*<img src=\"[^\"]*/images/stars/stars([0-9_]+)\\.gif\" alt=\"[^\"]+\"[^>]*>[^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternOwner = Pattern.compile("<span class=\"minorCacheDetails\">[^\\w]*An?([^\\w]*Event)?[^\\w]*cache[^\\w]*by[^<]*<a href=\"[^\"]+\">([^<]+)</a>[^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternOwnerReal = Pattern.compile("<a id=\"ctl00_ContentBody_uxFindLinksHiddenByThisUser\" href=\"[^\"]*/seek/nearest\\.aspx\\?u=*([^\"]+)\">[^<]+</a>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternHidden = Pattern.compile("<span[^>]*>[^\\w]*Hidden[^:]*:[^\\d]*((\\d+)\\/(\\d+)\\/(\\d+))[^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternHiddenEvent = Pattern.compile("<span[^>]*>[^\\w]*Event[^\\w]*Date[^:]*:[^\\w]*[a-zA-Z]+,[^\\d]*((\\d+)[^\\w]*(\\w+)[^\\d]*(\\d+))[^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternFavourite = Pattern.compile("<a id=\"uxFavContainerLink\"[^>]*>[^<]*<div[^<]*<span class=\"favorite-value\">[^\\d]*([0-9]+)[^\\d^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+
+ final Pattern patternFound = Pattern.compile("<p>[^<]*<a id=\"ctl00_ContentBody_hlFoundItLog\"[^<]*<img src=\".*/images/stockholm/16x16/check\\.gif\"[^>]*>[^<]*</a>[^<]*</p>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternLatLon = Pattern.compile("<span id=\"ctl00_ContentBody_LatLon\"[^>]*>(<b>)?([^<]*)(<\\/b>)?<\\/span>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternLocation = Pattern.compile("<span id=\"ctl00_ContentBody_Location\"[^>]*>In ([^<]*)", Pattern.CASE_INSENSITIVE);
+ final Pattern patternHint = Pattern.compile("<p>([^<]*<strong>)?[^\\w]*Additional Hints([^<]*<\\/strong>)?[^\\(]*\\(<a[^>]+>Encrypt</a>\\)[^<]*<\\/p>[^<]*<div id=\"div_hint\"[^>]*>(.*)</div>[^<]*<div id=[\\'|\"]dk[\\'|\"]", Pattern.CASE_INSENSITIVE);
+ final Pattern patternDescShort = Pattern.compile("<div class=\"UserSuppliedContent\">[^<]*<span id=\"ctl00_ContentBody_ShortDescription\"[^>]*>((?:(?!</span>[^\\w^<]*</div>).)*)</span>[^\\w^<]*</div>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternDesc = Pattern.compile("<div class=\"UserSuppliedContent\">[^<]*<span id=\"ctl00_ContentBody_LongDescription\"[^>]*>((?:(?!</span>[^\\w^<]*</div>).)*)</span>[^<]*</div>[^<]*<p>[^<]*</p>[^<]*<p>[^<]*<strong>[^\\w]*Additional Hints</strong>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternCountLogs = Pattern.compile("<span id=\"ctl00_ContentBody_lblFindCounts\"><p>(.*)<\\/p><\\/span>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternCountLog = Pattern.compile(" src=\"\\/images\\/icons\\/([^\\.]*).gif\" alt=\"[^\"]*\" title=\"[^\"]*\" />([0-9]*)[^0-9]+", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternLogs = Pattern.compile("<table class=\"LogsTable[^\"]*\"[^>]*>[^<]*<tr>(.*)</tr>[^<]*</table>[^<]*<p", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternLog = Pattern.compile("<td[^>]*>[^<]*<strong>[^<]*<img src=\"[^\"]*/images/icons/([^\\.]+)\\.[a-z]{2,5}\"[^>]*>&nbsp;([a-zA-Z]+) (\\d+)(, (\\d+))? by <a href=[^>]+>([^<]+)</a>[<^]*</strong>([^\\(]*\\((\\d+) found\\))?(<br[^>]*>)+((?:(?!<small>).)*)(<br[^>]*>)+<small>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternAttributes = Pattern.compile("<h3 class=\"WidgetHeader\">[^<]*<img[^>]+>[^\\w]*Attributes[^<]*</h3>[^<]*<div class=\"WidgetBody\">(([^<]*<img src=\"[^\"]+\" alt=\"[^\"]+\"[^>]*>)+)[^<]*<p", Pattern.CASE_INSENSITIVE);
+ final Pattern patternAttributesInside = Pattern.compile("[^<]*<img src=\"([^\"]+)\" alt=\"([^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternSpoilers = Pattern.compile("<span id=\"ctl00_ContentBody_Images\">((<a href=\"[^\"]+\"[^>]*>[^<]*<img[^>]+>[^<]*<span>[^>]+</span>[^<]*</a>[^<]*<br[^>]*>([^<]*(<br[^>]*>)+)?)+)[^<]*</span>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternSpoilersInside = Pattern.compile("[^<]*<a href=\"([^\"]+)\"[^>]*>[^<]*<img[^>]+>[^<]*<span>([^>]+)</span>[^<]*</a>[^<]*<br[^>]*>(([^<]*)(<br[^<]*>)+)?", Pattern.CASE_INSENSITIVE);
+ final Pattern patternInventory = Pattern.compile("<span id=\"ctl00_ContentBody_uxTravelBugList_uxInventoryLabel\">[^\\w]*Inventory[^<]*</span>[^<]*</h3>[^<]*<div class=\"WidgetBody\">([^<]*<ul>(([^<]*<li>[^<]*<a href=\"[^\"]+\"[^>]*>[^<]*<img src=\"[^\"]+\"[^>]*>[^<]*<span>[^<]+<\\/span>[^<]*<\\/a>[^<]*<\\/li>)+)[^<]*<\\/ul>)?", Pattern.CASE_INSENSITIVE);
+ final Pattern patternInventoryInside = Pattern.compile("[^<]*<li>[^<]*<a href=\"[a-z0-9\\-\\_\\.\\?\\/\\:\\@]*\\/track\\/details\\.aspx\\?guid=([0-9a-z\\-]+)[^\"]*\"[^>]*>[^<]*<img src=\"[^\"]+\"[^>]*>[^<]*<span>([^<]+)<\\/span>[^<]*<\\/a>[^<]*<\\/li>", Pattern.CASE_INSENSITIVE);
+
+ final cgCacheWrap caches = new cgCacheWrap();
+ final cgCache cache = new cgCache();
+
+ if (page.indexOf("Cache is Unpublished") > -1) {
+ caches.error = "cache was unpublished";
+ return caches;
+ }
+
+ if (page.indexOf("Sorry, the owner of this listing has made it viewable to Premium Members only.") != -1) {
+ caches.error = "requested cache is for premium members only";
+ return caches;
+ }
+
+ if (page.indexOf("has chosen to make this cache listing visible to Premium Members only.") != -1) {
+ caches.error = "requested cache is for premium members only";
+ return caches;
+ }
+
+ if (page.indexOf("<li>This cache is temporarily unavailable.") != -1) {
+ cache.disabled = true;
+ } else {
+ cache.disabled = false;
+ }
+
+ if (page.indexOf("<li>This cache has been archived,") != -1) {
+ cache.archived = true;
+ } else {
+ cache.archived = false;
+ }
+
+ if (page.indexOf("<p class=\"Warning\">This is a Premium Member Only cache.</p>") != -1) {
+ cache.members = true;
+ } else {
+ cache.members = false;
+ }
+
+ cache.reason = reason;
+
+ // cache geocode
+ try {
+ final Matcher matcherGeocode = patternGeocode.matcher(page);
+ while (matcherGeocode.find()) {
+ if (matcherGeocode.groupCount() > 0) {
+ cache.geocode = (String) matcherGeocode.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache geocode
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache geocode");
+ }
+
+ // cache id
+ try {
+ final Matcher matcherCacheId = patternCacheId.matcher(page);
+ while (matcherCacheId.find()) {
+ if (matcherCacheId.groupCount() > 0) {
+ cache.cacheid = (String) matcherCacheId.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache id
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache id");
+ }
+
+ // cache guid
+ try {
+ final Matcher matcherCacheGuid = patternCacheGuid.matcher(page);
+ while (matcherCacheGuid.find()) {
+ if (matcherCacheGuid.groupCount() > 0) {
+ cache.guid = (String) matcherCacheGuid.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache guid
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache guid");
+ }
+
+ // name
+ try {
+ final Matcher matcherName = patternName.matcher(page);
+ while (matcherName.find()) {
+ if (matcherName.groupCount() > 0) {
+ cache.name = Html.fromHtml(matcherName.group(1)).toString();
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache name
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache name");
+ }
+
+ // owner real name
+ try {
+ final Matcher matcherOwnerReal = patternOwnerReal.matcher(page);
+ while (matcherOwnerReal.find()) {
+ if (matcherOwnerReal.groupCount() > 0) {
+ cache.ownerReal = URLDecoder.decode(matcherOwnerReal.group(1));
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse owner real name
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache owner real name");
+ }
+
+ final String username = settings.getUsername();
+ if (cache.ownerReal != null && username != null && cache.ownerReal.equalsIgnoreCase(username)) {
+ cache.own = true;
+ }
+
+ int pos = -1;
+ String tableInside = page;
+
+ pos = tableInside.indexOf("id=\"cacheDetails\"");
+ if (pos == -1) {
+ Log.e(cgSettings.tag, "cgeoBase.parseCache: ID \"cacheDetails\" not found on page");
+ return null;
+ }
+
+ tableInside = tableInside.substring(pos);
+
+ pos = tableInside.indexOf("<div class=\"CacheInformationTable\"");
+ if (pos == -1) {
+ Log.e(cgSettings.tag, "cgeoBase.parseCache: ID \"CacheInformationTable\" not found on page");
+ return null;
+ }
+
+ tableInside = tableInside.substring(0, pos);
+
+ if (tableInside != null && tableInside.length() > 0) {
+ // cache terrain
+ try {
+ final Matcher matcherTerrain = patternTerrain.matcher(tableInside);
+ while (matcherTerrain.find()) {
+ if (matcherTerrain.groupCount() > 0) {
+ cache.terrain = new Float(Pattern.compile("_").matcher(matcherTerrain.group(1)).replaceAll("."));
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse terrain
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache terrain");
+ }
+
+ // cache difficulty
+ try {
+ final Matcher matcherDifficulty = patternDifficulty.matcher(tableInside);
+ while (matcherDifficulty.find()) {
+ if (matcherDifficulty.groupCount() > 0) {
+ cache.difficulty = new Float(Pattern.compile("_").matcher(matcherDifficulty.group(1)).replaceAll("."));
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse difficulty
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache difficulty");
+ }
+
+ // owner
+ try {
+ final Matcher matcherOwner = patternOwner.matcher(tableInside);
+ while (matcherOwner.find()) {
+ if (matcherOwner.groupCount() > 0) {
+ cache.owner = Html.fromHtml(matcherOwner.group(2)).toString();
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse owner
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache owner");
+ }
+
+ // hidden
+ try {
+ final Matcher matcherHidden = patternHidden.matcher(tableInside);
+ while (matcherHidden.find()) {
+ if (matcherHidden.groupCount() > 0) {
+ cache.hidden = dateIn.parse(matcherHidden.group(1));
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache hidden date
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache hidden date");
+ }
+
+ if (cache.hidden == null) {
+ // event date
+ try {
+ final Matcher matcherHiddenEvent = patternHiddenEvent.matcher(tableInside);
+ while (matcherHiddenEvent.find()) {
+ if (matcherHiddenEvent.groupCount() > 0) {
+ cache.hidden = dateEvIn.parse(matcherHiddenEvent.group(1));
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache event date
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache event date");
+ }
+ }
+
+ // favourite
+ try {
+ final Matcher matcherFavourite = patternFavourite.matcher(tableInside);
+ while (matcherFavourite.find()) {
+ if (matcherFavourite.groupCount() > 0) {
+ cache.favouriteCnt = Integer.parseInt(matcherFavourite.group(1));
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse favourite count
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse favourite count");
+ }
+
+ // cache size
+ try {
+ final Matcher matcherSize = patternSize.matcher(tableInside);
+ while (matcherSize.find()) {
+ if (matcherSize.groupCount() > 0) {
+ cache.size = matcherSize.group(1).toLowerCase();
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse size
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache size");
+ }
+ }
+
+ // cache found
+ try {
+ final Matcher matcherFound = patternFound.matcher(page);
+ while (matcherFound.find()) {
+ if (matcherFound.group() != null && matcherFound.group().length() > 0) {
+ cache.found = true;
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse found
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse found");
+ }
+
+ // cache type
+ try {
+ final Matcher matcherType = patternType.matcher(page);
+ while (matcherType.find()) {
+ if (matcherType.groupCount() > 0) {
+ cache.type = cacheTypes.get(matcherType.group(1).toLowerCase());
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse type
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache type");
+ }
+
+ // latitude and logitude
+ try {
+ final Matcher matcherLatLon = patternLatLon.matcher(page);
+ while (matcherLatLon.find()) {
+ if (matcherLatLon.groupCount() > 0) {
+ cache.latlon = matcherLatLon.group(2); // first is <b>
+
+ HashMap<String, Object> tmp = this.parseLatlon(cache.latlon);
+ if (tmp.size() > 0) {
+ cache.latitude = (Double) tmp.get("latitude");
+ cache.longitude = (Double) tmp.get("longitude");
+ cache.latitudeString = (String) tmp.get("latitudeString");
+ cache.longitudeString = (String) tmp.get("longitudeString");
+ cache.reliableLatLon = true;
+ }
+ tmp = null;
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse latitude and/or longitude
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache coordinates");
+ }
+
+ // cache location
+ try {
+ final Matcher matcherLocation = patternLocation.matcher(page);
+ while (matcherLocation.find()) {
+ if (matcherLocation.groupCount() > 0) {
+ cache.location = matcherLocation.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse location
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache location");
+ }
+
+ // cache hint
+ try {
+ final Matcher matcherHint = patternHint.matcher(page);
+ while (matcherHint.find()) {
+ if (matcherHint.groupCount() > 2 && matcherHint.group(3) != null) {
+ // replace linebreak and paragraph tags
+ String hint = Pattern.compile("<(br|p)[^>]*>").matcher(matcherHint.group(3)).replaceAll("\n");
+ if (hint != null) {
+ cache.hint = hint.replaceAll(Pattern.quote("</p>"), "").trim();
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse hint
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache hint");
+ }
+
+ /*
+ // short info debug
+ Log.d(cgSettings.tag, "gc-code: " + cache.geocode);
+ Log.d(cgSettings.tag, "id: " + cache.cacheid);
+ Log.d(cgSettings.tag, "guid: " + cache.guid);
+ Log.d(cgSettings.tag, "name: " + cache.name);
+ Log.d(cgSettings.tag, "terrain: " + cache.terrain);
+ Log.d(cgSettings.tag, "difficulty: " + cache.difficulty);
+ Log.d(cgSettings.tag, "owner: " + cache.owner);
+ Log.d(cgSettings.tag, "owner (real): " + cache.ownerReal);
+ Log.d(cgSettings.tag, "hidden: " + dateOutShort.format(cache.hidden));
+ Log.d(cgSettings.tag, "favorite: " + cache.favouriteCnt);
+ Log.d(cgSettings.tag, "size: " + cache.size);
+ if (cache.found) {
+ Log.d(cgSettings.tag, "found!");
+ } else {
+ Log.d(cgSettings.tag, "not found");
+ }
+ Log.d(cgSettings.tag, "type: " + cache.type);
+ Log.d(cgSettings.tag, "latitude: " + String.format("%.6f", cache.latitude));
+ Log.d(cgSettings.tag, "longitude: " + String.format("%.6f", cache.longitude));
+ Log.d(cgSettings.tag, "location: " + cache.location);
+ Log.d(cgSettings.tag, "hint: " + cache.hint);
+ */
+
+ // cache short description
+ try {
+ final Matcher matcherDescShort = patternDescShort.matcher(page);
+ while (matcherDescShort.find()) {
+ if (matcherDescShort.groupCount() > 0) {
+ cache.shortdesc = matcherDescShort.group(1).trim();
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse short description
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache short description");
+ }
+
+ // cache description
+ try {
+ final Matcher matcherDesc = patternDesc.matcher(page);
+ while (matcherDesc.find()) {
+ if (matcherDesc.groupCount() > 0) {
+ cache.description = matcherDesc.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse short description
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache description");
+ }
+
+ // cache attributes
+ try {
+ final Matcher matcherAttributes = patternAttributes.matcher(page);
+ while (matcherAttributes.find()) {
+ if (matcherAttributes.groupCount() > 0) {
+ final String attributesPre = matcherAttributes.group(1);
+ final Matcher matcherAttributesInside = patternAttributesInside.matcher(attributesPre);
+
+ while (matcherAttributesInside.find()) {
+ if (matcherAttributesInside.groupCount() > 1 && matcherAttributesInside.group(2).equalsIgnoreCase("blank") != true) {
+ if (cache.attributes == null) {
+ cache.attributes = new ArrayList<String>();
+ }
+ // by default, use the tooltip of the attribute
+ String attribute = matcherAttributesInside.group(2).toLowerCase();
+
+ // if the image name can be recognized, use the image name as attribute
+ String imageName = matcherAttributesInside.group(1).trim();
+ if (imageName.length() > 0) {
+ int start = imageName.lastIndexOf('/');
+ int end = imageName.lastIndexOf('.');
+ if (start >= 0 && end>= 0) {
+ attribute = imageName.substring(start + 1, end).replace('-', '_');
+ }
+ }
+ cache.attributes.add(attribute);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache attributes
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache attributes");
+ }
+
+ // cache spoilers
+ try {
+ final Matcher matcherSpoilers = patternSpoilers.matcher(page);
+ while (matcherSpoilers.find()) {
+ if (matcherSpoilers.groupCount() > 0) {
+ final String spoilersPre = matcherSpoilers.group(1);
+ final Matcher matcherSpoilersInside = patternSpoilersInside.matcher(spoilersPre);
+
+ while (matcherSpoilersInside.find()) {
+ if (matcherSpoilersInside.groupCount() > 0) {
+ final cgSpoiler spoiler = new cgSpoiler();
+ spoiler.url = matcherSpoilersInside.group(1);
+
+ if (matcherSpoilersInside.group(2) != null) {
+ spoiler.title = matcherSpoilersInside.group(2);
+ }
+ if (matcherSpoilersInside.group(4) != null) {
+ spoiler.description = matcherSpoilersInside.group(4);
+ }
+
+ if (cache.spoilers == null) {
+ cache.spoilers = new ArrayList<cgSpoiler>();
+ }
+ cache.spoilers.add(spoiler);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache spoilers
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache spoilers");
+ }
+
+ // cache inventory
+ try {
+ cache.inventoryItems = 0;
+
+ final Matcher matcherInventory = patternInventory.matcher(page);
+ while (matcherInventory.find()) {
+ if (cache.inventory == null) {
+ cache.inventory = new ArrayList<cgTrackable>();
+ }
+
+ if (matcherInventory.groupCount() > 1) {
+ final String inventoryPre = matcherInventory.group(2);
+
+ if (inventoryPre != null && inventoryPre.length() > 0) {
+ final Matcher matcherInventoryInside = patternInventoryInside.matcher(inventoryPre);
+
+ while (matcherInventoryInside.find()) {
+ if (matcherInventoryInside.groupCount() > 0) {
+ final cgTrackable inventoryItem = new cgTrackable();
+ inventoryItem.guid = matcherInventoryInside.group(1);
+ inventoryItem.name = matcherInventoryInside.group(2);
+
+ cache.inventory.add(inventoryItem);
+ cache.inventoryItems++;
+ }
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache inventory
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache inventory (2)");
+ }
+
+ // cache logs counts
+ try {
+ final Matcher matcherLogCounts = patternCountLogs.matcher(page);
+ while (matcherLogCounts.find()) {
+ if (matcherLogCounts.groupCount() > 0) {
+ final String[] logs = matcherLogCounts.group(1).split("<img");
+ final int logsCnt = logs.length;
+
+ for (int k = 1; k < logsCnt; k++) {
+ Integer type = null;
+ Integer count = null;
+ final Matcher matcherLog = patternCountLog.matcher(logs[k]);
+
+ if (matcherLog.find()) {
+ String typeStr = matcherLog.group(1);
+ String countStr = matcherLog.group(2);
+ if (typeStr != null && typeStr.length() > 0) {
+ if (logTypes.containsKey(typeStr.toLowerCase()) == true) {
+ type = logTypes.get(typeStr.toLowerCase());
+ }
+ }
+ if (countStr != null && countStr.length() > 0) {
+ count = Integer.parseInt(countStr);
+ }
+ if (type != null && count != null) {
+ cache.logCounts.put(type, count);
+ }
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse logs
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache log count");
+ }
+
+ // cache logs
+ try {
+ final Matcher matcherLogs = patternLogs.matcher(page);
+ while (matcherLogs.find()) {
+ if (matcherLogs.groupCount() > 0) {
+ final String[] logs = matcherLogs.group(1).split("</tr><tr>");
+ final int logsCnt = logs.length;
+
+ for (int k = 0; k < logsCnt; k++) {
+ final Matcher matcherLog = patternLog.matcher(logs[k]);
+
+ if (matcherLog.find()) {
+ final cgLog logDone = new cgLog();
+
+ String logTmp = matcherLog.group(10);
+
+ int day = -1;
+ try {
+ day = Integer.parseInt(matcherLog.group(3));
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse logs date (day): " + e.toString());
+ }
+
+ int month = -1;
+ // January | February | March | April | May | June | July | August | September | October | November | December
+ if (matcherLog.group(2).equalsIgnoreCase("January")) {
+ month = 0;
+ } else if (matcherLog.group(2).equalsIgnoreCase("February")) {
+ month = 1;
+ } else if (matcherLog.group(2).equalsIgnoreCase("March")) {
+ month = 2;
+ } else if (matcherLog.group(2).equalsIgnoreCase("April")) {
+ month = 3;
+ } else if (matcherLog.group(2).equalsIgnoreCase("May")) {
+ month = 4;
+ } else if (matcherLog.group(2).equalsIgnoreCase("June")) {
+ month = 5;
+ } else if (matcherLog.group(2).equalsIgnoreCase("July")) {
+ month = 6;
+ } else if (matcherLog.group(2).equalsIgnoreCase("August")) {
+ month = 7;
+ } else if (matcherLog.group(2).equalsIgnoreCase("September")) {
+ month = 8;
+ } else if (matcherLog.group(2).equalsIgnoreCase("October")) {
+ month = 9;
+ } else if (matcherLog.group(2).equalsIgnoreCase("November")) {
+ month = 10;
+ } else if (matcherLog.group(2).equalsIgnoreCase("December")) {
+ month = 11;
+ } else {
+ Log.w(cgSettings.tag, "Failed to parse logs date (month).");
+ }
+
+
+ int year = -1;
+ final String yearPre = matcherLog.group(5);
+
+ if (yearPre == null) {
+ Calendar date = Calendar.getInstance();
+ year = date.get(Calendar.YEAR);
+ } else {
+ try {
+ year = Integer.parseInt(matcherLog.group(5));
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse logs date (year): " + e.toString());
+ }
+ }
+
+ long logDate;
+ if (year > 0 && month >= 0 && day > 0) {
+ Calendar date = Calendar.getInstance();
+ date.set(year, month, day, 12, 0, 0);
+ logDate = date.getTimeInMillis();
+ logDate = (long) (Math.ceil(logDate / 1000)) * 1000;
+ } else {
+ logDate = 0;
+ }
+
+ if (logTypes.containsKey(matcherLog.group(1).toLowerCase()) == true) {
+ logDone.type = logTypes.get(matcherLog.group(1).toLowerCase());
+ } else {
+ logDone.type = logTypes.get("icon_note");
+ }
+
+ logDone.author = Html.fromHtml(matcherLog.group(6)).toString();
+ logDone.date = logDate;
+ if (matcherLog.group(8) != null) {
+ logDone.found = new Integer(matcherLog.group(8));
+ }
+ logDone.log = logTmp;
+
+ if (cache.logs == null) {
+ cache.logs = new ArrayList<cgLog>();
+ }
+ cache.logs.add(logDone);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse logs
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache logs");
+ }
+
+ int wpBegin = 0;
+ int wpEnd = 0;
+
+ wpBegin = page.indexOf("<table class=\"Table\" id=\"ctl00_ContentBody_Waypoints\">");
+ if (wpBegin != -1) { // parse waypoints
+ final Pattern patternWpType = Pattern.compile("\\/wpttypes\\/sm\\/(.+)\\.jpg", Pattern.CASE_INSENSITIVE);
+ final Pattern patternWpPrefixOrLookupOrLatlon = Pattern.compile(">([^<]*<[^>]+>)?([^<]+)(<[^>]+>[^<]*)?<\\/td>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternWpName = Pattern.compile(">[^<]*<a[^>]+>([^<]*)<\\/a>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternWpNote = Pattern.compile("colspan=\"6\">(.*)<\\/td>", Pattern.CASE_INSENSITIVE);
+
+ String wpList = page.substring(wpBegin);
+
+ wpEnd = wpList.indexOf("</p>");
+ if (wpEnd > -1 && wpEnd <= wpList.length()) {
+ wpList = wpList.substring(0, wpEnd);
+ }
+
+ if (wpList.indexOf("No additional waypoints to display.") == -1) {
+ wpEnd = wpList.indexOf("</table>");
+ wpList = wpList.substring(0, wpEnd);
+
+ wpBegin = wpList.indexOf("<tbody>");
+ wpEnd = wpList.indexOf("</tbody>");
+ if (wpBegin >= 0 && wpEnd >= 0 && wpEnd <= wpList.length()) {
+ wpList = wpList.substring(wpBegin + 7, wpEnd);
+ }
+
+ final String[] wpItems = wpList.split("<tr");
+
+ String[] wp;
+ for (int j = 1; j < wpItems.length; j++) {
+ final cgWaypoint waypoint = new cgWaypoint();
+
+ wp = wpItems[j].split("<td");
+
+ // waypoint type
+ try {
+ final Matcher matcherWpType = patternWpType.matcher(wp[3]);
+ while (matcherWpType.find()) {
+ if (matcherWpType.groupCount() > 0) {
+ waypoint.type = matcherWpType.group(1);
+ if (waypoint.type != null) {
+ waypoint.type = waypoint.type.trim();
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse type
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse waypoint type");
+ }
+
+ // waypoint prefix
+ try {
+ final Matcher matcherWpPrefix = patternWpPrefixOrLookupOrLatlon.matcher(wp[4]);
+ while (matcherWpPrefix.find()) {
+ if (matcherWpPrefix.groupCount() > 1) {
+ waypoint.prefix = matcherWpPrefix.group(2);
+ if (waypoint.prefix != null) {
+ waypoint.prefix = waypoint.prefix.trim();
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse prefix
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse waypoint prefix");
+ }
+
+ // waypoint lookup
+ try {
+ final Matcher matcherWpLookup = patternWpPrefixOrLookupOrLatlon.matcher(wp[5]);
+ while (matcherWpLookup.find()) {
+ if (matcherWpLookup.groupCount() > 1) {
+ waypoint.lookup = matcherWpLookup.group(2);
+ if (waypoint.lookup != null) {
+ waypoint.lookup = waypoint.lookup.trim();
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse lookup
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse waypoint lookup");
+ }
+
+ // waypoint name
+ try {
+ final Matcher matcherWpName = patternWpName.matcher(wp[6]);
+ while (matcherWpName.find()) {
+ if (matcherWpName.groupCount() > 0) {
+ waypoint.name = matcherWpName.group(1);
+ if (waypoint.name != null) {
+ waypoint.name = waypoint.name.trim();
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse name
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse waypoint name");
+ }
+
+ // waypoint latitude and logitude
+ try {
+ final Matcher matcherWpLatLon = patternWpPrefixOrLookupOrLatlon.matcher(wp[7]);
+ while (matcherWpLatLon.find()) {
+ if (matcherWpLatLon.groupCount() > 1) {
+ waypoint.latlon = Html.fromHtml(matcherWpLatLon.group(2)).toString();
+
+ final HashMap<String, Object> tmp = this.parseLatlon(waypoint.latlon);
+ if (tmp.size() > 0) {
+ waypoint.latitude = (Double) tmp.get("latitude");
+ waypoint.longitude = (Double) tmp.get("longitude");
+ waypoint.latitudeString = (String) tmp.get("latitudeString");
+ waypoint.longitudeString = (String) tmp.get("longitudeString");
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse latitude and/or longitude
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse waypoint coordinates");
+ }
+
+ j++;
+ if (wpItems.length > j) {
+ wp = wpItems[j].split("<td");
+ }
+
+ // waypoint note
+ try {
+ final Matcher matcherWpNote = patternWpNote.matcher(wp[3]);
+ while (matcherWpNote.find()) {
+ if (matcherWpNote.groupCount() > 0) {
+ waypoint.note = matcherWpNote.group(1);
+ if (waypoint.note != null) {
+ waypoint.note = waypoint.note.trim();
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse note
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse waypoint note");
+ }
+
+ if (cache.waypoints == null)
+ cache.waypoints = new ArrayList<cgWaypoint>();
+ cache.waypoints.add(waypoint);
+ }
+ }
+ }
+
+ if (cache.latitude != null && cache.longitude != null) {
+ cache.elevation = getElevation(cache.latitude, cache.longitude);
+ }
+
+ final cgRating rating = getRating(cache.guid, cache.geocode);
+ if (rating != null) {
+ cache.rating = rating.rating;
+ cache.votes = rating.votes;
+ cache.myVote = rating.myVote;
+ }
+
+ cache.updated = System.currentTimeMillis();
+ cache.detailedUpdate = System.currentTimeMillis();
+ cache.detailed = true;
+ caches.cacheList.add(cache);
+
+ return caches;
+ }
+
+ public cgRating getRating(String guid, String geocode) {
+ ArrayList<String> guids = null;
+ ArrayList<String> geocodes = null;
+
+ if (guid != null && guid.length() > 0) {
+ guids = new ArrayList<String>();
+ guids.add(guid);
+ } else if (geocode != null && geocode.length() > 0) {
+ geocodes = new ArrayList<String>();
+ geocodes.add(geocode);
+ } else {
+ return null;
+ }
+
+ final HashMap<String, cgRating> ratings = getRating(guids, geocodes);
+ if(ratings != null){
+ final Set<String> ratingKeys = ratings.keySet();
+ for (String ratingKey : ratingKeys) {
+ return ratings.get(ratingKey);
+ }
+ }
+
+ return null;
+ }
+
+ public HashMap<String, cgRating> getRating(ArrayList<String> guids, ArrayList<String> geocodes) {
+ if (guids == null && geocodes == null) {
+ return null;
+ }
+
+ final HashMap<String, cgRating> ratings = new HashMap<String, cgRating>();
+
+ try {
+ final HashMap<String, String> params = new HashMap<String, String>();
+ if (settings.isLogin() == true) {
+ final HashMap<String, String> login = settings.getGCvoteLogin();
+ if (login != null) {
+ params.put("userName", login.get("username"));
+ params.put("password", login.get("password"));
+ }
+ }
+ if (guids != null && guids.size() > 0) {
+ params.put("cacheIds", implode(",", guids.toArray()));
+ } else {
+ params.put("waypoints", implode(",", geocodes.toArray()));
+ }
+ params.put("version", "cgeo");
+ final String votes = request(false, "gcvote.com", "/getVotes.php", "GET", params, false, false, false).getData();
+ if (votes == null) {
+ return null;
+ }
+
+ final Pattern patternLogIn = Pattern.compile("loggedIn='([^']+)'", Pattern.CASE_INSENSITIVE);
+ final Pattern patternGuid = Pattern.compile("cacheId='([^']+)'", Pattern.CASE_INSENSITIVE);
+ final Pattern patternRating = Pattern.compile("voteAvg='([0-9\\.]+)'", Pattern.CASE_INSENSITIVE);
+ final Pattern patternVotes = Pattern.compile("voteCnt='([0-9]+)'", Pattern.CASE_INSENSITIVE);
+ final Pattern patternVote = Pattern.compile("voteUser='([0-9\\.]+)'", Pattern.CASE_INSENSITIVE);
+
+ String voteData = null;
+ final Pattern patternVoteElement = Pattern.compile("<vote ([^>]+)>", Pattern.CASE_INSENSITIVE);
+ final Matcher matcherVoteElement = patternVoteElement.matcher(votes);
+ while (matcherVoteElement.find()) {
+ if (matcherVoteElement.groupCount() > 0) {
+ voteData = matcherVoteElement.group(1);
+ }
+
+ if (voteData == null) {
+ continue;
+ }
+
+ String guid = null;
+ cgRating rating = new cgRating();
+ boolean loggedIn = false;
+
+ try {
+ final Matcher matcherGuid = patternGuid.matcher(voteData);
+ if (matcherGuid.find()) {
+ if (matcherGuid.groupCount() > 0) {
+ guid = (String) matcherGuid.group(1);
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgBase.getRating: Failed to parse guid");
+ }
+
+ try {
+ final Matcher matcherLoggedIn = patternLogIn.matcher(votes);
+ if (matcherLoggedIn.find()) {
+ if (matcherLoggedIn.groupCount() > 0) {
+ if (matcherLoggedIn.group(1).equalsIgnoreCase("true") == true) {
+ loggedIn = true;
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgBase.getRating: Failed to parse loggedIn");
+ }
+
+ try {
+ final Matcher matcherRating = patternRating.matcher(voteData);
+ if (matcherRating.find()) {
+ if (matcherRating.groupCount() > 0) {
+ rating.rating = Float.parseFloat(matcherRating.group(1));
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgBase.getRating: Failed to parse rating");
+ }
+
+ try {
+ final Matcher matcherVotes = patternVotes.matcher(voteData);
+ if (matcherVotes.find()) {
+ if (matcherVotes.groupCount() > 0) {
+ rating.votes = Integer.parseInt(matcherVotes.group(1));
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgBase.getRating: Failed to parse vote count");
+ }
+
+ if (loggedIn == true) {
+ try {
+ final Matcher matcherVote = patternVote.matcher(voteData);
+ if (matcherVote.find()) {
+ if (matcherVote.groupCount() > 0) {
+ rating.myVote = Float.parseFloat(matcherVote.group(1));
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgBase.getRating: Failed to parse user's vote");
+ }
+ }
+
+ if (guid != null) {
+ ratings.put(guid, rating);
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.getRating: " + e.toString());
+ }
+
+ return ratings;
+ }
+
+ public boolean setRating(String guid, int vote) {
+ if (guid == null || guid.length() == 0) {
+ return false;
+ }
+ if (vote < 0 || vote > 5) {
+ return false;
+ }
+
+ final HashMap<String, String> login = settings.getGCvoteLogin();
+ if (login == null) {
+ return false;
+ }
+
+ final HashMap<String, String> params = new HashMap<String, String>();
+ params.put("userName", login.get("username"));
+ params.put("password", login.get("password"));
+ params.put("cacheId", guid);
+ params.put("voteUser", Integer.toString(vote));
+ params.put("version", "cgeo");
+
+ final String result = request(false, "gcvote.com", "/setVote.php", "GET", params, false, false, false).getData();
+
+ if (result.trim().equalsIgnoreCase("ok") == true) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public Long parseGPX(cgeoapplication app, File file, int listId, Handler handler) {
+ cgSearch search = new cgSearch();
+ long searchId = 0l;
+
+ try {
+ cgGPXParser GPXparser = new cgGPXParser(app, this, listId, search);
+
+ searchId = GPXparser.parse(file, 10, handler);
+ if (searchId == 0l) {
+ searchId = GPXparser.parse(file, 11, handler);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.parseGPX: " + e.toString());
+ }
+
+ Log.i(cgSettings.tag, "Caches found in .gpx file: " + app.getCount(searchId));
+
+ return search.getCurrentId();
+ }
+
+ public cgTrackable parseTrackable(String page) {
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.parseTrackable: No page given");
+ return null;
+ }
+
+ final Pattern patternTrackableId = Pattern.compile("<a id=\"ctl00_ContentBody_LogLink\" title=\"[^\"]*\" href=\".*log\\.aspx\\?wid=([a-z0-9\\-]+)\"[^>]*>[^<]*</a>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternGeocode = Pattern.compile("<span id=\"ctl00_ContentBody_BugDetails_BugTBNum\" String=\"[^\"]*\">Use[^<]*<strong>(TB[0-9a-z]+)[^<]*</strong> to reference this item.[^<]*</span>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternName = Pattern.compile("<h2>([^<]*<img[^>]*>)?[^<]*<span id=\"ctl00_ContentBody_lbHeading\">([^<]+)</span>[^<]*</h2>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternOwner = Pattern.compile("<dt>[^\\w]*Owner:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugOwner\" title=\"[^\"]*\" href=\"[^\"]*/profile/\\?guid=([a-z0-9\\-]+)\">([^<]+)<\\/a>[^<]*</dd>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternReleased = Pattern.compile("<dt>[^\\w]*Released:[^<]*</dt>[^<]*<dd>[^<]*<span id=\"ctl00_ContentBody_BugDetails_BugReleaseDate\">([^<]+)<\\/span>[^<]*</dd>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternOrigin = Pattern.compile("<dt>[^\\w]*Origin:[^<]*</dt>[^<]*<dd>[^<]*<span id=\"ctl00_ContentBody_BugDetails_BugOrigin\">([^<]+)<\\/span>[^<]*</dd>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternSpottedCache = Pattern.compile("<dt>[^\\w]*Recently Spotted:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugLocation\" title=\"[^\"]*\" href=\"[^\"]*/seek/cache_details.aspx\\?guid=([a-z0-9\\-]+)\">In ([^<]+)</a>[^<]*</dd>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternSpottedUser = Pattern.compile("<dt>[^\\w]*Recently Spotted:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugLocation\" href=\"[^\"]*/profile/\\?guid=([a-z0-9\\-]+)\">In the hands of ([^<]+).</a>[^<]*</dd>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternSpottedUnknown = Pattern.compile("<dt>[^\\w]*Recently Spotted:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugLocation\">Unknown Location[^<]*</a>[^<]*</dd>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternSpottedOwner = Pattern.compile("<dt>[^\\w]*Recently Spotted:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugLocation\">In the hands of the owner[^<]*</a>[^<]*</dd>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternGoal = Pattern.compile("<h3>[^\\w]*Current GOAL[^<]*</h3>[^<]*<p[^>]*>(.*)</p>[^<]*<h3>[^\\w]*About This Item[^<]*</h3>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternDetailsImage = Pattern.compile("<h3>[^\\w]*About This Item[^<]*</h3>([^<]*<p>([^<]*<img id=\"ctl00_ContentBody_BugDetails_BugImage\" class=\"[^\"]+\" src=\"([^\"]+)\"[^>]*>)?[^<]*</p>)?[^<]*<p[^>]*>(.*)</p>[^<]*<div id=\"ctl00_ContentBody_BugDetails_uxAbuseReport\">", Pattern.CASE_INSENSITIVE);
+ final Pattern patternLogs = Pattern.compile("<table class=\"TrackableItemLogTable Table\">(.*)<\\/table>[^<]*<ul", Pattern.CASE_INSENSITIVE);
+ final Pattern patternIcon = Pattern.compile("<img id=\"ctl00_ContentBody_BugTypeImage\" class=\"TravelBugHeaderIcon\" src=\"([^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternType = Pattern.compile("<img id=\"ctl00_ContentBody_BugTypeImage\" class=\"TravelBugHeaderIcon\" src=\"[^\"]+\" alt=\"([^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternDistance = Pattern.compile("<h4[^>]*[^\\w]*Tracking History \\(([0-9\\.,]+(km|mi))[^\\)]*\\)", Pattern.CASE_INSENSITIVE);
+
+ final cgTrackable trackable = new cgTrackable();
+
+ // trackable geocode
+ try {
+ final Matcher matcherGeocode = patternGeocode.matcher(page);
+ while (matcherGeocode.find()) {
+ if (matcherGeocode.groupCount() > 0) {
+ trackable.geocode = matcherGeocode.group(1).toUpperCase();
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable geocode
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable geocode");
+ }
+
+ // trackable id
+ try {
+ final Matcher matcherTrackableId = patternTrackableId.matcher(page);
+ while (matcherTrackableId.find()) {
+ if (matcherTrackableId.groupCount() > 0) {
+ trackable.guid = matcherTrackableId.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable id
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable id");
+ }
+
+ // trackable icon
+ try {
+ final Matcher matcherTrackableIcon = patternIcon.matcher(page);
+ while (matcherTrackableIcon.find()) {
+ if (matcherTrackableIcon.groupCount() > 0) {
+ trackable.iconUrl = matcherTrackableIcon.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable icon
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable icon");
+ }
+
+ // trackable name
+ try {
+ final Matcher matcherName = patternName.matcher(page);
+ while (matcherName.find()) {
+ if (matcherName.groupCount() > 1) {
+ trackable.name = matcherName.group(2);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable name
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable name");
+ }
+
+ // trackable type
+ if (trackable.name != null && trackable.name.length() > 0) {
+ try {
+ final Matcher matcherType = patternType.matcher(page);
+ while (matcherType.find()) {
+ if (matcherType.groupCount() > 0) {
+ trackable.type = matcherType.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable type
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable type");
+ }
+ }
+
+ // trackable owner name
+ try {
+ final Matcher matcherOwner = patternOwner.matcher(page);
+ while (matcherOwner.find()) {
+ if (matcherOwner.groupCount() > 0) {
+ trackable.ownerGuid = matcherOwner.group(1);
+ trackable.owner = matcherOwner.group(2);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable owner name
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable owner name");
+ }
+
+ // trackable origin
+ try {
+ final Matcher matcherOrigin = patternOrigin.matcher(page);
+ while (matcherOrigin.find()) {
+ if (matcherOrigin.groupCount() > 0) {
+ trackable.origin = matcherOrigin.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable origin
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable origin");
+ }
+
+ // trackable spotted
+ try {
+ final Matcher matcherSpottedCache = patternSpottedCache.matcher(page);
+ while (matcherSpottedCache.find()) {
+ if (matcherSpottedCache.groupCount() > 0) {
+ trackable.spottedGuid = matcherSpottedCache.group(1);
+ trackable.spottedName = matcherSpottedCache.group(2);
+ trackable.spottedType = cgTrackable.SPOTTED_CACHE;
+ }
+ }
+
+ final Matcher matcherSpottedUser = patternSpottedUser.matcher(page);
+ while (matcherSpottedUser.find()) {
+ if (matcherSpottedUser.groupCount() > 0) {
+ trackable.spottedGuid = matcherSpottedUser.group(1);
+ trackable.spottedName = matcherSpottedUser.group(2);
+ trackable.spottedType = cgTrackable.SPOTTED_USER;
+ }
+ }
+
+ final Matcher matcherSpottedUnknown = patternSpottedUnknown.matcher(page);
+ if (matcherSpottedUnknown.find()) {
+ trackable.spottedType = cgTrackable.SPOTTED_UNKNOWN;
+ }
+
+ final Matcher matcherSpottedOwner = patternSpottedOwner.matcher(page);
+ if (matcherSpottedOwner.find()) {
+ trackable.spottedType = cgTrackable.SPOTTED_OWNER;
+ }
+ } catch (Exception e) {
+ // failed to parse trackable last known place
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable last known place");
+ }
+
+ // released
+ try {
+ final Matcher matcherReleased = patternReleased.matcher(page);
+ while (matcherReleased.find()) {
+ if (matcherReleased.groupCount() > 0 && matcherReleased.group(1) != null) {
+ try {
+ if (trackable.released == null) {
+ trackable.released = dateTbIn1.parse(matcherReleased.group(1));
+ }
+ } catch (Exception e) {
+ //
+ }
+
+ try {
+ if (trackable.released == null) {
+ trackable.released = dateTbIn2.parse(matcherReleased.group(1));
+ }
+ } catch (Exception e) {
+ //
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable released date
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable released date");
+ }
+
+ // trackable distance
+ try {
+ final Matcher matcherDistance = patternDistance.matcher(page);
+ while (matcherDistance.find()) {
+ if (matcherDistance.groupCount() > 0) {
+ trackable.distance = parseDistance(matcherDistance.group(1));
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable distance
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable distance");
+ }
+
+ // trackable goal
+ try {
+ final Matcher matcherGoal = patternGoal.matcher(page);
+ while (matcherGoal.find()) {
+ if (matcherGoal.groupCount() > 0) {
+ trackable.goal = matcherGoal.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable goal
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable goal");
+ }
+
+ // trackable details & image
+ try {
+ final Matcher matcherDetailsImage = patternDetailsImage.matcher(page);
+ while (matcherDetailsImage.find()) {
+ if (matcherDetailsImage.groupCount() > 0) {
+ final String image = matcherDetailsImage.group(3);
+ final String details = matcherDetailsImage.group(4);
+
+ if (image != null) {
+ trackable.image = image;
+ }
+ if (details != null) {
+ trackable.details = details;
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable details & image
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable details & image");
+ }
+
+ // trackable logs
+ try {
+ final Matcher matcherLogs = patternLogs.matcher(page);
+ while (matcherLogs.find()) {
+ if (matcherLogs.groupCount() > 0) {
+ final Pattern patternLog = Pattern.compile("[^>]*>" +
+ "[^<]*<td[^<]*<img src=[\"|'].*\\/icons\\/([^\\.]+)\\.[a-z]{2,5}[\"|'][^>]*>&nbsp;(\\d+).(\\d+).(\\d+)[^<]*</td>" +
+ "[^<]*<td>[^<]*<a href=[^>]+>([^<]+)<.a>([^<]*|[^<]*<a href=[\"|'].*guid=([^\"]*)\">([^<]*)</a>[^<]*)</td>" +
+ "[^<]*<td>[^<]*</td>" +
+ "[^<]*<td[^<]*<a href=[^>]+>[^<]+</a>[^<]*</td>[^<]*</tr>" +
+ "[^<]*<tr[^>]*>[^<]*<td[^>]*>(.*?)</td>[^<]*</tr>.*" +
+ "");
+ // 1 filename == type
+ // 2 month
+ // 3 date
+ // 4 year
+ // 5 user
+ // 6 action dependent
+ // 7 cache guid
+ // 8 cache name
+ // 9 text
+ final String[] logs = matcherLogs.group(1).split("<tr class=\"Data BorderTop");
+ final int logsCnt = logs.length;
+
+ for (int k = 1; k < logsCnt; k++) {
+ final Matcher matcherLog = patternLog.matcher(logs[k]);
+ if (matcherLog.find()) {
+ final cgLog logDone = new cgLog();
+
+ String logTmp = matcherLog.group(9);
+ logTmp = Pattern.compile("<p>").matcher(logTmp).replaceAll("\n");
+ logTmp = Pattern.compile("<br[^>]*>").matcher(logTmp).replaceAll("\n");
+ logTmp = Pattern.compile("<\\/p>").matcher(logTmp).replaceAll("");
+ logTmp = Pattern.compile("\r+").matcher(logTmp).replaceAll("\n");
+
+ int day = -1;
+ try {
+ day = Integer.parseInt(matcherLog.group(3));
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse logs date (day): " + e.toString());
+ }
+
+ int month = -1;
+ try {
+ month = Integer.parseInt(matcherLog.group(2));
+ month -= 1;
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse logs date (month): " + e.toString());
+ }
+
+ int year = -1;
+ try {
+ year = Integer.parseInt(matcherLog.group(4));
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse logs date (year): " + e.toString());
+ }
+
+ long logDate;
+ if (year > 0 && month >= 0 && day > 0) {
+ Calendar date = Calendar.getInstance();
+ date.set(year, month, day, 12, 0, 0);
+ logDate = date.getTimeInMillis();
+ logDate = (long) (Math.ceil(logDate / 1000)) * 1000;
+ } else {
+ logDate = 0;
+ }
+
+ if (logTypes.containsKey(matcherLog.group(1).toLowerCase()) == true) {
+ logDone.type = logTypes.get(matcherLog.group(1).toLowerCase());
+ } else {
+ logDone.type = logTypes.get("icon_note");
+ }
+
+ logDone.author = Html.fromHtml(matcherLog.group(5)).toString();
+ logDone.date = logDate;
+ logDone.log = logTmp;
+ if (matcherLog.group(7) != null && matcherLog.group(8) != null) {
+ logDone.cacheGuid = matcherLog.group(7);
+ logDone.cacheName = matcherLog.group(8);
+ }
+
+ trackable.logs.add(logDone);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse logs
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache logs");
+ }
+
+ app.saveTrackable(trackable);
+
+ return trackable;
+ }
+
+ public ArrayList<Integer> parseTypes(String page) {
+ if (page == null || page.length() == 0) {
+ return null;
+ }
+
+ final ArrayList<Integer> types = new ArrayList<Integer>();
+
+ final Pattern typeBoxPattern = Pattern.compile("<select name=\"ctl00\\$ContentBody\\$LogBookPanel1\\$ddLogType\" id=\"ctl00_ContentBody_LogBookPanel1_ddLogType\"[^>]*>"
+ + "(([^<]*<option[^>]*>[^<]+</option>)+)[^<]*</select>", Pattern.CASE_INSENSITIVE);
+ final Matcher typeBoxMatcher = typeBoxPattern.matcher(page);
+ String typesText = null;
+ if (typeBoxMatcher.find()) {
+ if (typeBoxMatcher.groupCount() > 0) {
+ typesText = typeBoxMatcher.group(1);
+ }
+ }
+
+ if (typesText != null) {
+ final Pattern typePattern = Pattern.compile("<option( selected=\"selected\")? value=\"(\\d+)\">[^<]+</option>", Pattern.CASE_INSENSITIVE);
+ final Matcher typeMatcher = typePattern.matcher(typesText);
+ while (typeMatcher.find()) {
+ if (typeMatcher.groupCount() > 1) {
+ final int type = Integer.parseInt(typeMatcher.group(2));
+
+ if (type > 0) {
+ types.add(type);
+ }
+ }
+ }
+ }
+
+ return types;
+ }
+
+ public ArrayList<cgTrackableLog> parseTrackableLog(String page) {
+ if (page == null || page.length() == 0) {
+ return null;
+ }
+
+ final ArrayList<cgTrackableLog> trackables = new ArrayList<cgTrackableLog>();
+
+ int startPos = -1;
+ int endPos = -1;
+
+ startPos = page.indexOf("<table id=\"tblTravelBugs\"");
+ if (startPos == -1) {
+ Log.e(cgSettings.tag, "cgeoBase.parseTrackableLog: ID \"tblTravelBugs\" not found on page");
+ return null;
+ }
+
+ page = page.substring(startPos); // cut on <table
+
+ endPos = page.indexOf("</table>");
+ if (endPos == -1) {
+ Log.e(cgSettings.tag, "cgeoBase.parseTrackableLog: end of ID \"tblTravelBugs\" not found on page");
+ return null;
+ }
+
+ page = page.substring(0, endPos); // cut on </table>
+
+ startPos = page.indexOf("<tbody>");
+ if (startPos == -1) {
+ Log.e(cgSettings.tag, "cgeoBase.parseTrackableLog: tbody not found on page");
+ return null;
+ }
+
+ page = page.substring(startPos); // cut on <tbody>
+
+ endPos = page.indexOf("</tbody>");
+ if (endPos == -1) {
+ Log.e(cgSettings.tag, "cgeoBase.parseTrackableLog: end of tbody not found on page");
+ return null;
+ }
+
+ page = page.substring(0, endPos); // cut on </tbody>
+
+ final Pattern trackablePattern = Pattern.compile("<tr id=\"ctl00_ContentBody_LogBookPanel1_uxTrackables_repTravelBugs_ctl[0-9]+_row\"[^>]*>"
+ + "[^<]*<td>[^<]*<a href=\"[^\"]+\">([A-Z0-9]+)</a>[^<]*</td>[^<]*<td>([^<]+)</td>[^<]*<td>"
+ + "[^<]*<select name=\"ctl00\\$ContentBody\\$LogBookPanel1\\$uxTrackables\\$repTravelBugs\\$ctl([0-9]+)\\$ddlAction\"[^>]*>"
+ + "([^<]*<option value=\"([0-9]+)(_[a-z]+)?\">[^<]+</option>)+"
+ + "[^<]*</select>[^<]*</td>[^<]*</tr>", Pattern.CASE_INSENSITIVE);
+ final Matcher trackableMatcher = trackablePattern.matcher(page);
+ while (trackableMatcher.find()) {
+ if (trackableMatcher.groupCount() > 0) {
+ final cgTrackableLog trackable = new cgTrackableLog();
+
+ if (trackableMatcher.group(1) != null) {
+ trackable.trackCode = trackableMatcher.group(1);
+ } else {
+ continue;
+ }
+ if (trackableMatcher.group(2) != null) {
+ trackable.name = Html.fromHtml(trackableMatcher.group(2)).toString();
+ } else {
+ continue;
+ }
+ if (trackableMatcher.group(3) != null) {
+ trackable.ctl = new Integer(trackableMatcher.group(3));
+ } else {
+ continue;
+ }
+ if (trackableMatcher.group(5) != null) {
+ trackable.id = new Integer(trackableMatcher.group(5));
+ } else {
+ continue;
+ }
+
+ Log.i(cgSettings.tag, "Trackable in inventory (#" + trackable.ctl + "/" + trackable.id + "): " + trackable.trackCode + " - " + trackable.name);
+
+ trackables.add(trackable);
+ }
+ }
+
+ return trackables;
+ }
+
+ public int parseFindCount(String page) {
+ if (page == null || page.length() == 0) {
+ return -1;
+ }
+
+ int findCount = -1;
+
+ try {
+ final Pattern findPattern = Pattern.compile("<strong>Caches Found:<\\/strong>([^<]+)<br", Pattern.CASE_INSENSITIVE);
+ final Matcher findMatcher = findPattern.matcher(page);
+ if (findMatcher.find() == true) {
+ if (findMatcher.groupCount() > 0) {
+ String count = findMatcher.group(1);
+
+ if (count != null) {
+ count = count.trim();
+
+ if (count.length() == 0) {
+ findCount = 0;
+ } else {
+ findCount = Integer.parseInt(count);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgBase.parseFindCount: " + e.toString());
+ }
+
+ return findCount;
+ }
+
+
+ public static String stripParagraphs(String text) {
+ if (text == null) {
+ return "";
+ }
+
+ final Pattern patternP = Pattern.compile("(<p>|</p>|<br \\/>|<br>)", Pattern.CASE_INSENSITIVE);
+ final Pattern patternP2 = Pattern.compile("([ ]+)", Pattern.CASE_INSENSITIVE);
+ final Matcher matcherP = patternP.matcher(text);
+ final Matcher matcherP2 = patternP2.matcher(text);
+
+ matcherP.replaceAll(" ");
+ matcherP2.replaceAll(" ");
+
+ return text.trim();
+ }
+
+ public static String stripTags(String text) {
+ if (text == null) {
+ return "";
+ }
+
+ final Pattern patternP = Pattern.compile("(<[^>]+>)", Pattern.CASE_INSENSITIVE);
+ final Matcher matcherP = patternP.matcher(text);
+
+ matcherP.replaceAll(" ");
+
+ return text.trim();
+ }
+
+ public static String capitalizeSentence(String sentence) {
+ if (sentence == null) {
+ return "";
+ }
+
+ final String[] word = sentence.split(" ");
+
+ for (int i = 0; i < word.length; i++) {
+ word[i] = capitalizeWord(word[i]);
+ }
+
+ return implode(" ", word);
+ }
+
+ public static String capitalizeWord(String word) {
+ if (word.length() == 0) {
+ return word;
+ }
+
+ return (word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase());
+ }
+
+ public static Double parseDistance(String dst) {
+ Double distance = null;
+
+ final Pattern pattern = Pattern.compile("([0-9\\.,]+)[ ]*(km|mi)", Pattern.CASE_INSENSITIVE);
+ final Matcher matcher = pattern.matcher(dst);
+ while (matcher.find()) {
+ if (matcher.groupCount() > 1) {
+ if (matcher.group(2).equalsIgnoreCase("km") == true) {
+ distance = new Double(matcher.group(1));
+ } else {
+ distance = new Double(matcher.group(1)) / kmInMiles;
+ }
+ }
+ }
+
+ return distance;
+ }
+
+ public static double getDistance(Double lat1, Double lon1, Double lat2, Double lon2) {
+ if (lat1 == null || lon1 == null || lat2 == null || lon2 == null) {
+ return 0d;
+ }
+
+ lat1 *= deg2rad;
+ lon1 *= deg2rad;
+ lat2 *= deg2rad;
+ lon2 *= deg2rad;
+
+ final double d = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2);
+ final double distance = erad * Math.acos(d); // distance in km
+
+ if (Double.isNaN(distance) == false && distance > 0) {
+ return distance;
+ } else {
+ return 0d;
+ }
+ }
+
+ public static Double getHeading(Double lat1, Double lon1, Double lat2, Double lon2) {
+ Double result = new Double(0);
+
+ int ilat1 = (int) Math.round(0.5 + lat1 * 360000);
+ int ilon1 = (int) Math.round(0.5 + lon1 * 360000);
+ int ilat2 = (int) Math.round(0.5 + lat2 * 360000);
+ int ilon2 = (int) Math.round(0.5 + lon2 * 360000);
+
+ lat1 *= deg2rad;
+ lon1 *= deg2rad;
+ lat2 *= deg2rad;
+ lon2 *= deg2rad;
+
+ if (ilat1 == ilat2 && ilon1 == ilon2) {
+ return new Double(result);
+ } else if (ilat1 == ilat2) {
+ if (ilon1 > ilon2) {
+ result = new Double(270);
+ } else {
+ result = new Double(90);
+ }
+ } else if (ilon1 == ilon2) {
+ if (ilat1 > ilat2) {
+ result = new Double(180);
+ }
+ } else {
+ Double c = Math.acos(Math.sin(lat2) * Math.sin(lat1) + Math.cos(lat2) * Math.cos(lat1) * Math.cos(lon2 - lon1));
+ Double A = Math.asin(Math.cos(lat2) * Math.sin(lon2 - lon1) / Math.sin(c));
+ result = new Double(A * rad2deg);
+ if (ilat2 > ilat1 && ilon2 > ilon1) {
+ // result don't need change
+ } else if (ilat2 < ilat1 && ilon2 < ilon1) {
+ result = 180f - result;
+ } else if (ilat2 < ilat1 && ilon2 > ilon1) {
+ result = 180f - result;
+ } else if (ilat2 > ilat1 && ilon2 < ilon1) {
+ result += 360f;
+ }
+ }
+
+ return result;
+ }
+
+ public HashMap<String, Double> getRadialDistance(Double latitude, Double longitude, Double bearing, Double distance) {
+ final Double rlat1 = latitude * deg2rad;
+ final Double rlon1 = longitude * deg2rad;
+ final Double rbearing = bearing * deg2rad;
+ final Double rdistance = distance / erad;
+
+ final Double rlat = Math.asin(Math.sin(rlat1) * Math.cos(rdistance) + Math.cos(rlat1) * Math.sin(rdistance) * Math.cos(rbearing));
+ final Double rlon = rlon1 + Math.atan2(Math.sin(rbearing) * Math.sin(rdistance) * Math.cos(rlat1), Math.cos(rdistance) - Math.sin(rlat1) * Math.sin(rlat));
+
+ HashMap<String, Double> result = new HashMap<String, Double>();
+ result.put("latitude", rlat * rad2deg);
+ result.put("longitude", rlon * rad2deg);
+
+ return result;
+ }
+
+ public String getHumanDistance(Float distance) {
+ if (distance == null) {
+ return "?";
+ }
+
+ return getHumanDistance(new Double(distance));
+ }
+
+ public String getHumanDistance(Double distance) {
+ if (distance == null) {
+ return "?";
+ }
+
+ if (settings.units == cgSettings.unitsImperial) {
+ distance *= kmInMiles;
+ if (distance > 100) {
+ return String.format(Locale.getDefault(), "%.0f", new Double(Math.round(distance))) + " mi";
+ } else if (distance > 0.5) {
+ return String.format(Locale.getDefault(), "%.1f", new Double(Math.round(distance * 10.0) / 10.0)) + " mi";
+ } else if (distance > 0.1) {
+ return String.format(Locale.getDefault(), "%.2f", new Double(Math.round(distance * 100.0) / 100.0)) + " mi";
+ } else if (distance > 0.05) {
+ return String.format(Locale.getDefault(), "%.0f", new Double(Math.round(distance * 5280.0))) + " ft";
+ } else if (distance > 0.01) {
+ return String.format(Locale.getDefault(), "%.1f", new Double(Math.round(distance * 5280 * 10.0) / 10.0)) + " ft";
+ } else {
+ return String.format(Locale.getDefault(), "%.2f", new Double(Math.round(distance * 5280 * 100.0) / 100.0)) + " ft";
+ }
+ } else {
+ if (distance > 100) {
+ return String.format(Locale.getDefault(), "%.0f", new Double(Math.round(distance))) + " km";
+ } else if (distance > 10) {
+ return String.format(Locale.getDefault(), "%.1f", new Double(Math.round(distance * 10.0) / 10.0)) + " km";
+ } else if (distance > 1) {
+ return String.format(Locale.getDefault(), "%.2f", new Double(Math.round(distance * 100.0) / 100.0)) + " km";
+ } else if (distance > 0.1) {
+ return String.format(Locale.getDefault(), "%.0f", new Double(Math.round(distance * 1000.0))) + " m";
+ } else if (distance > 0.01) {
+ return String.format(Locale.getDefault(), "%.1f", new Double(Math.round(distance * 1000.0 * 10.0) / 10.0)) + " m";
+ } else {
+ return String.format(Locale.getDefault(), "%.2f", new Double(Math.round(distance * 1000.0 * 100.0) / 100.0)) + " m";
+ }
+ }
+ }
+
+ public String getHumanSpeed(float speed) {
+ double kph = speed * 3.6;
+ String unit = "kmh";
+
+ if (this.settings.units == cgSettings.unitsImperial) {
+ kph *= kmInMiles;
+ unit = "mph";
+ }
+
+ if (kph < 10) {
+ return String.format(Locale.getDefault(), "%.1f", new Double((Math.round(kph * 10) / 10))) + " " + unit;
+ } else {
+ return String.format(Locale.getDefault(), "%.0f", new Double(Math.round(kph))) + " " + unit;
+ }
+ }
+
+ public HashMap<String, Object> parseLatlon(String latlon) {
+ final HashMap<String, Object> result = new HashMap<String, Object>();
+ final Pattern patternLatlon = Pattern.compile("([NS])[^\\d]*(\\d+)[^°]*° (\\d+)\\.(\\d+) ([WE])[^\\d]*(\\d+)[^°]*° (\\d+)\\.(\\d+)", Pattern.CASE_INSENSITIVE);
+ final Matcher matcherLatlon = patternLatlon.matcher(latlon);
+
+ while (matcherLatlon.find()) {
+ if (matcherLatlon.groupCount() > 0) {
+ result.put("latitudeString", (String) (matcherLatlon.group(1) + " " + matcherLatlon.group(2) + "° " + matcherLatlon.group(3) + "." + matcherLatlon.group(4)));
+ result.put("longitudeString", (String) (matcherLatlon.group(5) + " " + matcherLatlon.group(6) + "° " + matcherLatlon.group(7) + "." + matcherLatlon.group(8)));
+ int latNegative = -1;
+ int lonNegative = -1;
+ if (matcherLatlon.group(1).equalsIgnoreCase("N")) {
+ latNegative = 1;
+ }
+ if (matcherLatlon.group(5).equalsIgnoreCase("E")) {
+ lonNegative = 1;
+ }
+ result.put("latitude", new Double(latNegative * (new Float(matcherLatlon.group(2)) + new Float(matcherLatlon.group(3) + "." + matcherLatlon.group(4)) / 60)));
+ result.put("longitude", new Double(lonNegative * (new Float(matcherLatlon.group(6)) + new Float(matcherLatlon.group(7) + "." + matcherLatlon.group(8)) / 60)));
+ } else {
+ Log.w(cgSettings.tag, "cgBase.parseLatlon: Failed to parse coordinates.");
+ }
+ }
+
+ return result;
+ }
+
+ public String formatCoordinate(Double coord, String latlon, boolean degrees) {
+ String formatted = "";
+
+ if (coord == null) {
+ return formatted;
+ }
+
+ String worldSide = "";
+ if (latlon.equalsIgnoreCase("lat") == true) {
+ if (coord >= 0) {
+ // have the blanks here at the direction to avoid one String concatenation
+ worldSide = "N ";
+ } else {
+ worldSide = "S ";
+ }
+ } else if (latlon.equalsIgnoreCase("lon") == true) {
+ if (coord >= 0) {
+ worldSide = "E ";
+ } else {
+ worldSide = "W ";
+ }
+ }
+
+ coord = Math.abs(coord);
+
+ if (latlon.equalsIgnoreCase("lat") == true) {
+ if (degrees == true) {
+ formatted = worldSide + String.format(Locale.getDefault(), "%02.0f", Math.floor(coord)) + "° " + String.format(Locale.getDefault(), "%06.3f", ((coord - Math.floor(coord)) * 60));
+ } else {
+ formatted = worldSide + String.format(Locale.getDefault(), "%02.0f", Math.floor(coord)) + " " + String.format(Locale.getDefault(), "%06.3f", ((coord - Math.floor(coord)) * 60));
+ }
+ } else {
+ if (degrees == true) {
+ formatted = worldSide + String.format(Locale.getDefault(), "%03.0f", Math.floor(coord)) + "° " + String.format(Locale.getDefault(), "%06.3f", ((coord - Math.floor(coord)) * 60));
+ } else {
+ formatted = worldSide + String.format(Locale.getDefault(), "%03.0f", Math.floor(coord)) + " " + String.format(Locale.getDefault(), "%06.3f", ((coord - Math.floor(coord)) * 60));
+ }
+ }
+
+ return formatted;
+ }
+
+ public HashMap<String, Object> parseCoordinate(String coord, String latlon) {
+ final HashMap<String, Object> coords = new HashMap<String, Object>();
+
+ final Pattern patternA = Pattern.compile("^([NSWE])[^\\d]*(\\d+)°? +(\\d+)([\\.|,](\\d+))?$", Pattern.CASE_INSENSITIVE);
+ final Pattern patternB = Pattern.compile("^([NSWE])[^\\d]*(\\d+)([\\.|,](\\d+))?$", Pattern.CASE_INSENSITIVE);
+ final Pattern patternC = Pattern.compile("^(-?\\d+)([\\.|,](\\d+))?$", Pattern.CASE_INSENSITIVE);
+ final Pattern patternD = Pattern.compile("^([NSWE])[^\\d]*(\\d+)°?$", Pattern.CASE_INSENSITIVE);
+ final Pattern patternE = Pattern.compile("^(-?\\d+)°?$", Pattern.CASE_INSENSITIVE);
+ final Pattern patternF = Pattern.compile("^([NSWE])[^\\d]*(\\d+)$", Pattern.CASE_INSENSITIVE);
+ final Pattern pattern0 = Pattern.compile("^(-?\\d+)([\\.|,](\\d+))?$", Pattern.CASE_INSENSITIVE);
+
+ coord = coord.trim().toUpperCase();
+
+ final Matcher matcherA = patternA.matcher(coord);
+ final Matcher matcherB = patternB.matcher(coord);
+ final Matcher matcherC = patternC.matcher(coord);
+ final Matcher matcherD = patternD.matcher(coord);
+ final Matcher matcherE = patternE.matcher(coord);
+ final Matcher matcherF = patternF.matcher(coord);
+ final Matcher matcher0 = pattern0.matcher(coord);
+
+ int latlonNegative;
+ if (matcherA.find() == true && matcherA.groupCount() > 0) {
+ if (matcherA.group(1).equalsIgnoreCase("N") || matcherA.group(1).equalsIgnoreCase("E")) {
+ latlonNegative = 1;
+ } else {
+ latlonNegative = -1;
+ }
+
+ if (matcherA.groupCount() < 5 || matcherA.group(5) == null) {
+ coords.put("coordinate", new Double(latlonNegative * (new Double(matcherA.group(2)) + new Double(matcherA.group(3) + ".0") / 60)));
+ coords.put("string", matcherA.group(1) + " " + matcherA.group(2) + "° " + matcherA.group(3) + ".000");
+ } else {
+ coords.put("coordinate", new Double(latlonNegative * (new Double(matcherA.group(2)) + new Double(matcherA.group(3) + "." + matcherA.group(5)) / 60)));
+ coords.put("string", matcherA.group(1) + " " + matcherA.group(2) + "° " + matcherA.group(3) + "." + matcherA.group(5));
+ }
+
+ return coords;
+ } else if (matcherB.find() == true && matcherB.groupCount() > 0) {
+ if (matcherB.group(1).equalsIgnoreCase("N") || matcherB.group(1).equalsIgnoreCase("E")) {
+ latlonNegative = 1;
+ } else {
+ latlonNegative = -1;
+ }
+
+ if (matcherB.groupCount() < 4 || matcherB.group(4) == null) {
+ coords.put("coordinate", new Double(latlonNegative * (new Double(matcherB.group(2) + ".0"))));
+ } else {
+ coords.put("coordinate", new Double(latlonNegative * (new Double(matcherB.group(2) + "." + matcherB.group(4)))));
+ }
+ } else if (matcherC.find() == true && matcherC.groupCount() > 0) {
+ if (matcherC.groupCount() < 3 || matcherC.group(3) == null) {
+ coords.put("coordinate", new Double(new Float(matcherC.group(1) + ".0")));
+ } else {
+ coords.put("coordinate", new Double(new Float(matcherC.group(1) + "." + matcherC.group(3))));
+ }
+ } else if (matcherD.find() == true && matcherD.groupCount() > 0) {
+ if (matcherD.group(1).equalsIgnoreCase("N") || matcherD.group(1).equalsIgnoreCase("E")) {
+ latlonNegative = 1;
+ } else {
+ latlonNegative = -1;
+ }
+
+ coords.put("coordinate", new Double(latlonNegative * (new Double(matcherB.group(2)))));
+ } else if (matcherE.find() == true && matcherE.groupCount() > 0) {
+ coords.put("coordinate", new Double(matcherE.group(1)));
+ } else if (matcherF.find() == true && matcherF.groupCount() > 0) {
+ if (matcherF.group(1).equalsIgnoreCase("N") || matcherF.group(1).equalsIgnoreCase("E")) {
+ latlonNegative = 1;
+ } else {
+ latlonNegative = -1;
+ }
+
+ coords.put("coordinate", new Double(latlonNegative * (new Double(matcherB.group(2)))));
+ } else {
+ return null;
+ }
+
+ if (matcher0.find() == true && matcher0.groupCount() > 0) {
+ String tmpDir = null;
+ Float tmpCoord;
+ if (matcher0.groupCount() < 3 || matcher0.group(3) == null) {
+ tmpCoord = new Float("0.0");
+ } else {
+ tmpCoord = new Float("0." + matcher0.group(3));
+ }
+
+ if (latlon.equalsIgnoreCase("lat")) {
+ if (matcher0.group(1).equals("+")) {
+ tmpDir = "N";
+ }
+ if (matcher0.group(1).equals("-")) {
+ tmpDir = "S";
+ }
+ } else if (latlon.equalsIgnoreCase("lon")) {
+ if (matcher0.group(1).equals("+")) {
+ tmpDir = "E";
+ }
+ if (matcher0.group(1).equals("-")) {
+ tmpDir = "W";
+ }
+ }
+
+ coords.put("string", tmpDir + " " + matcher0.group(1) + "° " + (Math.round(tmpCoord / (1 / 60) * 1000) * 1000));
+
+ return coords;
+ } else {
+ return new HashMap<String, Object>();
+ }
+ }
+
+ public Long searchByNextPage(cgSearchThread thread, Long searchId, int reason, boolean showCaptcha) {
+ final String viewstate = app.getViewstate(searchId);
+ final String viewstate1 = app.getViewstate1(searchId);
+ cgCacheWrap caches = new cgCacheWrap();
+ String url = app.getUrl(searchId);
+
+ if (url == null || url.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByNextPage: No url found");
+ return searchId;
+ }
+
+ if (viewstate == null || viewstate.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByNextPage: No viewstate given");
+ return searchId;
+ }
+
+ String host = "www.geocaching.com";
+ String path = "/";
+ final String method = "POST";
+
+ int dash = -1;
+ if (url.indexOf("http://") > -1) {
+ url = url.substring(7);
+ }
+
+ dash = url.indexOf("/");
+ if (dash > -1) {
+ host = url.substring(0, dash);
+ url = url.substring(dash);
+ } else {
+ host = url;
+ url = "";
+ }
+
+ dash = url.indexOf("?");
+ if (dash > -1) {
+ path = url.substring(0, dash);
+ } else {
+ path = url;
+ }
+
+ final HashMap<String, String> params = new HashMap<String, String>();
+ params.put("__VIEWSTATE", viewstate);
+ if (viewstate1 != null) {
+ params.put("__VIEWSTATE1", viewstate1);
+ params.put("__VIEWSTATEFIELDCOUNT", "2");
+ }
+ params.put("__EVENTTARGET", "ctl00$ContentBody$pgrBottom$ctl08");
+ params.put("__EVENTARGUMENT", "");
+
+ String page = request(false, host, path, method, params, false, false, true).getData();
+ if (checkLogin(page) == false) {
+ int loginState = login();
+ if (loginState == 1) {
+ page = request(false, host, path, method, params, false, false, true).getData();
+ } else if (loginState == -3) {
+ Log.i(cgSettings.tag, "Working as guest.");
+ } else {
+ app.setError(searchId, errorRetrieve.get(loginState));
+ Log.e(cgSettings.tag, "cgeoBase.searchByNextPage: Can not log in geocaching");
+ return searchId;
+ }
+ }
+
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByNextPage: No data from server");
+ return searchId;
+ }
+
+ caches = parseSearch(thread, url, page, showCaptcha);
+ if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByNextPage: No cache parsed");
+ return searchId;
+ }
+
+ // save to application
+ app.setError(searchId, caches.error);
+ app.setViewstate(searchId, caches.viewstate);
+ app.setViewstate1(searchId, caches.viewstate1);
+
+ final ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ for (cgCache cache : caches.cacheList) {
+ app.addGeocode(searchId, cache.geocode);
+ cacheList.add(cache);
+ }
+
+ app.addSearch(searchId, cacheList, true, reason);
+
+ return searchId;
+ }
+
+ public Long searchByGeocode(HashMap<String, String> parameters, int reason, boolean forceReload) {
+ final cgSearch search = new cgSearch();
+ String geocode = parameters.get("geocode");
+ String guid = parameters.get("guid");
+
+ if ((geocode == null || geocode.length() == 0) && ((guid == null || guid.length() == 0))) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByGeocode: No geocode nor guid given");
+ return null;
+ }
+
+ if (forceReload == false && reason == 0 && (app.isOffline(geocode, guid) == true || app.isThere(geocode, guid, true, true) == true)) {
+ if ((geocode == null || geocode.length() == 0) && guid != null && guid.length() > 0) {
+ geocode = app.getGeocode(guid);
+ }
+
+ ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ cacheList.add(app.getCacheByGeocode(geocode, true, true, true, true, true, true));
+ search.addGeocode(geocode);
+
+ app.addSearch(search, cacheList, false, reason);
+
+ cacheList.clear();
+ cacheList = null;
+
+ return search.getCurrentId();
+ }
+
+ final String host = "www.geocaching.com";
+ final String path = "/seek/cache_details.aspx";
+ final String method = "GET";
+ final HashMap<String, String> params = new HashMap<String, String>();
+ if (geocode != null && geocode.length() > 0) {
+ params.put("wp", geocode);
+ } else if (guid != null && guid.length() > 0) {
+ params.put("guid", guid);
+ }
+ params.put("decrypt", "y");
+ params.put("log", "y"); // download logs (more than 5
+ params.put("numlogs", "35"); // 35 logs
+
+ String page = requestLogged(false, host, path, method, params, false, false, false);
+
+ if (page == null || page.length() == 0) {
+ if (app.isThere(geocode, guid, true, false) == true) {
+ if ((geocode == null || geocode.length() == 0) && guid != null && guid.length() > 0) {
+ Log.i(cgSettings.tag, "Loading old cache from cache.");
+
+ geocode = app.getGeocode(guid);
+ }
+
+ final ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ cacheList.add(app.getCacheByGeocode(geocode));
+ search.addGeocode(geocode);
+ search.error = null;
+ search.errorRetrieve = 0; // reset errors from previous failed request
+
+ app.addSearch(search, cacheList, false, reason);
+
+ cacheList.clear();
+
+ return search.getCurrentId();
+ }
+
+ Log.e(cgSettings.tag, "cgeoBase.searchByGeocode: No data from server");
+ return null;
+ }
+
+ final cgCacheWrap caches = parseCache(page, reason);
+ if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) {
+ if (caches != null && caches.error != null && caches.error.length() > 0) {
+ search.error = caches.error;
+ }
+ if (caches != null && caches.url != null && caches.url.length() > 0) {
+ search.url = caches.url;
+ }
+
+ app.addSearch(search, null, true, reason);
+
+ Log.e(cgSettings.tag, "cgeoBase.searchByGeocode: No cache parsed");
+ return null;
+ }
+
+ if (app == null) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByGeocode: No application found");
+ return null;
+ }
+
+ final ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ if (caches != null) {
+ if (caches.error != null && caches.error.length() > 0) {
+ search.error = caches.error;
+ }
+ if (caches.url != null && caches.url.length() > 0) {
+ search.url = caches.url;
+ }
+ if (caches.viewstate != null && caches.viewstate.length() > 0) {
+ search.viewstate = caches.viewstate;
+ }
+ if (caches.viewstate1 != null && caches.viewstate1.length() > 0) {
+ search.viewstate1 = caches.viewstate1;
+ }
+ search.totalCnt = caches.totalCnt;
+
+ for (cgCache cache : caches.cacheList) {
+ search.addGeocode(cache.geocode);
+ cacheList.add(cache);
+ }
+ }
+
+ app.addSearch(search, cacheList, true, reason);
+
+ page = null;
+ cacheList.clear();
+
+ return search.getCurrentId();
+ }
+
+ public Long searchByOffline(HashMap<String, Object> parameters) {
+ if (app == null) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByOffline: No application found");
+ return null;
+ }
+
+ Double latitude = null;
+ Double longitude = null;
+ String cachetype = null;
+ Integer list = 1;
+
+ if (parameters.containsKey("latitude") == true && parameters.containsKey("longitude") == true) {
+ latitude = (Double) parameters.get("latitude");
+ longitude = (Double) parameters.get("longitude");
+ }
+
+ if (parameters.containsKey("cachetype") == true) {
+ cachetype = (String) parameters.get("cachetype");
+ }
+
+ if (parameters.containsKey("list") == true) {
+ list = (Integer) parameters.get("list");
+ }
+
+ final cgSearch search = app.getBatchOfStoredCaches(true, latitude, longitude, cachetype, list);
+ search.totalCnt = app.getAllStoredCachesCount(true, cachetype, list);
+
+ return search.getCurrentId();
+ }
+
+ public Long searchByHistory(HashMap<String, Object> parameters) {
+ if (app == null) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByHistory: No application found");
+ return null;
+ }
+
+ String cachetype = null;
+
+ if (parameters.containsKey("cachetype") == true) {
+ cachetype = (String) parameters.get("cachetype");
+ }
+
+ final cgSearch search = app.getHistoryOfCaches(true, cachetype);
+ search.totalCnt = app.getAllHistoricCachesCount(true, cachetype);
+
+ return search.getCurrentId();
+ }
+
+ public Long searchByCoords(cgSearchThread thread, HashMap<String, String> parameters, int reason, boolean showCaptcha) {
+ final cgSearch search = new cgSearch();
+ final String latitude = parameters.get("latitude");
+ final String longitude = parameters.get("longitude");
+ cgCacheWrap caches = new cgCacheWrap();
+ String cacheType = parameters.get("cachetype");
+
+ if (latitude == null || latitude.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No latitude given");
+ return null;
+ }
+
+ if (longitude == null || longitude.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No longitude given");
+ return null;
+ }
+
+ if (cacheType != null && cacheType.length() == 0) {
+ cacheType = null;
+ }
+
+ final String host = "www.geocaching.com";
+ final String path = "/seek/nearest.aspx";
+ final String method = "GET";
+ final HashMap<String, String> params = new HashMap<String, String>();
+ if (cacheType != null && cacheIDs.containsKey(cacheType) == true) {
+ params.put("tx", cacheIDs.get(cacheType));
+ } else {
+ params.put("tx", cacheIDs.get("all"));
+ }
+ params.put("lat", latitude);
+ params.put("lng", longitude);
+
+ final String url = "http://" + host + path + "?" + prepareParameters(params, false, true);
+ String page = requestLogged(false, host, path, method, params, false, false, true);
+
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No data from server");
+ return null;
+ }
+
+ caches = parseSearch(thread, url, page, showCaptcha);
+ if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No cache parsed");
+ }
+
+ if (app == null) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No application found");
+ return null;
+ }
+
+ final ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ if (caches != null) {
+ if (caches.error != null && caches.error.length() > 0) {
+ search.error = caches.error;
+ }
+ if (caches.url != null && caches.url.length() > 0) {
+ search.url = caches.url;
+ }
+ if (caches.viewstate != null && caches.viewstate.length() > 0) {
+ search.viewstate = caches.viewstate;
+ }
+ if (caches.viewstate1 != null && caches.viewstate1.length() > 0) {
+ search.viewstate1 = caches.viewstate1;
+ }
+ search.totalCnt = caches.totalCnt;
+
+ for (cgCache cache : caches.cacheList) {
+ if (settings.excludeDisabled == 0 || (settings.excludeDisabled == 1 && cache.disabled == false)) {
+ search.addGeocode(cache.geocode);
+ cacheList.add(cache);
+ }
+ }
+ }
+
+ app.addSearch(search, cacheList, true, reason);
+
+ return search.getCurrentId();
+ }
+
+ public Long searchByKeyword(cgSearchThread thread, HashMap<String, String> parameters, int reason, boolean showCaptcha) {
+ final cgSearch search = new cgSearch();
+ final String keyword = parameters.get("keyword");
+ cgCacheWrap caches = new cgCacheWrap();
+ String cacheType = parameters.get("cachetype");
+
+ if (keyword == null || keyword.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByKeyword: No keyword given");
+ return null;
+ }
+
+ if (cacheType != null && cacheType.length() == 0) {
+ cacheType = null;
+ }
+
+ final String host = "www.geocaching.com";
+ final String path = "/seek/nearest.aspx";
+ final String method = "GET";
+ final HashMap<String, String> params = new HashMap<String, String>();
+ if (cacheType != null && cacheIDs.containsKey(cacheType) == true) {
+ params.put("tx", cacheIDs.get(cacheType));
+ } else {
+ params.put("tx", cacheIDs.get("all"));
+ }
+ params.put("key", keyword);
+
+ final String url = "http://" + host + path + "?" + prepareParameters(params, false, true);
+ String page = requestLogged(false, host, path, method, params, false, false, true);
+
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByKeyword: No data from server");
+ return null;
+ }
+
+ caches = parseSearch(thread, url, page, showCaptcha);
+ if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByKeyword: No cache parsed");
+ }
+
+ if (app == null) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No application found");
+ return null;
+ }
+
+ final ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ if (caches != null) {
+ if (caches.error != null && caches.error.length() > 0) {
+ search.error = caches.error;
+ }
+ if (caches.url != null && caches.url.length() > 0) {
+ search.url = caches.url;
+ }
+ if (caches.viewstate != null && caches.viewstate.length() > 0) {
+ search.viewstate = caches.viewstate;
+ }
+ if (caches.viewstate1 != null && caches.viewstate1.length() > 0) {
+ search.viewstate1 = caches.viewstate1;
+ }
+ search.totalCnt = caches.totalCnt;
+
+ for (cgCache cache : caches.cacheList) {
+ if (settings.excludeDisabled == 0 || (settings.excludeDisabled == 1 && cache.disabled == false)) {
+ search.addGeocode(cache.geocode);
+ cacheList.add(cache);
+ }
+ }
+ }
+
+ app.addSearch(search, cacheList, true, reason);
+
+ return search.getCurrentId();
+ }
+
+ public Long searchByUsername(cgSearchThread thread, HashMap<String, String> parameters, int reason, boolean showCaptcha) {
+ final cgSearch search = new cgSearch();
+ final String userName = parameters.get("username");
+ cgCacheWrap caches = new cgCacheWrap();
+ String cacheType = parameters.get("cachetype");
+
+ if (userName == null || userName.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByUsername: No user name given");
+ return null;
+ }
+
+ if (cacheType != null && cacheType.length() == 0) {
+ cacheType = null;
+ }
+
+ final String host = "www.geocaching.com";
+ final String path = "/seek/nearest.aspx";
+ final String method = "GET";
+ final HashMap<String, String> params = new HashMap<String, String>();
+ if (cacheType != null && cacheIDs.containsKey(cacheType) == true) {
+ params.put("tx", cacheIDs.get(cacheType));
+ } else {
+ params.put("tx", cacheIDs.get("all"));
+ }
+ params.put("ul", userName);
+
+ boolean my = false;
+ if (userName.equalsIgnoreCase(settings.getLogin().get("username")) == true) {
+ my = true;
+ Log.i(cgSettings.tag, "cgBase.searchByUsername: Overriding users choice, downloading all caches.");
+ }
+
+ final String url = "http://" + host + path + "?" + prepareParameters(params, my, true);
+ String page = requestLogged(false, host, path, method, params, false, my, true);
+
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByUsername: No data from server");
+ return null;
+ }
+
+ caches = parseSearch(thread, url, page, showCaptcha);
+ if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByUsername: No cache parsed");
+ }
+
+ if (app == null) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No application found");
+ return null;
+ }
+
+ final ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ if (caches != null) {
+ if (caches.error != null && caches.error.length() > 0) {
+ search.error = caches.error;
+ }
+ if (caches.url != null && caches.url.length() > 0) {
+ search.url = caches.url;
+ }
+ if (caches.viewstate != null && caches.viewstate.length() > 0) {
+ search.viewstate = caches.viewstate;
+ }
+ if (caches.viewstate1 != null && caches.viewstate1.length() > 0) {
+ search.viewstate1 = caches.viewstate1;
+ }
+ search.totalCnt = caches.totalCnt;
+
+ for (cgCache cache : caches.cacheList) {
+ if (settings.excludeDisabled == 0 || (settings.excludeDisabled == 1 && cache.disabled == false)) {
+ search.addGeocode(cache.geocode);
+ cacheList.add(cache);
+ }
+ }
+ }
+
+ app.addSearch(search, cacheList, true, reason);
+
+ return search.getCurrentId();
+ }
+
+ public Long searchByOwner(cgSearchThread thread, HashMap<String, String> parameters, int reason, boolean showCaptcha) {
+ final cgSearch search = new cgSearch();
+ final String userName = parameters.get("username");
+ cgCacheWrap caches = new cgCacheWrap();
+ String cacheType = parameters.get("cachetype");
+
+ if (userName == null || userName.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByOwner: No user name given");
+ return null;
+ }
+
+ if (cacheType != null && cacheType.length() == 0) {
+ cacheType = null;
+ }
+
+ final String host = "www.geocaching.com";
+ final String path = "/seek/nearest.aspx";
+ final String method = "GET";
+ final HashMap<String, String> params = new HashMap<String, String>();
+ if (cacheType != null && cacheIDs.containsKey(cacheType) == true) {
+ params.put("tx", cacheIDs.get(cacheType));
+ } else {
+ params.put("tx", cacheIDs.get("all"));
+ }
+ params.put("u", userName);
+
+ final String url = "http://" + host + path + "?" + prepareParameters(params, false, true);
+ String page = requestLogged(false, host, path, method, params, false, false, true);
+
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByOwner: No data from server");
+ return null;
+ }
+
+ caches = parseSearch(thread, url, page, showCaptcha);
+ if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByOwner: No cache parsed");
+ }
+
+ if (app == null) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No application found");
+ return null;
+ }
+
+ final ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ if (caches != null) {
+ if (caches.error != null && caches.error.length() > 0) {
+ search.error = caches.error;
+ }
+ if (caches.url != null && caches.url.length() > 0) {
+ search.url = caches.url;
+ }
+ if (caches.viewstate != null && caches.viewstate.length() > 0) {
+ search.viewstate = caches.viewstate;
+ }
+ if (caches.viewstate1 != null && caches.viewstate1.length() > 0) {
+ search.viewstate1 = caches.viewstate1;
+ }
+ search.totalCnt = caches.totalCnt;
+
+ for (cgCache cache : caches.cacheList) {
+ if (settings.excludeDisabled == 0 || (settings.excludeDisabled == 1 && cache.disabled == false)) {
+ search.addGeocode(cache.geocode);
+ cacheList.add(cache);
+ }
+ }
+ }
+
+ app.addSearch(search, cacheList, true, reason);
+
+ return search.getCurrentId();
+ }
+
+ public Long searchByViewport(HashMap<String, String> parameters, int reason) {
+ final cgSearch search = new cgSearch();
+ final String latMin = parameters.get("latitude-min");
+ final String latMax = parameters.get("latitude-max");
+ final String lonMin = parameters.get("longitude-min");
+ final String lonMax = parameters.get("longitude-max");
+
+ String usertoken = null;
+ if (parameters.get("usertoken") != null) {
+ usertoken = parameters.get("usertoken");
+ } else {
+ usertoken = "";
+ }
+ cgCacheWrap caches = new cgCacheWrap();
+
+ String page = null;
+
+ if (latMin == null || latMin.length() == 0 || latMax == null || latMax.length() == 0 || lonMin == null || lonMin.length() == 0 || lonMax == null || lonMax.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByViewport: Not enough parameters to recognize viewport");
+ return null;
+ }
+
+ final String host = "www.geocaching.com";
+ final String path = "/map/default.aspx/MapAction";
+
+ String params = "{\"dto\":{\"data\":{\"c\":1,\"m\":\"\",\"d\":\"" + latMax + "|" + latMin + "|" + lonMax + "|" + lonMin + "\"},\"ut\":\"" + usertoken + "\"}}";
+
+ final String url = "http://" + host + path + "?" + params;
+ page = requestJSONgc(host, path, params);
+
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByViewport: No data from server");
+ return null;
+ }
+
+ caches = parseMapJSON(url, page);
+ if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByViewport: No cache parsed");
+ }
+
+ if (app == null) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByViewport: No application found");
+ return null;
+ }
+
+ final ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ if (caches != null) {
+ if (caches.error != null && caches.error.length() > 0) {
+ search.error = caches.error;
+ }
+ if (caches.url != null && caches.url.length() > 0) {
+ search.url = caches.url;
+ }
+ if (caches.viewstate != null && caches.viewstate.length() > 0) {
+ search.viewstate = caches.viewstate;
+ }
+ if (caches.viewstate1 != null && caches.viewstate1.length() > 0) {
+ search.viewstate1 = caches.viewstate1;
+ }
+ search.totalCnt = caches.totalCnt;
+
+ if (caches.cacheList != null && caches.cacheList.size() > 0) {
+ for (cgCache cache : caches.cacheList) {
+ if ((settings.excludeDisabled == 0 || (settings.excludeDisabled == 1 && cache.disabled == false))
+ && (settings.excludeMine == 0 || (settings.excludeMine == 1 && cache.own == false))
+ && (settings.excludeMine == 0 || (settings.excludeMine == 1 && cache.found == false))
+ && (settings.cacheType == null || (settings.cacheType.equals(cache.type) == true))) {
+ search.addGeocode(cache.geocode);
+ cacheList.add(cache);
+ }
+ }
+ }
+ }
+
+ app.addSearch(search, cacheList, true, reason);
+
+ return search.getCurrentId();
+ }
+
+ public ArrayList<cgUser> getGeocachersInViewport(String username, Double latMin, Double latMax, Double lonMin, Double lonMax) {
+ final ArrayList<cgUser> users = new ArrayList<cgUser>();
+
+ if (username == null) {
+ return users;
+ }
+ if (latMin == null || latMax == null || lonMin == null || lonMax == null) {
+ return users;
+ }
+
+ final String host = "api.go4cache.com";
+ final String path = "/get.php";
+ final String method = "POST";
+ final HashMap<String, String> params = new HashMap<String, String>();
+
+ params.put("u", username);
+ params.put("ltm", String.format((Locale) null, "%.6f", latMin));
+ params.put("ltx", String.format((Locale) null, "%.6f", latMax));
+ params.put("lnm", String.format((Locale) null, "%.6f", lonMin));
+ params.put("lnx", String.format((Locale) null, "%.6f", lonMax));
+
+ final String data = request(false, host, path, method, params, false, false, false).getData();
+
+ if (data == null || data.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.getGeocachersInViewport: No data from server");
+ return null;
+ }
+
+ try {
+ final JSONObject dataJSON = new JSONObject(data);
+
+ final JSONArray usersData = dataJSON.getJSONArray("users");
+ if (usersData != null && usersData.length() > 0) {
+ int count = usersData.length();
+ JSONObject oneUser = null;
+ for (int i = 0; i < count; i++) {
+ final cgUser user = new cgUser();
+ oneUser = usersData.getJSONObject(i);
+ if (oneUser != null) {
+ final String located = oneUser.getString("located");
+ if (located != null) {
+ user.located = dateSqlIn.parse(located);
+ } else {
+ user.located = new Date();
+ }
+ user.username = oneUser.getString("user");
+ user.latitude = oneUser.getDouble("latitude");
+ user.longitude = oneUser.getDouble("longitude");
+ user.action = oneUser.getString("action");
+ user.client = oneUser.getString("client");
+
+ if (user.latitude != null && user.longitude != null) {
+ users.add(user);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.getGeocachersInViewport: " + e.toString());
+ }
+
+ return users;
+ }
+
+ public cgTrackable searchTrackable(HashMap<String, String> parameters) {
+ final String geocode = parameters.get("geocode");
+ final String guid = parameters.get("guid");
+ final String id = parameters.get("id");
+ cgTrackable trackable = new cgTrackable();
+
+ if ((geocode == null || geocode.length() == 0) && (guid == null || guid.length() == 0) && (id == null || id.length() == 0)) {
+ Log.e(cgSettings.tag, "cgeoBase.searchTrackable: No geocode nor guid nor id given");
+ return null;
+ }
+
+ final String host = "www.geocaching.com";
+ final String path = "/track/details.aspx";
+ final String method = "GET";
+ final HashMap<String, String> params = new HashMap<String, String>();
+ if (geocode != null && geocode.length() > 0) {
+ params.put("tracker", geocode);
+ } else if (guid != null && guid.length() > 0) {
+ params.put("guid", guid);
+ } else if (id != null && id.length() > 0) {
+ params.put("id", id);
+ }
+
+ String page = requestLogged(false, host, path, method, params, false, false, false);
+
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchTrackable: No data from server");
+ return trackable;
+ }
+
+ trackable = parseTrackable(page);
+ if (trackable == null) {
+ Log.e(cgSettings.tag, "cgeoBase.searchTrackable: No trackable parsed");
+ return trackable;
+ }
+
+ return trackable;
+ }
+
+ public int postLog(cgeoapplication app, String geocode, String cacheid, String viewstate, String viewstate1, int logType, int year, int month, int day, String log, ArrayList<cgTrackableLog> trackables) {
+ if (viewstate == null || viewstate.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.postLog: No viewstate given");
+ return 1000;
+ }
+
+ if (logTypes2.containsKey(logType) == false) {
+ Log.e(cgSettings.tag, "cgeoBase.postLog: Unknown logtype");
+ return 1000;
+ }
+
+ if (log == null || log.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.postLog: No log text given");
+ return 1001;
+ }
+
+ // fix log (non-Latin characters converted to HTML entities)
+ final int logLen = log.length();
+ final StringBuilder logUpdated = new StringBuilder();
+
+ for (int i = 0; i < logLen; i++) {
+ char c = log.charAt(i);
+
+ if (c > 300) {
+ logUpdated.append("&#");
+ logUpdated.append(Integer.toString((int) c));
+ logUpdated.append(";");
+ } else {
+ logUpdated.append(c);
+ }
+ }
+ log = logUpdated.toString();
+
+ log = log.replace("\n", "\r\n"); // windows' eol
+
+ if (trackables != null) {
+ Log.i(cgSettings.tag, "Trying to post log for cache #" + cacheid + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + log + "; trackables: " + trackables.size());
+ } else {
+ Log.i(cgSettings.tag, "Trying to post log for cache #" + cacheid + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + log + "; trackables: 0");
+ }
+
+ final String host = "www.geocaching.com";
+ final String path = "/seek/log.aspx?ID=" + cacheid;
+ final String method = "POST";
+ final HashMap<String, String> params = new HashMap<String, String>();
+
+ params.put("__VIEWSTATE", viewstate);
+ if (viewstate1 != null) {
+ params.put("__VIEWSTATE1", viewstate1);
+ params.put("__VIEWSTATEFIELDCOUNT", "2");
+ }
+ params.put("__EVENTTARGET", "");
+ params.put("__EVENTARGUMENT", "");
+ params.put("__LASTFOCUS", "");
+ params.put("ctl00$ContentBody$LogBookPanel1$ddLogType", Integer.toString(logType));
+ params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged", String.format("%02d", month) + "/" + String.format("%02d", day) + "/" + String.format("%04d", year));
+ params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Month", Integer.toString(month));
+ params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Day", Integer.toString(day));
+ params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Year", Integer.toString(year));
+ params.put("ctl00$ContentBody$LogBookPanel1$uxLogInfo", log);
+ params.put("ctl00$ContentBody$LogBookPanel1$LogButton", "Submit Log Entry");
+ params.put("ctl00$ContentBody$uxVistOtherListingGC", "");
+ if (trackables != null && trackables.isEmpty() == false) { // we have some trackables to proceed
+ final StringBuilder hdnSelected = new StringBuilder();
+
+ for (cgTrackableLog tb : trackables) {
+ final String action = Integer.toString(tb.id) + logTypesTrackableAction.get(tb.action);
+
+ if (tb.action > 0) {
+ hdnSelected.append(action);
+ hdnSelected.append(",");
+ }
+ }
+
+ params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$hdnSelectedActions", hdnSelected.toString()); // selected trackables
+ params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$hdnCurrentFilter", "");
+ }
+
+ String page = request(false, host, path, method, params, false, false, false).getData();
+ if (checkLogin(page) == false) {
+ int loginState = login();
+ if (loginState == 1) {
+ page = request(false, host, path, method, params, false, false, false).getData();
+ } else {
+ Log.e(cgSettings.tag, "cgeoBase.postLog: Can not log in geocaching (error: " + loginState + ")");
+ return loginState;
+ }
+ }
+
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.postLog: No data from server");
+ return 1002;
+ }
+
+ // maintenance, archived needs to be confirmed
+ final Pattern pattern = Pattern.compile("<span id=\"ctl00_ContentBody_LogBookPanel1_lbConfirm\"[^>]*>([^<]*<font[^>]*>)?([^<]+)(</font>[^<]*)?</span>", Pattern.CASE_INSENSITIVE);
+ final Matcher matcher = pattern.matcher(page);
+
+ try {
+ if (matcher.find() == true && matcher.groupCount() > 0) {
+ final String viewstateConfirm = findViewstate(page, 0);
+ final String viewstate1Confirm = findViewstate(page, 1);
+
+ if (viewstateConfirm == null || viewstateConfirm.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.postLog: No viewstate for confirm log");
+ return 1000;
+ }
+
+ params.clear();
+ params.put("__VIEWSTATE", viewstateConfirm);
+ if (viewstate1 != null) {
+ params.put("__VIEWSTATE1", viewstate1Confirm);
+ params.put("__VIEWSTATEFIELDCOUNT", "2");
+ }
+ params.put("__EVENTTARGET", "");
+ params.put("__EVENTARGUMENT", "");
+ params.put("__LASTFOCUS", "");
+ params.put("ctl00$ContentBody$LogBookPanel1$btnConfirm", "Yes");
+ params.put("ctl00$ContentBody$LogBookPanel1$uxLogInfo", log);
+ params.put("ctl00$ContentBody$uxVistOtherListingGC", "");
+ if (trackables != null && trackables.isEmpty() == false) { // we have some trackables to proceed
+ final StringBuilder hdnSelected = new StringBuilder();
+
+ for (cgTrackableLog tb : trackables) {
+ String ctl = null;
+ final String action = Integer.toString(tb.id) + logTypesTrackableAction.get(tb.action);
+
+ if (tb.ctl < 10) {
+ ctl = "0" + Integer.toString(tb.ctl);
+ } else {
+ ctl = Integer.toString(tb.ctl);
+ }
+
+ params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$repTravelBugs$ctl" + ctl + "$ddlAction", action);
+ if (tb.action > 0) {
+ hdnSelected.append(action);
+ hdnSelected.append(",");
+ }
+ }
+
+ params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$hdnSelectedActions", hdnSelected.toString()); // selected trackables
+ params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$hdnCurrentFilter", "");
+ }
+
+ page = request(false, host, path, method, params, false, false, false).getData();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoBase.postLog.confim: " + e.toString());
+ }
+
+ try {
+ final Pattern patternOk = Pattern.compile("<h2[^>]*>[^<]*<span id=\"ctl00_ContentBody_lbHeading\"[^>]*>[^<]*</span>[^<]*</h2>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Matcher matcherOk = patternOk.matcher(page);
+ if (matcherOk.find() == true) {
+ Log.i(cgSettings.tag, "Log successfully posted to cache #" + cacheid);
+
+ if (app != null && geocode != null) {
+ app.saveVisitDate(geocode);
+ }
+
+ return 1;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoBase.postLog.check: " + e.toString());
+ }
+
+ Log.e(cgSettings.tag, "cgeoBase.postLog: Failed to post log because of unknown error");
+ return 1000;
+ }
+
+ public int postLogTrackable(String tbid, String trackingCode, String viewstate, String viewstate1, int logType, int year, int month, int day, String log) {
+ if (viewstate == null || viewstate.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.postLogTrackable: No viewstate given");
+ return 1000;
+ }
+
+ if (logTypes2.containsKey(logType) == false) {
+ Log.e(cgSettings.tag, "cgeoBase.postLogTrackable: Unknown logtype");
+ return 1000;
+ }
+
+ if (log == null || log.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.postLogTrackable: No log text given");
+ return 1001;
+ }
+
+ Log.i(cgSettings.tag, "Trying to post log for trackable #" + trackingCode + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + log);
+
+ log = log.replace("\n", "\r\n"); // windows' eol
+
+ final Calendar currentDate = Calendar.getInstance();
+ final String host = "www.geocaching.com";
+ final String path = "/track/log.aspx?wid=" + tbid;
+ final String method = "POST";
+ final HashMap<String, String> params = new HashMap<String, String>();
+
+ params.put("__VIEWSTATE", viewstate);
+ if (viewstate1 != null) {
+ params.put("__VIEWSTATE1", viewstate1);
+ params.put("__VIEWSTATEFIELDCOUNT", "2");
+ }
+ params.put("__EVENTTARGET", "");
+ params.put("__EVENTARGUMENT", "");
+ params.put("__LASTFOCUS", "");
+ params.put("ctl00$ContentBody$LogBookPanel1$ddLogType", Integer.toString(logType));
+ params.put("ctl00$ContentBody$LogBookPanel1$tbCode", trackingCode);
+ if (currentDate.get(Calendar.YEAR) == year && (currentDate.get(Calendar.MONTH) + 1) == month && currentDate.get(Calendar.DATE) == day) {
+ params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged", "");
+ } else {
+ params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged", Integer.toString(month) + "/" + Integer.toString(day) + "/" + Integer.toString(year));
+ }
+ params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Day", Integer.toString(day));
+ params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Month", Integer.toString(month));
+ params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Year", Integer.toString(year));
+ params.put("ctl00$ContentBody$LogBookPanel1$uxLogInfo", log);
+ params.put("ctl00$ContentBody$LogBookPanel1$LogButton", "Submit Log Entry");
+ params.put("ctl00$ContentBody$uxVistOtherListingGC", "");
+
+ String page = request(false, host, path, method, params, false, false, false).getData();
+ if (checkLogin(page) == false) {
+ int loginState = login();
+ if (loginState == 1) {
+ page = request(false, host, path, method, params, false, false, false).getData();
+ } else {
+ Log.e(cgSettings.tag, "cgeoBase.postLogTrackable: Can not log in geocaching (error: " + loginState + ")");
+ return loginState;
+ }
+ }
+
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.postLogTrackable: No data from server");
+ return 1002;
+ }
+
+ try {
+ final Pattern patternOk = Pattern.compile("<div id=[\"|']ctl00_ContentBody_LogBookPanel1_ViewLogPanel[\"|']>", Pattern.CASE_INSENSITIVE);
+ final Matcher matcherOk = patternOk.matcher(page);
+ if (matcherOk.find() == true) {
+ Log.i(cgSettings.tag, "Log successfully posted to trackable #" + trackingCode);
+ return 1;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoBase.postLogTrackable.check: " + e.toString());
+ }
+
+ Log.e(cgSettings.tag, "cgeoBase.postLogTrackable: Failed to post log because of unknown error");
+ return 1000;
+ }
+
+ final public static HostnameVerifier doNotVerify = new HostnameVerifier() {
+
+ public boolean verify(String hostname, SSLSession session) {
+ return true;
+ }
+ };
+
+ public static void trustAllHosts() {
+ TrustManager[] trustAllCerts = new TrustManager[]{
+ new X509TrustManager() {
+
+ public java.security.cert.X509Certificate[] getAcceptedIssuers() {
+ return new java.security.cert.X509Certificate[]{};
+ }
+
+ public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ }
+
+ public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ }
+ }
+ };
+
+ try {
+ SSLContext sc = SSLContext.getInstance("TLS");
+ sc.init(null, trustAllCerts, new java.security.SecureRandom());
+ HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.trustAllHosts: " + e.toString());
+ }
+ }
+
+ public void postTweetCache(cgeoapplication app, cgSettings settings, String geocode) {
+ final cgCache cache = app.getCacheByGeocode(geocode);
+ String name = cache.name;
+ if (name.length() > 84) {
+ name = name.substring(0, 81) + "...";
+ }
+ final String status = "I found " + name + " (http://coord.info/" + cache.geocode.toUpperCase() + ")! #cgeo #geocaching"; // 56 chars + cache name
+
+ postTweet(app, settings, status, null, null);
+ }
+
+ public void postTweetTrackable(cgeoapplication app, cgSettings settings, String geocode) {
+ final cgTrackable trackable = app.getTrackableByGeocode(geocode);
+ String name = trackable.name;
+ if (name.length() > 82) {
+ name = name.substring(0, 79) + "...";
+ }
+ final String status = "I touched " + name + " (http://coord.info/" + trackable.geocode.toUpperCase() + ")! #cgeo #geocaching"; // 58 chars + trackable name
+
+ postTweet(app, settings, status, null, null);
+ }
+
+ public void postTweet(cgeoapplication app, cgSettings settings, String status, Double latitude, Double longitude) {
+ if (app == null) {
+ return;
+ }
+ if (settings == null || settings.tokenPublic == null || settings.tokenPublic.length() == 0 || settings.tokenSecret == null || settings.tokenSecret.length() == 0) {
+ return;
+ }
+
+ try {
+ HashMap<String, String> parameters = new HashMap<String, String>();
+
+ parameters.put("status", status);
+ if (latitude != null && longitude != null) {
+ parameters.put("lat", String.format("%.6f", latitude));
+ parameters.put("long", String.format("%.6f", longitude));
+ parameters.put("display_coordinates", "true");
+ }
+
+ final String paramsDone = cgOAuth.signOAuth("api.twitter.com", "/1/statuses/update.json", "POST", false, parameters, settings.tokenPublic, settings.tokenSecret);
+
+ HttpURLConnection connection = null;
+ try {
+ final StringBuffer buffer = new StringBuffer();
+ final URL u = new URL("http://api.twitter.com/1/statuses/update.json");
+ final URLConnection uc = u.openConnection();
+
+ uc.setRequestProperty("Host", "api.twitter.com");
+
+ connection = (HttpURLConnection) uc;
+ connection.setReadTimeout(30000);
+ connection.setRequestMethod("POST");
+ HttpURLConnection.setFollowRedirects(true);
+ connection.setDoInput(true);
+ connection.setDoOutput(true);
+
+ final OutputStream out = connection.getOutputStream();
+ final OutputStreamWriter wr = new OutputStreamWriter(out);
+ wr.write(paramsDone);
+ wr.flush();
+ wr.close();
+
+ Log.i(cgSettings.tag, "Twitter.com: " + connection.getResponseCode() + " " + connection.getResponseMessage());
+
+ InputStream ins;
+ final String encoding = connection.getContentEncoding();
+
+ if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
+ ins = new GZIPInputStream(connection.getInputStream());
+ } else if (encoding != null && encoding.equalsIgnoreCase("deflate")) {
+ ins = new InflaterInputStream(connection.getInputStream(), new Inflater(true));
+ } else {
+ ins = connection.getInputStream();
+ }
+
+ final InputStreamReader inr = new InputStreamReader(ins);
+ final BufferedReader br = new BufferedReader(inr);
+
+ readIntoBuffer(br, buffer);
+
+ br.close();
+ ins.close();
+ inr.close();
+ connection.disconnect();
+ } catch (IOException e) {
+ Log.e(cgSettings.tag, "cgBase.postTweet.IO: " + connection.getResponseCode() + ": " + connection.getResponseMessage() + " ~ " + e.toString());
+
+ final InputStream ins = connection.getErrorStream();
+ final StringBuffer buffer = new StringBuffer();
+ final InputStreamReader inr = new InputStreamReader(ins);
+ final BufferedReader br = new BufferedReader(inr);
+
+ readIntoBuffer(br, buffer);
+
+ br.close();
+ ins.close();
+ inr.close();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.postTweet.inner: " + e.toString());
+ }
+
+ connection.disconnect();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.postTweet: " + e.toString());
+ }
+ }
+
+ private void readIntoBuffer(BufferedReader br, StringBuffer buffer) throws IOException {
+ int bufferSize = 1024*16;
+ char[] bytes = new char[bufferSize];
+ int bytesRead;
+ while ((bytesRead = br.read(bytes)) > 0) {
+ if (bytesRead == bufferSize) {
+ buffer.append(bytes);
+ }
+ else {
+ buffer.append(bytes, 0, bytesRead);
+ }
+ }
+ }
+
+ /*
+ public ArrayList<String> translate(ArrayList<String> text, String target) {
+ if (settings.translate == false) {
+ return text;
+ }
+
+ String[] languages = null;
+ if (settings.languages != null) {
+ languages = settings.languages.split(" ");
+ }
+
+ ArrayList<String> translated = new ArrayList<String>();
+ String language = null;
+
+ if (text == null || text.isEmpty()) {
+ return text;
+ }
+
+ // cut to 5000 characters (limitation of Google Translation API)
+ for (String textOne : text) {
+ int len = urlencode_rfc3986(textOne).length();
+ if (len > 5000) {
+ textOne = Html.fromHtml(textOne).toString();
+ len = urlencode_rfc3986(textOne).length();
+
+ if (len > 5000) {
+ int cut = 2000;
+ if (textOne.length() > cut) {
+ cut = 1000;
+ }
+
+ textOne = textOne.substring(0, cut) + "...";
+ }
+ }
+ }
+
+ try {
+ if (target == null) {
+ final Locale locale = Locale.getDefault();
+ target = locale.getLanguage();
+ }
+
+ final String scheme = "https://";
+ final String host = "www.googleapis.com";
+ final String path = "/language/translate/v2";
+
+ final ArrayList<String> params = new ArrayList<String>();
+ params.add("key=" + urlencode_rfc3986("AIzaSyAJH8x5etFHUbFifmgChlWoCVmwBFSwShQ"));
+ params.add("target=" + urlencode_rfc3986(target));
+ for (String textOne : text) {
+ params.add("q=" + urlencode_rfc3986(textOne));
+ }
+ params.add("format=" + urlencode_rfc3986("html"));
+
+ String page = requestJSON(scheme, host, path, "POST", implode("&", params.toArray()));
+
+ if (page == null || page.length() == 0) {
+ return text;
+ }
+
+ JSONObject json = new JSONObject(page);
+ JSONObject jsonData = json.getJSONObject("data");
+ JSONArray jsonTranslations = jsonData.getJSONArray("translations");
+ int translationCnt = jsonTranslations.length();
+
+ for (int i = 0; i < translationCnt; i ++) {
+ JSONObject jsonTranslation = jsonTranslations.getJSONObject(i);
+ language = jsonTranslation.getString("detectedSourceLanguage");
+
+ boolean toTranslate = true;
+ if (languages != null) {
+ for (String lng : languages) {
+ if (lng.equalsIgnoreCase(language)) {
+ toTranslate = false;
+ }
+ }
+ }
+
+ if (toTranslate == false) {
+ translated.add(text.get(i));
+ } else {
+ Log.i(cgSettings.tag, "Translating #" + i + ": " + language + ">" + target);
+ translated.add(jsonTranslation.getString("translatedText"));
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgBase.translate: " + e.toString());
+ }
+
+ return translated;
+ }
+ */
+
+ public String getLocalIpAddress() {
+ try {
+ for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
+ NetworkInterface intf = en.nextElement();
+ for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
+ InetAddress inetAddress = enumIpAddr.nextElement();
+ if (!inetAddress.isLoopbackAddress()) {
+ return inetAddress.getHostAddress().toString();
+ }
+ }
+ }
+ } catch (SocketException e) {
+ // nothing
+ }
+
+ return null;
+ }
+
+ public static String implode(String delim, Object[] array) {
+ String out = "";
+
+ try {
+ for (int i = 0; i < array.length; i++) {
+ if (i != 0) {
+ out += delim;
+ }
+ out += array[i].toString();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoBase.implode: " + e.toString());
+ }
+ return out;
+ }
+
+ public static String urlencode_rfc3986(String text) {
+ final String encoded = URLEncoder.encode(text).replace("+", "%20").replaceAll("%7E", "~");
+
+ return encoded;
+ }
+
+ public String prepareParameters(HashMap<String, String> params, boolean my, boolean addF) {
+ String paramsDone = null;
+
+ if (my != true && settings.excludeMine > 0) {
+ if (params == null) {
+ params = new HashMap<String, String>();
+ }
+ if (addF == true) {
+ params.put("f", "1");
+ }
+
+ Log.i(cgSettings.tag, "Skipping caches found or hidden by user.");
+ }
+
+ if (params != null) {
+ Object[] keys = params.keySet().toArray();
+ ArrayList<String> paramsEncoded = new ArrayList<String>();
+ String key;
+ String value;
+
+ for (int i = 0; i < keys.length; i++) {
+ key = (String) keys[i];
+ value = (String) params.get(key);
+
+ if (key.charAt(0) == '^') {
+ key = "";
+ }
+ if (value == null) {
+ value = "";
+ }
+
+ paramsEncoded.add(key + "=" + urlencode_rfc3986(value));
+ }
+
+ paramsDone = implode("&", paramsEncoded.toArray());
+ } else {
+ paramsDone = "";
+ }
+
+ return paramsDone;
+ }
+
+ public String requestViewstate(boolean secure, String host, String path, String method, HashMap<String, String> params, boolean xContentType, boolean my) {
+ final cgResponse response = request(secure, host, path, method, params, xContentType, my, false);
+
+ return findViewstate(response.getData(), 0);
+ }
+
+ public String requestViewstate1(boolean secure, String host, String path, String method, HashMap<String, String> params, boolean xContentType, boolean my) {
+ final cgResponse response = request(secure, host, path, method, params, xContentType, my, false);
+
+ return findViewstate(response.getData(), 1);
+ }
+
+ public String requestLogged(boolean secure, String host, String path, String method, HashMap<String, String> params, boolean xContentType, boolean my, boolean addF) {
+ cgResponse response = request(secure, host, path, method, params, xContentType, my, addF);
+ String data = response.getData();
+
+ if (checkLogin(data) == false) {
+ int loginState = login();
+ if (loginState == 1) {
+ response = request(secure, host, path, method, params, xContentType, my, addF);
+ data = response.getData();
+ } else {
+ Log.i(cgSettings.tag, "Working as guest.");
+ }
+ }
+
+ return data;
+ }
+
+ public cgResponse request(boolean secure, String host, String path, String method, HashMap<String, String> params, boolean xContentType, boolean my, boolean addF) {
+ // prepare parameters
+ final String paramsDone = prepareParameters(params, my, addF);
+
+ return request(secure, host, path, method, paramsDone, 0, xContentType);
+ }
+
+ public cgResponse request(boolean secure, String host, String path, String method, HashMap<String, String> params, int requestId, boolean xContentType, boolean my, boolean addF) {
+ // prepare parameters
+ final String paramsDone = prepareParameters(params, my, addF);
+
+ return request(secure, host, path, method, paramsDone, requestId, xContentType);
+ }
+
+ public cgResponse request(boolean secure, String host, String path, String method, String params, int requestId, Boolean xContentType) {
+ URL u = null;
+ int httpCode = -1;
+ String httpMessage = null;
+ String httpLocation = null;
+
+ if (requestId == 0) {
+ requestId = (int) (Math.random() * 1000);
+ }
+
+ if (method == null || (method.equalsIgnoreCase("GET") == false && method.equalsIgnoreCase("POST") == false)) {
+ method = "POST";
+ } else {
+ method = method.toUpperCase();
+ }
+
+ // https
+ String scheme = "http://";
+ if (secure) {
+ scheme = "https://";
+ }
+
+ // prepare cookies
+ String cookiesDone = null;
+ if (cookies == null || cookies.isEmpty() == true) {
+ if (cookies == null) {
+ cookies = new HashMap<String, String>();
+ }
+
+ final Map<String, ?> prefsAll = prefs.getAll();
+ final Set<String> prefsKeys = prefsAll.keySet();
+
+ for (String key : prefsKeys) {
+ if (key.matches("cookie_.+") == true) {
+ final String cookieKey = key.substring(7);
+ final String cookieValue = (String) prefsAll.get(key);
+
+ cookies.put(cookieKey, cookieValue);
+ }
+ }
+ }
+
+ if (cookies != null && !cookies.isEmpty() && cookies.keySet().size() > 0) {
+ final Object[] keys = cookies.keySet().toArray();
+ final ArrayList<String> cookiesEncoded = new ArrayList<String>();
+
+ for (int i = 0; i < keys.length; i++) {
+ String value = cookies.get(keys[i].toString());
+ cookiesEncoded.add(keys[i] + "=" + value);
+ }
+
+ if (cookiesEncoded.size() > 0) {
+ cookiesDone = implode("; ", cookiesEncoded.toArray());
+ }
+ }
+
+ if (cookiesDone == null) {
+ Map<String, ?> prefsValues = prefs.getAll();
+
+ if (prefsValues != null && prefsValues.size() > 0 && prefsValues.keySet().size() > 0) {
+ final Object[] keys = prefsValues.keySet().toArray();
+ final ArrayList<String> cookiesEncoded = new ArrayList<String>();
+ final int length = keys.length;
+
+ for (int i = 0; i < length; i++) {
+ if (keys[i].toString().length() > 7 && keys[i].toString().substring(0, 7).equals("cookie_") == true) {
+ cookiesEncoded.add(keys[i].toString().substring(7) + "=" + prefsValues.get(keys[i].toString()));
+ }
+ }
+
+ if (cookiesEncoded.size() > 0) {
+ cookiesDone = implode("; ", cookiesEncoded.toArray());
+ }
+ }
+ }
+
+ if (cookiesDone == null) {
+ cookiesDone = "";
+ }
+
+ URLConnection uc = null;
+ HttpURLConnection connection = null;
+ Integer timeout = 30000;
+ StringBuffer buffer = null;
+
+ for (int i = 0; i < 5; i++) {
+ if (i > 0) {
+ Log.w(cgSettings.tag, "Failed to download data, retrying. Attempt #" + (i + 1));
+ }
+
+ buffer = new StringBuffer();
+ timeout = 30000 + (i * 10000);
+
+ try {
+ if (method.equals("GET")) {
+ // GET
+ u = new URL(scheme + host + path + "?" + params);
+ uc = u.openConnection();
+
+ uc.setRequestProperty("Host", host);
+ uc.setRequestProperty("Cookie", cookiesDone);
+ if (xContentType == true) {
+ uc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+ }
+
+ if (settings.asBrowser == 1) {
+ uc.setRequestProperty("Accept", "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
+ // uc.setRequestProperty("Accept-Encoding", "gzip"); // not supported via cellular network
+ uc.setRequestProperty("Accept-Charset", "utf-8, iso-8859-1, utf-16, *;q=0.7");
+ uc.setRequestProperty("Accept-Language", "en-US");
+ uc.setRequestProperty("User-Agent", idBrowser);
+ uc.setRequestProperty("Connection", "keep-alive");
+ uc.setRequestProperty("Keep-Alive", "300");
+ }
+
+ connection = (HttpURLConnection) uc;
+ connection.setReadTimeout(timeout);
+ connection.setRequestMethod(method);
+ HttpURLConnection.setFollowRedirects(false);
+ connection.setDoInput(true);
+ connection.setDoOutput(false);
+ } else {
+ // POST
+ u = new URL(scheme + host + path);
+ uc = u.openConnection();
+
+ uc.setRequestProperty("Host", host);
+ uc.setRequestProperty("Cookie", cookiesDone);
+ if (xContentType == true) {
+ uc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+ }
+
+ if (settings.asBrowser == 1) {
+ uc.setRequestProperty("Accept", "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
+ // uc.setRequestProperty("Accept-Encoding", "gzip"); // not supported via cellular network
+ uc.setRequestProperty("Accept-Charset", "utf-8, iso-8859-1, utf-16, *;q=0.7");
+ uc.setRequestProperty("Accept-Language", "en-US");
+ uc.setRequestProperty("User-Agent", idBrowser);
+ uc.setRequestProperty("Connection", "keep-alive");
+ uc.setRequestProperty("Keep-Alive", "300");
+ }
+
+ connection = (HttpURLConnection) uc;
+ connection.setReadTimeout(timeout);
+ connection.setRequestMethod(method);
+ HttpURLConnection.setFollowRedirects(false);
+ connection.setDoInput(true);
+ connection.setDoOutput(true);
+
+ final OutputStream out = connection.getOutputStream();
+ final OutputStreamWriter wr = new OutputStreamWriter(out);
+ wr.write(params);
+ wr.flush();
+ wr.close();
+ }
+
+ String headerName = null;
+ final SharedPreferences.Editor prefsEditor = prefs.edit();
+ for (int j = 1; (headerName = uc.getHeaderFieldKey(j)) != null; j++) {
+ if (headerName != null && headerName.equalsIgnoreCase("Set-Cookie")) {
+ int index;
+ String cookie = uc.getHeaderField(j);
+
+ index = cookie.indexOf(";");
+ if (index > -1) {
+ cookie = cookie.substring(0, cookie.indexOf(";"));
+ }
+
+ index = cookie.indexOf("=");
+ if (index > - 1 && cookie.length() > (index + 1)) {
+ String name = cookie.substring(0, cookie.indexOf("="));
+ String value = cookie.substring(cookie.indexOf("=") + 1, cookie.length());
+
+ cookies.put(name, value);
+ prefsEditor.putString("cookie_" + name, value);
+ }
+ }
+ }
+ prefsEditor.commit();
+
+ final String encoding = connection.getContentEncoding();
+ InputStream ins;
+
+ if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
+ ins = new GZIPInputStream(connection.getInputStream());
+ } else if (encoding != null && encoding.equalsIgnoreCase("deflate")) {
+ ins = new InflaterInputStream(connection.getInputStream(), new Inflater(true));
+ } else {
+ ins = connection.getInputStream();
+ }
+ final InputStreamReader inr = new InputStreamReader(ins);
+ final BufferedReader br = new BufferedReader(inr);
+
+ readIntoBuffer(br, buffer);
+
+ httpCode = connection.getResponseCode();
+ httpMessage = connection.getResponseMessage();
+ httpLocation = uc.getHeaderField("Location");
+
+ final String paramsLog = params.replaceAll(passMatch, "password=***");
+ if (buffer != null && connection != null) {
+ Log.i(cgSettings.tag + "|" + requestId, "[" + method + " " + (int)(params.length() / 1024) + "k | " + httpCode + " | " + (int)(buffer.length() / 1024) + "k] Downloaded " + scheme + host + path + "?" + paramsLog);
+ } else {
+ Log.i(cgSettings.tag + "|" + requestId, "[" + method + " | " + httpCode + "] Failed to download " + scheme + host + path + "?" + paramsLog);
+ }
+
+ connection.disconnect();
+ br.close();
+ ins.close();
+ inr.close();
+ } catch (IOException e) {
+ Log.e(cgSettings.tag, "cgeoBase.request.IOException: " + e.toString());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoBase.request: " + e.toString());
+ }
+
+ if (buffer != null && buffer.length() > 0) {
+ break;
+ }
+ }
+
+ cgResponse response = new cgResponse();
+ String data = null;
+
+ try {
+ if (httpCode == 302 && httpLocation != null) {
+ final Uri newLocation = Uri.parse(httpLocation);
+ if (newLocation.isRelative() == true) {
+ response = request(secure, host, path, "GET", new HashMap<String, String>(), requestId, false, false, false);
+ } else {
+ boolean secureRedir = false;
+ if (newLocation.getScheme().equals("https")) {
+ secureRedir = true;
+ }
+ response = request(secureRedir, newLocation.getHost(), newLocation.getPath(), "GET", new HashMap<String, String>(), requestId, false, false, false);
+ }
+ } else {
+ if (buffer != null && buffer.length() > 0) {
+ data = replaceWhitespace(buffer);
+ buffer = null;
+
+ if (data != null) {
+ response.setData(data);
+ } else {
+ response.setData("");
+ }
+ response.setStatusCode(httpCode);
+ response.setStatusMessage(httpMessage);
+ response.setUrl(u.toString());
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoBase.page: " + e.toString());
+ }
+
+ return response;
+ }
+
+ private String replaceWhitespace(final StringBuffer buffer) {
+ final int length = buffer.length();
+ final char[] bytes = new char[length];
+ buffer.getChars(0, length, bytes, 0);
+ int resultSize = 0;
+ boolean lastWasWhitespace = false;
+ for (int i = 0; i < length; i++) {
+ char c = bytes[i];
+ if (c == ' ' || c == '\n' || c == '\r' || c == '\t') {
+ if (!lastWasWhitespace) {
+ bytes[resultSize++] =' ';
+ }
+ lastWasWhitespace = true;
+ } else {
+ bytes[resultSize++] = c;
+ lastWasWhitespace = false;
+ }
+ }
+
+ return new String(bytes, 0, resultSize);
+ }
+
+ public String requestJSONgc(String host, String path, String params) {
+ int httpCode = -1;
+ String httpLocation = null;
+
+ // prepare cookies
+ String cookiesDone = null;
+ if (cookies == null || cookies.isEmpty() == true) {
+ if (cookies == null) {
+ cookies = new HashMap<String, String>();
+ }
+
+ final Map<String, ?> prefsAll = prefs.getAll();
+ final Set<String> prefsKeys = prefsAll.keySet();
+
+ for (String key : prefsKeys) {
+ if (key.matches("cookie_.+") == true) {
+ final String cookieKey = key.substring(7);
+ final String cookieValue = (String) prefsAll.get(key);
+
+ cookies.put(cookieKey, cookieValue);
+ }
+ }
+ }
+
+ if (cookies != null) {
+ final Object[] keys = cookies.keySet().toArray();
+ final ArrayList<String> cookiesEncoded = new ArrayList<String>();
+
+ for (int i = 0; i < keys.length; i++) {
+ String value = cookies.get(keys[i].toString());
+ cookiesEncoded.add(keys[i] + "=" + value);
+ }
+
+ if (cookiesEncoded.size() > 0) {
+ cookiesDone = implode("; ", cookiesEncoded.toArray());
+ }
+ }
+
+ if (cookiesDone == null) {
+ Map<String, ?> prefsValues = prefs.getAll();
+
+ if (prefsValues != null && prefsValues.size() > 0) {
+ final Object[] keys = prefsValues.keySet().toArray();
+ final ArrayList<String> cookiesEncoded = new ArrayList<String>();
+ final int length = keys.length;
+
+ for (int i = 0; i < length; i++) {
+ if (keys[i].toString().length() > 7 && keys[i].toString().substring(0, 7).equals("cookie_") == true) {
+ cookiesEncoded.add(keys[i].toString().substring(7) + "=" + prefsValues.get(keys[i].toString()));
+ }
+ }
+
+ if (cookiesEncoded.size() > 0) {
+ cookiesDone = implode("; ", cookiesEncoded.toArray());
+ }
+ }
+ }
+
+ if (cookiesDone == null) {
+ cookiesDone = "";
+ }
+
+ URLConnection uc = null;
+ HttpURLConnection connection = null;
+ Integer timeout = 30000;
+ final StringBuffer buffer = new StringBuffer();
+
+ for (int i = 0; i < 3; i++) {
+ if (i > 0) {
+ Log.w(cgSettings.tag, "Failed to download data, retrying. Attempt #" + (i + 1));
+ }
+
+ buffer.delete(0, buffer.length());
+ timeout = 30000 + (i * 15000);
+
+ try {
+ // POST
+ final URL u = new URL("http://" + host + path);
+ uc = u.openConnection();
+
+ uc.setRequestProperty("Host", host);
+ uc.setRequestProperty("Cookie", cookiesDone);
+ uc.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
+ uc.setRequestProperty("X-Requested-With", "XMLHttpRequest");
+ uc.setRequestProperty("Accept", "application/json, text/javascript, */*; q=0.01");
+ uc.setRequestProperty("Referer", host + "/" + path);
+
+ if (settings.asBrowser == 1) {
+ uc.setRequestProperty("Accept-Charset", "utf-8, iso-8859-1, utf-16, *;q=0.7");
+ uc.setRequestProperty("Accept-Language", "en-US");
+ uc.setRequestProperty("User-Agent", idBrowser);
+ uc.setRequestProperty("Connection", "keep-alive");
+ uc.setRequestProperty("Keep-Alive", "300");
+ }
+
+ connection = (HttpURLConnection) uc;
+ connection.setReadTimeout(timeout);
+ connection.setRequestMethod("POST");
+ HttpURLConnection.setFollowRedirects(false); // TODO: Fix these (FilCab)
+ connection.setDoInput(true);
+ connection.setDoOutput(true);
+
+ final OutputStream out = connection.getOutputStream();
+ final OutputStreamWriter wr = new OutputStreamWriter(out);
+ wr.write(params);
+ wr.flush();
+ wr.close();
+
+ String headerName = null;
+ final SharedPreferences.Editor prefsEditor = prefs.edit();
+ for (int j = 1; (headerName = uc.getHeaderFieldKey(j)) != null; j++) {
+ if (headerName != null && headerName.equalsIgnoreCase("Set-Cookie")) {
+ int index;
+ String cookie = uc.getHeaderField(j);
+
+ index = cookie.indexOf(";");
+ if (index > -1) {
+ cookie = cookie.substring(0, cookie.indexOf(";"));
+ }
+
+ index = cookie.indexOf("=");
+ if (index > - 1 && cookie.length() > (index + 1)) {
+ String name = cookie.substring(0, cookie.indexOf("="));
+ String value = cookie.substring(cookie.indexOf("=") + 1, cookie.length());
+
+ cookies.put(name, value);
+ prefsEditor.putString("cookie_" + name, value);
+ }
+ }
+ }
+ prefsEditor.commit();
+
+ final String encoding = connection.getContentEncoding();
+ InputStream ins;
+
+ if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
+ ins = new GZIPInputStream(connection.getInputStream());
+ } else if (encoding != null && encoding.equalsIgnoreCase("deflate")) {
+ ins = new InflaterInputStream(connection.getInputStream(), new Inflater(true));
+ } else {
+ ins = connection.getInputStream();
+ }
+ final InputStreamReader inr = new InputStreamReader(ins);
+ final BufferedReader br = new BufferedReader(inr);
+
+ readIntoBuffer(br, buffer);
+
+ httpCode = connection.getResponseCode();
+ httpLocation = uc.getHeaderField("Location");
+
+ final String paramsLog = params.replaceAll(passMatch, "password=***");
+ Log.i(cgSettings.tag + " | JSON", "[POST " + (int)(params.length() / 1024) + "k | " + httpCode + " | " + (int)(buffer.length() / 1024) + "k] Downloaded " + "http://" + host + path + "?" + paramsLog);
+
+ connection.disconnect();
+ br.close();
+ ins.close();
+ inr.close();
+ } catch (IOException e) {
+ Log.e(cgSettings.tag, "cgeoBase.requestJSONgc.IOException: " + e.toString());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoBase.requestJSONgc: " + e.toString());
+ }
+
+ if (buffer != null && buffer.length() > 0) {
+ break;
+ }
+ }
+
+ String page = null;
+ if (httpCode == 302 && httpLocation != null) {
+ final Uri newLocation = Uri.parse(httpLocation);
+ if (newLocation.isRelative() == true) {
+ page = requestJSONgc(host, path, params);
+ } else {
+ page = requestJSONgc(newLocation.getHost(), newLocation.getPath(), params);
+ }
+ } else {
+ page = replaceWhitespace(buffer);
+ }
+
+ if (page != null) {
+ return page;
+ } else {
+ return "";
+ }
+ }
+
+ public String requestJSON(String host, String path, String params) {
+ return requestJSON("http://", host, path, "GET", params);
+ }
+
+ public String requestJSON(String scheme, String host, String path, String method, String params) {
+ int httpCode = -1;
+ String httpLocation = null;
+
+ if (method == null) {
+ method = "GET";
+ } else {
+ method = method.toUpperCase();
+ }
+
+ boolean methodPost = false;
+ if (method.equalsIgnoreCase("POST")) {
+ methodPost = true;
+ }
+
+ URLConnection uc = null;
+ HttpURLConnection connection = null;
+ Integer timeout = 30000;
+ final StringBuffer buffer = new StringBuffer();
+
+ for (int i = 0; i < 3; i++) {
+ if (i > 0) {
+ Log.w(cgSettings.tag, "Failed to download data, retrying. Attempt #" + (i + 1));
+ }
+
+ buffer.delete(0, buffer.length());
+ timeout = 30000 + (i * 15000);
+
+ try {
+ try {
+ URL u = null;
+ if (methodPost) {
+ u = new URL(scheme + host + path);
+ } else {
+ u = new URL(scheme + host + path + "?" + params);
+ }
+
+ if (u.getProtocol().toLowerCase().equals("https")) {
+ trustAllHosts();
+ HttpsURLConnection https = (HttpsURLConnection) u.openConnection();
+ https.setHostnameVerifier(doNotVerify);
+ uc = https;
+ } else {
+ uc = (HttpURLConnection) u.openConnection();
+ }
+
+ uc.setRequestProperty("Host", host);
+ uc.setRequestProperty("Accept", "application/json, text/javascript, */*; q=0.01");
+ if (methodPost) {
+ uc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+ uc.setRequestProperty("Content-Length", Integer.toString(params.length()));
+ uc.setRequestProperty("X-HTTP-Method-Override", "GET");
+ } else {
+ uc.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
+ }
+ uc.setRequestProperty("X-Requested-With", "XMLHttpRequest");
+
+ connection = (HttpURLConnection) uc;
+ connection.setReadTimeout(timeout);
+ connection.setRequestMethod(method);
+ HttpURLConnection.setFollowRedirects(false); // TODO: Fix these (FilCab)
+ connection.setDoInput(true);
+ if (methodPost) {
+ connection.setDoOutput(true);
+
+ final OutputStream out = connection.getOutputStream();
+ final OutputStreamWriter wr = new OutputStreamWriter(out);
+ wr.write(params);
+ wr.flush();
+ wr.close();
+ } else {
+ connection.setDoOutput(false);
+ }
+
+
+ final String encoding = connection.getContentEncoding();
+ InputStream ins;
+
+ if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
+ ins = new GZIPInputStream(connection.getInputStream());
+ } else if (encoding != null && encoding.equalsIgnoreCase("deflate")) {
+ ins = new InflaterInputStream(connection.getInputStream(), new Inflater(true));
+ } else {
+ ins = connection.getInputStream();
+ }
+ final InputStreamReader inr = new InputStreamReader(ins);
+ final BufferedReader br = new BufferedReader(inr);
+
+ readIntoBuffer(br, buffer);
+
+ httpCode = connection.getResponseCode();
+
+ final String paramsLog = params.replaceAll(passMatch, "password=***");
+ Log.i(cgSettings.tag + " | JSON", "[POST " + (int)(params.length() / 1024) + "k | " + httpCode + " | " + (int)(buffer.length() / 1024) + "k] Downloaded " + "http://" + host + path + "?" + paramsLog);
+
+ connection.disconnect();
+ br.close();
+ ins.close();
+ inr.close();
+ } catch (IOException e) {
+ httpCode = connection.getResponseCode();
+
+ Log.e(cgSettings.tag, "cgeoBase.requestJSON.IOException: " + httpCode + ": " + connection.getResponseMessage() + " ~ " + e.toString());
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoBase.requestJSON: " + e.toString());
+ }
+
+ if (buffer != null && buffer.length() > 0) {
+ break;
+ }
+
+ if (httpCode == 403) {
+ // we're not allowed to download content, so let's move
+ break;
+ }
+ }
+
+ String page = null;
+ if (httpCode == 302 && httpLocation != null) {
+ final Uri newLocation = Uri.parse(httpLocation);
+ if (newLocation.isRelative() == true) {
+ page = requestJSONgc(host, path, params);
+ } else {
+ page = requestJSONgc(newLocation.getHost(), newLocation.getPath(), params);
+ }
+ } else {
+ page = replaceWhitespace(buffer);
+ }
+
+ if (page != null) {
+ return page;
+ } else {
+ return "";
+ }
+ }
+
+ public static String rot13(String text) {
+ final StringBuilder result = new StringBuilder();
+ // plaintext flag (do not convert)
+ boolean plaintext = false;
+
+ int length = text.length();
+ for (int index = 0; index < length; index++) {
+ int c = text.charAt(index);
+ if (c == '[') {
+ plaintext = true;
+ } else if (c == ']') {
+ plaintext = false;
+ } else if (!plaintext) {
+ int capitalized = c & 32;
+ c &= ~capitalized;
+ c = ((c >= 'A') && (c <= 'Z') ? ((c - 'A' + 13) % 26 + 'A') : c)
+ | capitalized;
+ }
+ result.append((char) c);
+ }
+ return result.toString();
+ }
+
+ public static String md5(String text) {
+ String hashed = "";
+
+ try {
+ MessageDigest digest = MessageDigest.getInstance("MD5");
+ digest.update(text.getBytes(), 0, text.length());
+ hashed = new BigInteger(1, digest.digest()).toString(16);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.md5: " + e.toString());
+ }
+
+ return hashed;
+ }
+
+ public static String sha1(String text) {
+ String hashed = "";
+
+ try {
+ MessageDigest digest = MessageDigest.getInstance("SHA-1");
+ digest.update(text.getBytes(), 0, text.length());
+ hashed = new BigInteger(1, digest.digest()).toString(16);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.sha1: " + e.toString());
+ }
+
+ return hashed;
+ }
+
+ public static byte[] hashHmac(String text, String salt) {
+ byte[] macBytes = {};
+
+ try {
+ SecretKeySpec secretKeySpec = new SecretKeySpec(salt.getBytes(), "HmacSHA1");
+ Mac mac = Mac.getInstance("HmacSHA1");
+ mac.init(secretKeySpec);
+ macBytes = mac.doFinal(text.getBytes());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.hashHmac: " + e.toString());
+ }
+
+ return macBytes;
+ }
+
+ public static boolean deleteDirectory(File path) {
+ if (path.exists()) {
+ File[] files = path.listFiles();
+
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].isDirectory()) {
+ deleteDirectory(files[i]);
+ } else {
+ files[i].delete();
+ }
+ }
+ }
+
+ return (path.delete());
+ }
+
+ public static boolean isIntentAvailable(Context context, String action) {
+ final Intent intent = new Intent(action);
+
+ return isIntentAvailable(context, intent);
+ }
+
+ public static boolean isIntentAvailable(Context context, Intent intent) {
+ final PackageManager packageManager = context.getPackageManager();
+ final List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
+
+ return (list.size() > 0);
+ }
+
+ public void storeCache(cgeoapplication app, Activity activity, cgCache cache, String geocode, int listId, Handler handler) {
+ try {
+ // cache details
+ if (cache != null) {
+ final HashMap<String, String> params = new HashMap<String, String>();
+ params.put("geocode", cache.geocode);
+ final Long searchId = searchByGeocode(params, listId, false);
+ cache = app.getCache(searchId);
+ } else if (geocode != null) {
+ final HashMap<String, String> params = new HashMap<String, String>();
+ params.put("geocode", geocode);
+ final Long searchId = searchByGeocode(params, listId, false);
+ cache = app.getCache(searchId);
+ }
+
+ if (cache == null) {
+ if (handler != null) {
+ handler.sendMessage(new Message());
+ }
+
+ return;
+ }
+
+ final cgHtmlImg imgGetter = new cgHtmlImg(activity, settings, cache.geocode, false, listId, true);
+
+ // store images from description
+ if (cache.description != null) {
+ Html.fromHtml(cache.description, imgGetter, null);
+ }
+
+ // store spoilers
+ if (cache.spoilers != null && cache.spoilers.isEmpty() == false) {
+ for (cgSpoiler oneSpoiler : cache.spoilers) {
+ imgGetter.getDrawable(oneSpoiler.url);
+ }
+ }
+
+ // store map previews
+ if (settings.storeOfflineMaps == 1 && cache.latitude != null && cache.longitude != null) {
+ final String latlonMap = String.format((Locale) null, "%.6f", cache.latitude) + "," + String.format((Locale) null, "%.6f", cache.longitude);
+ final Display display = ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+ final int maxWidth = display.getWidth() - 25;
+ final int maxHeight = display.getHeight() - 25;
+ int edge = 0;
+ if (maxWidth > maxHeight) {
+ edge = maxWidth;
+ } else {
+ edge = maxHeight;
+ }
+
+ String type = "mystery";
+ if (cache.found == true) {
+ type = cache.type + "_found";
+ } else if (cache.disabled == true) {
+ type = cache.type + "_disabled";
+ } else {
+ type = cache.type;
+ }
+
+ final String markerUrl = urlencode_rfc3986("http://cgeo.carnero.cc/_markers/marker_cache_" + type + ".png");
+ final StringBuilder waypoints = new StringBuilder();
+ if (cache.waypoints != null && cache.waypoints.size() > 0) {
+ for (cgWaypoint waypoint : cache.waypoints) {
+ if (waypoint.latitude == null && waypoint.longitude == null) {
+ continue;
+ }
+
+ waypoints.append("&markers=icon%3Ahttp://cgeo.carnero.cc/_markers/marker_waypoint_");
+ waypoints.append(waypoint.type);
+ waypoints.append(".png%7C");
+ waypoints.append(String.format((Locale) null, "%.6f", waypoint.latitude));
+ waypoints.append(",");
+ waypoints.append(String.format((Locale) null, "%.6f", waypoint.longitude));
+ }
+ }
+
+ // download map images in separate background thread for higher performance
+ final String code = cache.geocode;
+ final int finalEdge = edge;
+ Thread staticMapsThread = new Thread("getting static map") {@Override
+ public void run() {
+ cgMapImg mapGetter = new cgMapImg(settings, code);
+
+ mapGetter.getDrawable("http://maps.google.com/maps/api/staticmap?center=" + latlonMap + "&zoom=20&size=" + finalEdge + "x" + finalEdge + "&maptype=satellite&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints.toString() + "&sensor=false", 1);
+ mapGetter.getDrawable("http://maps.google.com/maps/api/staticmap?center=" + latlonMap + "&zoom=18&size=" + finalEdge + "x" + finalEdge + "&maptype=satellite&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints.toString() + "&sensor=false", 2);
+ mapGetter.getDrawable("http://maps.google.com/maps/api/staticmap?center=" + latlonMap + "&zoom=16&size=" + finalEdge + "x" + finalEdge + "&maptype=roadmap&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints.toString() + "&sensor=false", 3);
+ mapGetter.getDrawable("http://maps.google.com/maps/api/staticmap?center=" + latlonMap + "&zoom=14&size=" + finalEdge + "x" + finalEdge + "&maptype=roadmap&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints.toString() + "&sensor=false", 4);
+ mapGetter.getDrawable("http://maps.google.com/maps/api/staticmap?center=" + latlonMap + "&zoom=11&size=" + finalEdge + "x" + finalEdge + "&maptype=roadmap&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints.toString() + "&sensor=false", 5);
+ }};
+ staticMapsThread.setPriority(Thread.MIN_PRIORITY);
+ staticMapsThread.start();
+ }
+
+ app.markStored(cache.geocode, listId);
+ app.removeCacheFromCache(cache.geocode);
+
+ if (handler != null) {
+ handler.sendMessage(new Message());
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.storeCache: " + e.toString());
+ }
+ }
+
+ public void dropCache(cgeoapplication app, Activity activity, cgCache cache, Handler handler) {
+ try {
+ app.markDropped(cache.geocode);
+ app.removeCacheFromCache(cache.geocode);
+
+ handler.sendMessage(new Message());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.dropCache: " + e.toString());
+ }
+ }
+
+ public boolean isInViewPort(int centerLat1, int centerLon1, int centerLat2, int centerLon2, int spanLat1, int spanLon1, int spanLat2, int spanLon2) {
+ try {
+ // expects coordinates in E6 format
+ final int left1 = centerLat1 - (spanLat1 / 2);
+ final int right1 = centerLat1 + (spanLat1 / 2);
+ final int top1 = centerLon1 + (spanLon1 / 2);
+ final int bottom1 = centerLon1 - (spanLon1 / 2);
+
+ final int left2 = centerLat2 - (spanLat2 / 2);
+ final int right2 = centerLat2 + (spanLat2 / 2);
+ final int top2 = centerLon2 + (spanLon2 / 2);
+ final int bottom2 = centerLon2 - (spanLon2 / 2);
+
+ if (left2 <= left1) {
+ return false;
+ }
+ if (right2 >= right1) {
+ return false;
+ }
+ if (top2 >= top1) {
+ return false;
+ }
+ if (bottom2 <= bottom1) {
+ return false;
+ }
+
+ return true;
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.isInViewPort: " + e.toString());
+ return false;
+ }
+ }
+
+ public boolean isCacheInViewPort(int centerLat, int centerLon, int spanLat, int spanLon, Double cacheLat, Double cacheLon) {
+ if (cacheLat == null || cacheLon == null) {
+ return false;
+ }
+
+ // viewport is defined by center, span and some (10%) reserve on every side
+ int minLat = centerLat - (spanLat / 2) - (spanLat / 10);
+ int maxLat = centerLat + (spanLat / 2) + (spanLat / 10);
+ int minLon = centerLon - (spanLon / 2) - (spanLon / 10);
+ int maxLon = centerLon + (spanLon / 2) + (spanLon / 10);
+ int cLat = (int) Math.round(cacheLat * 1e6);
+ int cLon = (int) Math.round(cacheLon * 1e6);
+ int mid = 0;
+
+ if (maxLat < minLat) {
+ mid = minLat;
+ minLat = maxLat;
+ maxLat = mid;
+ }
+
+ if (maxLon < minLon) {
+ mid = minLon;
+ minLon = maxLon;
+ maxLon = mid;
+ }
+
+ boolean latOk = false;
+ boolean lonOk = false;
+
+ if (cLat >= minLat && cLat <= maxLat) {
+ latOk = true;
+ }
+ if (cLon >= minLon && cLon <= maxLon) {
+ lonOk = true;
+ }
+
+ if (latOk == true && lonOk == true) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ private static char[] base64map1 = new char[64];
+
+ static {
+ int i = 0;
+ for (char c = 'A'; c <= 'Z'; c++) {
+ base64map1[i++] = c;
+ }
+ for (char c = 'a'; c <= 'z'; c++) {
+ base64map1[i++] = c;
+ }
+ for (char c = '0'; c <= '9'; c++) {
+ base64map1[i++] = c;
+ }
+ base64map1[i++] = '+';
+ base64map1[i++] = '/';
+ }
+ private static byte[] base64map2 = new byte[128];
+
+ static {
+ for (int i = 0; i < base64map2.length; i++) {
+ base64map2[i] = -1;
+ }
+ for (int i = 0; i < 64; i++) {
+ base64map2[base64map1[i]] = (byte) i;
+ }
+ }
+
+ public static String base64Encode(byte[] in) {
+ int iLen = in.length;
+ int oDataLen = (iLen * 4 + 2) / 3; // output length without padding
+ int oLen = ((iLen + 2) / 3) * 4; // output length including padding
+ char[] out = new char[oLen];
+ int ip = 0;
+ int op = 0;
+
+ while (ip < iLen) {
+ int i0 = in[ip++] & 0xff;
+ int i1 = ip < iLen ? in[ip++] & 0xff : 0;
+ int i2 = ip < iLen ? in[ip++] & 0xff : 0;
+ int o0 = i0 >>> 2;
+ int o1 = ((i0 & 3) << 4) | (i1 >>> 4);
+ int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
+ int o3 = i2 & 0x3F;
+ out[op++] = base64map1[o0];
+ out[op++] = base64map1[o1];
+ out[op] = op < oDataLen ? base64map1[o2] : '=';
+ op++;
+ out[op] = op < oDataLen ? base64map1[o3] : '=';
+ op++;
+ }
+
+ return new String(out);
+ }
+
+ public static byte[] base64Decode(String text) {
+ char[] in = text.toCharArray();
+
+ int iLen = in.length;
+ if (iLen % 4 != 0) {
+ throw new IllegalArgumentException("Length of Base64 encoded input string is not a multiple of 4.");
+ }
+ while (iLen > 0 && in[iLen - 1] == '=') {
+ iLen--;
+ }
+ int oLen = (iLen * 3) / 4;
+ byte[] out = new byte[oLen];
+ int ip = 0;
+ int op = 0;
+ while (ip < iLen) {
+ int i0 = in[ip++];
+ int i1 = in[ip++];
+ int i2 = ip < iLen ? in[ip++] : 'A';
+ int i3 = ip < iLen ? in[ip++] : 'A';
+ if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) {
+ throw new IllegalArgumentException("Illegal character in Base64 encoded data.");
+ }
+ int b0 = base64map2[i0];
+ int b1 = base64map2[i1];
+ int b2 = base64map2[i2];
+ int b3 = base64map2[i3];
+ if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) {
+ throw new IllegalArgumentException("Illegal character in Base64 encoded data.");
+ }
+ int o0 = (b0 << 2) | (b1 >>> 4);
+ int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2);
+ int o2 = ((b2 & 3) << 6) | b3;
+ out[op++] = (byte) o0;
+ if (op < oLen) {
+ out[op++] = (byte) o1;
+ }
+ if (op < oLen) {
+ out[op++] = (byte) o2;
+ }
+ }
+ return out;
+ }
+
+ public int getIcon(boolean cache, String type, boolean own, boolean found, boolean disabled) {
+ if (gcIcons.isEmpty()) {
+ // default markers
+ gcIcons.put("ape", R.drawable.marker_cache_ape);
+ gcIcons.put("cito", R.drawable.marker_cache_cito);
+ gcIcons.put("earth", R.drawable.marker_cache_earth);
+ gcIcons.put("event", R.drawable.marker_cache_event);
+ gcIcons.put("letterbox", R.drawable.marker_cache_letterbox);
+ gcIcons.put("locationless", R.drawable.marker_cache_locationless);
+ gcIcons.put("mega", R.drawable.marker_cache_mega);
+ gcIcons.put("multi", R.drawable.marker_cache_multi);
+ gcIcons.put("traditional", R.drawable.marker_cache_traditional);
+ gcIcons.put("virtual", R.drawable.marker_cache_virtual);
+ gcIcons.put("webcam", R.drawable.marker_cache_webcam);
+ gcIcons.put("wherigo", R.drawable.marker_cache_wherigo);
+ gcIcons.put("mystery", R.drawable.marker_cache_mystery);
+ gcIcons.put("gchq", R.drawable.marker_cache_gchq);
+ // own cache markers
+ gcIcons.put("ape-own", R.drawable.marker_cache_ape_own);
+ gcIcons.put("cito-own", R.drawable.marker_cache_cito_own);
+ gcIcons.put("earth-own", R.drawable.marker_cache_earth_own);
+ gcIcons.put("event-own", R.drawable.marker_cache_event_own);
+ gcIcons.put("letterbox-own", R.drawable.marker_cache_letterbox_own);
+ gcIcons.put("locationless-own", R.drawable.marker_cache_locationless_own);
+ gcIcons.put("mega-own", R.drawable.marker_cache_mega_own);
+ gcIcons.put("multi-own", R.drawable.marker_cache_multi_own);
+ gcIcons.put("traditional-own", R.drawable.marker_cache_traditional_own);
+ gcIcons.put("virtual-own", R.drawable.marker_cache_virtual_own);
+ gcIcons.put("webcam-own", R.drawable.marker_cache_webcam_own);
+ gcIcons.put("wherigo-own", R.drawable.marker_cache_wherigo_own);
+ gcIcons.put("mystery-own", R.drawable.marker_cache_mystery_own);
+ gcIcons.put("gchq-own", R.drawable.marker_cache_gchq_own);
+ // found cache markers
+ gcIcons.put("ape-found", R.drawable.marker_cache_ape_found);
+ gcIcons.put("cito-found", R.drawable.marker_cache_cito_found);
+ gcIcons.put("earth-found", R.drawable.marker_cache_earth_found);
+ gcIcons.put("event-found", R.drawable.marker_cache_event_found);
+ gcIcons.put("letterbox-found", R.drawable.marker_cache_letterbox_found);
+ gcIcons.put("locationless-found", R.drawable.marker_cache_locationless_found);
+ gcIcons.put("mega-found", R.drawable.marker_cache_mega_found);
+ gcIcons.put("multi-found", R.drawable.marker_cache_multi_found);
+ gcIcons.put("traditional-found", R.drawable.marker_cache_traditional_found);
+ gcIcons.put("virtual-found", R.drawable.marker_cache_virtual_found);
+ gcIcons.put("webcam-found", R.drawable.marker_cache_webcam_found);
+ gcIcons.put("wherigo-found", R.drawable.marker_cache_wherigo_found);
+ gcIcons.put("mystery-found", R.drawable.marker_cache_mystery_found);
+ gcIcons.put("gchq-found", R.drawable.marker_cache_gchq_found);
+ // disabled cache markers
+ gcIcons.put("ape-disabled", R.drawable.marker_cache_ape_disabled);
+ gcIcons.put("cito-disabled", R.drawable.marker_cache_cito_disabled);
+ gcIcons.put("earth-disabled", R.drawable.marker_cache_earth_disabled);
+ gcIcons.put("event-disabled", R.drawable.marker_cache_event_disabled);
+ gcIcons.put("letterbox-disabled", R.drawable.marker_cache_letterbox_disabled);
+ gcIcons.put("locationless-disabled", R.drawable.marker_cache_locationless_disabled);
+ gcIcons.put("mega-disabled", R.drawable.marker_cache_mega_disabled);
+ gcIcons.put("multi-disabled", R.drawable.marker_cache_multi_disabled);
+ gcIcons.put("traditional-disabled", R.drawable.marker_cache_traditional_disabled);
+ gcIcons.put("virtual-disabled", R.drawable.marker_cache_virtual_disabled);
+ gcIcons.put("webcam-disabled", R.drawable.marker_cache_webcam_disabled);
+ gcIcons.put("wherigo-disabled", R.drawable.marker_cache_wherigo_disabled);
+ gcIcons.put("mystery-disabled", R.drawable.marker_cache_mystery_disabled);
+ gcIcons.put("gchq-disabled", R.drawable.marker_cache_gchq_disabled);
+ }
+
+ if (wpIcons.isEmpty()) {
+ wpIcons.put("waypoint", R.drawable.marker_waypoint_waypoint);
+ wpIcons.put("flag", R.drawable.marker_waypoint_flag);
+ wpIcons.put("pkg", R.drawable.marker_waypoint_pkg);
+ wpIcons.put("puzzle", R.drawable.marker_waypoint_puzzle);
+ wpIcons.put("stage", R.drawable.marker_waypoint_stage);
+ wpIcons.put("trailhead", R.drawable.marker_waypoint_trailhead);
+ }
+
+ int icon = -1;
+ String iconTxt = null;
+
+ if (cache == true) {
+ if (type != null && type.length() > 0) {
+ if (own == true) {
+ iconTxt = type + "-own";
+ } else if (found == true) {
+ iconTxt = type + "-found";
+ } else if (disabled == true) {
+ iconTxt = type + "-disabled";
+ } else {
+ iconTxt = type;
+ }
+ } else {
+ iconTxt = "traditional";
+ }
+
+ if (gcIcons.containsKey(iconTxt) == true) {
+ icon = gcIcons.get(iconTxt);
+ } else {
+ icon = gcIcons.get("traditional");
+ }
+ } else {
+ if (type != null && type.length() > 0) {
+ iconTxt = type;
+ } else {
+ iconTxt = "waypoint";
+ }
+
+ if (wpIcons.containsKey(iconTxt) == true) {
+ icon = wpIcons.get(iconTxt);
+ } else {
+ icon = wpIcons.get("waypoint");
+ }
+ }
+
+ return icon;
+ }
+
+ public boolean isLocus(Context context) {
+ boolean locus = false;
+ final Intent intentTest = new Intent(Intent.ACTION_VIEW);
+ intentTest.setData(Uri.parse("menion.points:x"));
+ if (isIntentAvailable(context, intentTest) == true) {
+ locus = true;
+ }
+
+ return locus;
+ }
+
+ public boolean isRmaps(Context context) {
+ boolean rmaps = false;
+ final Intent intent = new Intent("com.robert.maps.action.SHOW_POINTS");
+ if (isIntentAvailable(context, intent) == true) {
+ rmaps = true;
+ }
+
+ return rmaps;
+ }
+
+ public boolean runExternalMap(int application, Activity activity, Resources res, cgWarning warning, GoogleAnalyticsTracker tracker, Double latitude, Double longitude) {
+ // waypoint
+ return runExternalMap(application, activity, res, warning, tracker, null, null, latitude, longitude);
+ }
+
+ public boolean runExternalMap(int application, Activity activity, Resources res, cgWarning warning, GoogleAnalyticsTracker tracker, cgWaypoint waypoint) {
+ // waypoint
+ return runExternalMap(application, activity, res, warning, tracker, null, waypoint, null, null);
+ }
+
+ public boolean runExternalMap(int application, Activity activity, Resources res, cgWarning warning, GoogleAnalyticsTracker tracker, cgCache cache) {
+ // cache
+ return runExternalMap(application, activity, res, warning, tracker, cache, null, null, null);
+ }
+
+ public boolean runExternalMap(int application, Activity activity, Resources res, cgWarning warning, GoogleAnalyticsTracker tracker, cgCache cache, cgWaypoint waypoint, Double latitude, Double longitude) {
+ if (cache == null && waypoint == null && latitude == null && longitude == null) {
+ return false;
+ }
+
+ if (application == mapAppLocus) {
+ // locus
+ try {
+ final Intent intentTest = new Intent(Intent.ACTION_VIEW);
+ intentTest.setData(Uri.parse("menion.points:x"));
+
+ if (isIntentAvailable(activity, intentTest) == true) {
+ final ArrayList<cgWaypoint> waypoints = new ArrayList<cgWaypoint>();
+ // get only waypoints with coordinates
+ if (cache != null && cache.waypoints != null && cache.waypoints.isEmpty() == false) {
+ for (cgWaypoint wp : cache.waypoints) {
+ if (wp.latitude != null && wp.longitude != null) {
+ waypoints.add(wp);
+ }
+ }
+ }
+
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ final DataOutputStream dos = new DataOutputStream(baos);
+
+ dos.writeInt(1); // not used
+ if (cache != null) {
+ if (waypoints == null || waypoints.isEmpty() == true) {
+ dos.writeInt(1); // cache only
+ } else {
+ dos.writeInt((1 + waypoints.size())); // cache and waypoints
+ }
+ } else {
+ dos.writeInt(1); // one waypoint
+ }
+
+ int icon = -1;
+ if (cache != null) {
+ icon = getIcon(true, cache.type, cache.own, cache.found, cache.disabled || cache.archived);
+ } else if (waypoint != null) {
+ icon = getIcon(false, waypoint.type, false, false, false);
+ } else {
+ icon = getIcon(false, "waypoint", false, false, false);
+ }
+
+ if (icon > 0) {
+ // load icon
+ Bitmap bitmap = BitmapFactory.decodeResource(res, icon);
+ ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos2);
+ byte[] image = baos2.toByteArray();
+
+ dos.writeInt(image.length);
+ dos.write(image);
+ } else {
+ // no icon
+ dos.writeInt(0); // no image
+ }
+
+ // name
+ if (cache != null && cache.name != null && cache.name.length() > 0) {
+ dos.writeUTF(cache.name);
+ } else if (waypoint != null && waypoint.name != null && waypoint.name.length() > 0) {
+ dos.writeUTF(waypoint.name);
+ } else {
+ dos.writeUTF("");
+ }
+
+ // description
+ if (cache != null && cache.geocode != null && cache.geocode.length() > 0) {
+ dos.writeUTF(cache.geocode.toUpperCase());
+ } else if (waypoint != null && waypoint.lookup != null && waypoint.lookup.length() > 0) {
+ dos.writeUTF(waypoint.lookup.toUpperCase());
+ } else {
+ dos.writeUTF("");
+ }
+
+ // additional data :: keyword, button title, package, activity, data name, data content
+ if (cache != null && cache.geocode != null && cache.geocode.length() > 0) {
+ dos.writeUTF("intent;c:geo;cgeo.geocaching;cgeo.geocaching.cgeodetail;geocode;" + cache.geocode);
+ } else if (waypoint != null && waypoint.id != null && waypoint.id > 0) {
+ dos.writeUTF("intent;c:geo;cgeo.geocaching;cgeo.geocaching.cgeowaypoint;id;" + waypoint.id);
+ } else {
+ dos.writeUTF("");
+ }
+
+ if (cache != null && cache.latitude != null && cache.longitude != null) {
+ dos.writeDouble(cache.latitude); // latitude
+ dos.writeDouble(cache.longitude); // longitude
+ } else if (waypoint != null && waypoint.latitude != null && waypoint.longitude != null) {
+ dos.writeDouble(waypoint.latitude); // latitude
+ dos.writeDouble(waypoint.longitude); // longitude
+ } else {
+ dos.writeDouble(latitude); // latitude
+ dos.writeDouble(longitude); // longitude
+ }
+
+ // cache waypoints
+ if (waypoints != null && waypoints.isEmpty() == false) {
+ for (cgWaypoint wp : waypoints) {
+ if (wp == null || wp.latitude == null || wp.longitude == null) {
+ continue;
+ }
+
+ final int wpIcon = getIcon(false, wp.type, false, false, false);
+
+ if (wpIcon > 0) {
+ // load icon
+ Bitmap bitmap = BitmapFactory.decodeResource(res, wpIcon);
+ ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos2);
+ byte[] image = baos2.toByteArray();
+
+ dos.writeInt(image.length);
+ dos.write(image);
+ } else {
+ // no icon
+ dos.writeInt(0); // no image
+ }
+
+ // name
+ if (wp.lookup != null && wp.lookup.length() > 0) {
+ dos.writeUTF(wp.lookup.toUpperCase());
+ } else {
+ dos.writeUTF("");
+ }
+
+ // description
+ if (wp.name != null && wp.name.length() > 0) {
+ dos.writeUTF(wp.name);
+ } else {
+ dos.writeUTF("");
+ }
+
+ // additional data :: keyword, button title, package, activity, data name, data content
+ if (wp.id != null && wp.id > 0) {
+ dos.writeUTF("intent;c:geo;cgeo.geocaching;cgeo.geocaching.cgeowaypoint;id;" + wp.id);
+ } else {
+ dos.writeUTF("");
+ }
+
+ dos.writeDouble(wp.latitude); // latitude
+ dos.writeDouble(wp.longitude); // longitude
+ }
+ }
+
+ final Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse("menion.points:data"));
+ intent.putExtra("data", baos.toByteArray());
+
+ activity.startActivity(intent);
+
+ sendAnal(activity, tracker, "/external/locus");
+
+ return true;
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ if (application == mapAppRmaps) {
+ // rmaps
+ try {
+ final Intent intent = new Intent("com.robert.maps.action.SHOW_POINTS");
+
+ if (isIntentAvailable(activity, intent) == true) {
+ final ArrayList<String> locations = new ArrayList<String>();
+ if (cache != null && cache.latitude != null && cache.longitude != null) {
+ locations.add(String.format((Locale) null, "%.6f", cache.latitude) + "," + String.format((Locale) null, "%.6f", cache.longitude) + ";" + cache.geocode + ";" + cache.name);
+ } else if (waypoint != null && waypoint.latitude != null && waypoint.longitude != null) {
+ locations.add(String.format((Locale) null, "%.6f", waypoint.latitude) + "," + String.format((Locale) null, "%.6f", waypoint.longitude) + ";" + waypoint.lookup + ";" + waypoint.name);
+ }
+
+ intent.putStringArrayListExtra("locations", locations);
+
+ activity.startActivity(intent);
+
+ sendAnal(activity, tracker, "/external/rmaps");
+
+ return true;
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ if (application == mapAppAny) {
+ // fallback
+ try {
+ if (cache != null && cache.latitude != null && cache.longitude != null) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("geo:" + cache.latitude + "," + cache.longitude)));
+ // INFO: q parameter works with Google Maps, but breaks cooperation with all other apps
+ } else if (waypoint != null && waypoint.latitude != null && waypoint.longitude != null) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("geo:" + waypoint.latitude + "," + waypoint.longitude)));
+ // INFO: q parameter works with Google Maps, but breaks cooperation with all other apps
+ }
+
+ sendAnal(activity, tracker, "/external/native/maps");
+
+ return true;
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ Log.i(cgSettings.tag, "cgBase.runExternalMap: No maps application available.");
+
+ if (warning != null && res != null) {
+ warning.showToast(res.getString(R.string.err_application_no));
+ }
+
+ return false;
+ }
+
+ public boolean runNavigation(Activity activity, Resources res, cgSettings settings, cgWarning warning, GoogleAnalyticsTracker tracker, Double latitude, Double longitude) {
+ return runNavigation(activity, res, settings, warning, tracker, latitude, longitude, null, null);
+ }
+
+ public boolean runNavigation(Activity activity, Resources res, cgSettings settings, cgWarning warning, GoogleAnalyticsTracker tracker, Double latitude, Double longitude, Double latitudeNow, Double longitudeNow) {
+ if (activity == null) {
+ return false;
+ }
+ if (settings == null) {
+ return false;
+ }
+
+ // Google Navigation
+ if (settings.useGNavigation == 1) {
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("google.navigation:ll=" + latitude + "," + longitude)));
+
+ sendAnal(activity, tracker, "/external/native/navigation");
+
+ return true;
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ // Google Maps Directions
+ try {
+ if (latitudeNow != null && longitudeNow != null) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://maps.google.com/maps?f=d&saddr=" + latitudeNow + "," + longitudeNow + "&daddr=" + latitude + "," + longitude)));
+ } else {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://maps.google.com/maps?f=d&daddr=" + latitude + "," + longitude)));
+ }
+
+ sendAnal(activity, tracker, "/external/native/maps");
+
+ return true;
+ } catch (Exception e) {
+ // nothing
+ }
+
+ Log.i(cgSettings.tag, "cgBase.runNavigation: No navigation application available.");
+
+ if (warning != null && res != null) {
+ warning.showToast(res.getString(R.string.err_navigation_no));
+ }
+
+ return false;
+ }
+
+ public String getMapUserToken(Handler noTokenHandler) {
+ final cgResponse response = request(false, "www.geocaching.com", "/map/default.aspx", "GET", "", 0, false);
+ final String data = response.getData();
+ String usertoken = null;
+
+ if (data != null && data.length() > 0) {
+ final Pattern pattern = Pattern.compile("var userToken[^=]*=[^']*'([^']+)';", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+
+ final Matcher matcher = pattern.matcher(data);
+ while (matcher.find()) {
+ if (matcher.groupCount() > 0) {
+ usertoken = matcher.group(1);
+ }
+ }
+ }
+
+ if (noTokenHandler != null && (usertoken == null || usertoken.length() == 0)) {
+ noTokenHandler.sendEmptyMessage(0);
+ }
+
+ return usertoken;
+ }
+
+ public void sendAnal(Context context, String page) {
+ (new sendAnalThread(context, null, page)).start();
+ }
+
+ public void sendAnal(Context context, GoogleAnalyticsTracker tracker, String page) {
+ (new sendAnalThread(context, tracker, page)).start();
+ }
+
+ private class sendAnalThread extends Thread {
+
+ Context context = null;
+ GoogleAnalyticsTracker tracker = null;
+ String page = null;
+ boolean startedHere = false;
+
+ public sendAnalThread(Context contextIn, GoogleAnalyticsTracker trackerIn, String pageIn) {
+ context = contextIn;
+ tracker = trackerIn;
+ page = pageIn;
+ }
+
+ @Override
+ public void run() {
+ try {
+ if (page == null || page.length() == 0) {
+ page = "/";
+ }
+
+ if (tracker == null && context != null) {
+ startedHere = true;
+ tracker = GoogleAnalyticsTracker.getInstance();
+ tracker.start(cgSettings.analytics, context);
+ }
+
+ tracker.trackPageView(page);
+ tracker.dispatch();
+
+ Log.i(cgSettings.tag, "Logged use of " + page);
+
+ if (startedHere == true) {
+ tracker.stop();
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ }
+
+ public Double getElevation(Double latitude, Double longitude) {
+ Double elv = null;
+
+ try {
+ final String host = "maps.googleapis.com";
+ final String path = "/maps/api/elevation/json";
+ final String params = "sensor=false&locations=" + String.format((Locale) null, "%.6f", latitude) + "," + String.format((Locale) null, "%.6f", longitude);
+
+ final String data = requestJSON(host, path, params);
+
+ if (data == null || data.length() == 0) {
+ return elv;
+ }
+
+ JSONObject response = new JSONObject(data);
+ String status = response.getString("status");
+
+ if (status == null || status.equalsIgnoreCase("OK") == false) {
+ return elv;
+ }
+
+ if (response.has("results") == true) {
+ JSONArray results = response.getJSONArray("results");
+ JSONObject result = results.getJSONObject(0);
+ elv = result.getDouble("elevation");
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgBase.getElevation: " + e.toString());
+ }
+
+ return elv;
+ }
+
+ public void showProgress(Activity activity, boolean status) {
+ if (activity == null) {
+ return;
+ }
+
+ final ProgressBar progress = (ProgressBar) activity.findViewById(R.id.actionbar_progress);
+ if (status == true) {
+ progress.setVisibility(View.VISIBLE);
+ } else {
+ progress.setVisibility(View.GONE);
+ }
+ }
+
+ public void goHome(Activity activity) {
+ final Intent intent = new Intent(activity, cgeo.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+
+ activity.startActivity(intent);
+ activity.finish();
+ }
+
+ public void setTitle(Activity activity, String text) {
+ if (activity == null || text == null) {
+ return;
+ }
+
+ final TextView title = (TextView) activity.findViewById(R.id.actionbar_title);
+ if (title != null) {
+ title.setText(text);
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgCache.java b/src/cgeo/geocaching/cgCache.java
new file mode 100644
index 0000000..5bf42f2
--- /dev/null
+++ b/src/cgeo/geocaching/cgCache.java
@@ -0,0 +1,218 @@
+package cgeo.geocaching;
+
+import android.text.Spannable;
+import java.util.Date;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class cgCache {
+
+ public Long updated = null;
+ public Long detailedUpdate = null;
+ public Long visitedDate = null;
+ public Integer reason = 0;
+ public Boolean detailed = false;
+ public String geocode = "";
+ public String cacheid = "";
+ public String guid = "";
+ public String type = "";
+ public String name = "";
+ public Spannable nameSp = null;
+ public String owner = "";
+ public String ownerReal = "";
+ public Date hidden = null;
+ public String hint = "";
+ public String size = "";
+ public Float difficulty = new Float(0);
+ public Float terrain = new Float(0);
+ public Double direction = null;
+ public Double distance = null;
+ public String latlon = "";
+ public String latitudeString = "";
+ public String longitudeString = "";
+ public String location = "";
+ public Double latitude = null;
+ public Double longitude = null;
+ public boolean reliableLatLon = false;
+ public Double elevation = null;
+ public String shortdesc = "";
+ public String description = "";
+ public boolean disabled = false;
+ public boolean archived = false;
+ public boolean members = false;
+ public boolean found = false;
+ public boolean favourite = false;
+ public boolean own = false;
+ public Integer favouriteCnt = null;
+ public Float rating = null;
+ public Integer votes = null;
+ public Float myVote = null;
+ public int inventoryItems = 0;
+ public ArrayList<String> attributes = null;
+ public ArrayList<cgWaypoint> waypoints = null;
+ public ArrayList<cgSpoiler> spoilers = null;
+ public ArrayList<cgLog> logs = null;
+ public ArrayList<cgTrackable> inventory = null;
+ public HashMap<Integer, Integer> logCounts = new HashMap<Integer, Integer>();
+ public boolean logOffline = false;
+ // temporary values
+ public boolean statusChecked = false;
+ public boolean statusCheckedView = false;
+ public String directionImg = null;
+
+ public cgCache merge(cgData storage) {
+ //LeeB - loading cache from db is slow
+ if(false){
+ return this;
+ }
+
+ boolean loadA = true;
+ boolean loadW = true;
+ boolean loadS = true;
+ boolean loadL = true;
+ boolean loadI = true;
+
+ if (attributes == null || attributes.isEmpty() == true) {
+ loadA = false;
+ }
+ if (waypoints == null || waypoints.isEmpty() == true) {
+ loadW = false;
+ }
+ if (spoilers == null || spoilers.isEmpty() == true) {
+ loadS = false;
+ }
+ if (logs == null || logs.isEmpty() == true) {
+ loadL = false;
+ }
+ if (inventory == null || inventory.isEmpty() == true) {
+ loadI = false;
+ }
+
+ final cgCache oldCache = storage.loadCache(geocode, guid, loadA, loadW, loadS, loadL, loadI, false);
+
+ if (oldCache == null) {
+ return this;
+ }
+
+ updated = System.currentTimeMillis();
+ if (detailed == false && oldCache.detailed == true) {
+ detailed = true;
+ detailedUpdate = System.currentTimeMillis();
+ }
+
+ if (visitedDate == null || visitedDate == 0) {
+ visitedDate = oldCache.visitedDate;
+ }
+ if (reason == null || reason == 0) {
+ reason = oldCache.reason;
+ }
+ if (geocode == null || geocode.length() == 0) {
+ geocode = oldCache.geocode;
+ }
+ if (cacheid == null || cacheid.length() == 0) {
+ cacheid = oldCache.cacheid;
+ }
+ if (guid == null || guid.length() == 0) {
+ guid = oldCache.guid;
+ }
+ if (type == null || type.length() == 0) {
+ type = oldCache.type;
+ }
+ if (name == null || name.length() == 0) {
+ name = oldCache.name;
+ }
+ if (nameSp == null || nameSp.length() == 0) {
+ nameSp = oldCache.nameSp;
+ }
+ if (owner == null || owner.length() == 0) {
+ owner = oldCache.owner;
+ }
+ if (ownerReal == null || ownerReal.length() == 0) {
+ ownerReal = oldCache.ownerReal;
+ }
+ if (hidden == null) {
+ hidden = oldCache.hidden;
+ }
+ if (hint == null || hint.length() == 0) {
+ hint = oldCache.hint;
+ }
+ if (size == null || size.length() == 0) {
+ size = oldCache.size;
+ }
+ if (difficulty == null || difficulty == 0) {
+ difficulty = oldCache.difficulty;
+ }
+ if (terrain == null || terrain == 0) {
+ terrain = oldCache.terrain;
+ }
+ if (direction == null) {
+ direction = oldCache.direction;
+ }
+ if (distance == null) {
+ distance = oldCache.distance;
+ }
+ if (latlon == null || latlon.length() == 0) {
+ latlon = oldCache.latlon;
+ }
+ if (latitudeString == null || latitudeString.length() == 0) {
+ latitudeString = oldCache.latitudeString;
+ }
+ if (longitudeString == null || longitudeString.length() == 0) {
+ longitudeString = oldCache.longitudeString;
+ }
+ if (location == null || location.length() == 0) {
+ location = oldCache.location;
+ }
+ if (latitude == null) {
+ latitude = oldCache.latitude;
+ }
+ if (longitude == null) {
+ longitude = oldCache.longitude;
+ }
+ if (elevation == null) {
+ elevation = oldCache.elevation;
+ }
+ if (shortdesc == null || shortdesc.length() == 0) {
+ shortdesc = oldCache.shortdesc;
+ }
+ if (description == null || description.length() == 0) {
+ description = oldCache.description;
+ }
+ if (favouriteCnt == null) {
+ favouriteCnt = oldCache.favouriteCnt;
+ }
+ if (rating == null) {
+ rating = oldCache.rating;
+ }
+ if (votes == null) {
+ votes = oldCache.votes;
+ }
+ if (myVote == null) {
+ myVote = oldCache.myVote;
+ }
+ if (inventoryItems == 0) {
+ inventoryItems = oldCache.inventoryItems;
+ }
+ if (attributes == null) {
+ attributes = oldCache.attributes;
+ }
+ if (waypoints == null) {
+ waypoints = oldCache.waypoints;
+ }
+ if (spoilers == null) {
+ spoilers = oldCache.spoilers;
+ }
+ if (inventory == null) {
+ inventory = oldCache.inventory;
+ }
+ if (logs == null || logs.isEmpty()) { // keep last known logs if none
+ logs = oldCache.logs;
+ }
+
+ return this;
+ }
+
+ public boolean hasTrackables(){
+ return inventoryItems > 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheDifficultyComparator.java b/src/cgeo/geocaching/cgCacheDifficultyComparator.java
new file mode 100644
index 0000000..69971a4
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheDifficultyComparator.java
@@ -0,0 +1,26 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+public class cgCacheDifficultyComparator implements Comparator<cgCache> {
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ if (cache1.difficulty == null || cache2.difficulty == null) {
+ return 0;
+ }
+
+ if (cache1.difficulty > cache2.difficulty) {
+ return 1;
+ } else if (cache2.difficulty > cache1.difficulty) {
+ return -1;
+ } else {
+ return 0;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheDifficultyComparator.compare: " + e.toString());
+ }
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheDistanceComparator.java b/src/cgeo/geocaching/cgCacheDistanceComparator.java
new file mode 100644
index 0000000..2fbdd64
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheDistanceComparator.java
@@ -0,0 +1,51 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+public class cgCacheDistanceComparator implements Comparator<cgCache> {
+ private Double latitude = null;
+ private Double longitude = null;
+
+ public cgCacheDistanceComparator() {
+ // nothing
+ }
+
+ public cgCacheDistanceComparator(Double latitudeIn, Double longitudeIn) {
+ latitude = latitudeIn;
+ longitude = longitudeIn;
+ }
+
+ public void setCoords(Double latitudeIn, Double longitudeIn) {
+ latitude = latitudeIn;
+ longitude = longitudeIn;
+ }
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ int result = 0;
+ try {
+ if (
+ (cache1.latitude == null || cache1.longitude == null || cache2.latitude == null || cache2.longitude == null) &&
+ cache1.distance != null && cache2.distance != null
+ ) {
+ if (cache1.distance < cache2.distance) return -1;
+ else if (cache1.distance > cache2.distance) return 1;
+ else return 0;
+ } else {
+ if (cache1.latitude == null || cache1.longitude == null) return 1;
+ if (cache2.latitude == null || cache2.longitude == null) return -1;
+
+ Double distance1 = cgBase.getDistance(latitude, longitude, cache1.latitude, cache1.longitude);
+ Double distance2 = cgBase.getDistance(latitude, longitude, cache2.latitude, cache2.longitude);
+
+ if (distance1 < distance2) result = -1;
+ else if (distance1 > distance2) result = 1;
+ else result = 0;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheDistanceComparator.compare: " + e.toString());
+ }
+
+ return result;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheGeocodeComparator.java b/src/cgeo/geocaching/cgCacheGeocodeComparator.java
new file mode 100644
index 0000000..e06d9f3
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheGeocodeComparator.java
@@ -0,0 +1,26 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+public class cgCacheGeocodeComparator implements Comparator<cgCache> {
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ if (cache1.geocode == null || cache1.geocode.length() <= 0 || cache2.geocode == null || cache2.geocode.length() <= 0) {
+ return 0;
+ }
+
+ if (cache1.geocode.length() > cache2.geocode.length()) {
+ return 1;
+ } else if (cache2.geocode.length() > cache1.geocode.length()) {
+ return -1;
+ } else {
+ return cache1.geocode.compareToIgnoreCase(cache2.geocode);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheGeocodeComparator.compare: " + e.toString());
+ }
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheInventoryComparator.java b/src/cgeo/geocaching/cgCacheInventoryComparator.java
new file mode 100644
index 0000000..e58eb43
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheInventoryComparator.java
@@ -0,0 +1,36 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+/**
+ * compares by number of items in inventory
+ * @author bananeweizen
+ *
+ */
+public class cgCacheInventoryComparator implements Comparator<cgCache> {
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ int itemCount1 = 0;
+ int itemCount2 = 0;
+ if (cache1.difficulty != null) {
+ itemCount1 = cache1.inventoryItems;
+ }
+ if (cache2.difficulty != null) {
+ itemCount2 = cache2.inventoryItems;
+ }
+
+ if (itemCount1 < itemCount2) {
+ return 1;
+ } else if (itemCount2 < itemCount1) {
+ return -1;
+ } else {
+ return 0;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheInventoryComparator.compare: " + e.toString());
+ }
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheListAdapter.java b/src/cgeo/geocaching/cgCacheListAdapter.java
new file mode 100644
index 0000000..b1eded2
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheListAdapter.java
@@ -0,0 +1,909 @@
+package cgeo.geocaching;
+
+import java.util.List;
+import java.util.HashMap;
+import android.app.Activity;
+import android.text.Spannable;
+import android.text.style.StrikethroughSpan;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.widget.ArrayAdapter;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Drawable;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.AnimationSet;
+import android.view.animation.TranslateAnimation;
+import android.widget.CheckBox;
+import android.widget.ImageView;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Locale;
+
+import cgeo.geocaching.filter.cgFilter;
+
+public class cgCacheListAdapter extends ArrayAdapter<cgCache> {
+
+ private Resources res = null;
+ private List<cgCache> list = null;
+ private cgSettings settings = null;
+ private cgCacheView holder = null;
+ private LayoutInflater inflater = null;
+ private Activity activity = null;
+ private cgBase base = null;
+ private cgCacheDistanceComparator dstComparator = null;
+ private Comparator statComparator = null;
+ private boolean historic = false;
+ private Double latitude = null;
+ private Double longitude = null;
+ private Double azimuth = new Double(0);
+ private long lastSort = 0l;
+ private boolean sort = true;
+ private int checked = 0;
+ private boolean selectMode = false;
+ private HashMap<String, Drawable> gcIcons = new HashMap<String, Drawable>();
+ private ArrayList<cgCompassMini> compasses = new ArrayList<cgCompassMini>();
+ private ArrayList<cgDistanceView> distances = new ArrayList<cgDistanceView>();
+ private int[] ratingBcgs = new int[3];
+ private float pixelDensity = 1f;
+ private static final int SWIPE_MIN_DISTANCE = 60;
+ private static final int SWIPE_MAX_OFF_PATH = 100;
+ private static final int SWIPE_DISTANCE = 80;
+ private static final float SWIPE_OPACITY = 0.5f;
+ private cgFilter currentFilter = null;
+ private List<cgCache> originalList = null;
+
+ public cgCacheListAdapter(Activity activityIn, cgSettings settingsIn, List<cgCache> listIn, cgBase baseIn) {
+ super(activityIn, 0, listIn);
+
+ res = activityIn.getResources();
+ activity = activityIn;
+ settings = settingsIn;
+ list = listIn;
+ base = baseIn;
+ dstComparator = new cgCacheDistanceComparator();
+
+ DisplayMetrics metrics = new DisplayMetrics();
+ activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ pixelDensity = metrics.density;
+
+ if (gcIcons == null || gcIcons.isEmpty()) {
+ gcIcons.put("ape", (Drawable) activity.getResources().getDrawable(R.drawable.type_ape));
+ gcIcons.put("cito", (Drawable) activity.getResources().getDrawable(R.drawable.type_cito));
+ gcIcons.put("earth", (Drawable) activity.getResources().getDrawable(R.drawable.type_earth));
+ gcIcons.put("event", (Drawable) activity.getResources().getDrawable(R.drawable.type_event));
+ gcIcons.put("letterbox", (Drawable) activity.getResources().getDrawable(R.drawable.type_letterbox));
+ gcIcons.put("locationless", (Drawable) activity.getResources().getDrawable(R.drawable.type_locationless));
+ gcIcons.put("mega", (Drawable) activity.getResources().getDrawable(R.drawable.type_mega));
+ gcIcons.put("multi", (Drawable) activity.getResources().getDrawable(R.drawable.type_multi));
+ gcIcons.put("traditional", (Drawable) activity.getResources().getDrawable(R.drawable.type_traditional));
+ gcIcons.put("virtual", (Drawable) activity.getResources().getDrawable(R.drawable.type_virtual));
+ gcIcons.put("webcam", (Drawable) activity.getResources().getDrawable(R.drawable.type_webcam));
+ gcIcons.put("wherigo", (Drawable) activity.getResources().getDrawable(R.drawable.type_wherigo));
+ gcIcons.put("mystery", (Drawable) activity.getResources().getDrawable(R.drawable.type_mystery));
+ gcIcons.put("gchq", (Drawable) activity.getResources().getDrawable(R.drawable.type_hq));
+ }
+
+ if (settings.skin == 0) {
+ ratingBcgs[0] = R.drawable.favourite_background_red_dark;
+ ratingBcgs[1] = R.drawable.favourite_background_orange_dark;
+ ratingBcgs[2] = R.drawable.favourite_background_green_dark;
+ } else {
+ ratingBcgs[0] = R.drawable.favourite_background_red_light;
+ ratingBcgs[1] = R.drawable.favourite_background_orange_light;
+ ratingBcgs[2] = R.drawable.favourite_background_green_light;
+ }
+ }
+
+ public void setComparator(Comparator comparator) {
+ statComparator = comparator;
+
+ forceSort(latitude, longitude);
+ }
+
+ /**
+ * Called when a new page of caches was loaded.
+ */
+ public void reFilter(){
+ if(currentFilter != null){
+ // Back up the list again
+ originalList = new ArrayList<cgCache>(list);
+
+ currentFilter.filter(list);
+ }
+ }
+
+ /**
+ * Called after a user action on the filter menu.
+ */
+ public void setFilter(cgFilter filter){
+ // Backup current caches list if it isn't backed up yet
+ if (originalList == null) {
+ originalList = new ArrayList<cgCache>(list);
+ }
+
+ // If there is already a filter in place, this is a request to change or clear the filter, so we have to
+ // replace the original cache list
+ if (currentFilter != null) {
+ list.clear();
+ list.addAll(originalList);
+ }
+
+ // Do the filtering or clear it
+ if (filter != null) {
+ filter.filter(list);
+ }
+ currentFilter = filter;
+
+ notifyDataSetChanged();
+ }
+
+ public void clearFilter() {
+ if (originalList != null) {
+ list.clear();
+ list.addAll(originalList);
+
+ currentFilter = null;
+ }
+
+ notifyDataSetChanged();
+ }
+
+ public boolean isFilter() {
+ if (currentFilter != null) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public void setHistoric(boolean historicIn) {
+ historic = historicIn;
+
+ if (historic == true) {
+ statComparator = new cgCacheVisitComparator();
+ } else {
+ statComparator = null;
+ }
+ }
+
+ public int getChecked() {
+ return checked;
+ }
+
+ public boolean setSelectMode(boolean status, boolean clear) {
+ selectMode = status;
+
+ if (selectMode == false && clear == true) {
+ for (cgCache cache : list) {
+ cache.statusChecked = false;
+ cache.statusCheckedView = false;
+ }
+ checked = 0;
+ } else if (selectMode == true) {
+ for (cgCache cache : list) {
+ cache.statusCheckedView = false;
+ }
+ }
+ checkChecked(0);
+
+ notifyDataSetChanged();
+
+ return selectMode;
+ }
+
+ public boolean getSelectMode() {
+ return selectMode;
+ }
+
+ public void switchSelectMode() {
+ selectMode = !selectMode;
+
+ if (selectMode == false) {
+ for (cgCache cache : list) {
+ cache.statusChecked = false;
+ cache.statusCheckedView = false;
+ }
+ checked = 0;
+ } else if (selectMode == true) {
+ for (cgCache cache : list) {
+ cache.statusCheckedView = false;
+ }
+ }
+ checkChecked(0);
+
+ notifyDataSetChanged();
+ }
+
+ public void invertSelection() {
+ int check = 0;
+
+ for (cgCache cache : list) {
+ if (cache.statusChecked == true) {
+ cache.statusChecked = false;
+ cache.statusCheckedView = false;
+ } else {
+ cache.statusChecked = true;
+ cache.statusCheckedView = true;
+
+ check++;
+ }
+ }
+ checkChecked(check);
+
+ notifyDataSetChanged();
+ }
+
+ public void forceSort(Double latitudeIn, Double longitudeIn) {
+ if (list == null || list.isEmpty() == true) {
+ return;
+ }
+ if (sort == false) {
+ return;
+ }
+
+ try {
+ if (statComparator != null) {
+ Collections.sort((List<cgCache>) list, statComparator);
+ } else {
+ if (latitudeIn == null || longitudeIn == null) {
+ return;
+ }
+
+ dstComparator.setCoords(latitudeIn, longitudeIn);
+ Collections.sort((List<cgCache>) list, dstComparator);
+ }
+ notifyDataSetChanged();
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgCacheListAdapter.setActualCoordinates: failed to sort caches in list");
+ }
+ }
+
+ public void setActualCoordinates(Double latitudeIn, Double longitudeIn) {
+ if (latitudeIn == null || longitudeIn == null) {
+ return;
+ }
+
+ latitude = latitudeIn;
+ longitude = longitudeIn;
+
+ if (list != null && list.isEmpty() == false && (System.currentTimeMillis() - lastSort) > 1000 && sort == true) {
+ try {
+ if (statComparator != null) {
+ Collections.sort((List<cgCache>) list, statComparator);
+ } else {
+ dstComparator.setCoords(latitudeIn, longitudeIn);
+ Collections.sort((List<cgCache>) list, dstComparator);
+ }
+ notifyDataSetChanged();
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgCacheListAdapter.setActualCoordinates: failed to sort caches in list");
+ }
+
+ lastSort = System.currentTimeMillis();
+ }
+
+ if (distances != null && distances.size() > 0) {
+ for (cgDistanceView distance : distances) {
+ distance.update(latitudeIn, longitudeIn);
+ }
+ }
+
+ if (compasses != null && compasses.size() > 0) {
+ for (cgCompassMini compass : compasses) {
+ compass.updateCoords(latitudeIn, longitudeIn);
+ }
+ }
+ }
+
+ public void setActualHeading(Double azimuthIn) {
+ if (azimuthIn == null) {
+ return;
+ }
+
+ azimuth = azimuthIn;
+
+ if (compasses != null && compasses.size() > 0) {
+ for (cgCompassMini compass : compasses) {
+ compass.updateAzimuth(azimuth);
+ }
+ }
+ }
+
+ public boolean resetChecks() {
+ if (list.isEmpty() == true) {
+ return false;
+ }
+ if (checked <= 0) {
+ return false;
+ }
+
+ boolean status = getSelectMode();
+ int cleared = 0;
+ for (cgCache cache : list) {
+ if (cache.statusChecked == true) {
+ cache.statusChecked = false;
+
+ checkChecked(-1);
+ cleared++;
+ }
+ }
+ setSelectMode(false, false);
+ notifyDataSetChanged();
+
+ if (cleared > 0 || status == true) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public View getView(int position, View rowView, ViewGroup parent) {
+ if (inflater == null) {
+ inflater = ((Activity) getContext()).getLayoutInflater();
+ }
+
+ if (position > getCount()) {
+ Log.w(cgSettings.tag, "cgCacheListAdapter.getView: Attempt to access missing item #" + position);
+ return null;
+ }
+
+ cgCache cache = getItem(position);
+
+ if (rowView == null) {
+ rowView = (View) inflater.inflate(R.layout.cache, null);
+
+ holder = new cgCacheView();
+ holder.oneCache = (RelativeLayout) rowView.findViewById(R.id.one_cache);
+ holder.checkbox = (CheckBox) rowView.findViewById(R.id.checkbox);
+ holder.oneInfo = (RelativeLayout) rowView.findViewById(R.id.one_info);
+ holder.oneCheckbox = (RelativeLayout) rowView.findViewById(R.id.one_checkbox);
+ holder.foundMark = (ImageView) rowView.findViewById(R.id.found_mark);
+ holder.offlineMark = (ImageView) rowView.findViewById(R.id.offline_mark);
+ holder.oneCache = (RelativeLayout) rowView.findViewById(R.id.one_cache);
+ holder.text = (TextView) rowView.findViewById(R.id.text);
+ holder.directionLayout = (RelativeLayout) rowView.findViewById(R.id.direction_layout);
+ holder.distance = (cgDistanceView) rowView.findViewById(R.id.distance);
+ holder.direction = (cgCompassMini) rowView.findViewById(R.id.direction);
+ holder.dirImgLayout = (RelativeLayout) rowView.findViewById(R.id.dirimg_layout);
+ holder.dirImg = (ImageView) rowView.findViewById(R.id.dirimg);
+ holder.inventory = (RelativeLayout) rowView.findViewById(R.id.inventory);
+ holder.favourite = (TextView) rowView.findViewById(R.id.favourite);
+ holder.info = (TextView) rowView.findViewById(R.id.info);
+
+ rowView.setTag(holder);
+ } else {
+ holder = (cgCacheView) rowView.getTag();
+ }
+
+ if (cache.own == true) {
+ if (settings.skin == 1) {
+ holder.oneInfo.setBackgroundResource(R.color.owncache_background_light);
+ holder.oneCheckbox.setBackgroundResource(R.color.owncache_background_light);
+ } else {
+ holder.oneInfo.setBackgroundResource(R.color.owncache_background_dark);
+ holder.oneCheckbox.setBackgroundResource(R.color.owncache_background_dark);
+ }
+ } else {
+ if (settings.skin == 1) {
+ holder.oneInfo.setBackgroundResource(R.color.background_light);
+ holder.oneCheckbox.setBackgroundResource(R.color.background_light);
+ } else {
+ holder.oneInfo.setBackgroundResource(R.color.background_dark);
+ holder.oneCheckbox.setBackgroundResource(R.color.background_dark);
+ }
+ }
+
+ final touchListener touchLst = new touchListener(cache.geocode, cache.name, cache);
+ rowView.setOnClickListener(touchLst);
+ rowView.setOnLongClickListener(touchLst);
+ rowView.setOnTouchListener(touchLst);
+ rowView.setLongClickable(true);
+
+ if (selectMode == true) {
+ if (cache.statusCheckedView == true) {
+ moveRight(holder, cache, true); // move fast when already slided
+ } else {
+ moveRight(holder, cache, false);
+ }
+ } else if (cache.statusChecked == true) {
+ holder.checkbox.setChecked(true);
+ if (cache.statusCheckedView == true) {
+ moveRight(holder, cache, true); // move fast when already slided
+ } else {
+ moveRight(holder, cache, false);
+ }
+ } else {
+ holder.checkbox.setChecked(false);
+ if (cache.statusCheckedView == false) {
+ holder.oneInfo.clearAnimation();
+ } else {
+ moveLeft(holder, cache, false);
+ }
+ }
+
+ holder.checkbox.setOnClickListener(new checkBoxListener(cache));
+
+ if (distances.contains(holder.distance) == false) {
+ distances.add(holder.distance);
+ }
+ holder.distance.setContent(base, cache.latitude, cache.longitude);
+ if (compasses.contains(holder.direction) == false) {
+ compasses.add(holder.direction);
+ }
+ holder.direction.setContent(base, cache.latitude, cache.longitude);
+
+ if (cache.logOffline == true) {
+ holder.offlineMark.setVisibility(View.VISIBLE);
+ holder.foundMark.setVisibility(View.GONE);
+ } else if (cache.found == true) {
+ holder.offlineMark.setVisibility(View.GONE);
+ holder.foundMark.setVisibility(View.VISIBLE);
+ } else {
+ holder.offlineMark.setVisibility(View.GONE);
+ holder.foundMark.setVisibility(View.GONE);
+ }
+
+ if (cache.nameSp == null) {
+ cache.nameSp = (new Spannable.Factory()).newSpannable(cache.name);
+ if (cache.disabled == true || cache.archived == true) { // strike
+ cache.nameSp.setSpan(new StrikethroughSpan(), 0, cache.nameSp.toString().length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+
+ holder.text.setText(cache.nameSp, TextView.BufferType.SPANNABLE);
+ if (gcIcons.containsKey(cache.type) == true) { // cache icon
+ holder.text.setCompoundDrawablesWithIntrinsicBounds(gcIcons.get(cache.type), null, null, null);
+ } else { // unknown cache type, "mystery" icon
+ holder.text.setCompoundDrawablesWithIntrinsicBounds(gcIcons.get("mystery"), null, null, null);
+ }
+
+ if (holder.inventory.getChildCount() > 0) {
+ holder.inventory.removeAllViews();
+ }
+
+ ImageView tbIcon = null;
+ if (cache.inventoryItems > 0) {
+ tbIcon = (ImageView) inflater.inflate(R.layout.trackable_icon, null);
+ tbIcon.setImageResource(R.drawable.trackable_all);
+
+ holder.inventory.addView(tbIcon);
+ holder.inventory.setVisibility(View.VISIBLE);
+ } else {
+ holder.inventory.setVisibility(View.GONE);
+ }
+
+ boolean setDiDi = false;
+ if (cache.latitude != null && cache.longitude != null) {
+ holder.direction.setVisibility(View.VISIBLE);
+ holder.direction.updateAzimuth(azimuth);
+ if (latitude != null && longitude != null) {
+ holder.distance.update(latitude, longitude);
+ holder.direction.updateCoords(latitude, longitude);
+ }
+ setDiDi = true;
+ } else {
+ if (cache.distance != null) {
+ holder.distance.setDistance(cache.distance);
+ setDiDi = true;
+ }
+ if (cache.direction != null) {
+ holder.direction.setVisibility(View.VISIBLE);
+ holder.direction.updateAzimuth(azimuth);
+ holder.direction.updateHeading(cache.direction);
+ setDiDi = true;
+ }
+ }
+
+ if (setDiDi == true) {
+ holder.directionLayout.setVisibility(View.VISIBLE);
+ holder.dirImgLayout.setVisibility(View.GONE);
+ } else {
+ holder.directionLayout.setVisibility(View.GONE);
+ holder.distance.clear();
+
+ Bitmap dirImgPre = null;
+ Bitmap dirImg = null;
+ try {
+ dirImgPre = BitmapFactory.decodeFile(settings.getStorage() + cache.geocode + "/direction.png");
+ dirImg = dirImgPre.copy(Bitmap.Config.ARGB_8888, true);
+
+ dirImgPre.recycle();
+ dirImgPre = null;
+ } catch (Exception e) {
+ // nothing
+ }
+
+ if (dirImg != null) {
+ if (settings.skin == 0) {
+ int length = dirImg.getWidth() * dirImg.getHeight();
+ int[] pixels = new int[length];
+ dirImg.getPixels(pixels, 0, dirImg.getWidth(), 0, 0, dirImg.getWidth(), dirImg.getHeight());
+ for (int i = 0; i < length; i++) {
+ if (pixels[i] == 0xff000000) { // replace black with white
+ pixels[i] = 0xffffffff;
+ }
+ }
+ dirImg.setPixels(pixels, 0, dirImg.getWidth(), 0, 0, dirImg.getWidth(), dirImg.getHeight());
+ }
+
+ holder.dirImg.setImageBitmap(dirImg);
+ holder.dirImgLayout.setVisibility(View.VISIBLE);
+ } else {
+ holder.dirImg.setImageBitmap(null);
+ holder.dirImgLayout.setVisibility(View.GONE);
+ }
+ }
+
+ if (cache.favouriteCnt != null) {
+ holder.favourite.setText(String.format("%d", cache.favouriteCnt));
+ } else {
+ holder.favourite.setText("---");
+ }
+
+ int favoriteBack;
+ // set default background, neither vote nor rating may be available
+ if (settings.skin == 1) {
+ favoriteBack = R.drawable.favourite_background_light;
+ } else {
+ favoriteBack = R.drawable.favourite_background_dark;
+ }
+ if (cache.myVote != null && cache.myVote > 0) {
+ if (cache.myVote >= 4) {
+ favoriteBack = ratingBcgs[2];
+ } else if (cache.myVote >= 3) {
+ favoriteBack = ratingBcgs[1];
+ } else if (cache.myVote > 0) {
+ favoriteBack = ratingBcgs[0];
+ }
+ } else if (cache.rating != null && cache.rating > 0) {
+ if (cache.rating >= 3.5) {
+ favoriteBack = ratingBcgs[2];
+ } else if (cache.rating >= 2.1) {
+ favoriteBack = ratingBcgs[1];
+ } else if (cache.rating > 0.0) {
+ favoriteBack = ratingBcgs[0];
+ }
+ }
+ holder.favourite.setBackgroundResource(favoriteBack);
+
+ StringBuilder cacheInfo = new StringBuilder();
+ if (historic == true && cache.visitedDate != null) {
+ cacheInfo.append(cgBase.timeOut.format(cache.visitedDate));
+ cacheInfo.append("; ");
+ cacheInfo.append(cgBase.dateOut.format(cache.visitedDate));
+ } else {
+ if (cache.geocode != null && cache.geocode.length() > 0) {
+ cacheInfo.append(cache.geocode);
+ }
+ if (cache.size != null && cache.size.length() > 0) {
+ if (cacheInfo.length() > 0) {
+ cacheInfo.append(" | ");
+ }
+ cacheInfo.append(cache.size);
+ }
+ if ((cache.difficulty != null && cache.difficulty > 0f) || (cache.terrain != null && cache.terrain > 0f) || (cache.rating != null && cache.rating > 0f)) {
+ if (cacheInfo.length() > 0 && ((cache.difficulty != null && cache.difficulty > 0f) || (cache.terrain != null && cache.terrain > 0f))) {
+ cacheInfo.append(" |");
+ }
+
+ if (cache.difficulty != null && cache.difficulty > 0f) {
+ cacheInfo.append(" D:");
+ cacheInfo.append(String.format(Locale.getDefault(), "%.1f", cache.difficulty));
+ }
+ if (cache.terrain != null && cache.terrain > 0f) {
+ cacheInfo.append(" T:");
+ cacheInfo.append(String.format(Locale.getDefault(), "%.1f", cache.terrain));
+ }
+ }
+ if (cache.members == true) {
+ if (cacheInfo.length() > 0) {
+ cacheInfo.append(" | ");
+ }
+ cacheInfo.append(res.getString(R.string.cache_premium));
+ }
+ if (cache.reason != null && cache.reason == 1) {
+ if (cacheInfo.length() > 0) {
+ cacheInfo.append(" | ");
+ }
+ cacheInfo.append(res.getString(R.string.cache_offline));
+ }
+ }
+ holder.info.setText(cacheInfo.toString());
+
+ return rowView;
+ }
+
+ @Override
+ public void notifyDataSetChanged() {
+ super.notifyDataSetChanged();
+
+ checked = 0;
+ for (cgCache cache : list) {
+ if (cache.statusChecked == true) {
+ checked++;
+ }
+ }
+
+ distances.clear();
+ compasses.clear();
+ }
+
+ private class checkBoxListener implements View.OnClickListener {
+
+ private cgCache cache = null;
+
+ public checkBoxListener(cgCache cacheIn) {
+ cache = cacheIn;
+ }
+
+ public void onClick(View view) {
+ final boolean checkNow = ((CheckBox) view).isChecked();
+
+ if (checkNow == true) {
+ cache.statusChecked = true;
+ checked++;
+ } else {
+ cache.statusChecked = false;
+ checked--;
+ }
+ }
+ }
+
+ private class touchListener implements View.OnLongClickListener, View.OnClickListener, View.OnTouchListener {
+
+ private String geocode = null;
+ private String name = null;
+ private cgCache cache = null;
+ private boolean touch = true;
+ private GestureDetector gestureDetector = null;
+
+ public touchListener(String geocodeIn, String nameIn, cgCache cacheIn) {
+ geocode = geocodeIn;
+ name = nameIn;
+ cache = cacheIn;
+
+ final detectGesture dGesture = new detectGesture(holder, cache);
+ gestureDetector = new GestureDetector(dGesture);
+ }
+
+ // tap on item
+ public void onClick(View view) {
+ if (touch == false) {
+ touch = true;
+
+ return;
+ }
+
+ if (getSelectMode() == true || getChecked() > 0) {
+ return;
+ }
+
+ // load cache details
+ Intent cachesIntent = new Intent(getContext(), cgeodetail.class);
+ cachesIntent.putExtra("geocode", geocode);
+ cachesIntent.putExtra("name", name);
+ getContext().startActivity(cachesIntent);
+ }
+
+ // long tap on item
+ public boolean onLongClick(View view) {
+ if (touch == false) {
+ touch = true;
+
+ return true;
+ }
+
+ return view.showContextMenu();
+ }
+
+ // swipe on item
+ public boolean onTouch(View view, MotionEvent event) {
+ if (gestureDetector.onTouchEvent(event) == true) {
+ touch = false;
+
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ class detectGesture extends GestureDetector.SimpleOnGestureListener {
+
+ private cgCacheView holder = null;
+ private cgCache cache = null;
+
+ public detectGesture(cgCacheView holderIn, cgCache cacheIn) {
+ holder = holderIn;
+ cache = cacheIn;
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+ try {
+ if (getSelectMode() == true) {
+ return false;
+ }
+
+ if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) {
+ return false;
+ }
+
+ if ((e2.getX() - e1.getX()) > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > Math.abs(velocityY)) {
+ // left to right swipe
+ if (cache.statusChecked == true) {
+ return true;
+ }
+
+ if (holder != null && holder.oneInfo != null) {
+ checkChecked(+1);
+ holder.checkbox.setChecked(true);
+ cache.statusChecked = true;
+ moveRight(holder, cache, false);
+ }
+
+ return true;
+ } else if ((e1.getX() - e2.getX()) > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > Math.abs(velocityY)) {
+ // right to left swipe
+ if (cache.statusChecked == false) {
+ return true;
+ }
+
+ if (holder != null && holder.oneInfo != null) {
+ if (getSelectMode() == true) {
+ setSelectMode(false, false);
+ }
+
+ checkChecked(-1);
+ holder.checkbox.setChecked(false);
+ cache.statusChecked = false;
+ moveLeft(holder, cache, false);
+ }
+
+ return true;
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgCacheListAdapter.detectGesture.onFling: " + e.toString());
+ }
+
+ return false;
+ }
+ }
+
+ private void checkChecked(int cnt) {
+ // check how many caches are selected, if any block sorting of list
+ boolean statusChecked = false;
+ boolean statusSort = false;
+ checked += cnt;
+
+ if (checked > 0) {
+ statusChecked = false;
+ } else {
+ statusChecked = true;
+ }
+
+ if (getSelectMode() == true) {
+ statusSort = false;
+ } else {
+ statusSort = true;
+ }
+
+ if (statusChecked == false || statusSort == false) {
+ sort = false;
+ } else {
+ sort = true;
+ }
+
+ if (sort == true) {
+ forceSort(latitude, longitude);
+ }
+ }
+
+ private void moveRight(cgCacheView holder, cgCache cache, boolean force) {
+ if (cache == null) {
+ return;
+ }
+
+ try {
+ holder.checkbox.setChecked(cache.statusChecked);
+
+ // slide cache info
+ Animation showCheckbox = new TranslateAnimation(0, (int) (SWIPE_DISTANCE * pixelDensity), 0, 0);
+ showCheckbox.setRepeatCount(0);
+ if (force == true) {
+ showCheckbox.setDuration(0);
+ } else {
+ showCheckbox.setDuration(400);
+ }
+ showCheckbox.setFillEnabled(true);
+ showCheckbox.setFillAfter(true);
+ showCheckbox.setInterpolator(new AccelerateDecelerateInterpolator());
+
+ // dim cache info
+ Animation dimInfo = new AlphaAnimation(1.0f, SWIPE_OPACITY);
+ dimInfo.setRepeatCount(0);
+ if (force == true) {
+ dimInfo.setDuration(0);
+ } else {
+ dimInfo.setDuration(400);
+ }
+ dimInfo.setFillEnabled(true);
+ dimInfo.setFillAfter(true);
+ dimInfo.setInterpolator(new AccelerateDecelerateInterpolator());
+
+ // animation set (container)
+ AnimationSet selectAnimation = new AnimationSet(true);
+ selectAnimation.setFillEnabled(true);
+ selectAnimation.setFillAfter(true);
+
+ selectAnimation.addAnimation(showCheckbox);
+ selectAnimation.addAnimation(dimInfo);
+
+ holder.oneInfo.startAnimation(selectAnimation);
+ cache.statusCheckedView = true;
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ private void moveLeft(cgCacheView holder, cgCache cache, boolean force) {
+ if (cache == null) {
+ return;
+ }
+
+ try {
+ holder.checkbox.setChecked(cache.statusChecked);
+
+ // slide cache info
+ Animation hideCheckbox = new TranslateAnimation((int) (SWIPE_DISTANCE * pixelDensity), 0, 0, 0);
+ hideCheckbox.setRepeatCount(0);
+ if (force == true) {
+ hideCheckbox.setDuration(0);
+ } else {
+ hideCheckbox.setDuration(400);
+ }
+ hideCheckbox.setFillEnabled(true);
+ hideCheckbox.setFillAfter(true);
+ hideCheckbox.setInterpolator(new AccelerateDecelerateInterpolator());
+
+ // brighten cache info
+ Animation brightenInfo = new AlphaAnimation(SWIPE_OPACITY, 1.0f);
+ brightenInfo.setRepeatCount(0);
+ if (force == true) {
+ brightenInfo.setDuration(0);
+ } else {
+ brightenInfo.setDuration(400);
+ }
+ brightenInfo.setFillEnabled(true);
+ brightenInfo.setFillAfter(true);
+ brightenInfo.setInterpolator(new AccelerateDecelerateInterpolator());
+
+ // animation set (container)
+ AnimationSet selectAnimation = new AnimationSet(true);
+ selectAnimation.setFillEnabled(true);
+ selectAnimation.setFillAfter(true);
+
+ selectAnimation.addAnimation(hideCheckbox);
+ selectAnimation.addAnimation(brightenInfo);
+
+ holder.oneInfo.startAnimation(selectAnimation);
+ cache.statusCheckedView = false;
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheNameComparator.java b/src/cgeo/geocaching/cgCacheNameComparator.java
new file mode 100644
index 0000000..fa247fa
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheNameComparator.java
@@ -0,0 +1,20 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+public class cgCacheNameComparator implements Comparator<cgCache> {
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ if (cache1.name == null || cache2.name == null) {
+ return 0;
+ }
+
+ return cache1.name.compareToIgnoreCase(cache2.name);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheNameComparator.compare: " + e.toString());
+ }
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCachePopularityComparator.java b/src/cgeo/geocaching/cgCachePopularityComparator.java
new file mode 100644
index 0000000..10500f9
--- /dev/null
+++ b/src/cgeo/geocaching/cgCachePopularityComparator.java
@@ -0,0 +1,26 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+public class cgCachePopularityComparator implements Comparator<cgCache> {
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ if (cache1.favouriteCnt == null || cache2.favouriteCnt == null) {
+ return 0;
+ }
+
+ if (cache1.favouriteCnt < cache2.favouriteCnt) {
+ return 1;
+ } else if (cache2.favouriteCnt < cache1.favouriteCnt) {
+ return -1;
+ } else {
+ return 0;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCachePopularityComparator.compare: " + e.toString());
+ }
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheRatingComparator.java b/src/cgeo/geocaching/cgCacheRatingComparator.java
new file mode 100644
index 0000000..b7b9720
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheRatingComparator.java
@@ -0,0 +1,36 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+public class cgCacheRatingComparator implements Comparator<cgCache> {
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ Float rating1 = cache1.rating;
+ Float rating2 = cache2.rating;
+ if (rating1 == null || rating2 == null) {
+ return 0;
+ }
+
+ // voting can be disabled for caches, then assume an average rating instead
+ if (rating1 == 0.0) {
+ rating1 = 2.5f;
+ }
+ if (rating2 == 0.0) {
+ rating2 = 2.5f;
+ }
+
+ if (rating1 < rating2) {
+ return 1;
+ } else if (rating2 < rating1) {
+ return -1;
+ } else {
+ return 0;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheRatingComparator.compare: " + e.toString());
+ }
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheSizeComparator.java b/src/cgeo/geocaching/cgCacheSizeComparator.java
new file mode 100644
index 0000000..a5d0298
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheSizeComparator.java
@@ -0,0 +1,47 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+import java.util.ArrayList;
+
+public class cgCacheSizeComparator implements Comparator<cgCache> {
+ public static ArrayList<String> cacheSizes = new ArrayList<String>();
+
+ public cgCacheSizeComparator() {
+ // list sizes
+ cacheSizes.add("micro");
+ cacheSizes.add("small");
+ cacheSizes.add("regular");
+ cacheSizes.add("large");
+ }
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ if (cache1.size == null || cache1.size.length() == 0 || cache2.size == null || cache2.size.length() == 0) {
+ return 0;
+ }
+
+ int size1 = 0;
+ int size2 = 0;
+
+ int cnt = 1;
+ for (String size : cacheSizes) {
+ if (size.equalsIgnoreCase(cache1.size)) size1 = cnt;
+ if (size.equalsIgnoreCase(cache2.size)) size2 = cnt;
+
+ cnt ++;
+ }
+
+ if (size1 < size2) {
+ return 1;
+ } else if (size2 < size1) {
+ return -1;
+ } else {
+ return 0;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheSizeComparator.compare: " + e.toString());
+ }
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheTerrainComparator.java b/src/cgeo/geocaching/cgCacheTerrainComparator.java
new file mode 100644
index 0000000..3d31a37
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheTerrainComparator.java
@@ -0,0 +1,26 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+public class cgCacheTerrainComparator implements Comparator<cgCache> {
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ if (cache1.terrain == null || cache2.terrain == null) {
+ return 0;
+ }
+
+ if (cache1.terrain > cache2.terrain) {
+ return 1;
+ } else if (cache2.terrain > cache1.terrain) {
+ return -1;
+ } else {
+ return 0;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheTerrainComparator.compare: " + e.toString());
+ }
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheView.java b/src/cgeo/geocaching/cgCacheView.java
new file mode 100644
index 0000000..6705729
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheView.java
@@ -0,0 +1,29 @@
+package cgeo.geocaching;
+
+import android.widget.CheckBox;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+public class cgCacheView {
+ // layouts & views
+ public RelativeLayout oneCache;
+ public RelativeLayout oneInfo;
+ public RelativeLayout oneCheckbox;
+ public CheckBox checkbox;
+ public ImageView foundMark;
+ public ImageView offlineMark;
+ public TextView text;
+ public TextView favourite;
+ public TextView info;
+ public RelativeLayout inventory;
+ public RelativeLayout directionLayout;
+ public cgDistanceView distance;
+ public cgCompassMini direction;
+ public RelativeLayout dirImgLayout;
+ public ImageView dirImg;
+
+ // status
+ public float startX = -1;
+ public float prevX = -1;
+}
diff --git a/src/cgeo/geocaching/cgCacheVisitComparator.java b/src/cgeo/geocaching/cgCacheVisitComparator.java
new file mode 100644
index 0000000..19a4b52
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheVisitComparator.java
@@ -0,0 +1,27 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+public class cgCacheVisitComparator implements Comparator<cgCache> {
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ if (cache1.visitedDate == null || cache1.visitedDate <= 0 || cache2.visitedDate == null || cache2.visitedDate <= 0) {
+ return 0;
+ }
+
+ if (cache1.visitedDate > cache2.visitedDate) {
+ return -1;
+ } else if (cache1.visitedDate < cache2.visitedDate) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheVisitComparator.compare: " + e.toString());
+ }
+
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheVoteComparator.java b/src/cgeo/geocaching/cgCacheVoteComparator.java
new file mode 100644
index 0000000..581656c
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheVoteComparator.java
@@ -0,0 +1,38 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+/**
+ * sorts caches by the users own voting (if available at all)
+ * @author bananeweizen
+ *
+ */
+public class cgCacheVoteComparator implements Comparator<cgCache> {
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ // if there is no vote available, put that cache at the end of the list
+ float vote1 = 0;
+ if (cache1.myVote != null) {
+ vote1 = cache1.myVote;
+ }
+
+ float vote2 = 0;
+ if (cache2.myVote != null) {
+ vote2 = cache2.myVote;
+ }
+
+ if (vote1 < vote2) {
+ return 1;
+ } else if (vote2 < vote1) {
+ return -1;
+ } else {
+ return 0;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheVoteComparator.compare: " + e.toString());
+ }
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheWrap.java b/src/cgeo/geocaching/cgCacheWrap.java
new file mode 100644
index 0000000..23d77f5
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheWrap.java
@@ -0,0 +1,12 @@
+package cgeo.geocaching;
+
+import java.util.ArrayList;
+
+public class cgCacheWrap {
+ public String error = null;
+ public String url = "";
+ public String viewstate = "";
+ public String viewstate1 = "";
+ public int totalCnt = 0;
+ public ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgCompass.java b/src/cgeo/geocaching/cgCompass.java
new file mode 100644
index 0000000..9d4473e
--- /dev/null
+++ b/src/cgeo/geocaching/cgCompass.java
@@ -0,0 +1,322 @@
+package cgeo.geocaching;
+
+import android.util.AttributeSet;
+import android.view.View;
+import android.content.Context;
+import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.Canvas;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+public class cgCompass extends View {
+
+ private changeThread watchdog = null;
+ private boolean wantStop = false;
+ private boolean lock = false;
+ private boolean drawing = false;
+ private Context context = null;
+ private Bitmap compassUnderlay = null;
+ private Bitmap compassRose = null;
+ private Bitmap compassArrow = null;
+ private Bitmap compassOverlay = null;
+ private Double azimuth = new Double(0);
+ private Double heading = new Double(0);
+ private Double cacheHeading = new Double(0);
+ private Double northHeading = new Double(0);
+ private PaintFlagsDrawFilter setfil = null;
+ private PaintFlagsDrawFilter remfil = null;
+ private int compassUnderlayWidth = 0;
+ private int compassUnderlayHeight = 0;
+ private int compassRoseWidth = 0;
+ private int compassRoseHeight = 0;
+ private int compassArrowWidth = 0;
+ private int compassArrowHeight = 0;
+ private int compassOverlayWidth = 0;
+ private int compassOverlayHeight = 0;
+ private Handler changeHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message message) {
+ try {
+ invalidate();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCompass.changeHandler: " + e.toString());
+ }
+ }
+ };
+
+ public cgCompass(Context contextIn) {
+ super(contextIn);
+ context = contextIn;
+ }
+
+ public cgCompass(Context contextIn, AttributeSet attrs) {
+ super(contextIn, attrs);
+ context = contextIn;
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ compassUnderlay = BitmapFactory.decodeResource(context.getResources(), R.drawable.compass_underlay);
+ compassRose = BitmapFactory.decodeResource(context.getResources(), R.drawable.compass_rose);
+ compassArrow = BitmapFactory.decodeResource(context.getResources(), R.drawable.compass_arrow);
+ compassOverlay = BitmapFactory.decodeResource(context.getResources(), R.drawable.compass_overlay);
+
+ compassUnderlayWidth = compassUnderlay.getWidth();
+ compassUnderlayHeight = compassUnderlay.getWidth();
+ compassRoseWidth = compassRose.getWidth();
+ compassRoseHeight = compassRose.getWidth();
+ compassArrowWidth = compassArrow.getWidth();
+ compassArrowHeight = compassArrow.getWidth();
+ compassOverlayWidth = compassOverlay.getWidth();
+ compassOverlayHeight = compassOverlay.getWidth();
+
+ setfil = new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG);
+ remfil = new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0);
+
+ wantStop = false;
+
+ watchdog = new changeThread(changeHandler);
+ watchdog.start();
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ wantStop = true;
+
+ if (compassUnderlay != null) {
+ compassUnderlay.recycle();
+ }
+
+ if (compassRose != null) {
+ compassRose.recycle();
+ }
+
+ if (compassArrow != null) {
+ compassArrow.recycle();
+ }
+
+ if (compassOverlay != null) {
+ compassOverlay.recycle();
+ }
+ }
+
+ protected void updateNorth(Double northHeadingIn, Double cacheHeadingIn) {
+ northHeading = northHeadingIn;
+ cacheHeading = cacheHeadingIn;
+ }
+
+ private class changeThread extends Thread {
+
+ Handler handler = null;
+
+ public changeThread(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ while (wantStop == false) {
+ try {
+ sleep(50);
+ } catch (Exception e) {
+ // nothing
+ }
+
+ if (Math.abs(azimuth - northHeading) < 2 && Math.abs(heading - cacheHeading) < 2) {
+ continue;
+ }
+
+ lock = true;
+
+ Double diff = new Double(0);
+ Double diffAbs = new Double(0);
+ Double tempAzimuth = new Double(0);
+ Double tempHeading = new Double(0);
+
+ Double actualAzimuth = azimuth;
+ Double actualHeading = heading;
+
+ diff = northHeading - actualAzimuth;
+ diffAbs = Math.abs(northHeading - actualAzimuth);
+ if (diff < 0) {
+ diff = diff + 360;
+ } else if (diff >= 360) {
+ diff = diff - 360;
+ }
+
+ if (diff > 0 && diff <= 180) {
+ if (diffAbs > 5) {
+ tempAzimuth = actualAzimuth + 2;
+ } else if (diffAbs > 1) {
+ tempAzimuth = actualAzimuth + 1;
+ } else {
+ tempAzimuth = actualAzimuth;
+ }
+ } else if (diff > 180 && diff < 360) {
+ if (diffAbs > 5) {
+ tempAzimuth = actualAzimuth - 2;
+ } else if (diffAbs > 1) {
+ tempAzimuth = actualAzimuth - 1;
+ } else {
+ tempAzimuth = actualAzimuth;
+ }
+ } else {
+ tempAzimuth = actualAzimuth;
+ }
+
+ diff = cacheHeading - actualHeading;
+ diffAbs = Math.abs(cacheHeading - actualHeading);
+ if (diff < 0) {
+ diff = diff + 360;
+ } else if (diff >= 360) {
+ diff = diff - 360;
+ }
+
+ if (diff > 0 && diff <= 180) {
+ if (diffAbs > 5) {
+ tempHeading = actualHeading + 2;
+ } else if (diffAbs > 1) {
+ tempHeading = actualHeading + 1;
+ } else {
+ tempHeading = actualHeading;
+ }
+ } else if (diff > 180 && diff < 360) {
+ if (diffAbs > 5) {
+ tempHeading = actualHeading - 2;
+ } else if (diffAbs > 1) {
+ tempHeading = actualHeading - 1;
+ } else {
+ tempHeading = actualHeading;
+ }
+ } else {
+ tempHeading = actualHeading;
+ }
+
+ if (tempAzimuth >= 360) {
+ tempAzimuth = tempAzimuth - 360;
+ } else if (tempAzimuth < 0) {
+ tempAzimuth = tempAzimuth + 360;
+ }
+
+ if (tempHeading >= 360) {
+ tempHeading = tempHeading - 360;
+ } else if (tempHeading < 0) {
+ tempHeading = tempHeading + 360;
+ }
+
+ azimuth = tempAzimuth;
+ heading = tempHeading;
+
+ lock = false;
+
+ changeHandler.sendMessage(new Message());
+ }
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (lock == true) {
+ return;
+ }
+ if (drawing == true) {
+ return;
+ }
+
+ Double azimuthTemp = azimuth;
+ Double azimuthRelative = azimuthTemp - heading;
+ if (azimuthRelative < 0) {
+ azimuthRelative = azimuthRelative + 360;
+ } else if (azimuthRelative >= 360) {
+ azimuthRelative = azimuthRelative - 360;
+ }
+
+ // compass margins
+ int canvasCenterX = (compassRoseWidth / 2) + ((getWidth() - compassRoseWidth) / 2);
+ int canvasCenterY = (compassRoseHeight / 2) + ((getHeight() - compassRoseHeight) / 2);
+
+ int marginLeftTemp = 0;
+ int marginTopTemp = 0;
+
+ drawing = true;
+ super.onDraw(canvas);
+
+ canvas.save();
+ canvas.setDrawFilter(setfil);
+
+ marginLeftTemp = (getWidth() - compassUnderlayWidth) / 2;
+ marginTopTemp = (getHeight() - compassUnderlayHeight) / 2;
+
+ canvas.drawBitmap(compassUnderlay, marginLeftTemp, marginTopTemp, null);
+
+ marginLeftTemp = (getWidth() - compassRoseWidth) / 2;
+ marginTopTemp = (getHeight() - compassRoseHeight) / 2;
+
+ canvas.rotate(new Float(-(azimuthTemp)), canvasCenterX, canvasCenterY);
+ canvas.drawBitmap(compassRose, marginLeftTemp, marginTopTemp, null);
+ canvas.rotate(new Float(azimuthTemp), canvasCenterX, canvasCenterY);
+
+ marginLeftTemp = (getWidth() - compassArrowWidth) / 2;
+ marginTopTemp = (getHeight() - compassArrowHeight) / 2;
+
+ canvas.rotate(new Float(-(azimuthRelative)), canvasCenterX, canvasCenterY);
+ canvas.drawBitmap(compassArrow, marginLeftTemp, marginTopTemp, null);
+ canvas.rotate(new Float(azimuthRelative), canvasCenterX, canvasCenterY);
+
+ marginLeftTemp = (getWidth() - compassOverlayWidth) / 2;
+ marginTopTemp = (getHeight() - compassOverlayHeight) / 2;
+
+ canvas.drawBitmap(compassOverlay, marginLeftTemp, marginTopTemp, null);
+
+ canvas.setDrawFilter(remfil);
+ canvas.restore();
+
+ drawing = false;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
+ }
+
+ private int measureWidth(int measureSpec) {
+ int result = 0;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ if (specMode == MeasureSpec.EXACTLY) {
+ result = specSize;
+ } else {
+ result = compassArrow.getWidth() + getPaddingLeft() + getPaddingRight();
+
+ if (specMode == MeasureSpec.AT_MOST) {
+ result = Math.min(result, specSize);
+ }
+ }
+
+ return result;
+ }
+
+ private int measureHeight(int measureSpec) {
+ int result = 0;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ if (specMode == MeasureSpec.EXACTLY) {
+ result = specSize;
+ } else {
+ result = compassArrow.getHeight() + getPaddingTop() + getPaddingBottom();
+
+ if (specMode == MeasureSpec.AT_MOST) {
+ result = Math.min(result, specSize);
+ }
+ }
+
+ return result;
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgCompassMini.java b/src/cgeo/geocaching/cgCompassMini.java
new file mode 100644
index 0000000..cc815bf
--- /dev/null
+++ b/src/cgeo/geocaching/cgCompassMini.java
@@ -0,0 +1,176 @@
+package cgeo.geocaching;
+
+import android.util.AttributeSet;
+import android.view.View;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.Canvas;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+public class cgCompassMini extends View {
+ private int arrowSkin = R.drawable.compass_arrow_mini_white;
+ private Boolean lock = false;
+ private Context context = null;
+ private cgBase base = null;
+ private Double cacheLat = null;
+ private Double cacheLon = null;
+ private Bitmap compassArrow = null;
+ private Double azimuth = new Double(0);
+ private Double heading = new Double(0);
+ private PaintFlagsDrawFilter setfil = null;
+ private PaintFlagsDrawFilter remfil = null;
+
+ public cgCompassMini(Context contextIn) {
+ super(contextIn);
+ context = contextIn;
+ }
+
+ public cgCompassMini(Context contextIn, AttributeSet attrs) {
+ super(contextIn, attrs);
+ context = contextIn;
+
+ TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.cgCompassMini);
+ int usedSkin = attributes.getInt(R.styleable.cgCompassMini_skin, 0);
+ if (usedSkin == 1) arrowSkin = R.drawable.compass_arrow_mini_black;
+ else arrowSkin = R.drawable.compass_arrow_mini_white;
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ compassArrow = BitmapFactory.decodeResource(context.getResources(), arrowSkin);
+
+ setfil = new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG);
+ remfil = new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0);
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ if (compassArrow != null) {
+ compassArrow.recycle();
+ compassArrow = null;
+ }
+ }
+
+ public void setContent(cgBase baseIn, Double cacheLatIn, Double cacheLonIn) {
+ base = baseIn;
+ cacheLat = cacheLatIn;
+ cacheLon = cacheLonIn;
+ }
+
+ protected void updateAzimuth(Double azimuthIn) {
+ azimuth = azimuthIn;
+
+ updateDirection();
+ }
+
+ protected void updateHeading(Double headingIn) {
+ heading = headingIn;
+
+ updateDirection();
+ }
+
+ protected void updateCoords(Double latitudeIn, Double longitudeIn) {
+ if (latitudeIn == null || longitudeIn == null || cacheLat == null || cacheLon == null) {
+ return;
+ }
+
+ heading = cgBase.getHeading(latitudeIn, longitudeIn, cacheLat, cacheLon);
+
+ updateDirection();
+ }
+
+ protected void updateDirection() {
+ if (compassArrow == null || compassArrow.isRecycled() == true) {
+ return;
+ }
+
+ // compass margins
+ int compassRoseWidth = compassArrow.getWidth();
+ int compassRoseHeight = compassArrow.getWidth();
+ int marginLeft = (getWidth() - compassRoseWidth) / 2;
+ int marginTop = (getHeight() - compassRoseHeight) / 2;
+
+ invalidate(marginLeft, marginTop, (marginLeft + compassRoseWidth), (marginTop + compassRoseHeight));
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas){
+ lock = true;
+
+ super.onDraw(canvas);
+
+ Double azimuthRelative = azimuth - heading;
+ if (azimuthRelative < 0) {
+ azimuthRelative = azimuthRelative + 360;
+ } else if (azimuthRelative >= 360) {
+ azimuthRelative = azimuthRelative - 360;
+ }
+
+ // compass margins
+ canvas.setDrawFilter(setfil);
+
+ int marginLeft = 0;
+ int marginTop = 0;
+
+ int compassArrowWidth = compassArrow.getWidth();
+ int compassArrowHeight = compassArrow.getWidth();
+
+ int canvasCenterX = (compassArrowWidth / 2) + ((getWidth() - compassArrowWidth) / 2);
+ int canvasCenterY = (compassArrowHeight / 2) + ((getHeight() - compassArrowHeight) / 2);
+
+ marginLeft = (getWidth() - compassArrowWidth) / 2;
+ marginTop = (getHeight() - compassArrowHeight) / 2;
+
+ canvas.rotate(new Float(-(azimuthRelative)), canvasCenterX, canvasCenterY);
+ canvas.drawBitmap(compassArrow, marginLeft, marginTop, null);
+ canvas.rotate(new Float(azimuthRelative), canvasCenterX, canvasCenterY);
+
+ canvas.setDrawFilter(remfil);
+
+ lock = false;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
+ }
+
+ private int measureWidth(int measureSpec) {
+ int result = 0;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ if (specMode == MeasureSpec.EXACTLY) {
+ result = specSize;
+ } else {
+ result = 21 + getPaddingLeft() + getPaddingRight();
+
+ if (specMode == MeasureSpec.AT_MOST) {
+ result = Math.min(result, specSize);
+ }
+ }
+
+ return result;
+ }
+
+ private int measureHeight(int measureSpec) {
+ int result = 0;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ if (specMode == MeasureSpec.EXACTLY) {
+ result = specSize;
+ } else {
+ result = 21 + getPaddingTop() + getPaddingBottom();
+
+ if (specMode == MeasureSpec.AT_MOST) {
+ result = Math.min(result, specSize);
+ }
+ }
+
+ return result;
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgCoord.java b/src/cgeo/geocaching/cgCoord.java
new file mode 100644
index 0000000..4e7d3b2
--- /dev/null
+++ b/src/cgeo/geocaching/cgCoord.java
@@ -0,0 +1,46 @@
+package cgeo.geocaching;
+
+public class cgCoord {
+
+ public Integer id = null;
+ public String geocode = "";
+ public String type = "cache";
+ public String typeSpec = "traditional";
+ public String name = "";
+ public boolean found = false;
+ public boolean disabled = false;
+ public Double latitude = new Double(0);
+ public Double longitude = new Double(0);
+ public Float difficulty = null;
+ public Float terrain = null;
+ public String size = null;
+
+ public cgCoord() {
+ }
+
+ public cgCoord(cgCache cache) {
+ disabled = cache.disabled;
+ found = cache.found;
+ geocode = cache.geocode;
+ latitude = cache.latitude;
+ longitude = cache.longitude;
+ name = cache.name;
+ type = "cache";
+ typeSpec = cache.type;
+ difficulty = cache.difficulty;
+ terrain = cache.terrain;
+ size = cache.size;
+ }
+
+ public cgCoord(cgWaypoint waypoint) {
+ id = waypoint.id;
+ disabled = false;
+ found = false;
+ geocode = "";
+ latitude = waypoint.latitude;
+ longitude = waypoint.longitude;
+ name = waypoint.name;
+ type = "waypoint";
+ typeSpec = waypoint.type;
+ }
+}
diff --git a/src/cgeo/geocaching/cgData.java b/src/cgeo/geocaching/cgData.java
new file mode 100644
index 0000000..0338cf7
--- /dev/null
+++ b/src/cgeo/geocaching/cgData.java
@@ -0,0 +1,3046 @@
+package cgeo.geocaching;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.util.Log;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteStatement;
+import android.os.Environment;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map.Entry;
+import java.util.Set;
+
+public class cgData {
+
+ public cgCacheWrap caches;
+ private Context context = null;
+ private String path = null;
+ private cgDbHelper dbHelper = null;
+ private SQLiteDatabase databaseRO = null;
+ private SQLiteDatabase databaseRW = null;
+ private static final int dbVersion = 51;
+ private static final String dbName = "data";
+ private static final String dbTableCaches = "cg_caches";
+ private static final String dbTableLists = "cg_lists";
+ private static final String dbTableAttributes = "cg_attributes";
+ private static final String dbTableWaypoints = "cg_waypoints";
+ private static final String dbTableSpoilers = "cg_spoilers";
+ private static final String dbTableLogs = "cg_logs";
+ private static final String dbTableLogCount = "cg_logCount";
+ private static final String dbTableLogsOffline = "cg_logs_offline";
+ private static final String dbTableTrackables = "cg_trackables";
+ private static final String dbCreateCaches = ""
+ + "create table " + dbTableCaches + " ("
+ + "_id integer primary key autoincrement, "
+ + "updated long not null, "
+ + "detailed integer not null default 0, "
+ + "detailedupdate long, "
+ + "visiteddate long, "
+ + "geocode text unique not null, "
+ + "reason integer not null default 0, " // cached, favourite...
+ + "cacheid text, "
+ + "guid text, "
+ + "type text, "
+ + "name text, "
+ + "own integer not null default 0, "
+ + "owner text, "
+ + "owner_real text, "
+ + "hidden long, "
+ + "hint text, "
+ + "size text, "
+ + "difficulty float, "
+ + "terrain float, "
+ + "latlon text, "
+ + "latitude_string text, "
+ + "longitude_string text, "
+ + "location text, "
+ + "direction double, "
+ + "distance double, "
+ + "latitude double, "
+ + "longitude double, "
+ + "reliable_latlon integer, "
+ + "elevation double, "
+ + "shortdesc text, "
+ + "description text, "
+ + "favourite_cnt integer, "
+ + "rating float, "
+ + "votes integer, "
+ + "myvote float, "
+ + "disabled integer not null default 0, "
+ + "archived integer not null default 0, "
+ + "members integer not null default 0, "
+ + "found integer not null default 0, "
+ + "favourite integer not null default 0, "
+ + "inventorycoins integer default 0, "
+ + "inventorytags integer default 0, "
+ + "inventoryunknown integer default 0 "
+ + "); ";
+ private static final String dbCreateLists = ""
+ + "create table " + dbTableLists + " ("
+ + "_id integer primary key autoincrement, "
+ + "title text not null, "
+ + "updated long not null, "
+ + "latitude double, "
+ + "longitude double "
+ + "); ";
+ private static final String dbCreateAttributes = ""
+ + "create table " + dbTableAttributes + " ("
+ + "_id integer primary key autoincrement, "
+ + "geocode text not null, "
+ + "updated long not null, " // date of save
+ + "attribute text "
+ + "); ";
+ private static final String dbCreateWaypoints = ""
+ + "create table " + dbTableWaypoints + " ("
+ + "_id integer primary key autoincrement, "
+ + "geocode text not null, "
+ + "updated long not null, " // date of save
+ + "type text not null default 'waypoint', "
+ + "prefix text, "
+ + "lookup text, "
+ + "name text, "
+ + "latlon text, "
+ + "latitude_string text, "
+ + "longitude_string text, "
+ + "latitude double, "
+ + "longitude double, "
+ + "note text "
+ + "); ";
+ private static final String dbCreateSpoilers = ""
+ + "create table " + dbTableSpoilers + " ("
+ + "_id integer primary key autoincrement, "
+ + "geocode text not null, "
+ + "updated long not null, " // date of save
+ + "url text, "
+ + "title text, "
+ + "description text "
+ + "); ";
+ private static final String dbCreateLogs = ""
+ + "create table " + dbTableLogs + " ("
+ + "_id integer primary key autoincrement, "
+ + "geocode text not null, "
+ + "updated long not null, " // date of save
+ + "type integer not null default 4, "
+ + "author text, "
+ + "log text, "
+ + "date long, "
+ + "found integer not null default 0 "
+ + "); ";
+ private static final String dbCreateLogCount = ""
+ + "create table " + dbTableLogCount + " ("
+ + "_id integer primary key autoincrement, "
+ + "geocode text not null, "
+ + "updated long not null, " // date of save
+ + "type integer not null default 4, "
+ + "count integer not null default 0 "
+ + "); ";
+ private static final String dbCreateLogsOffline = ""
+ + "create table " + dbTableLogsOffline + " ("
+ + "_id integer primary key autoincrement, "
+ + "geocode text not null, "
+ + "updated long not null, " // date of save
+ + "type integer not null default 4, "
+ + "log text, "
+ + "date long "
+ + "); ";
+ private static final String dbCreateTrackables = ""
+ + "create table " + dbTableTrackables + " ("
+ + "_id integer primary key autoincrement, "
+ + "updated long not null, " // date of save
+ + "tbcode text not null, "
+ + "guid text, "
+ + "title text, "
+ + "owner text, "
+ + "released long, "
+ + "goal text, "
+ + "description text, "
+ + "geocode text "
+ + "); ";
+ public boolean initialized = false;
+
+ public cgData(Context contextIn) {
+ context = contextIn;
+ }
+
+ public void init() {
+ if (databaseRW == null || databaseRW.isOpen() == false) {
+ try {
+ if (dbHelper == null) {
+ dbHelper = new cgDbHelper(context);
+ }
+ databaseRW = dbHelper.getWritableDatabase();
+
+ if (databaseRW != null && databaseRW.isOpen()) {
+ Log.i(cgSettings.tag, "Connection to RW database established.");
+ } else {
+ Log.e(cgSettings.tag, "Failed to open connection to RW database.");
+ }
+
+ if (databaseRW.inTransaction() == true) {
+ databaseRW.endTransaction();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.openDb.RW: " + e.toString());
+ }
+ }
+
+ if (databaseRO == null || databaseRO.isOpen() == false) {
+ try {
+ if (dbHelper == null) {
+ dbHelper = new cgDbHelper(context);
+ }
+ databaseRO = dbHelper.getReadableDatabase();
+
+ if (databaseRO.needUpgrade(dbVersion) == true) {
+ databaseRO = null;
+ }
+
+ if (databaseRO != null && databaseRO.isOpen()) {
+ Log.i(cgSettings.tag, "Connection to RO database established.");
+ } else {
+ Log.e(cgSettings.tag, "Failed to open connection to RO database.");
+ }
+
+ if (databaseRO.inTransaction() == true) {
+ databaseRO.endTransaction();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.openDb.RO: " + e.toString());
+ }
+ }
+
+ initialized = true;
+ }
+
+ public void closeDb() {
+ if (databaseRO != null) {
+ path = databaseRO.getPath();
+
+ if (databaseRO.inTransaction() == true) {
+ databaseRO.endTransaction();
+ }
+
+ databaseRO.close();
+ databaseRO = null;
+ SQLiteDatabase.releaseMemory();
+
+ Log.d(cgSettings.tag, "Closing RO database");
+ }
+
+ if (databaseRW != null) {
+ path = databaseRW.getPath();
+
+ if (databaseRW.inTransaction() == true) {
+ databaseRW.endTransaction();
+ }
+
+ databaseRW.close();
+ databaseRW = null;
+ SQLiteDatabase.releaseMemory();
+
+ Log.d(cgSettings.tag, "Closing RW database");
+ }
+
+ if (dbHelper != null) {
+ dbHelper.close();
+ dbHelper = null;
+ }
+ }
+
+ public String backupDatabase() {
+ if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) == false) {
+ Log.w(cgSettings.tag, "Database wasn't backed up: no external memory");
+
+ return null;
+ }
+
+ closeDb();
+
+ try {
+ final String directoryImg = cgSettings.cache;
+ final String directoryTarget = Environment.getExternalStorageDirectory() + "/" + directoryImg + "/";
+ final String fileTarget = directoryTarget + "cgeo.sqlite";
+ final String fileSource = path;
+
+ File directoryTargetFile = new File(directoryTarget);
+ if (directoryTargetFile.exists() == false) {
+ directoryTargetFile.mkdir();
+ }
+
+ InputStream input = new FileInputStream(fileSource);
+ OutputStream output = new FileOutputStream(fileTarget);
+
+ byte[] buffer = new byte[1024];
+ int length;
+ while ((length = input.read(buffer)) > 0) {
+ output.write(buffer, 0, length);
+ }
+
+ output.flush();
+ output.close();
+ input.close();
+
+ Log.i(cgSettings.tag, "Database was copied to " + fileTarget);
+
+ init();
+
+ return fileTarget;
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Database wasn't backed up: " + e.toString());
+ }
+
+ init();
+
+ return null;
+ }
+
+ public File isRestoreFile() {
+ final String directoryImg = cgSettings.cache;
+ final String fileSource = Environment.getExternalStorageDirectory() + "/" + directoryImg + "/cgeo.sqlite";
+
+ File fileSourceFile = new File(fileSource);
+ if (fileSourceFile.exists()) {
+ return fileSourceFile;
+ } else {
+ return null;
+ }
+ }
+
+ public boolean restoreDatabase() {
+ if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) == false) {
+ Log.w(cgSettings.tag, "Database wasn't restored: no external memory");
+
+ return false;
+ }
+
+ closeDb();
+
+ try {
+ final String directoryImg = cgSettings.cache;
+ final String fileSource = Environment.getExternalStorageDirectory() + "/" + directoryImg + "/cgeo.sqlite";
+ final String fileTarget = path;
+
+ File fileSourceFile = new File(fileSource);
+ if (fileSourceFile.exists() == false) {
+ Log.w(cgSettings.tag, "Database backup was not found");
+
+ init();
+
+ return false;
+ }
+
+ InputStream input = new FileInputStream(fileSource);
+ OutputStream output = new FileOutputStream(fileTarget);
+
+ byte[] buffer = new byte[1024];
+ int length;
+ while ((length = input.read(buffer)) > 0) {
+ output.write(buffer, 0, length);
+ }
+
+ output.flush();
+ output.close();
+ input.close();
+
+ Log.i(cgSettings.tag, "Database was restored");
+
+ init();
+
+ return true;
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Database wasn't restored: " + e.toString());
+ }
+
+ init();
+
+ return false;
+ }
+
+ private class cgDbHelper extends SQLiteOpenHelper {
+
+ cgDbHelper(Context context) {
+ super(context, dbName, null, dbVersion);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL(dbCreateCaches);
+ db.execSQL(dbCreateLists);
+ db.execSQL(dbCreateAttributes);
+ db.execSQL(dbCreateWaypoints);
+ db.execSQL(dbCreateSpoilers);
+ db.execSQL(dbCreateLogs);
+ db.execSQL(dbCreateLogCount);
+ db.execSQL(dbCreateLogsOffline);
+ db.execSQL(dbCreateTrackables);
+
+ db.execSQL("create index if not exists in_a on " + dbTableCaches + " (geocode)");
+ db.execSQL("create index if not exists in_b on " + dbTableCaches + " (guid)");
+ db.execSQL("create index if not exists in_c on " + dbTableCaches + " (reason)");
+ db.execSQL("create index if not exists in_d on " + dbTableCaches + " (detailed)");
+ db.execSQL("create index if not exists in_e on " + dbTableCaches + " (type)");
+ db.execSQL("create index if not exists in_f on " + dbTableCaches + " (visiteddate, detailedupdate)");
+ db.execSQL("create index if not exists in_a on " + dbTableAttributes + " (geocode)");
+ db.execSQL("create index if not exists in_a on " + dbTableWaypoints + " (geocode)");
+ db.execSQL("create index if not exists in_b on " + dbTableWaypoints + " (geocode, type)");
+ db.execSQL("create index if not exists in_a on " + dbTableSpoilers + " (geocode)");
+ db.execSQL("create index if not exists in_a on " + dbTableLogs + " (geocode)");
+ db.execSQL("create index if not exists in_a on " + dbTableLogCount + " (geocode)");
+ db.execSQL("create index if not exists in_a on " + dbTableLogsOffline + " (geocode)");
+ db.execSQL("create index if not exists in_a on " + dbTableTrackables + " (geocode)");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ Log.i(cgSettings.tag, "Upgrade database from ver. " + oldVersion + " to ver. " + newVersion + ": start");
+
+ try {
+ if (db.isReadOnly() == true) {
+ return;
+ }
+
+ db.beginTransaction();
+
+ if (oldVersion <= 0) { // new table
+ dropDatabase(db);
+ onCreate(db);
+
+ Log.i(cgSettings.tag, "Database structure created.");
+ }
+
+ if (oldVersion > 0) {
+ db.execSQL("delete from " + dbTableCaches + " where reason = 0");
+
+ if (oldVersion < 34) { // upgrade to 34
+ try {
+ db.execSQL("create index if not exists in_a on " + dbTableCaches + " (geocode)");
+ db.execSQL("create index if not exists in_b on " + dbTableCaches + " (guid)");
+ db.execSQL("create index if not exists in_c on " + dbTableCaches + " (reason)");
+ db.execSQL("create index if not exists in_d on " + dbTableCaches + " (detailed)");
+ db.execSQL("create index if not exists in_e on " + dbTableCaches + " (type)");
+ db.execSQL("create index if not exists in_a on " + dbTableAttributes + " (geocode)");
+ db.execSQL("create index if not exists in_a on " + dbTableWaypoints + " (geocode)");
+ db.execSQL("create index if not exists in_b on " + dbTableWaypoints + " (geocode, type)");
+ db.execSQL("create index if not exists in_a on " + dbTableSpoilers + " (geocode)");
+ db.execSQL("create index if not exists in_a on " + dbTableLogs + " (geocode)");
+ db.execSQL("create index if not exists in_a on " + dbTableTrackables + " (geocode)");
+
+ Log.i(cgSettings.tag, "Indexes added.");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 34: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 37) { // upgrade to 37
+ try {
+ db.execSQL("alter table " + dbTableCaches + " add column direction text");
+ db.execSQL("alter table " + dbTableCaches + " add column distance double");
+
+ Log.i(cgSettings.tag, "Columns direction and distance added to " + dbTableCaches + ".");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 37: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 38) { // upgrade to 38
+ try {
+ db.execSQL("drop table " + dbTableLogs);
+ db.execSQL(dbCreateLogs);
+
+ Log.i(cgSettings.tag, "Changed type column in " + dbTableLogs + " to integer.");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 38: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 39) { // upgrade to 39
+ try {
+ db.execSQL(dbCreateLists);
+
+ Log.i(cgSettings.tag, "Created lists table.");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 39: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 40) { // upgrade to 40
+ try {
+ db.execSQL("drop table " + dbTableTrackables);
+ db.execSQL(dbCreateTrackables);
+
+ Log.i(cgSettings.tag, "Changed type of geocode column in trackables table.");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 40: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 41) { // upgrade to 41
+ try {
+ db.execSQL("alter table " + dbTableCaches + " add column rating float");
+ db.execSQL("alter table " + dbTableCaches + " add column votes integer");
+ db.execSQL("alter table " + dbTableCaches + " add column vote integer");
+
+ Log.i(cgSettings.tag, "Added columns for GCvote.");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 41: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 42) { // upgrade to 42
+ try {
+ db.execSQL(dbCreateLogsOffline);
+
+ Log.i(cgSettings.tag, "Added table for offline logs");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 42: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 43) { // upgrade to 43
+ try {
+ final String dbCreateCachesTemp = ""
+ + "create temporary table " + dbTableCaches + "_temp ("
+ + "_id integer primary key autoincrement, "
+ + "updated long not null, "
+ + "detailed integer not null default 0, "
+ + "detailedupdate long, "
+ + "geocode text unique not null, "
+ + "reason integer not null default 0, " // cached, favourite...
+ + "cacheid text, "
+ + "guid text, "
+ + "type text, "
+ + "name text, "
+ + "owner text, "
+ + "hidden long, "
+ + "hint text, "
+ + "size text, "
+ + "difficulty float, "
+ + "terrain float, "
+ + "latlon text, "
+ + "latitude_string text, "
+ + "longitude_string text, "
+ + "location text, "
+ + "distance double, "
+ + "latitude double, "
+ + "longitude double, "
+ + "shortdesc text, "
+ + "description text, "
+ + "rating float, "
+ + "votes integer, "
+ + "vote integer, "
+ + "disabled integer not null default 0, "
+ + "archived integer not null default 0, "
+ + "members integer not null default 0, "
+ + "found integer not null default 0, "
+ + "favourite integer not null default 0, "
+ + "inventorycoins integer default 0, "
+ + "inventorytags integer default 0, "
+ + "inventoryunknown integer default 0 "
+ + "); ";
+ final String dbCreateCachesNew = ""
+ + "create table " + dbTableCaches + " ("
+ + "_id integer primary key autoincrement, "
+ + "updated long not null, "
+ + "detailed integer not null default 0, "
+ + "detailedupdate long, "
+ + "geocode text unique not null, "
+ + "reason integer not null default 0, " // cached, favourite...
+ + "cacheid text, "
+ + "guid text, "
+ + "type text, "
+ + "name text, "
+ + "owner text, "
+ + "hidden long, "
+ + "hint text, "
+ + "size text, "
+ + "difficulty float, "
+ + "terrain float, "
+ + "latlon text, "
+ + "latitude_string text, "
+ + "longitude_string text, "
+ + "location text, "
+ + "direction double, "
+ + "distance double, "
+ + "latitude double, "
+ + "longitude double, "
+ + "shortdesc text, "
+ + "description text, "
+ + "rating float, "
+ + "votes integer, "
+ + "vote integer, "
+ + "disabled integer not null default 0, "
+ + "archived integer not null default 0, "
+ + "members integer not null default 0, "
+ + "found integer not null default 0, "
+ + "favourite integer not null default 0, "
+ + "inventorycoins integer default 0, "
+ + "inventorytags integer default 0, "
+ + "inventoryunknown integer default 0 "
+ + "); ";
+
+ db.beginTransaction();
+ db.execSQL(dbCreateCachesTemp);
+ db.execSQL("insert into " + dbTableCaches + "_temp select _id, updated, detailed, detailedupdate, geocode, reason, cacheid, guid, type, name, owner, hidden, hint, size, difficulty, terrain, latlon, latitude_string, longitude_string, location, distance, latitude, longitude, shortdesc, description, rating, votes, vote, disabled, archived, members, found, favourite, inventorycoins, inventorytags, inventoryunknown from " + dbTableCaches);
+ db.execSQL("drop table " + dbTableCaches);
+ db.execSQL(dbCreateCachesNew);
+ db.execSQL("insert into " + dbTableCaches + " select _id, updated, detailed, detailedupdate, geocode, reason, cacheid, guid, type, name, owner, hidden, hint, size, difficulty, terrain, latlon, latitude_string, longitude_string, location, null, distance, latitude, longitude, shortdesc, description, rating, votes, vote, disabled, archived, members, found, favourite, inventorycoins, inventorytags, inventoryunknown from " + dbTableCaches + "_temp");
+ db.execSQL("drop table " + dbTableCaches + "_temp");
+ db.setTransactionSuccessful();
+
+ Log.i(cgSettings.tag, "Changed direction column");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 43: " + e.toString());
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ if (oldVersion < 44) { // upgrade to 44
+ try {
+ db.execSQL("alter table " + dbTableCaches + " add column favourite_cnt integer");
+
+ Log.i(cgSettings.tag, "Column favourite_cnt added to " + dbTableCaches + ".");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 44: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 45) { // upgrade to 45
+ try {
+ db.execSQL("alter table " + dbTableCaches + " add column owner_real text");
+
+ Log.i(cgSettings.tag, "Column owner_real added to " + dbTableCaches + ".");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 45: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 46) { // upgrade to 46
+ try {
+ db.execSQL("alter table " + dbTableCaches + " add column visiteddate long");
+ db.execSQL("create index if not exists in_f on " + dbTableCaches + " (visiteddate, detailedupdate)");
+
+ Log.i(cgSettings.tag, "Added column for date of visit.");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 46: " + e.toString());
+ }
+ }
+ if (oldVersion < 47) { // upgrade to 47
+ try {
+ db.execSQL("alter table " + dbTableCaches + " add column own integer not null default 0");
+
+ Log.i(cgSettings.tag, "Added column own.");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 47: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 48) { // upgrade to 48
+ try {
+ db.execSQL("alter table " + dbTableCaches + " add column elevation double");
+
+ Log.i(cgSettings.tag, "Column elevation added to " + dbTableCaches + ".");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 48: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 49) { // upgrade to 49
+ try {
+ db.execSQL(dbCreateLogCount);
+
+ Log.i(cgSettings.tag, "Created table " + dbTableLogCount + ".");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 49: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 50) { // upgrade to 50
+ try {
+ db.execSQL("alter table " + dbTableCaches + " add column myvote float");
+
+ Log.i(cgSettings.tag, "Added float column for votes to " + dbTableCaches + ".");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 50: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 51) { // upgrade to 51
+ try {
+ db.execSQL("alter table " + dbTableCaches + " add column reliable_latlon integer");
+
+ Log.i(cgSettings.tag, "Column reliable_latlon added to " + dbTableCaches + ".");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 51: " + e.toString());
+ }
+ }
+ }
+
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+
+ Log.i(cgSettings.tag, "Upgrade database from ver. " + oldVersion + " to ver. " + newVersion + ": completed");
+ }
+ }
+
+ private static void dropDatabase(SQLiteDatabase db) {
+ db.execSQL("drop table if exists " + dbTableCaches);
+ db.execSQL("drop table if exists " + dbTableAttributes);
+ db.execSQL("drop table if exists " + dbTableWaypoints);
+ db.execSQL("drop table if exists " + dbTableSpoilers);
+ db.execSQL("drop table if exists " + dbTableLogs);
+ db.execSQL("drop table if exists " + dbTableLogCount);
+ db.execSQL("drop table if exists " + dbTableLogsOffline);
+ db.execSQL("drop table if exists " + dbTableTrackables);
+ }
+
+ public String[] allDetailedThere() {
+ init();
+
+ Cursor cursor = null;
+ ArrayList<String> thereA = new ArrayList<String>();
+
+ try {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "geocode"},
+ "(detailed = 1 and detailedupdate > " + (System.currentTimeMillis() - (3 * 24 * 60 * 60 * 1000)) + ") or reason > 0",
+ null,
+ null,
+ null,
+ "detailedupdate desc",
+ "100");
+
+ if (cursor != null) {
+ int index = 0;
+ String geocode = null;
+
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ index = cursor.getColumnIndex("geocode");
+ geocode = (String) cursor.getString(index);
+
+ thereA.add(geocode);
+ } while (cursor.moveToNext());
+ } else {
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return null;
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.allDetailedThere: " + e.toString());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return thereA.toArray(new String[thereA.size()]);
+ }
+
+ public boolean isThere(String geocode, String guid, boolean detailed, boolean checkTime) {
+ init();
+
+ Cursor cursor = null;
+
+ int cnt = 0;
+ long dataUpdated = 0;
+ long dataDetailedUpdate = 0;
+ int dataDetailed = 0;
+
+ try {
+ if (geocode != null && geocode.length() > 0) {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "detailed", "detailedupdate", "updated"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "1");
+ } else if (guid != null && guid.length() > 0) {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "detailed", "detailedupdate", "updated"},
+ "guid = \"" + guid + "\"",
+ null,
+ null,
+ null,
+ null,
+ "1");
+ } else {
+ return false;
+ }
+
+ if (cursor != null) {
+ int index = 0;
+ cnt = cursor.getCount();
+
+ if (cnt > 0) {
+ cursor.moveToFirst();
+
+ index = cursor.getColumnIndex("updated");
+ dataUpdated = (long) cursor.getLong(index);
+ index = cursor.getColumnIndex("detailedupdate");
+ dataDetailedUpdate = (long) cursor.getLong(index);
+ index = cursor.getColumnIndex("detailed");
+ dataDetailed = (int) cursor.getInt(index);
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.isThere: " + e.toString());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ if (cnt > 0) {
+ if (detailed == true && dataDetailed == 0) {
+ // we want details, but these are not stored
+ return false;
+ }
+
+ if (checkTime == true && detailed == true && dataDetailedUpdate < (System.currentTimeMillis() - (3 * 24 * 60 * 60 * 1000))) {
+ // we want to check time for detailed cache, but data are older than 3 hours
+ return false;
+ }
+
+ if (checkTime == true && detailed == false && dataUpdated < (System.currentTimeMillis() - (3 * 24 * 60 * 60 * 1000))) {
+ // we want to check time for short cache, but data are older than 3 hours
+ return false;
+ }
+
+ // we have some cache
+ return true;
+ }
+
+ // we have no such cache stored in cache
+ return false;
+ }
+
+ public boolean isOffline(String geocode, String guid) {
+ init();
+
+ Cursor cursor = null;
+ long reason = 0;
+
+ try {
+ if (geocode != null && geocode.length() > 0) {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"reason"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "1");
+ } else if (guid != null && guid.length() > 0) {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"reason"},
+ "guid = \"" + guid + "\"",
+ null,
+ null,
+ null,
+ null,
+ "1");
+ } else {
+ return false;
+ }
+
+ if (cursor != null) {
+ final int cnt = cursor.getCount();
+ int index = 0;
+
+ if (cnt > 0) {
+ cursor.moveToFirst();
+
+ index = cursor.getColumnIndex("reason");
+ reason = (long) cursor.getLong(index);
+ }
+
+ cursor.close();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.isOffline: " + e.toString());
+ }
+
+ if (reason >= 1) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public boolean isReliableLatLon(String geocode, String guid) {
+ init();
+
+ Cursor cursor = null;
+ int rel = 0;
+
+ try {
+ if (geocode != null && geocode.length() > 0) {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"reliable_latlon"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "1");
+ } else if (guid != null && guid.length() > 0) {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"reliable_latlon"},
+ "guid = \"" + guid + "\"",
+ null,
+ null,
+ null,
+ null,
+ "1");
+ } else {
+ return false;
+ }
+
+ if (cursor != null) {
+ final int cnt = cursor.getCount();
+ int index = 0;
+
+ if (cnt > 0) {
+ cursor.moveToFirst();
+
+ index = cursor.getColumnIndex("reliable_latlon");
+ rel = (int) cursor.getInt(index);
+ }
+
+ cursor.close();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.isOffline: " + e.toString());
+ }
+
+ if (rel >= 1) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public String getGeocodeForGuid(String guid) {
+ init();
+
+ if (guid == null || guid.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ String geocode = null;
+
+ try {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "geocode"},
+ "guid = \"" + guid + "\"",
+ null,
+ null,
+ null,
+ null,
+ "1");
+
+ if (cursor != null) {
+ int index = 0;
+
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ index = cursor.getColumnIndex("geocode");
+ geocode = (String) cursor.getString(index);
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.getGeocodeForGuid: " + e.toString());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return geocode;
+ }
+
+ public String getCacheidForGeocode(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ String cacheid = null;
+
+ try {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "cacheid"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "1");
+
+ if (cursor != null) {
+ int index = 0;
+
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ index = cursor.getColumnIndex("cacheid");
+ cacheid = (String) cursor.getString(index);
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.getCacheidForGeocode: " + e.toString());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return cacheid;
+ }
+
+ public boolean saveCache(cgCache cache) {
+ //LeeB - writing to the DB is slow
+ if (cache == null) {
+ return false;
+ }
+
+ ContentValues values = new ContentValues();
+
+ if (cache.updated == null) {
+ values.put("updated", System.currentTimeMillis());
+ } else {
+ values.put("updated", cache.updated);
+ }
+ values.put("reason", cache.reason);
+ if (cache.detailed == true) {
+ values.put("detailed", 1);
+ } else {
+ values.put("detailed", 0);
+ }
+ values.put("detailedupdate", cache.detailedUpdate);
+ values.put("visiteddate", cache.visitedDate);
+ values.put("geocode", cache.geocode);
+ values.put("cacheid", cache.cacheid);
+ values.put("guid", cache.guid);
+ values.put("type", cache.type);
+ values.put("name", cache.name);
+ if (cache.own == true) {
+ values.put("own", 1);
+ } else {
+ values.put("own", 0);
+ }
+ values.put("owner", cache.owner);
+ values.put("owner_real", cache.ownerReal);
+ if (cache.hidden == null) {
+ values.put("hidden", 0);
+ } else {
+ values.put("hidden", cache.hidden.getTime());
+ }
+ values.put("hint", cache.hint);
+ values.put("size", cache.size);
+ values.put("difficulty", cache.difficulty);
+ values.put("terrain", cache.terrain);
+ values.put("latlon", cache.latlon);
+ values.put("latitude_string", cache.latitudeString);
+ values.put("longitude_string", cache.longitudeString);
+ values.put("location", cache.location);
+ values.put("distance", cache.distance);
+ values.put("direction", cache.direction);
+ // save coordinates
+ final boolean rel = isReliableLatLon(cache.geocode, cache.guid);
+ if (cache.reliableLatLon) { // new cache has reliable coordinates, store
+ values.put("latitude", cache.latitude);
+ values.put("longitude", cache.longitude);
+ values.put("reliable_latlon", 1);
+ } else if (!rel) { // new cache neither stored cache is not reliable, just update
+ values.put("latitude", cache.latitude);
+ values.put("longitude", cache.longitude);
+ values.put("reliable_latlon", 0);
+ }
+ values.put("elevation", cache.elevation);
+ values.put("shortdesc", cache.shortdesc);
+ values.put("description", cache.description);
+ values.put("favourite_cnt", cache.favouriteCnt);
+ values.put("rating", cache.rating);
+ values.put("votes", cache.votes);
+ values.put("myvote", cache.myVote);
+ if (cache.disabled == true) {
+ values.put("disabled", 1);
+ } else {
+ values.put("disabled", 0);
+ }
+ if (cache.archived == true) {
+ values.put("archived", 1);
+ } else {
+ values.put("archived", 0);
+ }
+ if (cache.members == true) {
+ values.put("members", 1);
+ } else {
+ values.put("members", 0);
+ }
+ if (cache.found == true) {
+ values.put("found", 1);
+ } else {
+ values.put("found", 0);
+ }
+ if (cache.favourite == true) {
+ values.put("favourite", 1);
+ } else {
+ values.put("favourite", 0);
+ }
+ values.put("inventoryunknown", cache.inventoryItems);
+
+ boolean status = false;
+ boolean statusOk = true;
+
+ if (cache.attributes != null) {
+ status = saveAttributes(cache.geocode, cache.attributes);
+ if (status == false) {
+ statusOk = false;
+ }
+ }
+
+ if (cache.waypoints != null) {
+ status = saveWaypoints(cache.geocode, cache.waypoints, true);
+ if (status == false) {
+ statusOk = false;
+ }
+ }
+
+ if (cache.spoilers != null) {
+ status = saveSpoilers(cache.geocode, cache.spoilers);
+ if (status == false) {
+ statusOk = false;
+ }
+ }
+
+ if (cache.logs != null) {
+ status = saveLogs(cache.geocode, cache.logs);
+ if (status == false) {
+ statusOk = false;
+ }
+ }
+
+ if (cache.logCounts != null && cache.logCounts.isEmpty() == false) {
+ status = saveLogCount(cache.geocode, cache.logCounts);
+ if (status == false) {
+ statusOk = false;
+ }
+ }
+
+ if (cache.inventory != null) {
+ status = saveInventory(cache.geocode, cache.inventory);
+ if (status == false) {
+ statusOk = false;
+ }
+ }
+
+ if (statusOk == false) {
+ cache.detailed = false;
+ cache.detailedUpdate = 0l;
+ }
+
+ init();
+
+ //try to update record else insert fresh..
+ try {
+ int rows = databaseRW.update(dbTableCaches, values, "geocode = \"" + cache.geocode + "\"", null);
+ if (rows > 0) {
+ values = null;
+ return true;
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+
+ try {
+ long id = databaseRW.insert(dbTableCaches, null, values);
+ if (id > 0) {
+ values = null;
+ return true;
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+
+ values = null;
+
+ return false;
+ }
+
+ public boolean saveAttributes(String geocode, ArrayList<String> attributes) {
+ init();
+
+ if (geocode == null || geocode.length() == 0 || attributes == null) {
+ return false;
+ }
+
+ databaseRW.beginTransaction();
+ try {
+ databaseRW.delete(dbTableAttributes, "geocode = \"" + geocode + "\"", null);
+
+ if (!attributes.isEmpty()) {
+ ContentValues values = new ContentValues();
+ for (String oneAttribute : attributes) {
+ values.clear();
+ values.put("geocode", geocode);
+ values.put("updated", System.currentTimeMillis());
+ values.put("attribute", oneAttribute);
+
+ databaseRW.insert(dbTableAttributes, null, values);
+ }
+ }
+ databaseRW.setTransactionSuccessful();
+ } finally {
+ databaseRW.endTransaction();
+ }
+
+ return true;
+ }
+
+ public boolean saveWaypoints(String geocode, ArrayList<cgWaypoint> waypoints, boolean drop) {
+ init();
+
+ if (geocode == null || geocode.length() == 0 || waypoints == null) {
+ return false;
+ }
+
+ boolean ok = false;
+ databaseRW.beginTransaction();
+ try {
+ if (drop == true) {
+ databaseRW.delete(dbTableWaypoints, "geocode = \"" + geocode + "\" and type <> \"own\"", null);
+ }
+
+ if (!waypoints.isEmpty()) {
+ ContentValues values = new ContentValues();
+ for (cgWaypoint oneWaypoint : waypoints) {
+ if (oneWaypoint.type.equalsIgnoreCase("own") == true) {
+ continue;
+ }
+
+ values.clear();
+ values.put("geocode", geocode);
+ values.put("updated", System.currentTimeMillis());
+ values.put("type", oneWaypoint.type);
+ values.put("prefix", oneWaypoint.prefix);
+ values.put("lookup", oneWaypoint.lookup);
+ values.put("name", oneWaypoint.name);
+ values.put("latlon", oneWaypoint.latlon);
+ values.put("latitude_string", oneWaypoint.latitudeString);
+ values.put("longitude_string", oneWaypoint.longitudeString);
+ values.put("latitude", oneWaypoint.latitude);
+ values.put("longitude", oneWaypoint.longitude);
+ values.put("note", oneWaypoint.note);
+
+ databaseRW.insert(dbTableWaypoints, null, values);
+ }
+ }
+
+ databaseRW.setTransactionSuccessful();
+ ok = true;
+ } finally {
+ databaseRW.endTransaction();
+ }
+
+ return ok;
+ }
+
+ public boolean saveOwnWaypoint(int id, String geocode, cgWaypoint waypoint) {
+ init();
+
+ if (((geocode == null || geocode.length() == 0) && id <= 0) || waypoint == null) {
+ return false;
+ }
+
+ boolean ok = false;
+ databaseRW.beginTransaction();
+ try {
+ ContentValues values = new ContentValues();
+ values.put("geocode", geocode);
+ values.put("updated", System.currentTimeMillis());
+ values.put("type", waypoint.type);
+ values.put("prefix", waypoint.prefix);
+ values.put("lookup", waypoint.lookup);
+ values.put("name", waypoint.name);
+ values.put("latlon", waypoint.latlon);
+ values.put("latitude_string", waypoint.latitudeString);
+ values.put("longitude_string", waypoint.longitudeString);
+ values.put("latitude", waypoint.latitude);
+ values.put("longitude", waypoint.longitude);
+ values.put("note", waypoint.note);
+
+ if (id <= 0) {
+ databaseRW.insert(dbTableWaypoints, null, values);
+ ok = true;
+ } else {
+ final int rows = databaseRW.update(dbTableWaypoints, values, "_id = " + id, null);
+ if (rows > 0) {
+ ok = true;
+ } else {
+ ok = false;
+ }
+ }
+ databaseRW.setTransactionSuccessful();
+ } finally {
+ databaseRW.endTransaction();
+ }
+
+ return ok;
+ }
+
+ public boolean deleteWaypoint(int id) {
+ init();
+
+ if (id == 0) {
+ return false;
+ }
+
+ int deleted = databaseRW.delete(dbTableWaypoints, "_id = " + id, null);
+
+ if (deleted > 0) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean saveSpoilers(String geocode, ArrayList<cgSpoiler> spoilers) {
+ init();
+
+ if (geocode == null || geocode.length() == 0 || spoilers == null) {
+ return false;
+ }
+
+ databaseRW.beginTransaction();
+ try {
+ databaseRW.delete(dbTableSpoilers, "geocode = \"" + geocode + "\"", null);
+
+ if (!spoilers.isEmpty()) {
+ ContentValues values = new ContentValues();
+ for (cgSpoiler oneSpoiler : spoilers) {
+ values.clear();
+ values.put("geocode", geocode);
+ values.put("updated", System.currentTimeMillis());
+ values.put("url", oneSpoiler.url);
+ values.put("title", oneSpoiler.title);
+ values.put("description", oneSpoiler.description);
+
+ databaseRW.insert(dbTableSpoilers, null, values);
+ }
+ }
+ databaseRW.setTransactionSuccessful();
+ } finally {
+ databaseRW.endTransaction();
+ }
+
+ return true;
+ }
+
+ public boolean saveLogs(String geocode, ArrayList<cgLog> logs) {
+ return saveLogs(geocode, logs, true);
+ }
+
+ public boolean saveLogs(String geocode, ArrayList<cgLog> logs, boolean drop) {
+ init();
+
+ if (geocode == null || geocode.length() == 0 || logs == null) {
+ return false;
+ }
+
+ databaseRW.beginTransaction();
+ try {
+ if (drop == true) {
+ databaseRW.delete(dbTableLogs, "geocode = \"" + geocode + "\"", null);
+ }
+
+ if (!logs.isEmpty()) {
+ ContentValues values = new ContentValues();
+ for (cgLog oneLog : logs) {
+ values.clear();
+ values.put("geocode", geocode);
+ values.put("updated", System.currentTimeMillis());
+ values.put("type", oneLog.type);
+ values.put("author", oneLog.author);
+ values.put("log", oneLog.log);
+ values.put("date", oneLog.date);
+ values.put("found", oneLog.found);
+
+ databaseRW.insert(dbTableLogs, null, values);
+ }
+ }
+ databaseRW.setTransactionSuccessful();
+ } finally {
+ databaseRW.endTransaction();
+ }
+
+ return true;
+ }
+
+ public boolean saveLogCount(String geocode, HashMap<Integer, Integer> logCounts) {
+ return saveLogCount(geocode, logCounts, true);
+ }
+
+ public boolean saveLogCount(String geocode, HashMap<Integer, Integer> logCounts, boolean drop) {
+ init();
+
+ if (geocode == null || geocode.length() == 0 || logCounts == null || logCounts.isEmpty()) {
+ return false;
+ }
+
+ databaseRW.beginTransaction();
+ try {
+ if (drop == true) {
+ databaseRW.delete(dbTableLogCount, "geocode = \"" + geocode + "\"", null);
+ }
+
+ ContentValues values = new ContentValues();
+
+ Set<Entry<Integer, Integer>> logCountsItems = logCounts.entrySet();
+ for (Entry<Integer, Integer> pair : logCountsItems) {
+ values.clear();
+ values.put("geocode", geocode);
+ values.put("updated", System.currentTimeMillis());
+ values.put("type", pair.getKey().intValue());
+ values.put("count", pair.getValue().intValue());
+
+ databaseRW.insert(dbTableLogCount, null, values);
+ }
+ databaseRW.setTransactionSuccessful();
+ } finally {
+ databaseRW.endTransaction();
+ }
+
+ return true;
+ }
+
+ public boolean saveInventory(String geocode, ArrayList<cgTrackable> trackables) {
+ init();
+
+ if (trackables == null) {
+ return false;
+ }
+
+ databaseRW.beginTransaction();
+ try {
+ if (geocode != null) {
+ databaseRW.delete(dbTableTrackables, "geocode = \"" + geocode + "\"", null);
+ }
+
+ if (!trackables.isEmpty()) {
+ ContentValues values = new ContentValues();
+ for (cgTrackable oneTrackable : trackables) {
+ values.clear();
+ if (geocode != null) {
+ values.put("geocode", geocode);
+ }
+ values.put("updated", System.currentTimeMillis());
+ values.put("tbcode", oneTrackable.geocode);
+ values.put("guid", oneTrackable.guid);
+ values.put("title", oneTrackable.name);
+ values.put("owner", oneTrackable.owner);
+ if (oneTrackable.released != null) {
+ values.put("released", oneTrackable.released.getTime());
+ } else {
+ values.put("released", 0l);
+ }
+ values.put("goal", oneTrackable.goal);
+ values.put("description", oneTrackable.details);
+
+ databaseRW.insert(dbTableTrackables, null, values);
+
+ saveLogs(oneTrackable.geocode, oneTrackable.logs);
+ }
+ }
+ databaseRW.setTransactionSuccessful();
+ } finally {
+ databaseRW.endTransaction();
+ }
+
+ return true;
+ }
+
+ public ArrayList<Object> getBounds(Object[] geocodes) {
+ init();
+
+ Cursor cursor = null;
+
+ final ArrayList<Object> viewport = new ArrayList<Object>();
+
+ try {
+ final StringBuilder where = new StringBuilder();
+
+ if (geocodes != null && geocodes.length > 0) {
+ StringBuilder all = new StringBuilder();
+ for (Object one : geocodes) {
+ if (all.length() > 0) {
+ all.append(", ");
+ }
+ all.append("\"");
+ all.append((String) one);
+ all.append("\"");
+ }
+
+ if (where.length() > 0) {
+ where.append(" and ");
+ }
+ where.append("geocode in (");
+ where.append(all);
+ where.append(")");
+ }
+
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"count(_id) as cnt", "min(latitude) as latMin", "max(latitude) as latMax", "min(longitude) as lonMin", "max(longitude) as lonMax"},
+ where.toString(),
+ null,
+ null,
+ null,
+ null,
+ null);
+
+ if (cursor != null) {
+ int cnt = cursor.getCount();
+
+ if (cnt > 0) {
+ cursor.moveToFirst();
+
+ viewport.add((Integer) cursor.getInt(cursor.getColumnIndex("cnt")));
+ viewport.add((Double) cursor.getDouble(cursor.getColumnIndex("latMin")));
+ viewport.add((Double) cursor.getDouble(cursor.getColumnIndex("latMax")));
+ viewport.add((Double) cursor.getDouble(cursor.getColumnIndex("lonMin")));
+ viewport.add((Double) cursor.getDouble(cursor.getColumnIndex("lonMax")));
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.getBounds: " + e.toString());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return viewport;
+ }
+
+ public cgCache loadCache(String geocode, String guid) {
+ return loadCache(geocode, guid, false, true, false, false, false, false);
+ }
+
+ public cgCache loadCache(String geocode, String guid, boolean loadA, boolean loadW, boolean loadS, boolean loadL, boolean loadI, boolean loadO) {
+ Object[] geocodes = new Object[1];
+ Object[] guids = new Object[1];
+
+ if (geocode != null && geocode.length() > 0) {
+ geocodes[0] = geocode;
+ } else {
+ geocodes = null;
+ }
+
+ if (guid != null && guid.length() > 0) {
+ guids[0] = guid;
+ } else {
+ guids = null;
+ }
+
+ ArrayList<cgCache> caches = loadCaches(geocodes, guids, null, null, null, null, loadA, loadW, loadS, loadL, loadI, loadO);
+ if (caches != null && caches.isEmpty() == false) {
+ return caches.get(0);
+ }
+
+ return null;
+ }
+
+ public ArrayList<cgCache> loadCaches(Object[] geocodes, Object[] guids) {
+ return loadCaches(geocodes, guids, null, null, null, null, false, true, false, false, false, false);
+ }
+
+ public ArrayList<cgCache> loadCaches(Object[] geocodes, Object[] guids, boolean lite) {
+ if (lite == true) {
+ return loadCaches(geocodes, guids, null, null, null, null, false, true, false, false, false, false);
+ } else {
+ return loadCaches(geocodes, guids, null, null, null, null, true, true, true, true, true, true);
+ }
+ }
+
+ public ArrayList<cgCache> loadCaches(Object[] geocodes, Object[] guids, Long centerLat, Long centerLon, Long spanLat, Long spanLon, boolean loadA, boolean loadW, boolean loadS, boolean loadL, boolean loadI, boolean loadO) {
+ init();
+
+ StringBuilder where = new StringBuilder();
+ Cursor cursor = null;
+ ArrayList<cgCache> caches = new ArrayList<cgCache>();
+
+ try {
+ if (geocodes != null && geocodes.length > 0) {
+ StringBuilder all = new StringBuilder();
+ for (Object one : geocodes) {
+ if (all.length() > 0) {
+ all.append(", ");
+ }
+ all.append("\"");
+ all.append((String) one);
+ all.append("\"");
+ }
+
+ if (where.length() > 0) {
+ where.append(" and ");
+ }
+ where.append("geocode in (");
+ where.append(all);
+ where.append(")");
+ } else if (guids != null && guids.length > 0) {
+ StringBuilder all = new StringBuilder();
+ for (Object one : guids) {
+ if (all.length() > 0) {
+ all.append(", ");
+ }
+ all.append("\"");
+ all.append((String) one);
+ all.append("\"");
+ }
+
+ if (where.length() > 0) {
+ where.append(" and ");
+ }
+ where.append("guid in (");
+ where.append(all);
+ where.append(")");
+ } else {
+ return caches;
+ }
+
+ // viewport limitation
+ if (centerLat != null && centerLon != null && spanLat != null && spanLon != null) {
+ double latMin = (centerLat / 1e6) - ((spanLat / 1e6) / 2) - ((spanLat / 1e6) / 4);
+ double latMax = (centerLat / 1e6) + ((spanLat / 1e6) / 2) + ((spanLat / 1e6) / 4);
+ double lonMin = (centerLon / 1e6) - ((spanLon / 1e6) / 2) - ((spanLon / 1e6) / 4);
+ double lonMax = (centerLon / 1e6) + ((spanLon / 1e6) / 2) + ((spanLon / 1e6) / 4);
+ double llCache;
+
+ if (latMin > latMax) {
+ llCache = latMax;
+ latMax = latMin;
+ latMin = llCache;
+ }
+ if (lonMin > lonMax) {
+ llCache = lonMax;
+ lonMax = lonMin;
+ lonMin = llCache;
+ }
+
+ if (where.length() > 0) {
+ where.append(" and ");
+ }
+ where.append("(");
+ where.append("latitude >= ");
+ where.append(String.format((Locale) null, "%.6f", latMin));
+ where.append(" and latitude <= ");
+ where.append(String.format((Locale) null, "%.6f", latMax));
+ where.append(" and longitude >= ");
+ where.append(String.format((Locale) null, "%.6f", lonMin));
+ where.append(" and longitude <= ");
+ where.append(String.format((Locale) null, "%.6f", lonMax));
+ where.append(")");
+ }
+
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{
+ "_id", "updated", "reason", "detailed", "detailedupdate", "visiteddate", "geocode", "cacheid", "guid", "type", "name", "own", "owner", "owner_real", "hidden", "hint", "size",
+ "difficulty", "distance", "direction", "terrain", "latlon", "latitude_string", "longitude_string", "location", "latitude", "longitude", "elevation", "shortdesc",
+ "description", "favourite_cnt", "rating", "votes", "myvote", "disabled", "archived", "members", "found", "favourite", "inventorycoins", "inventorytags",
+ "inventoryunknown"
+ },
+ where.toString(),
+ null,
+ null,
+ null,
+ null,
+ null);
+
+ if (cursor != null) {
+ int index = 0;
+
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ cgCache cache = new cgCache();
+
+ cache.updated = (long) cursor.getLong(cursor.getColumnIndex("updated"));
+ cache.reason = (int) cursor.getInt(cursor.getColumnIndex("reason"));
+ index = cursor.getColumnIndex("detailed");
+ if ((int) cursor.getInt(index) == 1) {
+ cache.detailed = true;
+ } else {
+ cache.detailed = false;
+ }
+ cache.detailedUpdate = (Long) cursor.getLong(cursor.getColumnIndex("detailedupdate"));
+ cache.visitedDate = (Long) cursor.getLong(cursor.getColumnIndex("visiteddate"));
+ cache.geocode = (String) cursor.getString(cursor.getColumnIndex("geocode"));
+ cache.cacheid = (String) cursor.getString(cursor.getColumnIndex("cacheid"));
+ cache.guid = (String) cursor.getString(cursor.getColumnIndex("guid"));
+ cache.type = (String) cursor.getString(cursor.getColumnIndex("type"));
+ cache.name = (String) cursor.getString(cursor.getColumnIndex("name"));
+ index = cursor.getColumnIndex("own");
+ if ((int) cursor.getInt(index) == 1) {
+ cache.own = true;
+ } else {
+ cache.own = false;
+ }
+ cache.owner = (String) cursor.getString(cursor.getColumnIndex("owner"));
+ cache.ownerReal = (String) cursor.getString(cursor.getColumnIndex("owner_real"));
+ cache.hidden = new Date((long) cursor.getLong(cursor.getColumnIndex("hidden")));
+ cache.hint = (String) cursor.getString(cursor.getColumnIndex("hint"));
+ cache.size = (String) cursor.getString(cursor.getColumnIndex("size"));
+ cache.difficulty = (Float) cursor.getFloat(cursor.getColumnIndex("difficulty"));
+ index = cursor.getColumnIndex("direction");
+ if (cursor.isNull(index) == true) {
+ cache.direction = null;
+ } else {
+ cache.direction = (Double) cursor.getDouble(index);
+ }
+ index = cursor.getColumnIndex("distance");
+ if (cursor.isNull(index) == true) {
+ cache.distance = null;
+ } else {
+ cache.distance = (Double) cursor.getDouble(index);
+ }
+ cache.terrain = (Float) cursor.getFloat(cursor.getColumnIndex("terrain"));
+ cache.latlon = (String) cursor.getString(cursor.getColumnIndex("latlon"));
+ cache.latitudeString = (String) cursor.getString(cursor.getColumnIndex("latitude_string"));
+ cache.longitudeString = (String) cursor.getString(cursor.getColumnIndex("longitude_string"));
+ cache.location = (String) cursor.getString(cursor.getColumnIndex("location"));
+ index = cursor.getColumnIndex("latitude");
+ if (cursor.isNull(index) == true) {
+ cache.latitude = null;
+ } else {
+ cache.latitude = (Double) cursor.getDouble(index);
+ }
+ index = cursor.getColumnIndex("longitude");
+ if (cursor.isNull(index) == true) {
+ cache.longitude = null;
+ } else {
+ cache.longitude = (Double) cursor.getDouble(index);
+ }
+ index = cursor.getColumnIndex("elevation");
+ if (cursor.isNull(index) == true) {
+ cache.elevation = null;
+ } else {
+ cache.elevation = (Double) cursor.getDouble(index);
+ }
+ cache.shortdesc = (String) cursor.getString(cursor.getColumnIndex("shortdesc"));
+ cache.description = (String) cursor.getString(cursor.getColumnIndex("description"));
+ cache.favouriteCnt = (Integer) cursor.getInt(cursor.getColumnIndex("favourite_cnt"));
+ cache.rating = (Float) cursor.getFloat(cursor.getColumnIndex("rating"));
+ cache.votes = (Integer) cursor.getInt(cursor.getColumnIndex("votes"));
+ cache.myVote = (Float) cursor.getFloat(cursor.getColumnIndex("myvote"));
+ index = cursor.getColumnIndex("disabled");
+ if ((int) cursor.getLong(index) == 1) {
+ cache.disabled = true;
+ } else {
+ cache.disabled = false;
+ }
+ index = cursor.getColumnIndex("archived");
+ if ((int) cursor.getLong(index) == 1) {
+ cache.archived = true;
+ } else {
+ cache.archived = false;
+ }
+ index = cursor.getColumnIndex("members");
+ if ((int) cursor.getLong(index) == 1) {
+ cache.members = true;
+ } else {
+ cache.members = false;
+ }
+ index = cursor.getColumnIndex("found");
+ if ((int) cursor.getLong(index) == 1) {
+ cache.found = true;
+ } else {
+ cache.found = false;
+ }
+ index = cursor.getColumnIndex("favourite");
+ if ((int) cursor.getLong(index) == 1) {
+ cache.favourite = true;
+ } else {
+ cache.favourite = false;
+ }
+ cache.inventoryItems = (Integer) cursor.getInt(cursor.getColumnIndex("inventoryunknown"));
+
+ if (loadA == true) {
+ ArrayList<String> attributes = loadAttributes(cache.geocode);
+ if (attributes != null && attributes.isEmpty() == false) {
+ if (cache.attributes == null)
+ cache.attributes = new ArrayList<String>();
+ else
+ cache.attributes.clear();
+ cache.attributes.addAll(attributes);
+ }
+ }
+
+ if (loadW == true) {
+ ArrayList<cgWaypoint> waypoints = loadWaypoints(cache.geocode);
+ if (waypoints != null && waypoints.isEmpty() == false) {
+ if (cache.waypoints == null)
+ cache.waypoints = new ArrayList<cgWaypoint>();
+ else
+ cache.waypoints.clear();
+ cache.waypoints.addAll(waypoints);
+ }
+ }
+
+ if (loadS == true) {
+ ArrayList<cgSpoiler> spoilers = loadSpoilers(cache.geocode);
+ if (spoilers != null && spoilers.isEmpty() == false) {
+ if (cache.spoilers == null)
+ cache.spoilers = new ArrayList<cgSpoiler>();
+ else
+ cache.spoilers.clear();
+ cache.spoilers.addAll(spoilers);
+ }
+ }
+
+ if (loadL == true) {
+ ArrayList<cgLog> logs = loadLogs(cache.geocode);
+ if (logs != null && logs.isEmpty() == false) {
+ if (cache.logs == null)
+ cache.logs = new ArrayList<cgLog>();
+ else
+ cache.logs.clear();
+ cache.logs.addAll(logs);
+ }
+ HashMap<Integer, Integer> logCounts = loadLogCounts(cache.geocode);
+ if (logCounts != null && logCounts.isEmpty() == false) {
+ cache.logCounts.clear();
+ cache.logCounts.putAll(logCounts);
+ }
+ }
+
+ if (loadI == true) {
+ ArrayList<cgTrackable> inventory = loadInventory(cache.geocode);
+ if (inventory != null && inventory.isEmpty() == false) {
+ if (cache.inventory == null)
+ cache.inventory = new ArrayList<cgTrackable>();
+ else
+ cache.inventory.clear();
+ cache.inventory.addAll(inventory);
+ }
+ }
+
+ if (loadO == true) {
+ cache.logOffline = hasLogOffline(cache.geocode);
+ }
+
+ caches.add(cache);
+ } while (cursor.moveToNext());
+ } else {
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return null;
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.loadCaches: " + e.toString());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return caches;
+ }
+
+ public ArrayList<String> loadAttributes(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ ArrayList<String> attributes = new ArrayList<String>();
+
+ cursor = databaseRO.query(
+ dbTableAttributes,
+ new String[]{"_id", "attribute"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "100");
+
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ attributes.add((String) cursor.getString(cursor.getColumnIndex("attribute")));
+ } while (cursor.moveToNext());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return attributes;
+ }
+
+ public cgWaypoint loadWaypoint(Integer id) {
+ init();
+
+ if (id == null || id == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ cgWaypoint waypoint = new cgWaypoint();
+
+ cursor = databaseRO.query(
+ dbTableWaypoints,
+ new String[]{"_id", "geocode", "updated", "type", "prefix", "lookup", "name", "latlon", "latitude_string", "longitude_string", "latitude", "longitude", "note"},
+ "_id = " + id,
+ null,
+ null,
+ null,
+ null,
+ "100");
+
+ if (cursor != null && cursor.getCount() > 0) {
+ int index;
+ cursor.moveToFirst();
+
+ waypoint.id = (int) cursor.getInt(cursor.getColumnIndex("_id"));
+ waypoint.geocode = (String) cursor.getString(cursor.getColumnIndex("geocode"));
+ waypoint.type = (String) cursor.getString(cursor.getColumnIndex("type"));
+ waypoint.prefix = (String) cursor.getString(cursor.getColumnIndex("prefix"));
+ waypoint.lookup = (String) cursor.getString(cursor.getColumnIndex("lookup"));
+ waypoint.name = (String) cursor.getString(cursor.getColumnIndex("name"));
+ waypoint.latlon = (String) cursor.getString(cursor.getColumnIndex("latlon"));
+ waypoint.latitudeString = (String) cursor.getString(cursor.getColumnIndex("latitude_string"));
+ waypoint.longitudeString = (String) cursor.getString(cursor.getColumnIndex("longitude_string"));
+ index = cursor.getColumnIndex("latitude");
+ if (cursor.isNull(index) == true) {
+ waypoint.latitude = null;
+ } else {
+ waypoint.latitude = (Double) cursor.getDouble(index);
+ }
+ index = cursor.getColumnIndex("longitude");
+ if (cursor.isNull(index) == true) {
+ waypoint.longitude = null;
+ } else {
+ waypoint.longitude = (Double) cursor.getDouble(index);
+ }
+ waypoint.note = (String) cursor.getString(cursor.getColumnIndex("note"));
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return waypoint;
+ }
+
+ public ArrayList<cgWaypoint> loadWaypoints(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ ArrayList<cgWaypoint> waypoints = new ArrayList<cgWaypoint>();
+
+ cursor = databaseRO.query(
+ dbTableWaypoints,
+ new String[]{"_id", "geocode", "updated", "type", "prefix", "lookup", "name", "latlon", "latitude_string", "longitude_string", "latitude", "longitude", "note"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "100");
+
+ if (cursor != null && cursor.getCount() > 0) {
+ int index;
+ cursor.moveToFirst();
+
+ do {
+ cgWaypoint waypoint = new cgWaypoint();
+ waypoint.id = (int) cursor.getInt(cursor.getColumnIndex("_id"));
+ waypoint.geocode = (String) cursor.getString(cursor.getColumnIndex("geocode"));
+ waypoint.type = (String) cursor.getString(cursor.getColumnIndex("type"));
+ waypoint.prefix = (String) cursor.getString(cursor.getColumnIndex("prefix"));
+ waypoint.lookup = (String) cursor.getString(cursor.getColumnIndex("lookup"));
+ waypoint.name = (String) cursor.getString(cursor.getColumnIndex("name"));
+ waypoint.latlon = (String) cursor.getString(cursor.getColumnIndex("latlon"));
+ waypoint.latitudeString = (String) cursor.getString(cursor.getColumnIndex("latitude_string"));
+ waypoint.longitudeString = (String) cursor.getString(cursor.getColumnIndex("longitude_string"));
+ index = cursor.getColumnIndex("latitude");
+ if (cursor.isNull(index) == true) {
+ waypoint.latitude = null;
+ } else {
+ waypoint.latitude = (Double) cursor.getDouble(index);
+ }
+ index = cursor.getColumnIndex("longitude");
+ if (cursor.isNull(index) == true) {
+ waypoint.longitude = null;
+ } else {
+ waypoint.longitude = (Double) cursor.getDouble(index);
+ }
+ waypoint.note = (String) cursor.getString(cursor.getColumnIndex("note"));
+
+ waypoints.add(waypoint);
+ } while (cursor.moveToNext());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return waypoints;
+ }
+
+ public ArrayList<cgSpoiler> loadSpoilers(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ ArrayList<cgSpoiler> spoilers = new ArrayList<cgSpoiler>();
+
+ cursor = databaseRO.query(
+ dbTableSpoilers,
+ new String[]{"_id", "url", "title", "description"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "100");
+
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ cgSpoiler spoiler = new cgSpoiler();
+ spoiler.url = (String) cursor.getString(cursor.getColumnIndex("url"));
+ spoiler.title = (String) cursor.getString(cursor.getColumnIndex("title"));
+ spoiler.description = (String) cursor.getString(cursor.getColumnIndex("description"));
+
+ spoilers.add(spoiler);
+ } while (cursor.moveToNext());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return spoilers;
+ }
+
+ public ArrayList<cgLog> loadLogs(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ ArrayList<cgLog> logs = new ArrayList<cgLog>();
+
+ cursor = databaseRO.query(
+ dbTableLogs,
+ new String[]{"_id", "type", "author", "log", "date", "found"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ "date desc, _id asc",
+ "100");
+
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ cgLog log = new cgLog();
+ log.id = (int) cursor.getInt(cursor.getColumnIndex("_id"));
+ log.type = (int) cursor.getInt(cursor.getColumnIndex("type"));
+ log.author = (String) cursor.getString(cursor.getColumnIndex("author"));
+ log.log = (String) cursor.getString(cursor.getColumnIndex("log"));
+ log.date = (long) cursor.getLong(cursor.getColumnIndex("date"));
+ log.found = (int) cursor.getInt(cursor.getColumnIndex("found"));
+
+ logs.add(log);
+ } while (cursor.moveToNext());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return logs;
+ }
+
+ public HashMap<Integer, Integer> loadLogCounts(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ HashMap<Integer, Integer> logCounts = new HashMap<Integer, Integer>();
+
+ cursor = databaseRO.query(
+ dbTableLogCount,
+ new String[]{"_id", "type", "count"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "100");
+
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ Integer type = new Integer(cursor.getInt(cursor.getColumnIndex("type")));
+ Integer count = new Integer(cursor.getInt(cursor.getColumnIndex("count")));
+
+ logCounts.put(type, count);
+ } while (cursor.moveToNext());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return logCounts;
+ }
+
+ public ArrayList<cgTrackable> loadInventory(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ ArrayList<cgTrackable> trackables = new ArrayList<cgTrackable>();
+
+ cursor = databaseRO.query(
+ dbTableTrackables,
+ new String[]{"_id", "updated", "tbcode", "guid", "title", "owner", "released", "goal", "description"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "100");
+
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ cgTrackable trackable = new cgTrackable();
+ trackable.geocode = (String) cursor.getString(cursor.getColumnIndex("tbcode"));
+ trackable.guid = (String) cursor.getString(cursor.getColumnIndex("guid"));
+ trackable.name = (String) cursor.getString(cursor.getColumnIndex("title"));
+ trackable.owner = (String) cursor.getString(cursor.getColumnIndex("owner"));
+ String releasedPre = cursor.getString(cursor.getColumnIndex("released"));
+ if (releasedPre != null && Long.getLong(releasedPre) != null) {
+ trackable.released = new Date(Long.getLong(releasedPre));
+ } else {
+ trackable.released = null;
+ }
+ trackable.goal = (String) cursor.getString(cursor.getColumnIndex("goal"));
+ trackable.details = (String) cursor.getString(cursor.getColumnIndex("description"));
+ trackable.logs = loadLogs(trackable.geocode);
+
+ trackables.add(trackable);
+ } while (cursor.moveToNext());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return trackables;
+ }
+
+ public cgTrackable loadTrackable(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ cgTrackable trackable = new cgTrackable();
+
+ cursor = databaseRO.query(
+ dbTableTrackables,
+ new String[]{"_id", "updated", "tbcode", "guid", "title", "owner", "released", "goal", "description"},
+ "tbcode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "1");
+
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ trackable.geocode = (String) cursor.getString(cursor.getColumnIndex("tbcode"));
+ trackable.guid = (String) cursor.getString(cursor.getColumnIndex("guid"));
+ trackable.name = (String) cursor.getString(cursor.getColumnIndex("title"));
+ trackable.owner = (String) cursor.getString(cursor.getColumnIndex("owner"));
+ String releasedPre = cursor.getString(cursor.getColumnIndex("released"));
+ if (releasedPre != null && Long.getLong(releasedPre) != null) {
+ trackable.released = new Date(Long.getLong(releasedPre));
+ } else {
+ trackable.released = null;
+ }
+ trackable.goal = (String) cursor.getString(cursor.getColumnIndex("goal"));
+ trackable.details = (String) cursor.getString(cursor.getColumnIndex("description"));
+ trackable.logs = loadLogs(trackable.geocode);
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return trackable;
+ }
+
+ public int getAllStoredCachesCount(boolean detailedOnly, String cachetype, Integer list) {
+ int count = 0;
+
+ String listSql = null;
+ String listSqlW = null;
+ if (list == null) {
+ listSql = " where reason >= 1";
+ listSqlW = " and reason >= 1";
+ } else if (list >= 1) {
+ listSql = " where reason = " + list;
+ listSqlW = " and reason = " + list;
+ } else {
+ return count;
+ }
+
+ try {
+ if (detailedOnly == false) {
+ if (cachetype == null) {
+ SQLiteStatement sqlCount = databaseRO.compileStatement("select count(_id) from " + dbTableCaches + listSql);
+ count = (int) sqlCount.simpleQueryForLong();
+ } else {
+ SQLiteStatement sqlCount = databaseRO.compileStatement("select count(_id) from " + dbTableCaches + " where type = \"" + cachetype + "\"" + listSqlW);
+ count = (int) sqlCount.simpleQueryForLong();
+ }
+ } else {
+ if (cachetype == null) {
+ SQLiteStatement sqlCount = databaseRO.compileStatement("select count(_id) from " + dbTableCaches + " where detailed = 1" + listSqlW);
+ count = (int) sqlCount.simpleQueryForLong();
+ } else {
+ SQLiteStatement sqlCount = databaseRO.compileStatement("select count(_id) from " + dbTableCaches + " where detailed = 1 and type = \"" + cachetype + "\"" + listSqlW);
+ count = (int) sqlCount.simpleQueryForLong();
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.loadAllStoredCachesCount: " + e.toString());
+ }
+
+ return count;
+ }
+
+ public int getAllHistoricCachesCount(boolean detailedOnly, String cachetype) {
+ init();
+
+ int count = 0;
+
+ try {
+ SQLiteStatement sqlCount = databaseRO.compileStatement("select count(_id) from " + dbTableCaches + " where visiteddate > 0");
+ count = (int) sqlCount.simpleQueryForLong();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.getAllHistoricCachesCount: " + e.toString());
+ }
+
+ return count;
+ }
+
+ public ArrayList<String> loadBatchOfStoredGeocodes(boolean detailedOnly, Double latitude, Double longitude, String cachetype, int list) {
+ init();
+
+ if (list < 1) {
+ list = 1;
+ }
+
+ Cursor cursor = null;
+ ArrayList<String> geocodes = new ArrayList<String>();
+
+ StringBuilder specifySql = new StringBuilder();
+
+ specifySql.append("reason = ");
+ specifySql.append(list);
+
+ if (detailedOnly == true) {
+ if (specifySql.length() > 0) {
+ specifySql.append(" and ");
+ }
+
+ specifySql.append("detailed = 1");
+ }
+
+ if (cachetype != null) {
+ if (specifySql.length() > 0) {
+ specifySql.append(" and ");
+ }
+
+ specifySql.append("type = \"");
+ specifySql.append(cachetype);
+ specifySql.append("\"");
+ }
+
+ try {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "geocode", "(abs(latitude-" + String.format((Locale) null, "%.6f", latitude) + ") + abs(longitude-" + String.format((Locale) null, "%.6f", longitude) + ")) as dif"},
+ specifySql.toString(),
+ null,
+ null,
+ null,
+ "dif",
+ null);
+
+ if (cursor != null) {
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ geocodes.add((String) cursor.getString(cursor.getColumnIndex("geocode")));
+ } while (cursor.moveToNext());
+ } else {
+ cursor.close();
+ return null;
+ }
+
+ cursor.close();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.loadBatchOfStoredGeocodes: " + e.toString());
+ }
+
+ return geocodes;
+ }
+
+ public ArrayList<String> loadBatchOfHistoricGeocodes(boolean detailedOnly, String cachetype) {
+ init();
+
+ Cursor cursor = null;
+ ArrayList<String> geocodes = new ArrayList<String>();
+
+ StringBuilder specifySql = new StringBuilder();
+ if (detailedOnly == true) {
+ specifySql.append(" and detailed = 1");
+ }
+ if (cachetype != null) {
+ specifySql.append(" and type = \"");
+ specifySql.append(cachetype);
+ specifySql.append("\"");
+ }
+
+ try {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "geocode"},
+ "visiteddate > 0" + specifySql.toString(),
+ null,
+ null,
+ null,
+ "visiteddate",
+ null);
+
+ if (cursor != null) {
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ geocodes.add((String) cursor.getString(cursor.getColumnIndex("geocode")));
+ } while (cursor.moveToNext());
+ } else {
+ cursor.close();
+ return null;
+ }
+
+ cursor.close();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.loadBatchOfHistoricGeocodes: " + e.toString());
+ }
+
+ return geocodes;
+ }
+
+ public ArrayList<String> getCachedInViewport(Long centerLat, Long centerLon, Long spanLat, Long spanLon, String cachetype) {
+ return getInViewport(false, centerLat, centerLon, spanLat, spanLon, cachetype);
+ }
+
+ public ArrayList<String> getStoredInViewport(Long centerLat, Long centerLon, Long spanLat, Long spanLon, String cachetype) {
+ return getInViewport(true, centerLat, centerLon, spanLat, spanLon, cachetype);
+ }
+
+ public ArrayList<String> getInViewport(boolean stored, Long centerLat, Long centerLon, Long spanLat, Long spanLon, String cachetype) {
+ if (centerLat == null || centerLon == null || spanLat == null || spanLon == null) {
+ return null;
+ }
+
+ init();
+
+ Cursor cursor = null;
+ ArrayList<String> geocodes = new ArrayList<String>();
+
+ // viewport limitation
+ double latMin = (centerLat / 1e6) - ((spanLat / 1e6) / 2) - ((spanLat / 1e6) / 4);
+ double latMax = (centerLat / 1e6) + ((spanLat / 1e6) / 2) + ((spanLat / 1e6) / 4);
+ double lonMin = (centerLon / 1e6) - ((spanLon / 1e6) / 2) - ((spanLon / 1e6) / 4);
+ double lonMax = (centerLon / 1e6) + ((spanLon / 1e6) / 2) + ((spanLon / 1e6) / 4);
+ double llCache;
+
+ if (latMin > latMax) {
+ llCache = latMax;
+ latMax = latMin;
+ latMin = llCache;
+ }
+ if (lonMin > lonMax) {
+ llCache = lonMax;
+ lonMax = lonMin;
+ lonMin = llCache;
+ }
+
+ StringBuilder where = new StringBuilder();
+ where.append("latitude >= ");
+ where.append(String.format((Locale) null, "%.6f", latMin));
+ where.append(" and latitude <= ");
+ where.append(String.format((Locale) null, "%.6f", latMax));
+ where.append(" and longitude >= ");
+ where.append(String.format((Locale) null, "%.6f", lonMin));
+ where.append(" and longitude <= ");
+ where.append(String.format((Locale) null, "%.6f", lonMax));
+
+ // cachetype limitation
+ if (cachetype != null) {
+ where.append(" and type = \"");
+ where.append(cachetype);
+ where.append("\"");
+ }
+
+ // offline caches only
+ if (stored) {
+ where.append(" and reason >= 1");
+ }
+
+ try {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "geocode"},
+ where.toString(),
+ null,
+ null,
+ null,
+ null,
+ "500");
+
+ if (cursor != null) {
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ geocodes.add((String) cursor.getString(cursor.getColumnIndex("geocode")));
+ } while (cursor.moveToNext());
+ } else {
+ cursor.close();
+ return null;
+ }
+
+ cursor.close();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.getOfflineInViewport: " + e.toString());
+ }
+
+ return geocodes;
+ }
+
+ public ArrayList<String> getOfflineAll(String cachetype) {
+ init();
+
+ Cursor cursor = null;
+ ArrayList<String> geocodes = new ArrayList<String>();
+
+ StringBuilder where = new StringBuilder();
+
+ // cachetype limitation
+ if (cachetype != null) {
+ where.append(cachetype);
+ where.append("\"");
+ }
+
+ // offline caches only
+ if (where.length() > 0) {
+ where.append(" and ");
+ }
+ where.append("reason >= 1");
+
+ try {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "geocode"},
+ where.toString(),
+ null,
+ null,
+ null,
+ null,
+ "5000");
+
+ if (cursor != null) {
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ geocodes.add((String) cursor.getString(cursor.getColumnIndex("geocode")));
+ } while (cursor.moveToNext());
+ } else {
+ cursor.close();
+ return null;
+ }
+
+ cursor.close();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.getOfflineAll: " + e.toString());
+ }
+
+ return geocodes;
+ }
+
+ public void markStored(String geocode, int listId) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return;
+ }
+
+ if (listId <= 0) {
+ listId = 1;
+ }
+
+ ContentValues values = new ContentValues();
+ values.put("reason", listId);
+ databaseRW.update(dbTableCaches, values, "geocode = \"" + geocode + "\" and reason < 1", null);
+ }
+
+ public boolean markDropped(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return false;
+ }
+
+ try {
+ ContentValues values = new ContentValues();
+ values.put("reason", 0);
+ int rows = databaseRW.update(dbTableCaches, values, "geocode = \"" + geocode + "\"", null);
+
+ if (rows > 0) {
+ return true;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.markDropped: " + e.toString());
+ }
+
+ return false;
+ }
+
+ public boolean markFound(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return false;
+ }
+
+ try {
+ ContentValues values = new ContentValues();
+ values.put("found", 1);
+ int rows = databaseRW.update(dbTableCaches, values, "geocode = \"" + geocode + "\"", null);
+
+ if (rows > 0) {
+ return true;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.markFound: " + e.toString());
+ }
+
+ return false;
+ }
+
+ public void clean() {
+ clean(false);
+ }
+
+ public void clean(boolean more) {
+ init();
+
+ Log.d(cgSettings.tag, "Database clean: started");
+
+ Cursor cursor = null;
+ ArrayList<String> geocodes = new ArrayList<String>();
+
+ try {
+ if (more) {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "geocode"},
+ "reason = 0",
+ null,
+ null,
+ null,
+ null,
+ null);
+ } else {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "geocode"},
+ "reason = 0 and detailed < " + (System.currentTimeMillis() - (3 * 24 * 60 * 60 * 1000)) + " and detailedupdate < " + (System.currentTimeMillis() - (3 * 24 * 60 * 60 * 1000)) + " and visiteddate < " + (System.currentTimeMillis() - (3 * 24 * 60 * 60 * 1000)),
+ null,
+ null,
+ null,
+ null,
+ null);
+ }
+
+ if (cursor != null) {
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ geocodes.add("\"" + (String) cursor.getString(cursor.getColumnIndex("geocode")) + "\"");
+ } while (cursor.moveToNext());
+ }
+
+ cursor.close();
+ }
+
+ final int size = geocodes.size();
+ if (size > 0) {
+ Log.d(cgSettings.tag, "Database clean: removing " + size + " geocaches");
+
+ databaseRW.execSQL("delete from " + dbTableCaches + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableAttributes + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableSpoilers + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableLogs + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableLogCount + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableLogsOffline + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableWaypoints + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ") and type <> \"own\"");
+ databaseRW.execSQL("delete from " + dbTableTrackables + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+
+ geocodes.clear();
+ }
+
+ databaseRW.execSQL("delete from " + dbTableCaches + " where geocode = \"\"");
+
+ final SQLiteStatement countSql = databaseRO.compileStatement("select count(_id) from " + dbTableCaches + " where reason = 0");
+ final int count = (int) countSql.simpleQueryForLong();
+ Log.d(cgSettings.tag, "Database clean: " + count + " cached geocaches remaining");
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgData.clean: " + e.toString());
+ }
+
+ Log.d(cgSettings.tag, "Database clean: finished");
+ }
+
+ public void dropStored(int listId) {
+ init();
+
+ Cursor cursor = null;
+ ArrayList<String> geocodes = new ArrayList<String>();
+
+ try {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "geocode"},
+ "reason = " + listId,
+ null,
+ null,
+ null,
+ null,
+ null);
+
+ if (cursor != null) {
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ geocodes.add("\"" + (String) cursor.getString(cursor.getColumnIndex("geocode")) + "\"");
+ } while (cursor.moveToNext());
+ } else {
+ cursor.close();
+ return;
+ }
+
+ cursor.close();
+ }
+
+ if (geocodes.size() > 0) {
+ databaseRW.execSQL("delete from " + dbTableCaches + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableAttributes + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableSpoilers + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableLogs + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableLogCount + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableLogsOffline + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableWaypoints + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ") and type <> \"own\"");
+ databaseRW.execSQL("delete from " + dbTableTrackables + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+
+ geocodes.clear();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.dropStored: " + e.toString());
+ }
+ }
+
+ public boolean saveLogOffline(String geocode, Date date, int type, String log) {
+ if (geocode == null || geocode.length() == 0) {
+ return false;
+ }
+ if (type <= 0 && (log == null || log.length() == 0)) {
+ return false;
+ }
+
+ boolean status = false;
+
+ ContentValues values = new ContentValues();
+ values.put("geocode", geocode);
+ values.put("updated", System.currentTimeMillis());
+ values.put("type", type);
+ values.put("log", log);
+ values.put("date", date.getTime());
+
+ try {
+ if (hasLogOffline(geocode) == true) {
+ final int rows = databaseRW.update(dbTableLogsOffline, values, "geocode = \"" + geocode + "\"", null);
+
+ if (rows > 0) {
+ status = true;
+ }
+ } else {
+ final long id = databaseRW.insert(dbTableLogsOffline, null, values);
+
+ if (id > 0) {
+ status = true;
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.saveLogOffline: " + e.toString());
+ }
+
+ return status;
+ }
+
+ public cgLog loadLogOffline(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ cgLog log = null;
+
+ cursor = databaseRO.query(
+ dbTableLogsOffline,
+ new String[]{"_id", "type", "log", "date"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ "_id desc",
+ "1");
+
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ log = new cgLog();
+ log.id = (int) cursor.getInt(cursor.getColumnIndex("_id"));
+ log.type = (int) cursor.getInt(cursor.getColumnIndex("type"));
+ log.log = (String) cursor.getString(cursor.getColumnIndex("log"));
+ log.date = (long) cursor.getLong(cursor.getColumnIndex("date"));
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return log;
+ }
+
+ public void clearLogOffline(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return;
+ }
+
+ databaseRW.delete(dbTableLogsOffline, "geocode = \"" + geocode + "\"", null);
+ }
+
+ public boolean hasLogOffline(String geocode) {
+ if (geocode == null || geocode.length() == 0) {
+ return false;
+ }
+
+ init();
+
+ try {
+ final SQLiteStatement countSql = databaseRO.compileStatement("select count(_id) from " + dbTableLogsOffline + " where geocode = \"" + geocode.toUpperCase() + "\"");
+ final int count = (int) countSql.simpleQueryForLong();
+
+ if (count > 0) {
+ return true;
+ }
+
+ countSql.close();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.hasLogOffline: " + e.toString());
+ }
+
+ return false;
+ }
+
+ public void saveVisitDate(String geocode) {
+ if (geocode == null || geocode.length() == 0) {
+ return;
+ }
+
+ ContentValues values = new ContentValues();
+ values.put("visiteddate", System.currentTimeMillis());
+
+ try {
+ databaseRW.update(dbTableCaches, values, "geocode = \"" + geocode + "\"", null);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.saveVisitDate: " + e.toString());
+ }
+ }
+
+ public ArrayList<cgList> getLists(Resources res) {
+ init();
+
+ Cursor cursor = null;
+ ArrayList<cgList> lists = new ArrayList<cgList>();
+
+ lists.add(new cgList(true, 1, res.getString(R.string.list_inbox)));
+ // lists.add(new cgList(true, 2, res.getString(R.string.list_wpt)));
+
+ try {
+ cursor = databaseRO.query(
+ dbTableLists,
+ new String[]{"_id", "title", "updated", "latitude", "longitude"},
+ null,
+ null,
+ null,
+ null,
+ "title COLLATE NOCASE ASC",
+ null);
+
+ if (cursor != null) {
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ cgList list = new cgList(false);
+
+ list.id = ((int) cursor.getInt(cursor.getColumnIndex("_id"))) + 10;
+ list.title = (String) cursor.getString(cursor.getColumnIndex("title"));
+ list.updated = (Long) cursor.getLong(cursor.getColumnIndex("updated"));
+ list.latitude = (Double) cursor.getDouble(cursor.getColumnIndex("latitude"));
+ list.longitude = (Double) cursor.getDouble(cursor.getColumnIndex("longitude"));
+
+ lists.add(list);
+ } while (cursor.moveToNext());
+ }
+
+ cursor.close();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.getLists: " + e.toString());
+ }
+
+ return lists;
+ }
+
+ public cgList getList(int id, Resources res) {
+ cgList list = null;
+
+ if (id == 1) {
+ list = new cgList(true, 1, res.getString(R.string.list_inbox));
+ } else if (id == 2) {
+ list = new cgList(true, 2, res.getString(R.string.list_wpt));
+ } else if (id >= 10) {
+ init();
+
+ Cursor cursor = null;
+
+ try {
+ cursor = databaseRO.query(
+ dbTableLists,
+ new String[]{"_id", "title", "updated", "latitude", "longitude"},
+ "_id = " + (id - 10),
+ null,
+ null,
+ null,
+ null,
+ null);
+
+ if (cursor != null) {
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ list = new cgList(false);
+
+ list.id = ((int) cursor.getInt(cursor.getColumnIndex("_id"))) + 10;
+ list.title = (String) cursor.getString(cursor.getColumnIndex("title"));
+ list.updated = (Long) cursor.getLong(cursor.getColumnIndex("updated"));
+ list.latitude = (Double) cursor.getDouble(cursor.getColumnIndex("latitude"));
+ list.longitude = (Double) cursor.getDouble(cursor.getColumnIndex("longitude"));
+ } while (cursor.moveToNext());
+ }
+
+ cursor.close();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.getList: " + e.toString());
+ }
+ }
+
+ return list;
+ }
+
+ public int createList(String name) {
+ init();
+
+ int id = -1;
+ if (name == null || name.length() == 0) {
+ return id;
+ }
+
+ databaseRW.beginTransaction();
+ try {
+ ContentValues values = new ContentValues();
+ values.put("title", name);
+ values.put("updated", System.currentTimeMillis());
+
+ id = (int) databaseRW.insert(dbTableLists, null, values);
+ databaseRW.setTransactionSuccessful();
+ } finally {
+ databaseRW.endTransaction();
+ }
+
+ if (id < 0) {
+ return -1;
+ } else {
+ return (id + 10);
+ }
+ }
+
+ public boolean removeList(int id) {
+ init();
+
+ boolean status = false;
+ if (id < 10) {
+ return status;
+ }
+
+ databaseRW.beginTransaction();
+ try {
+ int cnt = databaseRW.delete(dbTableLists, "_id = " + (id - 10), null);
+
+ if (cnt > 0) {
+ ContentValues values = new ContentValues();
+ values.put("reason", 1);
+ databaseRW.update(dbTableCaches, values, "reason = " + id, null);
+
+ status = true;
+ }
+
+ databaseRW.setTransactionSuccessful();
+ } finally {
+ databaseRW.endTransaction();
+ }
+
+ return status;
+ }
+
+ public void moveToList(String geocode, int listId) {
+ if (geocode == null || geocode.length() == 0 || listId <= 0) {
+ return;
+ }
+
+ databaseRW.beginTransaction();
+ try {
+ ContentValues values = new ContentValues();
+ values.put("reason", listId);
+ databaseRW.update(dbTableCaches, values, "geocode = \"" + geocode + "\"", null);
+
+ databaseRW.setTransactionSuccessful();
+ } finally {
+ databaseRW.endTransaction();
+ }
+ }
+
+ public boolean status() {
+ if (databaseRO == null || databaseRW == null || initialized == false) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/src/cgeo/geocaching/cgDirection.java b/src/cgeo/geocaching/cgDirection.java
new file mode 100644
index 0000000..daf5df6
--- /dev/null
+++ b/src/cgeo/geocaching/cgDirection.java
@@ -0,0 +1,102 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorManager;
+import android.hardware.SensorEventListener;
+import android.os.Build;
+import android.util.Log;
+import android.view.Display;
+import android.view.Surface;
+
+public class cgDirection {
+ private Resources res = null;
+ private cgDirection dir = null;
+ private cgeoapplication app = null;
+ private Context context = null;
+ private cgWarning warning = null;
+ private SensorManager sensorManager = null;
+ private cgeoSensorListener sensorListener = null;
+ private cgUpdateDir dirUpdate = null;
+ private cg8wrap cg8 = null;
+
+ public Double directionNow = null;
+
+ public cgDirection(cgeoapplication appIn, Context contextIn, cgUpdateDir dirUpdateIn, cgWarning warningIn) {
+ app = appIn;
+ context = contextIn;
+ dirUpdate = dirUpdateIn;
+ warning = warningIn;
+ res = context.getResources();
+
+ try {
+ final int sdk = new Integer(Build.VERSION.SDK).intValue();
+ if (sdk >= 8) cg8 = new cg8wrap((Activity)context);
+ } catch (Exception e) {
+ // nothing
+ }
+
+ sensorListener = new cgeoSensorListener();
+ }
+
+ public void initDir() {
+ dir = this;
+
+ if (sensorManager == null) {
+ sensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
+ }
+ sensorManager.registerListener(sensorListener, sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_NORMAL);
+ }
+
+ public void closeDir() {
+ if (sensorManager != null && sensorListener != null) {
+ sensorManager.unregisterListener(sensorListener);
+ }
+ }
+
+ public void replaceUpdate(cgUpdateDir dirUpdateIn) {
+ dirUpdate = dirUpdateIn;
+
+ if (dirUpdate != null && directionNow != null) dirUpdate.updateDir(dir);
+ }
+
+ private class cgeoSensorListener implements SensorEventListener {
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ /* There is a bug in Android, which appearently causes this method to be called every
+ * time the sensor _value_ changed, even if the _accuracy_ did not change. So logging
+ * this event leads to the log being flooded with multiple entries _per second_,
+ * which I experienced when running cgeo in a building (with GPS and network being
+ * unreliable).
+ *
+ * See for example https://code.google.com/p/android/issues/detail?id=14792
+ */
+
+ //Log.i(cgSettings.tag, "Compass' accuracy is low (" + accuracy + ")");
+ }
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ Double directionNowPre = new Double(event.values[0]);
+
+ if (cg8 != null) {
+ final int rotation = cg8.getRotation();
+ if (rotation == Surface.ROTATION_90) directionNowPre = directionNowPre + 90;
+ else if (rotation == Surface.ROTATION_180) directionNowPre = directionNowPre + 180;
+ else if (rotation == Surface.ROTATION_270) directionNowPre = directionNowPre + 270;
+ } else {
+ final Display display = ((Activity)context).getWindowManager().getDefaultDisplay();
+ final int rotation = display.getOrientation();
+ if (rotation == Configuration.ORIENTATION_LANDSCAPE) directionNowPre = directionNowPre + 90;
+ }
+
+ directionNow = directionNowPre;
+
+ if (dirUpdate != null && directionNow != null) dirUpdate.updateDir(dir);
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgDirectionImg.java b/src/cgeo/geocaching/cgDirectionImg.java
new file mode 100644
index 0000000..fdfc2c5
--- /dev/null
+++ b/src/cgeo/geocaching/cgDirectionImg.java
@@ -0,0 +1,96 @@
+package cgeo.geocaching;
+
+import android.util.Log;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.entity.BufferedHttpEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+
+public class cgDirectionImg {
+ private cgSettings settings = null;
+
+ public cgDirectionImg(cgSettings settingsIn) {
+ settings = settingsIn;
+ }
+
+ public void getDrawable(String geocode, String code) {
+ String dirName;
+ String fileName;
+
+ if (geocode == null || geocode.length() == 0 || code == null || code.length() == 0) {
+ return;
+ }
+
+ if (geocode != null && geocode.length() > 0) {
+ dirName = settings.getStorage() + geocode + "/";
+ fileName = settings.getStorage() + geocode + "/direction.png";
+ } else {
+ return;
+ }
+
+ File dir = null;
+ dir = new File(settings.getStorage());
+ if (dir.exists() == false) {
+ dir.mkdirs();
+ }
+ dir = new File(dirName);
+ if (dir.exists() == false) {
+ dir.mkdirs();
+ }
+ dir = null;
+
+ HttpClient client = null;
+ HttpGet getMethod = null;
+ HttpResponse httpResponse = null;
+ HttpEntity entity = null;
+ BufferedHttpEntity bufferedEntity = null;
+
+ boolean ok = false;
+
+ for (int i = 0; i < 3; i ++) {
+ if (i > 0) Log.w(cgSettings.tag, "cgDirectionImg.getDrawable: Failed to download data, retrying. Attempt #" + (i + 1));
+
+ try {
+ client = new DefaultHttpClient();
+ getMethod = new HttpGet("http://www.geocaching.com/ImgGen/seek/CacheDir.ashx?k=" + code);
+ httpResponse = client.execute(getMethod);
+ entity = httpResponse.getEntity();
+ bufferedEntity = new BufferedHttpEntity(entity);
+
+ Log.i(cgSettings.tag, "[" + entity.getContentLength() + "B] Downloading direction image " + code);
+
+ if (bufferedEntity != null) {
+ InputStream is = (InputStream)bufferedEntity.getContent();
+ FileOutputStream fos = new FileOutputStream(fileName);
+
+ try {
+ byte[] buffer = new byte[4096];
+ int l;
+ while ((l = is.read(buffer)) != -1) {
+ fos.write(buffer, 0, l);
+ }
+ ok = true;
+ } catch (IOException e) {
+ Log.e(cgSettings.tag, "cgDirectionImg.getDrawable (saving to cache): " + e.toString());
+ } finally {
+ is.close();
+ fos.flush();
+ fos.close();
+ }
+ }
+
+ if (ok == true) {
+ break;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgDirectionImg.getDrawable (downloading from web): " + e.toString());
+ }
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgDistanceView.java b/src/cgeo/geocaching/cgDistanceView.java
new file mode 100644
index 0000000..9610e4f
--- /dev/null
+++ b/src/cgeo/geocaching/cgDistanceView.java
@@ -0,0 +1,45 @@
+package cgeo.geocaching;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+public class cgDistanceView extends TextView {
+ private cgBase base = null;
+ private Double cacheLat = null;
+ private Double cacheLon = null;
+
+ public cgDistanceView(Context context) {
+ super(context);
+ }
+
+ public cgDistanceView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public cgDistanceView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public void setContent(cgBase baseIn, Double cacheLatIn, Double cacheLonIn) {
+ base = baseIn;
+ cacheLat = cacheLatIn;
+ cacheLon = cacheLonIn;
+ }
+
+ public void update(Double latitude, Double longitude) {
+ if (cacheLat == null || cacheLon == null) return;
+ if (latitude == null || longitude == null) return;
+ if (base == null) return;
+
+ setText(base.getHumanDistance(cgBase.getDistance(latitude, longitude, cacheLat, cacheLon)));
+ }
+
+ public void setDistance(Double distance) {
+ setText("~" + base.getHumanDistance(distance));
+ }
+
+ public void clear() {
+ setText(null);
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgGPXListAdapter.java b/src/cgeo/geocaching/cgGPXListAdapter.java
new file mode 100644
index 0000000..78ad881
--- /dev/null
+++ b/src/cgeo/geocaching/cgGPXListAdapter.java
@@ -0,0 +1,75 @@
+package cgeo.geocaching;
+
+import java.util.List;
+import android.app.Activity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.widget.TextView;
+import android.widget.ArrayAdapter;
+import android.util.Log;
+import java.io.File;
+
+public class cgGPXListAdapter extends ArrayAdapter<File> {
+ private cgGPXView holder = null;
+ private cgeogpxes parent = null;
+ private cgSettings settings = null;
+ private LayoutInflater inflater = null;
+
+ public cgGPXListAdapter(cgeogpxes parentIn, cgSettings settingsIn, List<File> listIn) {
+ super(parentIn, 0, listIn);
+
+ parent = parentIn;
+ settings = settingsIn;
+ }
+
+ @Override
+ public View getView(int position, View rowView, ViewGroup parent) {
+ if (inflater == null) inflater = ((Activity)getContext()).getLayoutInflater();
+
+ if (position > getCount()) {
+ Log.w(cgSettings.tag, "cgGPXListAdapter.getView: Attempt to access missing item #" + position);
+ return null;
+ }
+
+ File file = getItem(position);
+
+ if (rowView == null) {
+ rowView = (View)inflater.inflate(R.layout.gpx_item, null);
+
+ holder = new cgGPXView();
+ holder.filepath = (TextView)rowView.findViewById(R.id.filepath);
+ holder.filename = (TextView)rowView.findViewById(R.id.filename);
+
+ rowView.setTag(holder);
+ } else {
+ holder = (cgGPXView)rowView.getTag();
+ }
+
+ final touchListener touchLst = new touchListener(file);
+ rowView.setOnClickListener(touchLst);
+
+ holder.filepath.setText(file.getParent());
+ holder.filename.setText(file.getName());
+
+ return rowView;
+ }
+
+ @Override
+ public void notifyDataSetChanged() {
+ super.notifyDataSetChanged();
+ }
+
+ private class touchListener implements View.OnClickListener {
+ private File file = null;
+
+ public touchListener(File fileIn) {
+ file = fileIn;
+ }
+
+ // tap on item
+ public void onClick(View view) {
+ parent.loadGPX(file);
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgGPXParser.java b/src/cgeo/geocaching/cgGPXParser.java
new file mode 100644
index 0000000..a4b1961
--- /dev/null
+++ b/src/cgeo/geocaching/cgGPXParser.java
@@ -0,0 +1,547 @@
+package cgeo.geocaching;
+
+import android.os.Handler;
+import android.os.Message;
+import android.sax.Element;
+import android.sax.EndElementListener;
+import android.sax.EndTextElementListener;
+import android.sax.RootElement;
+import android.sax.StartElementListener;
+import android.text.Html;
+import android.util.Log;
+import android.util.Xml;
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.xml.sax.Attributes;
+
+public class cgGPXParser {
+
+ private cgeoapplication app = null;
+ private cgBase base = null;
+ private int listId = 1;
+ private cgSearch search = null;
+ private Handler handler = null;
+ private cgCache cache = new cgCache();
+ private cgTrackable trackable = new cgTrackable();
+ private cgLog log = new cgLog();
+ private boolean htmlShort = true;
+ private boolean htmlLong = true;
+ private String type = null;
+ private String sym = null;
+ private String ns = null;
+ private ArrayList<String> nsGCList = new ArrayList<String>();
+ private final Pattern patternGeocode = Pattern.compile("(GC[0-9A-Z]+)", Pattern.CASE_INSENSITIVE);
+ private String name = null;
+ private String cmt = null;
+ private String desc = null;
+
+ public cgGPXParser(cgeoapplication appIn, cgBase baseIn, int listIdIn, cgSearch searchIn) {
+ app = appIn;
+ base = baseIn;
+ listId = listIdIn;
+ search = searchIn;
+
+ nsGCList.add("http://www.groundspeak.com/cache/1/1"); // PQ 1.1
+ nsGCList.add("http://www.groundspeak.com/cache/1/0/1"); // PQ 1.0.1
+ nsGCList.add("http://www.groundspeak.com/cache/1/0"); // PQ 1.0
+ }
+
+ public long parse(File file, int version, Handler handlerIn) {
+ handler = handlerIn;
+ if (file == null) {
+ return 0l;
+ }
+
+ if (version == 11) {
+ ns = "http://www.topografix.com/GPX/1/1"; // GPX 1.1
+ } else {
+ ns = "http://www.topografix.com/GPX/1/0"; // GPX 1.0
+ }
+ final RootElement root = new RootElement(ns, "gpx");
+ final Element waypoint = root.getChild(ns, "wpt");
+
+ // waypoint - attributes
+ waypoint.setStartElementListener(new StartElementListener() {
+
+ public void start(Attributes attrs) {
+ try {
+ if (attrs.getIndex("lat") > -1) {
+ cache.latitude = new Double(attrs.getValue("lat"));
+ }
+ if (attrs.getIndex("lon") > -1) {
+ cache.longitude = new Double(attrs.getValue("lon"));
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse waypoint's latitude and/or longitude.");
+ }
+ }
+ });
+
+ // waypoint
+ waypoint.setEndElementListener(new EndElementListener() {
+
+ public void end() {
+ if (cache.geocode == null || cache.geocode.length() == 0) {
+ // try to find geocode somewhere else
+ String geocode = null;
+ Matcher matcherGeocode = null;
+
+ if (name != null && geocode == null) {
+ matcherGeocode = patternGeocode.matcher(name);
+ while (matcherGeocode.find()) {
+ if (matcherGeocode.groupCount() > 0) {
+ geocode = matcherGeocode.group(1);
+ }
+ }
+ }
+
+ if (desc != null && geocode == null) {
+ matcherGeocode = patternGeocode.matcher(desc);
+ while (matcherGeocode.find()) {
+ if (matcherGeocode.groupCount() > 0) {
+ geocode = matcherGeocode.group(1);
+ }
+ }
+ }
+
+ if (cmt != null && geocode == null) {
+ matcherGeocode = patternGeocode.matcher(cmt);
+ while (matcherGeocode.find()) {
+ if (matcherGeocode.groupCount() > 0) {
+ geocode = matcherGeocode.group(1);
+ }
+ }
+ }
+
+ if (geocode != null && geocode.length() > 0) {
+ cache.geocode = geocode;
+ }
+
+ geocode = null;
+ matcherGeocode = null;
+ }
+
+ if (cache.geocode != null && cache.geocode.length() > 0
+ && cache.latitude != null && cache.longitude != null
+ && ((type == null && sym == null)
+ || (type != null && type.indexOf("geocache") > -1)
+ || (sym != null && sym.indexOf("geocache") > -1))) {
+ cache.latitudeString = base.formatCoordinate(cache.latitude, "lat", true);
+ cache.longitudeString = base.formatCoordinate(cache.longitude, "lon", true);
+ if (cache.inventory != null) {
+ cache.inventoryItems = cache.inventory.size();
+ } else {
+ cache.inventoryItems = 0;
+ }
+ cache.reason = listId;
+ cache.updated = new Date().getTime();
+ cache.detailedUpdate = new Date().getTime();
+ cache.detailed = true;
+
+ app.addCacheToSearch(search, cache);
+ }
+
+ if (handler != null) {
+ final Message msg = new Message();
+ msg.obj = search.getCount();
+ handler.sendMessage(msg);
+ }
+
+ htmlShort = true;
+ htmlLong = true;
+ type = null;
+ sym = null;
+ name = null;
+ desc = null;
+ cmt = null;
+
+ cache = null;
+ cache = new cgCache();
+ }
+ });
+
+ // waypoint.time
+ waypoint.getChild(ns, "time").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ try {
+ cache.hidden = cgBase.dateGPXIn.parse(body.trim());
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse cache date: " + e.toString());
+ }
+ }
+ });
+
+ // waypoint.name
+ waypoint.getChild(ns, "name").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ name = body;
+
+ final String content = Html.fromHtml(body).toString().trim();
+ cache.name = content;
+ if (cache.name.length() > 2 && cache.name.substring(0, 2).equalsIgnoreCase("GC") == true) {
+ cache.geocode = cache.name.toUpperCase();
+ }
+ }
+ });
+
+ // waypoint.desc
+ waypoint.getChild(ns, "desc").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ desc = body;
+
+ final String content = Html.fromHtml(body).toString().trim();
+ cache.shortdesc = content;
+ }
+ });
+
+ // waypoint.cmt
+ waypoint.getChild(ns, "cmt").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ cmt = body;
+
+ final String content = Html.fromHtml(body).toString().trim();
+ cache.description = content;
+ }
+ });
+
+ // waypoint.type
+ waypoint.getChild(ns, "type").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ final String[] content = body.split("\\|");
+ if (content.length > 0) {
+ type = content[0].toLowerCase().trim();
+ }
+ }
+ });
+
+ // waypoint.sym
+ waypoint.getChild(ns, "sym").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ body = body.toLowerCase();
+ sym = body;
+ if (body.indexOf("geocache") != -1 && body.indexOf("found") != -1) {
+ cache.found = true;
+ }
+ }
+ });
+
+ for (String nsGC : nsGCList) {
+ // waypoints.cache
+ final Element gcCache = waypoint.getChild(nsGC, "cache");
+
+ gcCache.setStartElementListener(new StartElementListener() {
+
+ public void start(Attributes attrs) {
+ try {
+ if (attrs.getIndex("id") > -1) {
+ cache.cacheid = attrs.getValue("id");
+ }
+ if (attrs.getIndex("archived") > -1) {
+ final String at = attrs.getValue("archived").toLowerCase();
+ if (at.equals("true")) {
+ cache.archived = true;
+ } else {
+ cache.archived = false;
+ }
+ }
+ if (attrs.getIndex("available") > -1) {
+ final String at = attrs.getValue("available").toLowerCase();
+ if (at.equals("true")) {
+ cache.disabled = false;
+ } else {
+ cache.disabled = true;
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse cache attributes.");
+ }
+ }
+ });
+
+ // waypoint.cache.name
+ gcCache.getChild(nsGC, "name").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ final String content = Html.fromHtml(body).toString().trim();
+ cache.name = content;
+ }
+ });
+
+ // waypoint.cache.owner
+ gcCache.getChild(nsGC, "owner").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ final String content = Html.fromHtml(body).toString().trim();
+ cache.owner = content;
+ }
+ });
+
+ // waypoint.cache.type
+ gcCache.getChild(nsGC, "type").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ final String content = cgBase.cacheTypes.get(body.toLowerCase());
+ cache.type = content;
+ }
+ });
+
+ // waypoint.cache.container
+ gcCache.getChild(nsGC, "container").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ final String content = body.toLowerCase();
+ cache.size = content;
+ }
+ });
+
+ // waypoint.cache.difficulty
+ gcCache.getChild(nsGC, "difficulty").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ try {
+ cache.difficulty = new Float(body);
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse difficulty: " + e.toString());
+ }
+ }
+ });
+
+ // waypoint.cache.terrain
+ gcCache.getChild(nsGC, "terrain").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ try {
+ cache.terrain = new Float(body);
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse terrain: " + e.toString());
+ }
+ }
+ });
+
+ // waypoint.cache.country
+ gcCache.getChild(nsGC, "country").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ if (cache.location == null || cache.location.length() == 0) {
+ cache.location = body.trim();
+ } else {
+ cache.location = cache.location + ", " + body.trim();
+ }
+ }
+ });
+
+ // waypoint.cache.state
+ gcCache.getChild(nsGC, "state").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ if (cache.location == null || cache.location.length() == 0) {
+ cache.location = body.trim();
+ } else {
+ cache.location = body.trim() + ", " + cache.location;
+ }
+ }
+ });
+
+ // waypoint.cache.encoded_hints
+ gcCache.getChild(nsGC, "encoded_hints").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ cache.hint = body.trim();
+ }
+ });
+
+ // waypoint.cache.short_description
+ gcCache.getChild(nsGC, "short_description").setStartElementListener(new StartElementListener() {
+
+ public void start(Attributes attrs) {
+ try {
+ if (attrs.getIndex("html") > -1) {
+ final String at = attrs.getValue("html").toLowerCase();
+ if (at.equals("false")) {
+ htmlShort = false;
+ }
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ });
+
+ gcCache.getChild(nsGC, "short_description").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ if (htmlShort == false) {
+ cache.shortdesc = Html.fromHtml(body).toString();
+ } else {
+ cache.shortdesc = body;
+ }
+ }
+ });
+
+ // waypoint.cache.long_description
+ gcCache.getChild(nsGC, "long_description").setStartElementListener(new StartElementListener() {
+
+ public void start(Attributes attrs) {
+ try {
+ if (attrs.getIndex("html") > -1) {
+ final String at = attrs.getValue("html").toLowerCase();
+ if (at.equals("false")) {
+ htmlLong = false;
+ }
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ });
+
+ gcCache.getChild(nsGC, "long_description").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ if (htmlLong == false) {
+ cache.description = Html.fromHtml(body).toString().trim();
+ } else {
+ cache.description = body;
+ }
+ }
+ });
+
+ // waypoint.cache.travelbugs
+ final Element gcTBs = gcCache.getChild(nsGC, "travelbugs");
+
+ // waypoint.cache.travelbugs.travelbug
+ gcTBs.getChild(nsGC, "travelbug").setStartElementListener(new StartElementListener() {
+
+ public void start(Attributes attrs) {
+ trackable = new cgTrackable();
+
+ try {
+ if (attrs.getIndex("ref") > -1) {
+ trackable.geocode = attrs.getValue("ref").toUpperCase();
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ });
+
+ // waypoint.cache.travelbug
+ final Element gcTB = gcTBs.getChild(nsGC, "travelbug");
+
+ gcTB.setEndElementListener(new EndElementListener() {
+
+ public void end() {
+ if (trackable.geocode != null && trackable.geocode.length() > 0 && trackable.name != null && trackable.name.length() > 0) {
+ if (cache.inventory == null)
+ cache.inventory = new ArrayList<cgTrackable>();
+ cache.inventory.add(trackable);
+ }
+ }
+ });
+
+ // waypoint.cache.travelbugs.travelbug.name
+ gcTB.getChild(nsGC, "name").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ String content = Html.fromHtml(body).toString();
+ trackable.name = content;
+ }
+ });
+
+ // waypoint.cache.logs
+ final Element gcLogs = gcCache.getChild(nsGC, "logs");
+
+ // waypoint.cache.log
+ final Element gcLog = gcLogs.getChild(nsGC, "log");
+
+ gcLog.setStartElementListener(new StartElementListener() {
+
+ public void start(Attributes attrs) {
+ log = new cgLog();
+
+ try {
+ if (attrs.getIndex("id") > -1) {
+ log.id = Integer.parseInt(attrs.getValue("id"));
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ });
+
+ gcLog.setEndElementListener(new EndElementListener() {
+
+ public void end() {
+ if (log.log != null && log.log.length() > 0) {
+ if (cache.logs == null)
+ cache.logs = new ArrayList<cgLog>();
+ cache.logs.add(log);
+ }
+ }
+ });
+
+ // waypoint.cache.logs.log.date
+ gcLog.getChild(nsGC, "date").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ try {
+ log.date = cgBase.dateGPXIn.parse(body.trim()).getTime();
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse log date: " + e.toString());
+ }
+ }
+ });
+
+ // waypoint.cache.logs.log.type
+ gcLog.getChild(nsGC, "type").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ final String content = body.trim().toLowerCase();
+ if (cgBase.logTypes0.containsKey(content) == true) {
+ log.type = cgBase.logTypes0.get(content);
+ } else {
+ log.type = 4;
+ }
+ }
+ });
+
+ // waypoint.cache.logs.log.finder
+ gcLog.getChild(nsGC, "finder").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ String content = Html.fromHtml(body).toString();
+ log.author = content;
+ }
+ });
+
+ // waypoint.cache.logs.log.finder
+ gcLog.getChild(nsGC, "text").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ String content = Html.fromHtml(body).toString();
+ log.log = content;
+ }
+ });
+ }
+
+ try {
+ Xml.parse(new FileInputStream(file), Xml.Encoding.UTF_8, root.getContentHandler());
+
+ return search.getCurrentId();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Cannot parse .gpx file " + file.getAbsolutePath() + " as GPX " + version + ": " + e.toString());
+ }
+
+ return 0l;
+ }
+}
diff --git a/src/cgeo/geocaching/cgGPXView.java b/src/cgeo/geocaching/cgGPXView.java
new file mode 100644
index 0000000..f68b477
--- /dev/null
+++ b/src/cgeo/geocaching/cgGPXView.java
@@ -0,0 +1,9 @@
+package cgeo.geocaching;
+
+import android.widget.TextView;
+
+public class cgGPXView {
+ // layouts & views
+ public TextView filepath;
+ public TextView filename;
+}
diff --git a/src/cgeo/geocaching/cgGeo.java b/src/cgeo/geocaching/cgGeo.java
new file mode 100644
index 0000000..95c0b9d
--- /dev/null
+++ b/src/cgeo/geocaching/cgGeo.java
@@ -0,0 +1,445 @@
+package cgeo.geocaching;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.location.GpsSatellite;
+import android.location.GpsStatus;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.util.Log;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+
+public class cgGeo {
+
+ private Context context = null;
+ private cgeoapplication app = null;
+ private LocationManager geoManager = null;
+ private cgUpdateLoc geoUpdate = null;
+ private cgWarning warning = null;
+ private cgBase base = null;
+ private cgSettings settings = null;
+ private SharedPreferences prefs = null;
+ private cgeoGeoListener geoNetListener = null;
+ private cgeoGeoListener geoGpsListener = null;
+ private cgeoGpsStatusListener geoGpsStatusListener = null;
+ private Integer time = 0;
+ private Integer distance = 0;
+ private Location locGps = null;
+ private Location locNet = null;
+ private long locGpsLast = 0l;
+ private boolean g4cRunning = false;
+ private Double lastGo4cacheLat = null;
+ private Double lastGo4cacheLon = null;
+ public Location location = null;
+ public int gps = -1;
+ public Double latitudeNow = null;
+ public Double longitudeNow = null;
+ public Double latitudeBefore = null;
+ public Double longitudeBefore = null;
+ public Double altitudeNow = null;
+ public Double bearingNow = null;
+ public Float speedNow = null;
+ public Float accuracyNow = null;
+ public Integer satellitesVisible = null;
+ public Integer satellitesFixed = null;
+ public double distanceNow = 0d;
+
+ public cgGeo(Context contextIn, cgeoapplication appIn, cgUpdateLoc geoUpdateIn, cgBase baseIn, cgSettings settingsIn, cgWarning warningIn, int timeIn, int distanceIn) {
+ context = contextIn;
+ app = appIn;
+ geoUpdate = geoUpdateIn;
+ base = baseIn;
+ settings = settingsIn;
+ warning = warningIn;
+ time = timeIn;
+ distance = distanceIn;
+
+ if (prefs == null) {
+ prefs = context.getSharedPreferences(cgSettings.preferences, 0);
+ }
+ distanceNow = prefs.getFloat("dst", 0f);
+ if (Double.isNaN(distanceNow) == true) {
+ distanceNow = 0d;
+ }
+ if (distanceNow == 0f) {
+ final SharedPreferences.Editor prefsEdit = context.getSharedPreferences(cgSettings.preferences, 0).edit();
+ if (prefsEdit != null) {
+ prefsEdit.putLong("dst-since", System.currentTimeMillis());
+ prefsEdit.commit();
+ }
+ }
+
+ geoNetListener = new cgeoGeoListener();
+ geoNetListener.setProvider(LocationManager.NETWORK_PROVIDER);
+
+ geoGpsListener = new cgeoGeoListener();
+ geoGpsListener.setProvider(LocationManager.GPS_PROVIDER);
+
+ geoGpsStatusListener = new cgeoGpsStatusListener();
+ }
+
+ public void initGeo() {
+ location = null;
+ gps = -1;
+ latitudeNow = null;
+ longitudeNow = null;
+ altitudeNow = null;
+ bearingNow = null;
+ speedNow = null;
+ accuracyNow = null;
+ satellitesVisible = 0;
+ satellitesFixed = 0;
+
+ if (geoManager == null) {
+ geoManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+ }
+
+ lastLoc();
+
+ geoNetListener.setProvider(LocationManager.NETWORK_PROVIDER);
+ geoGpsListener.setProvider(LocationManager.GPS_PROVIDER);
+ geoManager.addGpsStatusListener(geoGpsStatusListener);
+
+ try {
+ geoManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, time, distance, geoNetListener);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "There is no NETWORK location provider");
+ }
+
+ try {
+ geoManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, time, distance, geoGpsListener);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "There is no GPS location provider");
+ }
+ }
+
+ public void closeGeo() {
+ if (geoManager != null && geoNetListener != null) {
+ geoManager.removeUpdates(geoNetListener);
+ }
+ if (geoManager != null && geoGpsListener != null) {
+ geoManager.removeUpdates(geoGpsListener);
+ }
+ if (geoManager != null) {
+ geoManager.removeGpsStatusListener(geoGpsStatusListener);
+ }
+
+ final SharedPreferences.Editor prefsEdit = context.getSharedPreferences(cgSettings.preferences, 0).edit();
+ if (prefsEdit != null && Double.isNaN(distanceNow) == false) {
+ prefsEdit.putFloat("dst", (float) distanceNow);
+ prefsEdit.commit();
+ }
+ }
+
+ public void replaceUpdate(cgUpdateLoc geoUpdateIn) {
+ geoUpdate = geoUpdateIn;
+
+ if (geoUpdate != null) {
+ geoUpdate.updateLoc(this);
+ }
+ }
+
+ public class cgeoGeoListener implements LocationListener {
+
+ public String active = null;
+
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ // nothing
+ }
+
+ @Override
+ public void onLocationChanged(Location location) {
+ if (location.getProvider().equals(LocationManager.GPS_PROVIDER) == true) {
+ locGps = location;
+ locGpsLast = System.currentTimeMillis();
+ } else if (location.getProvider().equals(LocationManager.NETWORK_PROVIDER) == true) {
+ locNet = location;
+ }
+
+ selectBest(location.getProvider());
+ }
+
+ @Override
+ public void onProviderDisabled(String provider) {
+ if (provider.equals(LocationManager.NETWORK_PROVIDER) == true) {
+ if (geoManager != null && geoNetListener != null) {
+ geoManager.removeUpdates(geoNetListener);
+ }
+ } else if (provider.equals(LocationManager.GPS_PROVIDER) == true) {
+ if (geoManager != null && geoGpsListener != null) {
+ geoManager.removeUpdates(geoGpsListener);
+ }
+ }
+ }
+
+ @Override
+ public void onProviderEnabled(String provider) {
+ if (provider.equals(LocationManager.NETWORK_PROVIDER) == true) {
+ if (geoNetListener == null) {
+ geoNetListener = new cgeoGeoListener();
+ }
+ geoNetListener.setProvider(LocationManager.NETWORK_PROVIDER);
+ } else if (provider.equals(LocationManager.GPS_PROVIDER) == true) {
+ if (geoGpsListener == null) {
+ geoGpsListener = new cgeoGeoListener();
+ }
+ geoGpsListener.setProvider(LocationManager.GPS_PROVIDER);
+ }
+ }
+
+ public void setProvider(String provider) {
+ if (provider.equals(LocationManager.GPS_PROVIDER) == true) {
+ if (geoManager != null && geoManager.isProviderEnabled(LocationManager.GPS_PROVIDER) == true) {
+ active = provider;
+ } else {
+ active = null;
+ }
+ } else if (provider.equals(LocationManager.NETWORK_PROVIDER) == true) {
+ if (geoManager != null && geoManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) == true) {
+ active = provider;
+ } else {
+ active = null;
+ }
+ }
+ }
+ }
+
+ public class cgeoGpsStatusListener implements GpsStatus.Listener {
+
+ @Override
+ public void onGpsStatusChanged(int event) {
+ if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS) {
+ GpsStatus status = geoManager.getGpsStatus(null);
+ Iterator<GpsSatellite> statusIterator = status.getSatellites().iterator();
+
+ int satellites = 0;
+ int fixed = 0;
+
+ while (statusIterator.hasNext()) {
+ GpsSatellite sat = statusIterator.next();
+ if (sat.usedInFix() == true) {
+ fixed++;
+ }
+ satellites++;
+
+ /* satellite signal strength
+ if (sat.usedInFix()) {
+ Log.d(cgSettings.tag, "Sat #" + satellites + ": " + sat.getSnr() + " FIX");
+ } else {
+ Log.d(cgSettings.tag, "Sat #" + satellites + ": " + sat.getSnr());
+ }
+ */
+ }
+
+ boolean changed = false;
+ if (satellitesVisible == null || satellites != satellitesVisible) {
+ satellitesVisible = satellites;
+ changed = true;
+ }
+ if (satellitesFixed == null || fixed != satellitesFixed) {
+ satellitesFixed = fixed;
+ changed = true;
+ }
+
+ if (changed == true) {
+ selectBest(null);
+ }
+ }
+ }
+ }
+
+ private void selectBest(String initProvider) {
+ if (locNet == null && locGps != null) { // we have only GPS
+ assign(locGps);
+ return;
+ }
+
+ if (locNet != null && locGps == null) { // we have only NET
+ assign(locNet);
+ return;
+ }
+
+ if (satellitesFixed > 0) { // GPS seems to be fixed
+ assign(locGps);
+ return;
+ }
+
+ if (initProvider != null && initProvider.equals(LocationManager.GPS_PROVIDER) == true) { // we have new location from GPS
+ assign(locGps);
+ return;
+ }
+
+ if (locGpsLast > (System.currentTimeMillis() - 30 * 1000)) { // GPS was working in last 30 seconds
+ assign(locGps);
+ return;
+ }
+
+ assign(locNet); // nothing else, using NET
+ }
+
+ private void assign(Double lat, Double lon) {
+ if (lat == null || lon == null) {
+ return;
+ }
+
+ gps = -1;
+ latitudeNow = lat;
+ longitudeNow = lon;
+ altitudeNow = null;
+ bearingNow = new Double(0);
+ speedNow = 0f;
+ accuracyNow = 999f;
+
+ if (geoUpdate != null) {
+ geoUpdate.updateLoc(this);
+ }
+ }
+
+ private void assign(Location loc) {
+ if (loc == null) {
+ gps = -1;
+ return;
+ }
+
+ location = loc;
+
+ String provider = location.getProvider();
+ if (provider.equals(LocationManager.GPS_PROVIDER) == true) {
+ gps = 1;
+ } else if (provider.equals(LocationManager.NETWORK_PROVIDER) == true) {
+ gps = 0;
+ } else if (provider.equals("last") == true) {
+ gps = -1;
+ }
+
+ latitudeNow = location.getLatitude();
+ longitudeNow = location.getLongitude();
+ app.setLastLoc(latitudeNow, longitudeNow);
+
+ if (location.hasAltitude() && gps != -1) {
+ altitudeNow = location.getAltitude() + settings.altCorrection;
+ } else {
+ altitudeNow = null;
+ }
+ if (location.hasBearing() && gps != -1) {
+ bearingNow = new Double(location.getBearing());
+ } else {
+ bearingNow = new Double(0);
+ }
+ if (location.hasSpeed() && gps != -1) {
+ speedNow = location.getSpeed();
+ } else {
+ speedNow = 0f;
+ }
+ if (location.hasAccuracy() && gps != -1) {
+ accuracyNow = location.getAccuracy();
+ } else {
+ accuracyNow = 999f;
+ }
+
+ if (gps == 1) {
+ // save travelled distance only when location is from GPS
+ if (latitudeBefore != null && longitudeBefore != null && latitudeNow != null && longitudeNow != null) {
+ final double dst = cgBase.getDistance(latitudeBefore, longitudeBefore, latitudeNow, longitudeNow);
+
+ if (Double.isNaN(dst) == false && dst > 0.005) {
+ distanceNow += dst;
+
+ latitudeBefore = latitudeNow;
+ longitudeBefore = longitudeNow;
+ }
+ } else if (latitudeBefore == null || longitudeBefore == null) { // values aren't initialized
+ latitudeBefore = latitudeNow;
+ longitudeBefore = longitudeNow;
+ }
+ }
+
+ if (geoUpdate != null) {
+ geoUpdate.updateLoc(this);
+ }
+
+ if (gps > -1) {
+ (new publishLoc()).start();
+ }
+ }
+
+ private class publishLoc extends Thread {
+
+ private publishLoc() {
+ setPriority(Thread.MIN_PRIORITY);
+ }
+
+ @Override
+ public void run() {
+ if (g4cRunning == true) {
+ return;
+ }
+
+ if (settings.publicLoc == 1 && (lastGo4cacheLat == null || lastGo4cacheLon == null || cgBase.getDistance(latitudeNow, longitudeNow, lastGo4cacheLat, lastGo4cacheLon) > 0.75)) {
+ g4cRunning = true;
+
+ final String host = "api.go4cache.com";
+ final String path = "/";
+ final String method = "POST";
+ String action = null;
+ if (app != null) {
+ action = app.getAction();
+ } else {
+ action = "";
+ }
+
+ final String username = settings.getUsername();
+ if (username != null) {
+ final HashMap<String, String> params = new HashMap<String, String>();
+ final String latStr = String.format((Locale) null, "%.6f", latitudeNow);
+ final String lonStr = String.format((Locale) null, "%.6f", longitudeNow);
+ params.put("u", username);
+ params.put("lt", latStr);
+ params.put("ln", lonStr);
+ params.put("a", action);
+ params.put("s", (cgBase.sha1(username + "|" + latStr + "|" + lonStr + "|" + action + "|" + cgBase.md5("carnero: developing your dreams"))).toLowerCase());
+ if (base.version != null) {
+ params.put("v", base.version);
+ }
+ final String res = base.request(false, host, path, method, params, false, false, false).getData();
+
+ if (res != null && res.length() > 0) {
+ lastGo4cacheLat = latitudeNow;
+ lastGo4cacheLon = longitudeNow;
+ }
+ }
+ }
+
+ g4cRunning = false;
+ }
+ }
+
+ public void lastLoc() {
+ assign(app.getLastLat(), app.getLastLon());
+
+ Location lastGps = geoManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
+
+ if (lastGps != null) {
+ lastGps.setProvider("last");
+ assign(lastGps);
+
+ Log.i(cgSettings.tag, "Using last location from GPS");
+ return;
+ }
+
+ Location lastGsm = geoManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
+
+ if (lastGsm != null) {
+ lastGsm.setProvider("last");
+ assign(lastGsm);
+
+ Log.i(cgSettings.tag, "Using last location from NETWORK");
+ return;
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgHtmlImg.java b/src/cgeo/geocaching/cgHtmlImg.java
new file mode 100644
index 0000000..023912a
--- /dev/null
+++ b/src/cgeo/geocaching/cgHtmlImg.java
@@ -0,0 +1,286 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import android.util.Log;
+import android.text.Html;
+import android.view.Display;
+import android.view.WindowManager;
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.net.Uri;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Date;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.entity.BufferedHttpEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+
+public class cgHtmlImg implements Html.ImageGetter {
+
+ private Activity activity = null;
+ private cgSettings settings = null;
+ private String geocode = null;
+ private boolean placement = true;
+ private int reason = 0;
+ private boolean onlySave = false;
+ private BitmapFactory.Options bfOptions = new BitmapFactory.Options();
+ private Display display = null;
+ private int maxWidth = 0;
+ private int maxHeight = 0;
+ private double ratio = 1.0d;
+ private int width = 0;
+ private int height = 0;
+
+ public cgHtmlImg(Activity activityIn, cgSettings settingsIn, String geocodeIn, boolean placementIn, int reasonIn, boolean onlySaveIn) {
+ activity = activityIn;
+ settings = settingsIn;
+ geocode = geocodeIn;
+ placement = placementIn;
+ reason = reasonIn;
+ onlySave = onlySaveIn;
+
+ bfOptions.inTempStorage = new byte[16 * 1024];
+
+ display = ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+ maxWidth = display.getWidth() - 25;
+ maxHeight = display.getHeight() - 25;
+ }
+
+ @Override
+ public BitmapDrawable getDrawable(String url) {
+ Bitmap imagePre = null;
+ String dirName = null;
+ String fileName = null;
+ String fileNameSec = null;
+
+ if (url == null || url.length() == 0) {
+ return null;
+ }
+
+ final String[] urlParts = url.split("\\.");
+ String urlExt = null;
+ if (urlParts.length > 1) {
+ urlExt = "." + urlParts[(urlParts.length - 1)];
+ if (urlExt.length() > 5) {
+ urlExt = "";
+ }
+ } else {
+ urlExt = "";
+ }
+
+ if (geocode != null && geocode.length() > 0) {
+ dirName = settings.getStorage() + geocode + "/";
+ fileName = settings.getStorage() + geocode + "/" + cgBase.md5(url) + urlExt;
+ fileNameSec = settings.getStorageSec() + geocode + "/" + cgBase.md5(url) + urlExt;
+ } else {
+ dirName = settings.getStorage() + "_others/";
+ fileName = settings.getStorage() + "_others/" + cgBase.md5(url) + urlExt;
+ fileNameSec = settings.getStorageSec() + "_others/" + cgBase.md5(url) + urlExt;
+ }
+
+ File dir = null;
+ dir = new File(settings.getStorage());
+ if (dir.exists() == false) {
+ dir.mkdirs();
+ }
+ dir = new File(dirName);
+ if (dir.exists() == false) {
+ dir.mkdirs();
+ }
+ dir = null;
+
+ // load image from cache
+ if (onlySave == false) {
+ try {
+ final Date now = new Date();
+
+ final File file = new File(fileName);
+ if (file.exists() == true) {
+ final long imageSize = file.length();
+
+ // large images will be downscaled on input to save memory
+ if (imageSize > (6 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 48;
+ } else if (imageSize > (4 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 16;
+ } else if (imageSize > (2 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 10;
+ } else if (imageSize > (1 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 6;
+ } else if (imageSize > (0.5 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 2;
+ }
+
+ if (reason > 0 || file.lastModified() > (now.getTime() - (24 * 60 * 60 * 1000))) {
+ imagePre = BitmapFactory.decodeFile(fileName, bfOptions);
+ }
+ }
+
+ if (imagePre == null) {
+ final File fileSec = new File(fileNameSec);
+ if (fileSec.exists() == true) {
+ final long imageSize = fileSec.length();
+
+ // large images will be downscaled on input to save memory
+ if (imageSize > (6 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 48;
+ } else if (imageSize > (4 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 16;
+ } else if (imageSize > (2 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 10;
+ } else if (imageSize > (1 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 6;
+ } else if (imageSize > (0.5 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 2;
+ }
+
+ if (reason > 0 || file.lastModified() > (now.getTime() - (24 * 60 * 60 * 1000))) {
+ imagePre = BitmapFactory.decodeFile(fileNameSec, bfOptions);
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgHtmlImg.getDrawable (reading cache): " + e.toString());
+ }
+ }
+
+ // download image and save it to the cache
+ if ((imagePre == null && reason == 0) || onlySave == true) {
+ Uri uri = null;
+ HttpClient client = null;
+ HttpGet getMethod = null;
+ HttpResponse httpResponse = null;
+ HttpEntity entity = null;
+ BufferedHttpEntity bufferedEntity = null;
+
+ try {
+ // check if uri is absolute or not, if not attach geocaching.com hostname and scheme
+ uri = Uri.parse(url);
+
+ if (uri.isAbsolute() == false) {
+ url = "http://www.geocaching.com" + url;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgHtmlImg.getDrawable (parse URL): " + e.toString());
+ }
+
+ if (uri != null) {
+ for (int i = 0; i < 2; i++) {
+ if (i > 0) {
+ Log.w(cgSettings.tag, "cgHtmlImg.getDrawable: Failed to download data, retrying. Attempt #" + (i + 1));
+ }
+
+ try {
+ client = new DefaultHttpClient();
+ getMethod = new HttpGet(url);
+ httpResponse = client.execute(getMethod);
+ entity = httpResponse.getEntity();
+ bufferedEntity = new BufferedHttpEntity(entity);
+
+ final long imageSize = bufferedEntity.getContentLength();
+
+ // large images will be downscaled on input to save memory
+ if (imageSize > (6 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 48;
+ } else if (imageSize > (4 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 16;
+ } else if (imageSize > (2 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 10;
+ } else if (imageSize > (1 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 6;
+ } else if (imageSize > (0.5 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 2;
+ }
+
+ if (bufferedEntity != null) {
+ imagePre = BitmapFactory.decodeStream(bufferedEntity.getContent(), null, bfOptions);
+ }
+ if (imagePre != null) {
+ break;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgHtmlImg.getDrawable (downloading from web): " + e.toString());
+ }
+ }
+ }
+
+ try {
+ // save to memory/SD cache
+ if (bufferedEntity != null) {
+ final InputStream is = (InputStream) bufferedEntity.getContent();
+ final FileOutputStream fos = new FileOutputStream(fileName);
+ try {
+ final byte[] buffer = new byte[4096];
+ int l;
+ while ((l = is.read(buffer)) != -1) {
+ fos.write(buffer, 0, l);
+ }
+ } catch (IOException e) {
+ Log.e(cgSettings.tag, "cgHtmlImg.getDrawable (saving to cache): " + e.toString());
+ } finally {
+ is.close();
+ fos.flush();
+ fos.close();
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgHtmlImg.getDrawable (saving to cache): " + e.toString());
+ }
+
+ entity = null;
+ bufferedEntity = null;
+ }
+
+ if (onlySave == true) {
+ return null;
+ }
+
+ // get image and return
+ if (imagePre == null) {
+ Log.d(cgSettings.tag, "cgHtmlImg.getDrawable: Failed to obtain image");
+
+ if (placement == false) {
+ imagePre = BitmapFactory.decodeResource(activity.getResources(), R.drawable.image_no_placement);
+ } else {
+ imagePre = BitmapFactory.decodeResource(activity.getResources(), R.drawable.image_not_loaded);
+ }
+ }
+
+ final int imgWidth = imagePre.getWidth();
+ final int imgHeight = imagePre.getHeight();
+
+ if (imgWidth > maxWidth || imgHeight > maxHeight) {
+ if ((maxWidth / imgWidth) > (maxHeight / imgHeight)) {
+ ratio = (double) maxHeight / (double) imgHeight;
+ } else {
+ ratio = (double) maxWidth / (double) imgWidth;
+ }
+
+ width = (int) Math.ceil(imgWidth * ratio);
+ height = (int) Math.ceil(imgHeight * ratio);
+
+ try {
+ imagePre = Bitmap.createScaledBitmap(imagePre, width, height, true);
+ } catch (Exception e) {
+ Log.d(cgSettings.tag, "cgHtmlImg.getDrawable: Failed to scale image");
+ return null;
+ }
+ } else {
+ width = imgWidth;
+ height = imgHeight;
+ }
+
+ final BitmapDrawable image = new BitmapDrawable(imagePre);
+ image.setBounds(new Rect(0, 0, width, height));
+
+ return image;
+ }
+}
diff --git a/src/cgeo/geocaching/cgList.java b/src/cgeo/geocaching/cgList.java
new file mode 100644
index 0000000..65d08ac
--- /dev/null
+++ b/src/cgeo/geocaching/cgList.java
@@ -0,0 +1,20 @@
+package cgeo.geocaching;
+
+public class cgList {
+ public boolean def = false;
+ public int id = 0;
+ public String title = null;
+ public Long updated = null;
+ public Double latitude = null;
+ public Double longitude = null;
+
+ public cgList(boolean defIn) {
+ def = defIn;
+ }
+
+ public cgList(boolean defIn, int idIn, String titleIn) {
+ def = defIn;
+ id = idIn;
+ title = titleIn;
+ }
+}
diff --git a/src/cgeo/geocaching/cgLog.java b/src/cgeo/geocaching/cgLog.java
new file mode 100644
index 0000000..5b1b44a
--- /dev/null
+++ b/src/cgeo/geocaching/cgLog.java
@@ -0,0 +1,12 @@
+package cgeo.geocaching;
+
+public class cgLog {
+ public int id = 0;
+ public int type = 4; // note
+ public String author = "";
+ public String log = "";
+ public long date = 0;
+ public int found = -1;
+ public String cacheName = ""; // used for trackables
+ public String cacheGuid = ""; // used for trackables
+}
diff --git a/src/cgeo/geocaching/cgLogForm.java b/src/cgeo/geocaching/cgLogForm.java
new file mode 100644
index 0000000..9cbd557
--- /dev/null
+++ b/src/cgeo/geocaching/cgLogForm.java
@@ -0,0 +1,10 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import java.util.Calendar;
+
+public class cgLogForm extends Activity {
+ public void setDate(Calendar dateIn) {
+ // to be overwritten
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgMapImg.java b/src/cgeo/geocaching/cgMapImg.java
new file mode 100644
index 0000000..57639ff
--- /dev/null
+++ b/src/cgeo/geocaching/cgMapImg.java
@@ -0,0 +1,114 @@
+package cgeo.geocaching;
+
+import android.util.Log;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.entity.BufferedHttpEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+
+public class cgMapImg {
+ /**
+ * in my tests the "no image available" image had 5470 bytes, while "street only" maps had at least 20000 bytes
+ */
+ private static final int MIN_MAP_IMAGE_BYTES = 6000;
+ private cgSettings settings = null;
+ private String geocode = null;
+
+ public cgMapImg(cgSettings settingsIn, String geocodeIn) {
+ geocode = geocodeIn;
+ settings = settingsIn;
+
+ if (geocode != null && geocode.length() > 0) {
+ final String dirName = settings.getStorage() + geocode + "/";
+
+ File dir = null;
+ dir = new File(settings.getStorage());
+ if (dir.exists() == false) {
+ dir.mkdirs();
+ }
+ dir = new File(dirName);
+ if (dir.exists() == false) {
+ dir.mkdirs();
+ }
+ dir = null;
+ }
+ }
+
+ public void getDrawable(String url, int level) {
+ if (url == null || url.length() == 0) {
+ return;
+ }
+
+ if (geocode == null || geocode.length() == 0) {
+ return;
+ }
+
+ final String fileName = settings.getStorage() + geocode + "/map_" + level;
+ HttpClient client = null;
+ HttpGet getMethod = null;
+ HttpResponse httpResponse = null;
+ HttpEntity entity = null;
+ BufferedHttpEntity bufferedEntity = null;
+
+ boolean ok = false;
+
+ for (int i = 0; i < 3; i ++) {
+ if (i > 0) Log.w(cgSettings.tag, "cgMapImg.getDrawable: Failed to download data, retrying. Attempt #" + (i + 1));
+
+ try {
+ client = new DefaultHttpClient();
+ getMethod = new HttpGet(url);
+ httpResponse = client.execute(getMethod);
+ entity = httpResponse.getEntity();
+
+ // if image is to small, don't download and save, there is no map data for this zoom level
+ long contentSize = entity.getContentLength();
+ if (contentSize > 0 && contentSize <= MIN_MAP_IMAGE_BYTES) {
+ break;
+ }
+
+ bufferedEntity = new BufferedHttpEntity(entity);
+ if (bufferedEntity != null) {
+ InputStream is = (InputStream)bufferedEntity.getContent();
+ FileOutputStream fos = new FileOutputStream(fileName);
+
+ int fileSize = 0;
+ try {
+ byte[] buffer = new byte[4096];
+ int bytesRead;
+ while ((bytesRead = is.read(buffer)) != -1) {
+ fos.write(buffer, 0, bytesRead);
+ fileSize += bytesRead;
+ }
+ ok = true;
+ } catch (IOException e) {
+ Log.e(cgSettings.tag, "cgMapImg.getDrawable (saving to cache): " + e.toString());
+ } finally {
+ is.close();
+ fos.flush();
+ fos.close();
+ }
+
+ bufferedEntity = null;
+
+ // delete image if it has no contents
+ if (ok && fileSize < MIN_MAP_IMAGE_BYTES) {
+ (new File(fileName)).delete();
+ }
+ }
+
+ if (ok == true) {
+ break;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapImg.getDrawable (downloading from web): " + e.toString());
+ }
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgOAuth.java b/src/cgeo/geocaching/cgOAuth.java
new file mode 100644
index 0000000..8897993
--- /dev/null
+++ b/src/cgeo/geocaching/cgOAuth.java
@@ -0,0 +1,53 @@
+package cgeo.geocaching;
+
+import java.util.Date;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class cgOAuth {
+ public static String signOAuth(String host, String path, String method, boolean https, HashMap<String, String> params, String token, String tokenSecret) {
+ String paramsDone = "";
+ if (method.equalsIgnoreCase("GET") == false && method.equalsIgnoreCase("POST") == false) {
+ method = "POST";
+ } else {
+ method = method.toUpperCase();
+ }
+
+ if (token == null) token = "";
+ if (tokenSecret == null) tokenSecret = "";
+
+ long currentTime = new Date().getTime(); // miliseconds
+ currentTime = currentTime / 1000; // seconds
+ currentTime = (long)Math.floor(currentTime);
+
+ params.put("oauth_consumer_key", cgSettings.keyConsumerPublic);
+ params.put("oauth_nonce", cgBase.md5(Long.toString(System.currentTimeMillis())));
+ params.put("oauth_signature_method", "HMAC-SHA1");
+ params.put("oauth_timestamp", Long.toString(currentTime));
+ params.put("oauth_token", token);
+ params.put("oauth_version", "1.0");
+
+ Object[] keys = params.keySet().toArray();
+ Arrays.sort(keys);
+
+ ArrayList<String> paramsEncoded = new ArrayList<String>();
+ for (int i = 0; i < keys.length; i++) {
+ String value = params.get(keys[i].toString());
+
+ paramsEncoded.add(keys[i] + "=" + cgBase.urlencode_rfc3986(value.toString()));
+ }
+
+ String keysPacked;
+ String requestPacked;
+
+ keysPacked = cgSettings.keyConsumerSecret + "&" + tokenSecret; // both even if empty some of them!
+ if (https == true) requestPacked = method + "&" + cgBase.urlencode_rfc3986("https://" + host + path) + "&" + cgBase.urlencode_rfc3986(cgBase.implode("&", paramsEncoded.toArray()));
+ else requestPacked = method + "&" + cgBase.urlencode_rfc3986("http://" + host + path) + "&" + cgBase.urlencode_rfc3986(cgBase.implode("&", paramsEncoded.toArray()));
+ paramsEncoded.add("oauth_signature=" + cgBase.urlencode_rfc3986(cgBase.base64Encode(cgBase.hashHmac(requestPacked, keysPacked))));
+
+ paramsDone = cgBase.implode("&", paramsEncoded.toArray());
+
+ return paramsDone;
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgRating.java b/src/cgeo/geocaching/cgRating.java
new file mode 100644
index 0000000..374ae7c
--- /dev/null
+++ b/src/cgeo/geocaching/cgRating.java
@@ -0,0 +1,7 @@
+package cgeo.geocaching;
+
+public class cgRating {
+ public Float rating = null;
+ public Integer votes = null;
+ public Float myVote = null;
+}
diff --git a/src/cgeo/geocaching/cgResponse.java b/src/cgeo/geocaching/cgResponse.java
new file mode 100644
index 0000000..6735d85
--- /dev/null
+++ b/src/cgeo/geocaching/cgResponse.java
@@ -0,0 +1,40 @@
+package cgeo.geocaching;
+
+public class cgResponse {
+ private String url;
+ private int statusCode;
+ private String statusMessage;
+ private String data;
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setStatusCode(int code) {
+ statusCode = code;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public void setStatusMessage(String message) {
+ statusMessage = message;
+ }
+
+ public String getStatusMessage() {
+ return statusMessage;
+ }
+
+ public void setData(String data) {
+ this.data = data;
+ }
+
+ public String getData() {
+ return data;
+ }
+}
diff --git a/src/cgeo/geocaching/cgSearch.java b/src/cgeo/geocaching/cgSearch.java
new file mode 100644
index 0000000..a6638e5
--- /dev/null
+++ b/src/cgeo/geocaching/cgSearch.java
@@ -0,0 +1,39 @@
+package cgeo.geocaching;
+
+import java.util.ArrayList;
+
+public class cgSearch {
+ private Long id = null;
+ private ArrayList<String> geocodes = new ArrayList<String>();
+
+ public int errorRetrieve = 0;
+ public String error = null;
+ public String url = "";
+ public String viewstate = "";
+ public String viewstate1 = "";
+ public int totalCnt = 0;
+
+ public cgSearch() {
+ id = System.currentTimeMillis(); // possible collisions here - not guaranteed to be unique
+ }
+
+ public Long getCurrentId() {
+ return id;
+ }
+
+ public ArrayList<String> getGeocodes() {
+ return geocodes;
+ }
+
+ public int getCount() {
+ return geocodes.size();
+ }
+
+ public void addGeocode(String geocode) {
+ if (geocodes == null) {
+ geocodes = new ArrayList<String>();
+ }
+
+ geocodes.add(geocode);
+ }
+}
diff --git a/src/cgeo/geocaching/cgSearchHandler.java b/src/cgeo/geocaching/cgSearchHandler.java
new file mode 100644
index 0000000..3563c6d
--- /dev/null
+++ b/src/cgeo/geocaching/cgSearchHandler.java
@@ -0,0 +1,104 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.ImageView;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+public class cgSearchHandler extends Handler {
+ private Activity activity = null;
+ private Resources res = null;
+ private cgSearchThread recaptchaThread = null;
+ private ImageView imageView = null;
+ private Bitmap img = null;
+
+ private Handler imgHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (img != null && imageView != null) {
+ imageView.setImageBitmap(img);
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ };
+
+ public cgSearchHandler(Activity activityIn, Resources resIn, cgSearchThread recaptchaThreadIn) {
+ activity = activityIn;
+ res = resIn;
+ recaptchaThread = recaptchaThreadIn;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (msg.what == 1) {
+ final AlertDialog.Builder dlg = new AlertDialog.Builder(activity);
+ final LayoutInflater inflater = activity.getLayoutInflater();
+ final View view = inflater.inflate(R.layout.recaptcha_dialog, null);
+
+ imageView = (ImageView) view.findViewById(R.id.image);
+
+ (new getCaptcha(new URL("http://www.google.com/recaptcha/api/image?c=" + recaptchaThread.getChallenge()))).start();
+
+ dlg.setTitle(res.getString(R.string.caches_recaptcha_title));
+ dlg.setView(view);
+ dlg.setNeutralButton(res.getString(R.string.caches_recaptcha_continue), new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ final String text = ((EditText) view.findViewById(R.id.text)).getText().toString();
+
+ recaptchaThread.setText(text);
+
+ dialog.cancel();
+ }
+ });
+
+ dlg.create().show();
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ private class getCaptcha extends Thread {
+ private URL uri = null;
+
+ public getCaptcha(URL uriIn) {
+ uri = uriIn;
+ }
+
+ @Override
+ public void run() {
+ try {
+ HttpURLConnection connection = (HttpURLConnection)uri.openConnection();
+ connection.setDoInput(true);
+ connection.connect();
+
+ InputStream is = connection.getInputStream();
+
+ img = BitmapFactory.decodeStream(is);
+
+ is.close();
+
+ imgHandler.sendEmptyMessage(0);
+ } catch (IOException e) {
+ Log.e(cgSettings.tag, "Failed to download reCAPTCHA image");
+ }
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgSearchThread.java b/src/cgeo/geocaching/cgSearchThread.java
new file mode 100644
index 0000000..0cd99ce
--- /dev/null
+++ b/src/cgeo/geocaching/cgSearchThread.java
@@ -0,0 +1,46 @@
+package cgeo.geocaching;
+
+import android.os.Handler;
+import android.util.Log;
+
+public class cgSearchThread extends Thread {
+ private Handler recaptchaHandler = null;
+ private String recaptchaChallenge = null;
+ private String recaptchaText = null;
+
+ public void setRecaptchaHandler(Handler recaptchaHandlerIn) {
+ recaptchaHandler = recaptchaHandlerIn;
+ }
+
+ public void notifyNeed() {
+ if (recaptchaHandler != null) {
+ recaptchaHandler.sendEmptyMessage(1);
+ }
+ }
+
+ public synchronized void waitForUser() {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ Log.w(cgSettings.tag, "searchThread is not waiting for user...");
+ }
+ }
+
+ public void setChallenge(String challenge) {
+ recaptchaChallenge = challenge;
+ }
+
+ public String getChallenge() {
+ return recaptchaChallenge;
+ }
+
+ public synchronized void setText(String text) {
+ recaptchaText = text;
+
+ notify();
+ }
+
+ public String getText() {
+ return recaptchaText;
+ }
+}
diff --git a/src/cgeo/geocaching/cgSettings.java b/src/cgeo/geocaching/cgSettings.java
new file mode 100644
index 0000000..b88de0b
--- /dev/null
+++ b/src/cgeo/geocaching/cgSettings.java
@@ -0,0 +1,513 @@
+package cgeo.geocaching;
+
+import java.util.Locale;
+import java.util.Map;
+import java.util.HashMap;
+
+import cgeo.geocaching.googlemaps.googleMapFactory;
+import cgeo.geocaching.mapinterfaces.MapFactory;
+import cgeo.geocaching.mapsforge.mfMapFactory;
+import android.os.Environment;
+import android.content.Intent;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.util.Log;
+
+public class cgSettings {
+
+ public enum mapSourceEnum {
+ googleMap,
+ mapsforgeMapnik,
+ mapsforgeOsmarender,
+ mapsforgeCycle,
+ mapsforgeOffline;
+
+ static mapSourceEnum fromInt(int id) {
+ mapSourceEnum[] values = mapSourceEnum.values();
+ if (id >= 0 && id < values.length) {
+ return values[id];
+ } else {
+ return googleMap;
+ }
+ }
+ }
+
+ // constants
+ public final static int unitsMetric = 1;
+ public final static int unitsImperial = 2;
+ public final static int mapSatellite = 1;
+ public final static int mapClassic = 2;
+ public final static String cache = ".cgeo";
+ public final static String analytics = "UA-1103507-15";
+
+ // twitter api keys
+ public final static String keyConsumerPublic = "RFafPiNi3xRhcS1TPE3wTw";
+ public final static String keyConsumerSecret = "7iDJprNPI9hzRwWhpzycSr9SPZMFrdVdsxD2OauI9k";
+
+ // version
+ public int version = 0;
+
+ // skin
+ public int skin = 0;
+ public int buttonActive = R.drawable.action_button_dark;
+ public int buttonInactive = R.drawable.action_button_dark_off;
+ public int buttonPressed = R.drawable.action_button_dark_pressed;
+
+ // settings
+ public boolean loaded = false;
+ public boolean hideMySearch = false;
+ public int helper = 0;
+ public int initialized = 0;
+ public String languages = null;
+ public int cachesFound = 0;
+ public int autoLoadDesc = 0;
+ public int units = unitsMetric;
+ public int livelist = 1;
+ public int maptype = mapSatellite;
+ public int mapzoom = 14;
+ public int maplive = 1;
+ public int maptrail = 1;
+ public boolean useEnglish = false;
+ public boolean showCaptcha = false;
+ public int excludeMine = 0;
+ public int excludeDisabled = 0;
+ public int storeOfflineMaps = 0;
+ public int asBrowser = 1;
+ public int useCompass = 1;
+ public int useGNavigation = 1;
+ public int showAddress = 1;
+ public int publicLoc = 0;
+ public int twitter = 0;
+ public int altCorrection = 0;
+ public String signature = null;
+ public String cacheType = null;
+ public String tokenPublic = null;
+ public String tokenSecret = null;
+ public String webDeviceName = null;
+ public String webDeviceCode = null;
+
+ // usable values
+ public static final String tag = "c:geo";
+
+ // preferences file
+ public static final String preferences = "cgeo.pref";
+
+ // private variables
+ private Context context = null;
+ private SharedPreferences prefs = null;
+ private String username = null;
+ private String password = null;
+ private String passVote = null;
+
+ // maps
+ public static final int MAP_GOOGLE = 0;
+ public static final int MAP_MF = 1;
+ public MapFactory mapFactory = null;
+ public mapSourceEnum mapProviderUsed = mapSourceEnum.googleMap;
+ public mapSourceEnum mapProvider = mapSourceEnum.googleMap;
+ public String mapFile = null;
+
+ public cgSettings(Context contextIn, SharedPreferences prefsIn) {
+ context = contextIn;
+ prefs = prefsIn;
+
+ load();
+ }
+
+ public void load() {
+ version = prefs.getInt("version", 0);
+
+ initialized = prefs.getInt("initialized", 0);
+ helper = prefs.getInt("helper", 0);
+
+ skin = prefs.getInt("skin", 0);
+ setSkinDefaults();
+
+ languages = prefs.getString("languages", null);
+ cachesFound = prefs.getInt("found", 0);
+ autoLoadDesc = prefs.getInt("autoloaddesc", 0);
+ units = prefs.getInt("units", 1);
+ livelist = prefs.getInt("livelist", 1);
+ maptype = prefs.getInt("maptype", 1);
+ maplive = prefs.getInt("maplive", 1);
+ mapzoom = prefs.getInt("mapzoom", 14);
+ maptrail = prefs.getInt("maptrail", 1);
+ useEnglish = prefs.getBoolean("useenglish", false);
+ showCaptcha = prefs.getBoolean("showcaptcha", false);
+ excludeMine = prefs.getInt("excludemine", 0);
+ excludeDisabled = prefs.getInt("excludedisabled", 0);
+ storeOfflineMaps = prefs.getInt("offlinemaps", 1);
+ asBrowser = prefs.getInt("asbrowser", 1);
+ useCompass = prefs.getInt("usecompass", 1);
+ useGNavigation = prefs.getInt("usegnav", 1);
+ showAddress = prefs.getInt("showaddress", 1);
+ publicLoc = prefs.getInt("publicloc", 0);
+ twitter = prefs.getInt("twitter", 0);
+ altCorrection = prefs.getInt("altcorrection", 0);
+ signature = prefs.getString("signature", null);
+ cacheType = prefs.getString("cachetype", null);
+ tokenPublic = prefs.getString("tokenpublic", null);
+ tokenSecret = prefs.getString("tokensecret", null);
+ mapFile = prefs.getString("mfmapfile", null);
+ mapProvider = mapSourceEnum.fromInt(prefs.getInt("mapsource", 0));
+ webDeviceName = prefs.getString("webDeviceName", null);
+ webDeviceCode = prefs.getString("webDeviceCode", null);
+
+ setLanguage(useEnglish);
+ }
+
+ private void setSkinDefaults() {
+ if (skin == 1) {
+ buttonActive = R.drawable.action_button_light;
+ buttonInactive = R.drawable.action_button_light_off;
+ buttonPressed = R.drawable.action_button_light_pressed;
+ } else {
+ skin = 0;
+ buttonActive = R.drawable.action_button_dark;
+ buttonInactive = R.drawable.action_button_dark_off;
+ buttonPressed = R.drawable.action_button_dark_pressed;
+ }
+ }
+
+ public void setSkin(int skinIn) {
+ if (skin == 1) {
+ skin = 1;
+ setSkinDefaults();
+ } else {
+ skin = 0;
+ setSkinDefaults();
+ }
+ }
+
+ public void setLanguage(boolean useEnglish) {
+ Locale locale = Locale.getDefault();
+ if (useEnglish) {
+ locale = new Locale("en");
+ }
+ Configuration config = new Configuration();
+ config.locale = locale;
+ context.getResources().updateConfiguration(config,
+ context.getResources().getDisplayMetrics());
+ }
+
+ public void reloadTwitterTokens() {
+ tokenPublic = prefs.getString("tokenpublic", null);
+ tokenSecret = prefs.getString("tokensecret", null);
+ }
+
+ public void reloadCacheType() {
+ cacheType = prefs.getString("cachetype", null);
+ }
+
+ public String getStorage() {
+ return getStorageSpecific(null)[0];
+ }
+
+ public String getStorageSec() {
+ return getStorageSpecific(null)[1];
+ }
+
+ public String[] getStorageSpecific(Boolean hidden) {
+ String[] storage = new String[2];
+
+ if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ storage[0] = Environment.getExternalStorageDirectory() + "/" + cache + "/";
+ storage[1] = Environment.getDataDirectory() + "/data/cgeo.geocaching/" + cache + "/";
+ } else {
+ storage[0] = Environment.getDataDirectory() + "/data/cgeo.geocaching/" + cache + "/";
+ storage[1] = Environment.getExternalStorageDirectory() + "/" + cache + "/";
+ }
+
+ return storage;
+ }
+
+ public boolean isLogin() {
+ final String preUsername = prefs.getString("username", null);
+ final String prePassword = prefs.getString("password", null);
+
+ if (preUsername == null || prePassword == null || preUsername.length() == 0 || prePassword.length() == 0) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ public HashMap<String, String> getLogin() {
+ final HashMap<String, String> login = new HashMap<String, String>();
+
+ if (username == null || password == null) {
+ final String preUsername = prefs.getString("username", null);
+ final String prePassword = prefs.getString("password", null);
+
+ if (initialized == 0 && (preUsername == null || prePassword == null)) {
+ Intent initIntent = new Intent(context, cgeoinit.class);
+ context.startActivity(initIntent);
+
+ final SharedPreferences.Editor prefsEdit = prefs.edit();
+ prefsEdit.putInt("initialized", 1);
+ prefsEdit.commit();
+
+ initialized = 1;
+
+ return null;
+ } else if (initialized == 1 && (preUsername == null || prePassword == null)) {
+ return null;
+ }
+
+ login.put("username", preUsername);
+ login.put("password", prePassword);
+
+ username = preUsername;
+ password = prePassword;
+ } else {
+ login.put("username", username);
+ login.put("password", password);
+ }
+
+ return login;
+ }
+
+ public String getUsername() {
+ String user = null;
+
+ if (username == null) {
+ user = prefs.getString("username", null);
+ } else {
+ user = username;
+ }
+
+ return user;
+ }
+
+ public boolean setLogin(String username, String password) {
+ final SharedPreferences.Editor prefsEdit = prefs.edit();
+
+ if (username == null || username.length() == 0 || password == null || password.length() == 0) {
+ // erase username and password
+ prefsEdit.remove("username");
+ prefsEdit.remove("password");
+ } else {
+ // save username and password
+ prefsEdit.putString("username", username);
+ prefsEdit.putString("password", password);
+ }
+
+ this.username = username;
+ this.password = password;
+
+ return prefsEdit.commit();
+ }
+
+ public boolean isGCvoteLogin() {
+ final String preUsername = prefs.getString("username", null);
+ final String prePassword = prefs.getString("pass-vote", null);
+
+ if (preUsername == null || prePassword == null || preUsername.length() == 0 || prePassword.length() == 0) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ public boolean setGCvoteLogin(String password) {
+ final SharedPreferences.Editor prefsEdit = prefs.edit();
+
+ if (password == null || password.length() == 0) {
+ // erase password
+ prefsEdit.remove("pass-vote");
+ } else {
+ // save password
+ prefsEdit.putString("pass-vote", password);
+ }
+
+ passVote = password;
+
+ return prefsEdit.commit();
+ }
+
+ public HashMap<String, String> getGCvoteLogin() {
+ final HashMap<String, String> login = new HashMap<String, String>();
+
+ if (username == null || password == null) {
+ final String preUsername = prefs.getString("username", null);
+ final String prePassword = prefs.getString("pass-vote", null);
+
+ if (preUsername == null || prePassword == null) {
+ return null;
+ }
+
+ login.put("username", preUsername);
+ login.put("password", prePassword);
+
+ username = preUsername;
+ passVote = prePassword;
+ } else {
+ login.put("username", username);
+ login.put("password", password);
+ }
+
+ return login;
+ }
+
+ public boolean setSignature(String signature) {
+ final SharedPreferences.Editor prefsEdit = prefs.edit();
+
+ if (signature == null || signature.length() == 0) {
+ // erase signature
+ prefsEdit.remove("signature");
+ } else {
+ // save signature
+ prefsEdit.putString("signature", signature);
+ }
+
+ this.signature = signature;
+
+ return prefsEdit.commit();
+ }
+
+ public String getSignature() {
+ return prefs.getString("signature", null);
+ }
+
+ public boolean setLanguages(String languages) {
+ final SharedPreferences.Editor prefsEdit = prefs.edit();
+
+ if (languages == null || languages.length() == 0) {
+ // erase languages
+ prefsEdit.remove("languages");
+ } else {
+ // save langauges
+ languages = languages.toLowerCase();
+ languages = languages.replaceAll("([^a-z]+)", " ");
+ languages = languages.replaceAll("([ ]+)", " ");
+
+ prefsEdit.putString("languages", languages);
+ }
+
+ this.languages = languages;
+
+ return prefsEdit.commit();
+ }
+
+ public boolean setAltCorrection(int altitude) {
+ final SharedPreferences.Editor prefsEdit = prefs.edit();
+
+ prefsEdit.putInt("altcorrection", altitude);
+
+ altCorrection = altitude;
+
+ return prefsEdit.commit();
+ }
+
+ public String getLanguages() {
+ return prefs.getString("languages", null);
+ }
+
+ public void deleteCookies() {
+ SharedPreferences.Editor prefsEdit = prefs.edit();
+
+ // delete cookies
+ Map<String, ?> prefsValues = prefs.getAll();
+
+ if (prefsValues != null && prefsValues.size() > 0) {
+ Log.i(cgSettings.tag, "Removing cookies");
+
+ Object[] keys = prefsValues.keySet().toArray();
+
+ for (int i = 0; i < keys.length; i++) {
+ if (keys[i].toString().length() > 7 && keys[i].toString().substring(0, 7).equals("cookie_") == true) {
+ prefsEdit.remove(keys[i].toString());
+ }
+ }
+ }
+
+ prefsEdit.commit();
+ }
+
+ public String setCacheType(String cacheTypeIn) {
+ final SharedPreferences.Editor edit = prefs.edit();
+ edit.putString("cachetype", cacheTypeIn);
+ edit.commit();
+
+ cacheType = cacheTypeIn;
+
+ return cacheType;
+ }
+
+ public void liveMapEnable() {
+ final SharedPreferences.Editor edit = prefs.edit();
+ edit.putInt("maplive", 1);
+
+ if (edit.commit() == true) {
+ maplive = 1;
+ }
+ }
+
+ public void liveMapDisable() {
+ final SharedPreferences.Editor edit = prefs.edit();
+ edit.putInt("maplive", 0);
+
+ if (edit.commit() == true) {
+ maplive = 0;
+ }
+ }
+
+ public int getLastList() {
+ int listId = prefs.getInt("lastlist", -1);
+
+ return listId;
+ }
+
+ public void saveLastList(int listId) {
+ final SharedPreferences.Editor edit = prefs.edit();
+
+ edit.putInt("lastlist", listId);
+ edit.commit();
+ }
+
+ public void setWebNameCode(String name, String code) {
+ final SharedPreferences.Editor edit = prefs.edit();
+
+ this.webDeviceCode=code;
+ this.webDeviceName=name;
+
+ edit.putString("webDeviceName", name);
+ edit.putString("webDeviceCode", code);
+ edit.commit();
+ }
+
+ public MapFactory getMapFactory() {
+ if (mapProvider == mapSourceEnum.googleMap) {
+ if (mapProviderUsed != mapSourceEnum.googleMap || mapFactory == null) {
+ mapFactory = new googleMapFactory();
+ mapProviderUsed = mapProvider;
+ }
+ } else if (mapProvider != mapSourceEnum.googleMap) {
+ if (mapProviderUsed == mapSourceEnum.googleMap || mapFactory == null) {
+ mapFactory = new mfMapFactory();
+ mapProviderUsed = mapProvider;
+ }
+ }
+
+ return mapFactory;
+ }
+
+ public String getMapFile() {
+ return mapFile;
+ }
+
+ public boolean setMapFile(String mapFileIn) {
+ final SharedPreferences.Editor prefsEdit = prefs.edit();
+
+ prefsEdit.putString("mfmapfile", mapFileIn);
+
+ mapFile = mapFileIn;
+
+ return prefsEdit.commit();
+ }
+
+ public Context getContext() {
+ return context;
+ }
+}
diff --git a/src/cgeo/geocaching/cgSpoiler.java b/src/cgeo/geocaching/cgSpoiler.java
new file mode 100644
index 0000000..fca5648
--- /dev/null
+++ b/src/cgeo/geocaching/cgSpoiler.java
@@ -0,0 +1,7 @@
+package cgeo.geocaching;
+
+public class cgSpoiler {
+ public String url = "";
+ public String title = "";
+ public String description = "";
+}
diff --git a/src/cgeo/geocaching/cgTrackable.java b/src/cgeo/geocaching/cgTrackable.java
new file mode 100644
index 0000000..2244fc7
--- /dev/null
+++ b/src/cgeo/geocaching/cgTrackable.java
@@ -0,0 +1,35 @@
+package cgeo.geocaching;
+
+import android.text.Spannable;
+import java.util.ArrayList;
+import java.util.Date;
+
+public class cgTrackable {
+ static public int SPOTTED_UNSET = 0;
+ static public int SPOTTED_CACHE = 1;
+ static public int SPOTTED_USER = 2;
+ static public int SPOTTED_UNKNOWN = 3;
+ static public int SPOTTED_OWNER = 4;
+
+ public int errorRetrieve = 0;
+ public String error = "";
+ public String guid = "";
+ public String geocode = "";
+ public String iconUrl = "";
+ public String name = "";
+ public String nameString = null;
+ public Spannable nameSp = null;
+ public String type = null;
+ public Date released = null;
+ public Double distance = null;
+ public String origin = null;
+ public String owner = null;
+ public String ownerGuid = null;
+ public String spottedName = null;
+ public int spottedType = SPOTTED_UNSET;
+ public String spottedGuid = null;
+ public String goal = null;
+ public String details = null;
+ public String image = null;
+ public ArrayList<cgLog> logs = new ArrayList<cgLog>();
+}
diff --git a/src/cgeo/geocaching/cgTrackableLog.java b/src/cgeo/geocaching/cgTrackableLog.java
new file mode 100644
index 0000000..7522d8d
--- /dev/null
+++ b/src/cgeo/geocaching/cgTrackableLog.java
@@ -0,0 +1,9 @@
+package cgeo.geocaching;
+
+public class cgTrackableLog {
+ public int ctl = -1;
+ public int id = -1;
+ public String trackCode = null;
+ public String name = null;
+ public int action = 0; // base.logTrackablesAction - no action
+}
diff --git a/src/cgeo/geocaching/cgUpdateDir.java b/src/cgeo/geocaching/cgUpdateDir.java
new file mode 100644
index 0000000..01346ec
--- /dev/null
+++ b/src/cgeo/geocaching/cgUpdateDir.java
@@ -0,0 +1,7 @@
+package cgeo.geocaching;
+
+public class cgUpdateDir {
+ public void updateDir(cgDirection dir) {
+ // to be overriden
+ }
+}
diff --git a/src/cgeo/geocaching/cgUpdateLoc.java b/src/cgeo/geocaching/cgUpdateLoc.java
new file mode 100644
index 0000000..3c063f2
--- /dev/null
+++ b/src/cgeo/geocaching/cgUpdateLoc.java
@@ -0,0 +1,7 @@
+package cgeo.geocaching;
+
+public class cgUpdateLoc {
+ public void updateLoc(cgGeo geo) {
+ // to be overriden
+ }
+}
diff --git a/src/cgeo/geocaching/cgUser.java b/src/cgeo/geocaching/cgUser.java
new file mode 100644
index 0000000..1389de8
--- /dev/null
+++ b/src/cgeo/geocaching/cgUser.java
@@ -0,0 +1,12 @@
+package cgeo.geocaching;
+
+import java.util.Date;
+
+public class cgUser {
+ public Date located = null;
+ public String username = null;
+ public Double latitude = null;
+ public Double longitude = null;
+ public String action = null;
+ public String client = null;
+}
diff --git a/src/cgeo/geocaching/cgWarning.java b/src/cgeo/geocaching/cgWarning.java
new file mode 100644
index 0000000..93ddec7
--- /dev/null
+++ b/src/cgeo/geocaching/cgWarning.java
@@ -0,0 +1,52 @@
+package cgeo.geocaching;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.widget.Toast;
+import android.view.Gravity;
+
+public class cgWarning {
+ public Context context = null;
+
+ public cgWarning(Context contextIn) {
+ context = contextIn;
+ }
+
+ public void showToast(String text) {
+ if (text.length() > 0) {
+ Toast toast = Toast.makeText(context, text, Toast.LENGTH_LONG);
+
+ toast.setGravity(Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM, 0, 100);
+ toast.show();
+ }
+ }
+
+ public void showShortToast(String text) {
+ if (text.length() > 0) {
+ Toast toast = Toast.makeText(context, text, Toast.LENGTH_SHORT);
+
+ toast.setGravity(Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM, 0, 100);
+ toast.show();
+ }
+ }
+
+ public void helpDialog(String title, String message) {
+ if (message == null || message.length() == 0) {
+ return;
+ }
+
+ AlertDialog.Builder dialog = new AlertDialog.Builder(context);
+ dialog.setTitle(title);
+ dialog.setMessage(message);
+ dialog.setCancelable(true);
+ dialog.setNeutralButton("Ok", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ }
+}
diff --git a/src/cgeo/geocaching/cgWaypoint.java b/src/cgeo/geocaching/cgWaypoint.java
new file mode 100644
index 0000000..d3f703c
--- /dev/null
+++ b/src/cgeo/geocaching/cgWaypoint.java
@@ -0,0 +1,16 @@
+package cgeo.geocaching;
+
+public class cgWaypoint {
+ public Integer id = 0;
+ public String geocode = "geocode";
+ public String type = "waypoint";
+ public String prefix = "";
+ public String lookup = "";
+ public String name = "";
+ public String latlon = "";
+ public String latitudeString = "";
+ public String longitudeString = "";
+ public Double latitude = null;
+ public Double longitude = null;
+ public String note = "";
+}
diff --git a/src/cgeo/geocaching/cgeo.java b/src/cgeo/geocaching/cgeo.java
new file mode 100644
index 0000000..67ff74a
--- /dev/null
+++ b/src/cgeo/geocaching/cgeo.java
@@ -0,0 +1,669 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.app.Activity;
+import android.view.View;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.Button;
+import android.widget.TextView;
+import android.content.Intent;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.location.Address;
+import android.location.Geocoder;
+import android.os.Message;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map.Entry;
+
+public class cgeo extends Activity {
+
+ private Resources res = null;
+ private cgeoapplication app = null;
+ private Context context = null;
+ private cgSettings settings = null;
+ private SharedPreferences prefs = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private Integer version = null;
+ private cgGeo geo = null;
+ private cgUpdateLoc geoUpdate = new update();
+ private TextView navType = null;
+ private TextView navAccuracy = null;
+ private TextView navSatellites = null;
+ private TextView navLocation = null;
+ private TextView filterTitle = null;
+ private TextView countBubble = null;
+ private boolean cleanupRunning = false;
+ private int countBubbleCnt = 0;
+ private Double addLat = null;
+ private Double addLon = null;
+ private List<Address> addresses = null;
+ private boolean addressObtaining = false;
+ private boolean initialized = false;
+ private Handler countBubbleHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (countBubble == null) {
+ countBubble = (TextView) findViewById(R.id.offline_count);
+ }
+
+ if (countBubbleCnt == 0) {
+ countBubble.setVisibility(View.GONE);
+ } else {
+ countBubble.setText(Integer.toString(countBubbleCnt));
+ countBubble.bringToFront();
+ countBubble.setVisibility(View.VISIBLE);
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgeo.countBubbleHander: " + e.toString());
+ }
+ }
+ };
+ private Handler obtainAddressHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (addresses != null && addresses.isEmpty() == false) {
+ final Address address = addresses.get(0);
+ final StringBuilder addText = new StringBuilder();
+
+ if (address.getCountryName() != null) {
+ addText.append(address.getCountryName());
+ }
+ if (address.getLocality() != null) {
+ if (addText.length() > 0) {
+ addText.append(", ");
+ }
+ addText.append(address.getLocality());
+ } else if (address.getAdminArea() != null) {
+ if (addText.length() > 0) {
+ addText.append(", ");
+ }
+ addText.append(address.getAdminArea());
+ }
+
+ addLat = geo.latitudeNow;
+ addLon = geo.longitudeNow;
+
+ if (navLocation == null) {
+ navLocation = (TextView) findViewById(R.id.nav_location);
+ }
+
+ navLocation.setText(addText.toString());
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+
+ addresses = null;
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ context = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ app.setAction(null);
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ prefs = getSharedPreferences(cgSettings.preferences, 0);
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ app.cleanGeo();
+ app.cleanDir();
+
+ setContentView(R.layout.main);
+ setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); // type to search
+
+ try {
+ PackageManager manager = this.getPackageManager();
+ PackageInfo info = manager.getPackageInfo(this.getPackageName(), 0);
+
+ version = info.versionCode;
+
+ base.sendAnal(context, "/?ver=" + info.versionCode);
+ Log.i(cgSettings.tag, "Starting " + info.packageName + " " + info.versionCode + " a.k.a " + info.versionName + "...");
+
+ info = null;
+ manager = null;
+ } catch (Exception e) {
+ base.sendAnal(context, "/");
+ Log.i(cgSettings.tag, "No info.");
+ }
+
+ try {
+ if (settings.helper == 0) {
+ RelativeLayout helper = (RelativeLayout) findViewById(R.id.helper);
+ if (helper != null) {
+ helper.setVisibility(View.VISIBLE);
+ helper.setClickable(true);
+ helper.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-intro",
+ context,
+ "http://cgeo.carnero.cc/manual/");
+ } catch (Exception e) {
+ // nothing
+ }
+
+ view.setVisibility(View.GONE);
+ }
+ });
+
+ final SharedPreferences.Editor edit = getSharedPreferences(cgSettings.preferences, 0).edit();
+ edit.putInt("helper", 1);
+ edit.commit();
+ }
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+
+ init();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ init();
+ }
+
+ @Override
+ public void onDestroy() {
+ initialized = false;
+
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStop() {
+ initialized = false;
+
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ initialized = false;
+
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onPause();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(0, 0, 0, res.getString(R.string.menu_about)).setIcon(android.R.drawable.ic_menu_help);
+ menu.add(0, 1, 0, res.getString(R.string.menu_helpers)).setIcon(android.R.drawable.ic_menu_add);
+ menu.add(0, 2, 0, res.getString(R.string.menu_settings)).setIcon(android.R.drawable.ic_menu_preferences);
+ menu.add(0, 3, 0, res.getString(R.string.menu_history)).setIcon(android.R.drawable.ic_menu_recent_history);
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ final int id = item.getItemId();
+ if (id == 0) {
+ showAbout(null);
+
+ return true;
+ } else if (id == 1) {
+ context.startActivity(new Intent(context, cgeohelpers.class));
+
+ return true;
+ } else if (id == 2) {
+ context.startActivity(new Intent(context, cgeoinit.class));
+
+ return true;
+ } else if (id == 3) {
+ final Intent cachesIntent = new Intent(context, cgeocaches.class);
+ cachesIntent.putExtra("type", "history");
+ context.startActivity(cachesIntent);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ menu.setHeaderTitle(res.getString(R.string.menu_filter));
+
+ //first add the most used types
+ menu.add(1, 0, 0, res.getString(R.string.all_types));
+ menu.add(1, 1, 0, res.getString(R.string.traditional));
+ menu.add(1, 2, 0, res.getString(R.string.multi));
+ menu.add(1, 3, 0, res.getString(R.string.mystery));
+
+ // then add all other cache types sorted alphabetically
+ HashMap<String, String> allTypes = (HashMap<String, String>) base.cacheTypesInv.clone();
+ allTypes.remove("traditional");
+ allTypes.remove("multi");
+ allTypes.remove("mystery");
+ ArrayList<String> sorted = new ArrayList<String>(allTypes.values());
+ Collections.sort(sorted);
+ for (String choice : sorted) {
+ menu.add(1, menu.size(), 0, choice);
+ }
+
+ // mark current filter as checked
+ menu.setGroupCheckable(1, true, true);
+ boolean foundItem = false;
+ int itemCount = menu.size();
+ if (settings.cacheType != null) {
+ String typeTitle = cgBase.cacheTypesInv.get(settings.cacheType);
+ if (typeTitle != null) {
+ for (int i = 0; i < itemCount; i++) {
+ if (menu.getItem(i).getTitle().equals(typeTitle)) {
+ menu.getItem(i).setChecked(true);
+ foundItem = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!foundItem) {
+ menu.getItem(0).setChecked(true);
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ final int id = item.getItemId();
+
+ if (id == 0) {
+ settings.setCacheType(null);
+ setFilterTitle();
+
+ return true;
+ } else if (id > 0) {
+ String itemTitle = item.getTitle().toString();
+ String choice = null;
+ for (Entry<String, String> entry : cgBase.cacheTypesInv.entrySet()) {
+ if (entry.getValue().equalsIgnoreCase(itemTitle)) {
+ choice = entry.getKey();
+ break;
+ }
+ }
+ if (choice == null) {
+ settings.setCacheType(null);
+ } else {
+ settings.setCacheType(choice);
+ }
+ setFilterTitle();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private void setFilterTitle() {
+ if (filterTitle == null) {
+ filterTitle = (TextView) findViewById(R.id.filter_button_title);
+ }
+ if (settings.cacheType != null) {
+ filterTitle.setText(cgBase.cacheTypesInv.get(settings.cacheType));
+ } else {
+ filterTitle.setText(res.getString(R.string.all));
+ }
+ }
+
+ private void init() {
+ if (initialized == true) {
+ return;
+ }
+
+ initialized = true;
+
+ settings.getLogin();
+ settings.reloadCacheType();
+
+ if (app.firstRun == true) {
+ new Thread() {
+
+ @Override
+ public void run() {
+ int status = base.login();
+
+ if (status == 1) {
+ app.firstRun = false;
+ }
+ }
+ }.start();
+ }
+
+ (new countBubbleUpdate()).start();
+ (new cleanDatabase()).start();
+
+ if (settings.cacheType != null && cgBase.cacheTypesInv.containsKey(settings.cacheType) == false) {
+ settings.setCacheType(null);
+ }
+
+ if (geo == null) {
+ geo = app.startGeo(context, geoUpdate, base, settings, warning, 0, 0);
+ }
+
+ navType = (TextView) findViewById(R.id.nav_type);
+ navAccuracy = (TextView) findViewById(R.id.nav_accuracy);
+ navLocation = (TextView) findViewById(R.id.nav_location);
+
+ final LinearLayout findOnMap = (LinearLayout) findViewById(R.id.map);
+ findOnMap.setClickable(true);
+ findOnMap.setOnClickListener(new cgeoFindOnMapListener());
+
+ final RelativeLayout findByOffline = (RelativeLayout) findViewById(R.id.search_offline);
+ findByOffline.setClickable(true);
+ findByOffline.setOnClickListener(new cgeoFindByOfflineListener());
+
+ (new countBubbleUpdate()).start();
+
+ final LinearLayout advanced = (LinearLayout) findViewById(R.id.advanced_button);
+ advanced.setClickable(true);
+ advanced.setOnClickListener(new cgeoSearchListener());
+
+ final LinearLayout any = (LinearLayout) findViewById(R.id.any_button);
+ any.setClickable(true);
+ any.setOnClickListener(new cgeoPointListener());
+
+ final LinearLayout filter = (LinearLayout) findViewById(R.id.filter_button);
+ registerForContextMenu(filter);
+ filter.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View view) {
+ openContextMenu(view);
+ }
+ });
+ filter.setClickable(true);
+
+ setFilterTitle();
+ }
+
+ private class update extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+
+ try {
+ if (navType == null || navLocation == null || navAccuracy == null) {
+ navType = (TextView) findViewById(R.id.nav_type);
+ navAccuracy = (TextView) findViewById(R.id.nav_accuracy);
+ navSatellites = (TextView) findViewById(R.id.nav_satellites);
+ navLocation = (TextView) findViewById(R.id.nav_location);
+ }
+
+ if (geo.latitudeNow != null && geo.longitudeNow != null) {
+ LinearLayout findNearest = (LinearLayout) findViewById(R.id.nearest);
+ findNearest.setClickable(true);
+ findNearest.setOnClickListener(new cgeoFindNearestListener());
+
+ String satellites = null;
+ if (geo.satellitesVisible != null && geo.satellitesFixed != null && geo.satellitesFixed > 0) {
+ satellites = res.getString(R.string.loc_sat) + ": " + geo.satellitesFixed + "/" + geo.satellitesVisible;
+ } else if (geo.satellitesVisible != null) {
+ satellites = res.getString(R.string.loc_sat) + ": 0/" + geo.satellitesVisible;
+ } else {
+ satellites = "";
+ }
+ navSatellites.setText(satellites);
+
+ if (geo.gps == -1) {
+ navType.setText(res.getString(R.string.loc_last));
+ } else if (geo.gps == 0) {
+ navType.setText(res.getString(R.string.loc_net));
+ } else {
+ navType.setText(res.getString(R.string.loc_gps));
+ }
+
+ if (geo.accuracyNow != null) {
+ if (settings.units == cgSettings.unitsImperial) {
+ navAccuracy.setText("±" + String.format(Locale.getDefault(), "%.0f", (geo.accuracyNow * 3.2808399)) + " ft");
+ } else {
+ navAccuracy.setText("±" + String.format(Locale.getDefault(), "%.0f", geo.accuracyNow) + " m");
+ }
+ } else {
+ navAccuracy.setText(null);
+ }
+
+ if (settings.showAddress == 1) {
+ if (addLat == null || addLon == null) {
+ navLocation.setText(res.getString(R.string.loc_no_addr));
+ }
+ if (addLat == null || addLon == null || (cgBase.getDistance(geo.latitudeNow, geo.longitudeNow, addLat, addLon) > 0.5 && addressObtaining == false)) {
+ (new obtainAddress()).start();
+ }
+ } else {
+ if (geo.altitudeNow != null) {
+ String humanAlt;
+ if (settings.units == cgSettings.unitsImperial) {
+ humanAlt = String.format("%.0f", (geo.altitudeNow * 3.2808399)) + " ft";
+ } else {
+ humanAlt = String.format("%.0f", geo.altitudeNow) + " m";
+ }
+ navLocation.setText(base.formatCoordinate(geo.latitudeNow, "lat", true) + " | " + base.formatCoordinate(geo.longitudeNow, "lon", true) + " | " + humanAlt);
+ } else {
+ navLocation.setText(base.formatCoordinate(geo.latitudeNow, "lat", true) + " | " + base.formatCoordinate(geo.longitudeNow, "lon", true));
+ }
+ }
+ } else {
+ Button findNearest = (Button) findViewById(R.id.nearest);
+ findNearest.setClickable(false);
+ findNearest.setOnClickListener(null);
+
+ navType.setText(null);
+ navAccuracy.setText(null);
+ navLocation.setText(res.getString(R.string.loc_trying));
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ private class cgeoFindNearestListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ if (geo == null) {
+ return;
+ }
+
+ final Intent cachesIntent = new Intent(context, cgeocaches.class);
+ cachesIntent.putExtra("type", "nearest");
+ cachesIntent.putExtra("latitude", geo.latitudeNow);
+ cachesIntent.putExtra("longitude", geo.longitudeNow);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+ context.startActivity(cachesIntent);
+ }
+ }
+
+ private class cgeoFindOnMapListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ context.startActivity(new Intent(context, settings.getMapFactory().getMapClass()));
+ }
+ }
+
+ private class cgeoFindByOfflineListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ final Intent cachesIntent = new Intent(context, cgeocaches.class);
+ cachesIntent.putExtra("type", "offline");
+ context.startActivity(cachesIntent);
+ }
+ }
+
+ private class cgeoSearchListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ context.startActivity(new Intent(context, cgeoadvsearch.class));
+ }
+ }
+
+ private class cgeoPointListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ context.startActivity(new Intent(context, cgeopoint.class));
+ }
+ }
+
+ private class countBubbleUpdate extends Thread {
+
+ @Override
+ public void run() {
+ if (app == null) {
+ return;
+ }
+
+ int checks = 0;
+ while (app.storageStatus() == false) {
+ try {
+ wait(500);
+ checks++;
+ } catch (Exception e) {
+ // nothing;
+ }
+
+ if (checks > 10) {
+ return;
+ }
+ }
+
+
+ countBubbleCnt = app.getAllStoredCachesCount(true, null, null);
+
+ countBubbleHandler.sendEmptyMessage(0);
+ }
+ }
+
+ private class cleanDatabase extends Thread {
+
+ @Override
+ public void run() {
+ if (app == null) {
+ return;
+ }
+ if (cleanupRunning == true) {
+ return;
+ }
+
+ boolean more = false;
+ if (version != settings.version) {
+ Log.i(cgSettings.tag, "Initializing hard cleanup - version changed from " + settings.version + " to " + version + ".");
+
+ more = true;
+ }
+
+ cleanupRunning = true;
+ app.cleanDatabase(more);
+ cleanupRunning = false;
+
+ if (version != null && version > 0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ edit.putInt("version", version);
+ edit.commit();
+ }
+ }
+ }
+
+ private class obtainAddress extends Thread {
+
+ public obtainAddress() {
+ setPriority(Thread.MIN_PRIORITY);
+ }
+
+ @Override
+ public void run() {
+ if (geo == null) {
+ return;
+ }
+ if (addressObtaining == true) {
+ return;
+ }
+ addressObtaining = true;
+
+ try {
+ Geocoder geocoder = new Geocoder(context, Locale.getDefault());
+
+ addresses = geocoder.getFromLocation(geo.latitudeNow, geo.longitudeNow, 1);
+ } catch (Exception e) {
+ Log.i(cgSettings.tag, "Failed to obtain address");
+ }
+
+ obtainAddressHandler.sendEmptyMessage(0);
+
+ addressObtaining = false;
+ }
+ }
+
+ public void showAbout(View view) {
+ context.startActivity(new Intent(context, cgeoabout.class));
+ }
+
+ public void goSearch(View view) {
+ onSearchRequested();
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-main-screen",
+ context,
+ "http://cgeo.carnero.cc/manual/");
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgeoabout.java b/src/cgeo/geocaching/cgeoabout.java
new file mode 100644
index 0000000..fe11660
--- /dev/null
+++ b/src/cgeo/geocaching/cgeoabout.java
@@ -0,0 +1,110 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.Bundle;
+import android.text.method.LinkMovementMethod;
+import android.util.Log;
+import android.view.View;
+import android.widget.TextView;
+
+public class cgeoabout extends Activity {
+ private Activity activity = null;
+ private Resources res = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ settings = new cgSettings(this, this.getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase((cgeoapplication) this.getApplication(), settings, this.getSharedPreferences(cgSettings.preferences, 0));
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.about);
+ base.setTitle(activity, res.getString(R.string.about));
+
+ // google analytics
+ base.sendAnal(activity, "/about");
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ private void init() {
+ try {
+ PackageManager manager = this.getPackageManager();
+ PackageInfo info = manager.getPackageInfo(this.getPackageName(), 0);
+
+ base.setTitle(activity, res.getString(R.string.about) + " (ver. " + info.versionName + ")");
+
+ manager = null;
+
+ ((TextView)findViewById(R.id.contributors)).setMovementMethod(LinkMovementMethod.getInstance());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoabout.init: Failed to obtain package version.");
+ }
+ }
+
+ public void donateMore(View view) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=N2FKGNCPPRUVE")));
+ //activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2Z69QWLRCBE9N&lc=US&item_name=c%3ageo&currency_code=EUR&amount=15&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted")));
+ }
+
+ public void donateLess(View view) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4PRD9CX4Y8XR6")));
+ //activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2Z69QWLRCBE9N&lc=US&item_name=c%3ageo&currency_code=EUR&amount=7&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted")));
+ }
+
+ public void author(View view) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://carnero.cc/")));
+ }
+
+ public void support(View view) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("mailto:support@cgeo.org")));
+ }
+
+ public void website(View view) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.cgeo.org/")));
+ }
+
+ public void facebook(View view) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.facebook.com/pages/cgeo/297269860090")));
+ }
+
+ public void twitter(View view) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://twitter.com/android_gc")));
+ }
+
+ public void nutshellmanual(View view) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://cgeo.carnero.cc/manual/")));
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+}
diff --git a/src/cgeo/geocaching/cgeoaddresses.java b/src/cgeo/geocaching/cgeoaddresses.java
new file mode 100644
index 0000000..c917d50
--- /dev/null
+++ b/src/cgeo/geocaching/cgeoaddresses.java
@@ -0,0 +1,201 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import java.util.ArrayList;
+import android.os.Bundle;
+import android.view.View;
+import android.view.LayoutInflater;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.location.Address;
+import android.location.Geocoder;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import java.util.List;
+import java.util.Locale;
+
+public class cgeoaddresses extends Activity {
+ private final ArrayList<Address> addresses = new ArrayList<Address>();
+ private String keyword = null;
+ private Activity activity = null;
+ private cgeoapplication app = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private Resources res = null;
+ private cgWarning warning = null;
+ private LayoutInflater inflater = null;
+ private LinearLayout addList = null;
+ private ProgressDialog waitDialog = null;
+ private Handler loadPlacesHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (addList == null) {
+ addList = (LinearLayout) findViewById(R.id.address_list);
+ }
+
+ if (addresses.isEmpty()) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ warning.showToast(res.getString(R.string.err_search_address_no_match));
+
+ finish();
+ return;
+ } else {
+ LinearLayout oneAddPre = null;
+ for (Address address : addresses) {
+ oneAddPre = (LinearLayout) inflater.inflate(R.layout.address_button, null);
+
+ Button oneAdd = (Button) oneAddPre.findViewById(R.id.button);
+ int index = 0;
+ StringBuilder allAdd = new StringBuilder();
+ StringBuilder allAddLine = new StringBuilder();
+
+ while (address.getAddressLine(index) != null) {
+ if (allAdd.length() > 0) {
+ allAdd.append("\n");
+ }
+ if (allAddLine.length() > 0) {
+ allAddLine.append("; ");
+ }
+
+ allAdd.append(address.getAddressLine(index));
+ allAddLine.append(address.getAddressLine(index));
+
+ index++;
+ }
+
+ oneAdd.setText(allAdd.toString());
+ oneAdd.setLines(allAdd.toString().split("\n").length);
+ oneAdd.setClickable(true);
+ oneAdd.setOnClickListener(new buttonListener(address.getLatitude(), address.getLongitude(), allAddLine.toString()));
+ addList.addView(oneAddPre);
+ }
+ }
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ } catch (Exception e) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ Log.e(cgSettings.tag, "cgeoaddresses.loadCachesHandler: " + e.toString());
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+ inflater = getLayoutInflater();
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.addresses);
+ base.setTitle(activity, res.getString(R.string.search_address_result));
+
+ // google analytics
+ base.sendAnal(activity, "/addresses");
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+
+ // try to get data from extras
+ if (extras != null) {
+ keyword = extras.getString("keyword");
+ }
+
+ if (keyword == null) {
+ warning.showToast(res.getString(R.string.err_search_address_forgot));
+ finish();
+ return;
+ }
+
+ waitDialog = ProgressDialog.show(this, res.getString(R.string.search_address_started), keyword, true);
+ waitDialog.setCancelable(true);
+
+ (new loadPlaces()).start();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ private class loadPlaces extends Thread {
+
+ @Override
+ public void run() {
+ Geocoder geocoder = new Geocoder(activity, Locale.getDefault());
+ try {
+ List<Address> knownLocations = geocoder.getFromLocationName(keyword, 20);
+
+ addresses.clear();
+ for (Address address : knownLocations) {
+ addresses.add(address);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoaddresses.loadPlaces.run: " + e.toString());
+ }
+
+ loadPlacesHandler.sendMessage(new Message());
+ }
+ }
+
+ private class buttonListener implements View.OnClickListener {
+
+ private Double latitude = null;
+ private Double longitude = null;
+ private String address = null;
+
+ public buttonListener(Double latitudeIn, Double longitudeIn, String addressIn) {
+ latitude = latitudeIn;
+ longitude = longitudeIn;
+ address = addressIn;
+ }
+
+ public void onClick(View arg0) {
+ Intent addressIntent = new Intent(activity, cgeocaches.class);
+ addressIntent.putExtra("type", "address");
+ addressIntent.putExtra("latitude", (Double) latitude);
+ addressIntent.putExtra("longitude", (Double) longitude);
+ addressIntent.putExtra("address", (String) address);
+ addressIntent.putExtra("cachetype", settings.cacheType);
+ activity.startActivity(addressIntent);
+
+ finish();
+ return;
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+}
diff --git a/src/cgeo/geocaching/cgeoadvsearch.java b/src/cgeo/geocaching/cgeoadvsearch.java
new file mode 100644
index 0000000..568cbce
--- /dev/null
+++ b/src/cgeo/geocaching/cgeoadvsearch.java
@@ -0,0 +1,552 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import java.util.HashMap;
+import android.os.Bundle;
+import android.app.Activity;
+import android.app.SearchManager;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.EditText;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.inputmethod.EditorInfo;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class cgeoadvsearch extends Activity {
+
+ private Resources res = null;
+ private Activity activity = null;
+ private cgeoapplication app = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private cgGeo geo = null;
+ private cgUpdateLoc geoUpdate = new update();
+ private EditText latEdit = null;
+ private EditText lonEdit = null;
+ private String[] geocodesInCache = null;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ app.setAction(null);
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // search query
+ Intent intent = getIntent();
+ if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
+ final String query = intent.getStringExtra(SearchManager.QUERY);
+ final boolean found = instantSearch(query);
+
+ if (found) {
+ finish();
+
+ return;
+ }
+ }
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.search);
+ base.setTitle(activity, res.getString(R.string.search));
+
+ // google analytics
+ base.sendAnal(activity, "/advanced-search");
+
+ init();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ init();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStop() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onPause();
+ }
+
+ private boolean instantSearch(String query) {
+ boolean found = false;
+
+ final Pattern gcCode = Pattern.compile("^GC[0-9A-Z]+$", Pattern.CASE_INSENSITIVE);
+ final Pattern tbCode = Pattern.compile("^TB[0-9A-Z]+$", Pattern.CASE_INSENSITIVE);
+ final Matcher gcCodeM = gcCode.matcher(query);
+ final Matcher tbCodeM = tbCode.matcher(query);
+
+ try {
+ if (gcCodeM.find()) { // GC-code
+ final Intent cachesIntent = new Intent(activity, cgeodetail.class);
+ cachesIntent.putExtra("geocode", query.trim().toUpperCase());
+ activity.startActivity(cachesIntent);
+
+ found = true;
+ } else if (tbCodeM.find()) { // TB-code
+ final Intent trackablesIntent = new Intent(activity, cgeotrackable.class);
+ trackablesIntent.putExtra("geocode", query.trim().toUpperCase());
+ activity.startActivity(trackablesIntent);
+
+ found = true;
+ } else { // keyword (fallback)
+ final Intent cachesIntent = new Intent(activity, cgeocaches.class);
+ cachesIntent.putExtra("type", "keyword");
+ cachesIntent.putExtra("keyword", query);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+ activity.startActivity(cachesIntent);
+
+ found = true;
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgeoadvsearch.instantSearch: " + e.toString());
+ }
+
+ return found;
+ }
+
+ private void init() {
+ settings.getLogin();
+ settings.reloadCacheType();
+
+ if (settings.cacheType != null && cgBase.cacheTypesInv.containsKey(settings.cacheType) == false) {
+ settings.setCacheType(null);
+ }
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+
+ ((EditText) findViewById(R.id.latitude)).setOnEditorActionListener(new findByCoordsAction());
+ ((EditText) findViewById(R.id.longitude)).setOnEditorActionListener(new findByCoordsAction());
+
+ final Button findByCoords = (Button) findViewById(R.id.search_coordinates);
+ findByCoords.setOnClickListener(new findByCoordsListener());
+
+ ((EditText) findViewById(R.id.address)).setOnEditorActionListener(new findByAddressAction());
+
+ final Button findByAddress = (Button) findViewById(R.id.search_address);
+ findByAddress.setOnClickListener(new findByAddressListener());
+
+ final AutoCompleteTextView geocodeEdit = (AutoCompleteTextView) findViewById(R.id.geocode);
+ geocodeEdit.setOnEditorActionListener(new findByGeocodeAction());
+ geocodesInCache = app.geocodesInCache();
+ if (geocodesInCache != null) {
+ final ArrayAdapter<String> geocodesAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, geocodesInCache);
+ geocodeEdit.setAdapter(geocodesAdapter);
+ }
+ // geocodeEdit.addTextChangedListener(new UpperCaseTextWatcher(geocodeEdit));
+
+ final Button displayByGeocode = (Button) findViewById(R.id.display_geocode);
+ displayByGeocode.setOnClickListener(new findByGeocodeListener());
+
+ ((EditText) findViewById(R.id.keyword)).setOnEditorActionListener(new findByKeywordAction());
+
+ final Button findByKeyword = (Button) findViewById(R.id.search_keyword);
+ findByKeyword.setOnClickListener(new findByKeywordListener());
+
+ ((EditText) findViewById(R.id.username)).setOnEditorActionListener(new findByUsernameAction());
+
+ final Button findByUserName = (Button) findViewById(R.id.search_username);
+ findByUserName.setOnClickListener(new findByUsernameListener());
+
+ ((EditText) findViewById(R.id.owner)).setOnEditorActionListener(new findByOwnerAction());
+
+ final Button findByOwner = (Button) findViewById(R.id.search_owner);
+ findByOwner.setOnClickListener(new findByOwnerListener());
+
+ EditText trackable = (EditText) findViewById(R.id.trackable);
+ trackable.setOnEditorActionListener(new findTrackableAction());
+ // trackable.addTextChangedListener(new UpperCaseTextWatcher(trackable)); // not working with HTC IMEs.
+
+ final Button displayTrackable = (Button) findViewById(R.id.display_trackable);
+ displayTrackable.setOnClickListener(new findTrackableListener());
+ }
+
+ /**
+ * converts user input to uppercase during typing
+ * @author bananeweizen
+ *
+ */
+ private final class UpperCaseTextWatcher implements TextWatcher {
+
+ private final EditText editText;
+
+ private UpperCaseTextWatcher(EditText editText) {
+ this.editText = editText;
+ }
+
+ @Override
+ public void afterTextChanged(Editable arg0) {
+ // empty
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
+ // empty
+ }
+
+ @Override
+ public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
+ String oldText = editText.getText().toString();
+ String upperText = oldText.toUpperCase();
+ if (!oldText.equals(upperText)) {
+ int selectionStart = editText.getSelectionStart();
+ int selectionEnd = editText.getSelectionEnd();
+ editText.setText(upperText);
+ editText.setSelection(selectionStart, selectionEnd);
+ }
+ }
+ }
+
+ private class update extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+
+ try {
+ if (latEdit == null) {
+ latEdit = (EditText) findViewById(R.id.latitude);
+ }
+ if (lonEdit == null) {
+ lonEdit = (EditText) findViewById(R.id.longitude);
+ }
+
+ if (geo.latitudeNow != null && geo.longitudeNow != null) {
+ latEdit.setHint(base.formatCoordinate(geo.latitudeNow, "lat", false));
+ lonEdit.setHint(base.formatCoordinate(geo.longitudeNow, "lon", false));
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ private class findByCoordsAction implements TextView.OnEditorActionListener {
+
+ @Override
+ public boolean onEditorAction(TextView view, int action, KeyEvent event) {
+ if (action == EditorInfo.IME_ACTION_GO) {
+ findByCoordsFn();
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ private class findByCoordsListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ findByCoordsFn();
+ }
+ }
+
+ private void findByCoordsFn() {
+ final EditText latView = (EditText) findViewById(R.id.latitude);
+ final EditText lonView = (EditText) findViewById(R.id.longitude);
+ final String latText = latView.getText().toString();
+ final String lonText = lonView.getText().toString();
+
+ if (latText == null || latText.length() == 0 || lonText == null || lonText.length() == 0) {
+ latView.setText(base.formatCoordinate(geo.latitudeNow, "lat", true));
+ lonView.setText(base.formatCoordinate(geo.longitudeNow, "lon", true));
+ } else {
+ HashMap<String, Object> latParsed = base.parseCoordinate(latText, "lat");
+ HashMap<String, Object> lonParsed = base.parseCoordinate(lonText, "lat");
+
+ if (latParsed == null || latParsed.get("coordinate") == null || latParsed.get("string") == null) {
+ warning.showToast(res.getString(R.string.err_parse_lat));
+ return;
+ }
+
+ if (lonParsed == null || lonParsed.get("coordinate") == null || lonParsed.get("string") == null) {
+ warning.showToast(res.getString(R.string.err_parse_lon));
+ return;
+ }
+
+ final Intent cachesIntent = new Intent(activity, cgeocaches.class);
+ cachesIntent.putExtra("type", "coordinate");
+ cachesIntent.putExtra("latitude", (Double) latParsed.get("coordinate"));
+ cachesIntent.putExtra("longitude", (Double) lonParsed.get("coordinate"));
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+ activity.startActivity(cachesIntent);
+ }
+ }
+
+ private class findByKeywordAction implements TextView.OnEditorActionListener {
+
+ @Override
+ public boolean onEditorAction(TextView view, int action, KeyEvent event) {
+ if (action == EditorInfo.IME_ACTION_GO) {
+ findByKeywordFn();
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ private class findByKeywordListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ findByKeywordFn();
+ }
+ }
+
+ private void findByKeywordFn() {
+ // find caches by coordinates
+ String keyText = ((EditText) findViewById(R.id.keyword)).getText().toString();
+
+ if (keyText == null || keyText.length() == 0) {
+ warning.helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_keyword));
+ return;
+ }
+
+ final Intent cachesIntent = new Intent(activity, cgeocaches.class);
+ cachesIntent.putExtra("type", "keyword");
+ cachesIntent.putExtra("keyword", keyText);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+ activity.startActivity(cachesIntent);
+ }
+
+ private class findByAddressAction implements TextView.OnEditorActionListener {
+
+ @Override
+ public boolean onEditorAction(TextView view, int action, KeyEvent event) {
+ if (action == EditorInfo.IME_ACTION_GO) {
+ findByAddressFn();
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ private class findByAddressListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ findByAddressFn();
+ }
+ }
+
+ private void findByAddressFn() {
+ final String addText = ((EditText) findViewById(R.id.address)).getText().toString();
+
+ if (addText == null || addText.length() == 0) {
+ warning.helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_address));
+ return;
+ }
+
+ final Intent addressesIntent = new Intent(activity, cgeoaddresses.class);
+ addressesIntent.putExtra("keyword", addText);
+ activity.startActivity(addressesIntent);
+ }
+
+ private class findByUsernameAction implements TextView.OnEditorActionListener {
+
+ @Override
+ public boolean onEditorAction(TextView view, int action, KeyEvent event) {
+ if (action == EditorInfo.IME_ACTION_GO) {
+ findByUsernameFn();
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ private class findByUsernameListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ findByUsernameFn();
+ }
+ }
+
+ public void findByUsernameFn() {
+ final String usernameText = ((EditText) findViewById(R.id.username)).getText().toString();
+
+ if (usernameText == null || usernameText.length() == 0) {
+ warning.helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_user));
+ return;
+ }
+
+ final Intent cachesIntent = new Intent(activity, cgeocaches.class);
+ cachesIntent.putExtra("type", "username");
+ cachesIntent.putExtra("username", usernameText);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+ activity.startActivity(cachesIntent);
+ }
+
+ private class findByOwnerAction implements TextView.OnEditorActionListener {
+
+ @Override
+ public boolean onEditorAction(TextView view, int action, KeyEvent event) {
+ if (action == EditorInfo.IME_ACTION_GO) {
+ findByOwnerFn();
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ private class findByOwnerListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ findByOwnerFn();
+ }
+ }
+
+ private void findByOwnerFn() {
+ final String usernameText = ((EditText) findViewById(R.id.owner)).getText().toString();
+
+ if (usernameText == null || usernameText.length() == 0) {
+ warning.helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_user));
+ return;
+ }
+
+ final Intent cachesIntent = new Intent(activity, cgeocaches.class);
+ cachesIntent.putExtra("type", "owner");
+ cachesIntent.putExtra("username", usernameText);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+ activity.startActivity(cachesIntent);
+ }
+
+ private class findByGeocodeAction implements TextView.OnEditorActionListener {
+
+ @Override
+ public boolean onEditorAction(TextView view, int action, KeyEvent event) {
+ if (action == EditorInfo.IME_ACTION_GO) {
+ findByGeocodeFn();
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ private class findByGeocodeListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ findByGeocodeFn();
+ }
+ }
+
+ private void findByGeocodeFn() {
+ final String geocodeText = ((EditText) findViewById(R.id.geocode)).getText().toString();
+
+ if (geocodeText == null || geocodeText.length() == 0 || geocodeText.equalsIgnoreCase("GC")) {
+ warning.helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_gccode));
+ return;
+ }
+
+ final Intent cachesIntent = new Intent(activity, cgeodetail.class);
+ cachesIntent.putExtra("geocode", geocodeText.toUpperCase());
+ activity.startActivity(cachesIntent);
+ }
+
+ private class findTrackableAction implements TextView.OnEditorActionListener {
+
+ @Override
+ public boolean onEditorAction(TextView view, int action, KeyEvent event) {
+ if (action == EditorInfo.IME_ACTION_GO) {
+ findTrackableFn();
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ private class findTrackableListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ findTrackableFn();
+ }
+ }
+
+ private void findTrackableFn() {
+ final String trackableText = ((EditText) findViewById(R.id.trackable)).getText().toString();
+
+ if (trackableText == null || trackableText.length() == 0 || trackableText.equalsIgnoreCase("TB")) {
+ warning.helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_tb));
+ return;
+ }
+
+ final Intent trackablesIntent = new Intent(activity, cgeotrackable.class);
+ trackablesIntent.putExtra("geocode", trackableText.toUpperCase());
+ activity.startActivity(trackablesIntent);
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-search",
+ activity,
+ "http://cgeo.carnero.cc/manual/");
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgeoapplication.java b/src/cgeo/geocaching/cgeoapplication.java
new file mode 100644
index 0000000..374f323
--- /dev/null
+++ b/src/cgeo/geocaching/cgeoapplication.java
@@ -0,0 +1,828 @@
+package cgeo.geocaching;
+
+import android.app.Application;
+import android.content.Context;
+import android.util.Log;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+
+public class cgeoapplication extends Application {
+
+ private cgData storage = null;
+ private String action = null;
+ private Double lastLatitude = null;
+ private Double lastLongitude = null;
+ private cgGeo geo = null;
+ private boolean geoInUse = false;
+ private cgDirection dir = null;
+ private boolean dirInUse = false;
+ final private HashMap<Long, cgSearch> searches = new HashMap<Long, cgSearch>(); // information about searches
+ final private HashMap<String, cgCache> cachesCache = new HashMap<String, cgCache>(); // caching caches into memory
+ public boolean firstRun = true; // c:geo is just launched
+ public boolean warnedLanguage = false; // user was warned about different language settings on geocaching.com
+ private boolean databaseCleaned = false; // database was cleaned
+
+ public cgeoapplication() {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ }
+
+ @Override
+ public void onLowMemory() {
+ Log.i(cgSettings.tag, "Cleaning applications cache.");
+
+ cachesCache.clear();
+ }
+
+ @Override
+ public void onTerminate() {
+ Log.d(cgSettings.tag, "Terminating c:geo...");
+
+ if (geo != null) {
+ geo.closeGeo();
+ geo = null;
+ }
+
+ if (dir != null) {
+ dir.closeDir();
+ dir = null;
+ }
+
+ if (storage != null) {
+ storage.clean();
+ storage.closeDb();
+ storage = null;
+ }
+
+ super.onTerminate();
+ }
+
+ public String backupDatabase() {
+ return storage.backupDatabase();
+ }
+
+ public File isRestoreFile() {
+ return storage.isRestoreFile();
+ }
+
+ public boolean restoreDatabase() {
+ return storage.restoreDatabase();
+ }
+
+ public void cleanGeo() {
+ if (geo != null) {
+ geo.closeGeo();
+ geo = null;
+ }
+ }
+
+ public void cleanDir() {
+ if (dir != null) {
+ dir.closeDir();
+ dir = null;
+ }
+ }
+
+ public boolean storageStatus() {
+ if (storage.status() == false) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public cgGeo startGeo(Context context, cgUpdateLoc geoUpdate, cgBase base, cgSettings settings, cgWarning warning, int time, int distance) {
+ if (geo == null) {
+ geo = new cgGeo(context, this, geoUpdate, base, settings, warning, time, distance);
+ geo.initGeo();
+
+ Log.i(cgSettings.tag, "Location service started");
+ }
+
+ geo.replaceUpdate(geoUpdate);
+ geoInUse = true;
+
+ return geo;
+ }
+
+ public cgGeo removeGeo() {
+ if (geo != null) {
+ geo.replaceUpdate(null);
+ }
+ geoInUse = false;
+
+ (new removeGeoThread()).start();
+
+ return null;
+ }
+
+ private class removeGeoThread extends Thread {
+
+ @Override
+ public void run() {
+ try {
+ sleep(2500);
+ } catch (Exception e) {
+ // nothing
+ }
+
+ if (geoInUse == false && geo != null) {
+ geo.closeGeo();
+ geo = null;
+
+ Log.i(cgSettings.tag, "Location service stopped");
+ }
+ }
+ }
+
+ public cgDirection startDir(Context context, cgUpdateDir dirUpdate, cgWarning warning) {
+ if (dir == null) {
+ dir = new cgDirection(this, context, dirUpdate, warning);
+ dir.initDir();
+
+ Log.i(cgSettings.tag, "Direction service started");
+ }
+
+ dir.replaceUpdate(dirUpdate);
+ dirInUse = true;
+
+ return dir;
+ }
+
+ public cgDirection removeDir() {
+ if (dir != null) {
+ dir.replaceUpdate(null);
+ }
+ dirInUse = false;
+
+ (new removeDirThread()).start();
+
+ return null;
+ }
+
+ private class removeDirThread extends Thread {
+
+ @Override
+ public void run() {
+ try {
+ sleep(2500);
+ } catch (Exception e) {
+ // nothing
+ }
+
+ if (dirInUse == false && dir != null) {
+ dir.closeDir();
+ dir = null;
+
+ Log.i(cgSettings.tag, "Direction service stopped");
+ }
+ }
+ }
+
+ public void cleanDatabase(boolean more) {
+ if (databaseCleaned == true) {
+ return;
+ }
+
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ storage.clean(more);
+ databaseCleaned = true;
+ }
+
+ public Boolean isThere(String geocode, String guid, boolean detailed, boolean checkTime) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.isThere(geocode, guid, detailed, checkTime);
+ }
+
+ public Boolean isOffline(String geocode, String guid) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.isOffline(geocode, guid);
+ }
+
+ public String getGeocode(String guid) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.getGeocodeForGuid(guid);
+ }
+
+ public String getCacheid(String geocode) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.getCacheidForGeocode(geocode);
+ }
+
+ public String getError(Long searchId) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return null;
+ }
+
+ return searches.get(searchId).error;
+ }
+
+ public boolean setError(Long searchId, String error) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return false;
+ }
+
+ searches.get(searchId).error = error;
+
+ return true;
+ }
+
+ public String getUrl(Long searchId) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return null;
+ }
+
+ return searches.get(searchId).url;
+ }
+
+ public boolean setUrl(Long searchId, String url) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return false;
+ }
+
+ searches.get(searchId).url = url;
+
+ return true;
+ }
+
+ public String getViewstate(Long searchId) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return null;
+ }
+
+ return searches.get(searchId).viewstate;
+ }
+
+ public String getViewstate1(Long searchId) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return null;
+ }
+
+ return searches.get(searchId).viewstate1;
+ }
+
+ public boolean setViewstate(Long searchId, String viewstate) {
+ if (viewstate == null || viewstate.length() == 0) {
+ return false;
+ }
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return false;
+ }
+
+ searches.get(searchId).viewstate = viewstate;
+
+ return true;
+ }
+
+ public boolean setViewstate1(Long searchId, String viewstate1) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return false;
+ }
+
+ searches.get(searchId).viewstate1 = viewstate1;
+
+ return true;
+ }
+
+ public Integer getTotal(Long searchId) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return null;
+ }
+
+ return searches.get(searchId).totalCnt;
+ }
+
+ public Integer getCount(Long searchId) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return 0;
+ }
+
+ return searches.get(searchId).getCount();
+ }
+
+ public Integer getNotOfflineCount(Long searchId) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return 0;
+ }
+
+ int count = 0;
+ ArrayList<String> geocodes = searches.get(searchId).getGeocodes();
+ if (geocodes != null) {
+ for (String geocode : geocodes) {
+ if (isOffline(geocode, null) == false) {
+ count++;
+ }
+ }
+ }
+
+ return count;
+ }
+
+ public cgCache getCacheByGeocode(String geocode) {
+ return getCacheByGeocode(geocode, false, true, false, false, false, false);
+ }
+
+ public cgCache getCacheByGeocode(String geocode, boolean loadA, boolean loadW, boolean loadS, boolean loadL, boolean loadI, boolean loadO) {
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ cgCache cache = null;
+ if (cachesCache.containsKey(geocode) == true) {
+ cache = cachesCache.get(geocode);
+ } else {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ cache = storage.loadCache(geocode, null, loadA, loadW, loadS, loadL, loadI, loadO);
+
+ if (cache != null && cache.detailed == true && loadA == true && loadW == true && loadS == true && loadL == true && loadI == true) {
+ putCacheInCache(cache);
+ }
+ }
+
+ return cache;
+ }
+
+ public cgTrackable getTrackableByGeocode(String geocode) {
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ cgTrackable trackable = null;
+ trackable = storage.loadTrackable(geocode);
+
+ return trackable;
+ }
+
+ public void removeCacheFromCache(String geocode) {
+ if (geocode != null && cachesCache.containsKey(geocode) == true) {
+ cachesCache.remove(geocode);
+ }
+ }
+
+ public void putCacheInCache(cgCache cache) {
+ if (cache == null || cache.geocode == null) {
+ return;
+ }
+
+ if (cachesCache.containsKey(cache.geocode) == true) {
+ cachesCache.remove(cache.geocode);
+ }
+
+ cachesCache.put(cache.geocode, cache);
+ }
+
+ public String[] geocodesInCache() {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+
+ return storage.allDetailedThere();
+ }
+
+ public cgWaypoint getWaypointById(Integer id) {
+ if (id == null || id == 0) {
+ return null;
+ }
+
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.loadWaypoint(id);
+ }
+
+ public ArrayList<Object> getBounds(String geocode) {
+ if (geocode == null) {
+ return null;
+ }
+
+ List<String> geocodeList = new ArrayList<String>();
+ geocodeList.add(geocode);
+
+ return getBounds(geocodeList);
+ }
+
+ public ArrayList<Object> getBounds(Long searchId) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return null;
+ }
+
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+
+ final cgSearch search = searches.get(searchId);
+ final ArrayList<String> geocodeList = search.getGeocodes();
+
+ return getBounds(geocodeList);
+ }
+
+ public ArrayList<Object> getBounds(List<String> geocodes) {
+ if (geocodes == null || geocodes.isEmpty()) {
+ return null;
+ }
+
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+
+ return storage.getBounds(geocodes.toArray());
+ }
+
+ public cgCache getCache(Long searchId) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return null;
+ }
+
+ cgSearch search = searches.get(searchId);
+ ArrayList<String> geocodeList = search.getGeocodes();
+
+ return getCacheByGeocode(geocodeList.get(0), true, true, true, true, true, true);
+ }
+
+ public ArrayList<cgCache> getCaches(Long searchId) {
+ return getCaches(searchId, null, null, null, null, false, true, false, false, false, true);
+ }
+
+ public ArrayList<cgCache> getCaches(Long searchId, boolean loadA, boolean loadW, boolean loadS, boolean loadL, boolean loadI, boolean loadO) {
+ return getCaches(searchId, null, null, null, null, loadA, loadW, loadS, loadL, loadI, loadO);
+ }
+
+ public ArrayList<cgCache> getCaches(Long searchId, Long centerLat, Long centerLon, Long spanLat, Long spanLon) {
+ return getCaches(searchId, centerLat, centerLon, spanLat, spanLon, false, true, false, false, false, true);
+ }
+
+ public ArrayList<cgCache> getCaches(Long searchId, Long centerLat, Long centerLon, Long spanLat, Long spanLon, boolean loadA, boolean loadW, boolean loadS, boolean loadL, boolean loadI, boolean loadO) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ ArrayList<cgCache> cachesOut = new ArrayList<cgCache>();
+
+ final ArrayList<cgCache> cachesPre = storage.loadCaches(null , null, centerLat, centerLon, spanLat, spanLon, loadA, loadW, loadS, loadL, loadI, loadO);
+
+ if (cachesPre != null) {
+ cachesOut.addAll(cachesPre);
+ }
+
+ return cachesOut;
+ }
+
+ ArrayList<cgCache> cachesOut = new ArrayList<cgCache>();
+
+ cgSearch search = searches.get(searchId);
+ ArrayList<String> geocodeList = search.getGeocodes();
+
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+
+ final ArrayList<cgCache> cachesPre = storage.loadCaches(geocodeList.toArray(), null, centerLat, centerLon, spanLat, spanLon, loadA, loadW, loadS, loadL, loadI, loadO);
+ if (cachesPre != null) {
+ cachesOut.addAll(cachesPre);
+ }
+
+ return cachesOut;
+ }
+
+ public cgSearch getBatchOfStoredCaches(boolean detailedOnly, Double latitude, Double longitude, String cachetype, int list) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ cgSearch search = new cgSearch();
+
+ ArrayList<String> geocodes = storage.loadBatchOfStoredGeocodes(detailedOnly, latitude, longitude, cachetype, list);
+ if (geocodes != null && geocodes.isEmpty() == false) {
+ for (String gccode : geocodes) {
+ search.addGeocode(gccode);
+ }
+ }
+ searches.put(search.getCurrentId(), search);
+
+ return search;
+ }
+
+ public cgSearch getHistoryOfCaches(boolean detailedOnly, String cachetype) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ cgSearch search = new cgSearch();
+
+ ArrayList<String> geocodes = storage.loadBatchOfHistoricGeocodes(detailedOnly, cachetype);
+ if (geocodes != null && geocodes.isEmpty() == false) {
+ for (String gccode : geocodes) {
+ search.addGeocode(gccode);
+ }
+ }
+ searches.put(search.getCurrentId(), search);
+
+ return search;
+ }
+
+ public Long getCachedInViewport(Long centerLat, Long centerLon, Long spanLat, Long spanLon, String cachetype) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ cgSearch search = new cgSearch();
+
+ ArrayList<String> geocodes = storage.getCachedInViewport(centerLat, centerLon, spanLat, spanLon, cachetype);
+ if (geocodes != null && geocodes.isEmpty() == false) {
+ for (String gccode : geocodes) {
+ search.addGeocode(gccode);
+ }
+ }
+ searches.put(search.getCurrentId(), search);
+
+ return search.getCurrentId();
+ }
+
+ public Long getStoredInViewport(Long centerLat, Long centerLon, Long spanLat, Long spanLon, String cachetype) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ cgSearch search = new cgSearch();
+
+ ArrayList<String> geocodes = storage.getStoredInViewport(centerLat, centerLon, spanLat, spanLon, cachetype);
+ if (geocodes != null && geocodes.isEmpty() == false) {
+ for (String gccode : geocodes) {
+ search.addGeocode(gccode);
+ }
+ }
+ searches.put(search.getCurrentId(), search);
+
+ return search.getCurrentId();
+ }
+
+ public Long getOfflineAll(String cachetype) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ cgSearch search = new cgSearch();
+
+ ArrayList<String> geocodes = storage.getOfflineAll(cachetype);
+ if (geocodes != null && geocodes.isEmpty() == false) {
+ for (String gccode : geocodes) {
+ search.addGeocode(gccode);
+ }
+ }
+ searches.put(search.getCurrentId(), search);
+
+ return search.getCurrentId();
+ }
+
+ public int getAllStoredCachesCount(boolean detailedOnly, String cachetype, Integer list) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+
+ return storage.getAllStoredCachesCount(detailedOnly, cachetype, list);
+ }
+
+ public int getAllHistoricCachesCount(boolean detailedOnly, String cachetype) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+
+ return storage.getAllHistoricCachesCount(detailedOnly, cachetype);
+ }
+
+ public void markStored(String geocode, int listId) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ storage.markStored(geocode, listId);
+ }
+
+ public boolean markDropped(String geocode) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.markDropped(geocode);
+ }
+
+ public boolean markFound(String geocode) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.markFound(geocode);
+ }
+
+ public boolean saveWaypoints(String geocode, ArrayList<cgWaypoint> waypoints, boolean drop) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.saveWaypoints(geocode, waypoints, drop);
+ }
+
+ public boolean saveOwnWaypoint(int id, String geocode, cgWaypoint waypoint) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.saveOwnWaypoint(id, geocode, waypoint);
+ }
+
+ public boolean deleteWaypoint(int id) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.deleteWaypoint(id);
+ }
+
+ public boolean saveTrackable(cgTrackable trackable) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+
+ final ArrayList<cgTrackable> list = new ArrayList<cgTrackable>();
+ list.add(trackable);
+
+ return storage.saveInventory("---", list);
+ }
+
+ public void addGeocode(Long searchId, String geocode) {
+ if (this.searches.containsKey(searchId) == false || geocode == null || geocode.length() == 0) {
+ return;
+ }
+
+ this.searches.get(searchId).addGeocode(geocode);
+ }
+
+ public Long addSearch(Long searchId, ArrayList<cgCache> cacheList, Boolean newItem, int reason) {
+ if (this.searches.containsKey(searchId) == false) {
+ return null;
+ }
+
+ cgSearch search = this.searches.get(searchId);
+
+ return addSearch(search, cacheList, newItem, reason);
+ }
+
+ public Long addSearch(cgSearch search, ArrayList<cgCache> cacheList, Boolean newItem, int reason) {
+ if (cacheList == null || cacheList.isEmpty()) {
+ return null;
+ }
+
+ final long searchId = search.getCurrentId();
+ searches.put(searchId, search);
+
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ if (newItem == true) {
+ // save only newly downloaded data
+ for (cgCache oneCache : cacheList) {
+ String oneGeocode = oneCache.geocode.toUpperCase();
+ String oneGuid = oneCache.guid.toLowerCase();
+
+ oneCache.reason = reason;
+
+ if (storage.isThere(oneGeocode, oneGuid, false, false) == false || reason >= 1) {
+ // cache is not saved, new data are for storing
+ storage.saveCache(oneCache);
+ } else {
+ cgCache mergedCache = oneCache.merge(storage);
+
+ storage.saveCache(mergedCache);
+ }
+ }
+ }
+
+ return searchId;
+ }
+
+ public boolean addCacheToSearch(cgSearch search, cgCache cache) {
+ if (search == null || cache == null) {
+ return false;
+ }
+
+ final long searchId = search.getCurrentId();
+
+ if (searches.containsKey(searchId) == false) {
+ searches.put(searchId, search);
+ }
+
+ String geocode = cache.geocode.toUpperCase();
+ String guid = cache.guid.toLowerCase();
+
+ boolean status = false;
+
+ if (storage.isThere(geocode, guid, false, false) == false || cache.reason >= 1) { // if for offline, do not merge
+ status = storage.saveCache(cache);
+ } else {
+ cgCache mergedCache = cache.merge(storage);
+
+ status = storage.saveCache(mergedCache);
+ }
+
+ if (status == true) {
+ search.addGeocode(cache.geocode);
+ }
+
+ return status;
+ }
+
+ public void dropStored(int listId) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ storage.dropStored(listId);
+ }
+
+ public ArrayList<cgTrackable> loadInventory(String geocode) {
+ return storage.loadInventory(geocode);
+ }
+
+ public ArrayList<cgSpoiler> loadSpoilers(String geocode) {
+ return storage.loadSpoilers(geocode);
+ }
+
+ public cgWaypoint loadWaypoint(int id) {
+ return storage.loadWaypoint(id);
+ }
+
+ public void setAction(String act) {
+ action = act;
+ }
+
+ public String getAction() {
+ if (action == null) {
+ return "";
+ }
+ return action;
+ }
+
+ public boolean addLog(String geocode, cgLog log) {
+ if (geocode == null || geocode.length() == 0) {
+ return false;
+ }
+ if (log == null) {
+ return false;
+ }
+
+ ArrayList<cgLog> list = new ArrayList<cgLog>();
+ list.add(log);
+
+ return storage.saveLogs(geocode, list, false);
+ }
+
+ public void setLastLoc(Double lat, Double lon) {
+ lastLatitude = lat;
+ lastLongitude = lon;
+ }
+
+ public Double getLastLat() {
+ return lastLatitude;
+ }
+
+ public Double getLastLon() {
+ return lastLongitude;
+ }
+
+ public boolean saveLogOffline(String geocode, Date date, int logtype, String log) {
+ return storage.saveLogOffline(geocode, date, logtype, log);
+ }
+
+ public cgLog loadLogOffline(String geocode) {
+ return storage.loadLogOffline(geocode);
+ }
+
+ public void clearLogOffline(String geocode) {
+ storage.clearLogOffline(geocode);
+ }
+
+ public void saveVisitDate(String geocode) {
+ storage.saveVisitDate(geocode);
+ }
+
+ public ArrayList<cgList> getLists() {
+ return storage.getLists(getResources());
+ }
+
+ public cgList getList(int id) {
+ return storage.getList(id, getResources());
+ }
+
+ public int createList(String title) {
+ return storage.createList(title);
+ }
+
+ public boolean removeList(int id) {
+ return storage.removeList(id);
+ }
+
+ public void moveToList(String geocode, int listId) {
+ storage.moveToList(geocode, listId);
+ }
+}
diff --git a/src/cgeo/geocaching/cgeoauth.java b/src/cgeo/geocaching/cgeoauth.java
new file mode 100644
index 0000000..84514ba
--- /dev/null
+++ b/src/cgeo/geocaching/cgeoauth.java
@@ -0,0 +1,413 @@
+package cgeo.geocaching;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.BufferedReader;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.HashMap;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import android.net.Uri;
+import android.content.Intent;
+import android.os.Bundle;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.view.View;
+import android.widget.EditText;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.widget.Button;
+import java.io.IOException;
+import javax.net.ssl.HttpsURLConnection;
+
+public class cgeoauth extends Activity {
+ private cgeoapplication app = null;
+ private Resources res = null;
+ private Activity activity = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private SharedPreferences prefs = null;
+ private String OAtoken = null;
+ private String OAtokenSecret = null;
+ private final Pattern paramsPattern1 = Pattern.compile("oauth_token=([a-zA-Z0-9\\-\\_\\.]+)");
+ private final Pattern paramsPattern2 = Pattern.compile("oauth_token_secret=([a-zA-Z0-9\\-\\_\\.]+)");
+ private Button startButton = null;
+ private EditText pinEntry = null;
+ private Button pinEntryButton = null;
+ private ProgressDialog requestTokenDialog = null;
+ private ProgressDialog changeTokensDialog = null;
+ private Handler requestTokenHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (requestTokenDialog != null && requestTokenDialog.isShowing() == true) {
+ requestTokenDialog.dismiss();
+ }
+
+ startButton.setOnClickListener(new startListener());
+ startButton.setEnabled(true);
+
+ if (msg.what == 1) {
+ startButton.setText(res.getString(R.string.auth_again));
+
+ pinEntry.setVisibility(View.VISIBLE);
+ pinEntryButton.setVisibility(View.VISIBLE);
+ pinEntryButton.setOnClickListener(new confirmPINListener());
+ } else {
+ warning.showToast(res.getString(R.string.err_auth_initialize));
+ startButton.setText(res.getString(R.string.auth_start));
+ }
+ }
+ };
+ private Handler changeTokensHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (changeTokensDialog != null && changeTokensDialog.isShowing() == true) {
+ changeTokensDialog.dismiss();
+ }
+
+ pinEntryButton.setOnClickListener(new confirmPINListener());
+ pinEntryButton.setEnabled(true);
+
+ if (msg.what == 1) {
+ warning.showToast(res.getString(R.string.auth_dialog_completed));
+
+ pinEntryButton.setVisibility(View.GONE);
+
+ finish();
+ } else {
+ warning.showToast(res.getString(R.string.err_auth_process));
+
+ pinEntry.setVisibility(View.GONE);
+ pinEntryButton.setVisibility(View.GONE);
+ startButton.setText(res.getString(R.string.auth_start));
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ app.setAction("setting up");
+ prefs = getSharedPreferences(cgSettings.preferences, 0);
+ settings = new cgSettings(this, prefs);
+ base = new cgBase(app, settings, prefs);
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.auth);
+ base.setTitle(activity, res.getString(R.string.auth_twitter));
+
+ // google analytics
+ base.sendAnal(activity, "/auth");
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ private void init() {
+ startButton = (Button) findViewById(R.id.start);
+ pinEntry = (EditText) findViewById(R.id.pin);
+ pinEntryButton = (Button) findViewById(R.id.pin_button);
+
+ OAtoken = prefs.getString("temp-token-public", null);
+ OAtokenSecret = prefs.getString("temp-token-secret", null);
+
+ startButton.setEnabled(true);
+ startButton.setOnClickListener(new startListener());
+
+ if (OAtoken == null || OAtoken.length() == 0 || OAtokenSecret == null || OAtokenSecret.length() == 0) {
+ // start authorization process
+ startButton.setText(res.getString(R.string.auth_start));
+ } else {
+ // already have temporary tokens, continue from pin
+ startButton.setText(res.getString(R.string.auth_again));
+
+ pinEntry.setVisibility(View.VISIBLE);
+ pinEntryButton.setVisibility(View.VISIBLE);
+ pinEntryButton.setOnClickListener(new confirmPINListener());
+ }
+ }
+
+ private void requestToken() {
+ final String host = "twitter.com";
+ final String pathRequest = "/oauth/request_token";
+ final String pathAuthorize = "/oauth/authorize";
+ final String method = "GET";
+
+ int status = 0;
+ try {
+ String lineOne = null;
+ HttpsURLConnection connection = null;
+
+ try {
+ final StringBuilder sb = new StringBuilder();
+ final String params = cgOAuth.signOAuth(host, pathRequest, method, true, new HashMap<String, String>(), null, null);
+
+ int code = -1;
+ int retries = 0;
+
+ do {
+ // base.trustAllHosts();
+ Log.d(cgSettings.tag, "https://" + host + pathRequest + "?" + params);
+ final URL u = new URL("https://" + host + pathRequest + "?" + params);
+ final URLConnection uc = u.openConnection();
+ connection = (HttpsURLConnection) uc;
+
+ // connection.setHostnameVerifier(base.doNotVerify);
+ connection.setReadTimeout(30000);
+ connection.setRequestMethod(method);
+ HttpsURLConnection.setFollowRedirects(true);
+ connection.setDoInput(true);
+ connection.setDoOutput(false);
+
+ final InputStream in = connection.getInputStream();
+ final InputStreamReader ins = new InputStreamReader(in);
+ final BufferedReader br = new BufferedReader(ins);
+
+ while ((lineOne = br.readLine()) != null) {
+ sb.append(lineOne);
+ sb.append("\n");
+ }
+
+ code = connection.getResponseCode();
+ retries++;
+
+ Log.i(cgSettings.tag, host + ": " + connection.getResponseCode() + " " + connection.getResponseMessage());
+
+ br.close();
+ in.close();
+ ins.close();
+ } while (code == -1 && retries < 5);
+
+ final String line = sb.toString();
+
+ if (line != null && line.length() > 0) {
+ final Matcher paramsMatcher1 = paramsPattern1.matcher(line);
+ if (paramsMatcher1.find() == true && paramsMatcher1.groupCount() > 0) {
+ OAtoken = paramsMatcher1.group(1).toString();
+ }
+ final Matcher paramsMatcher2 = paramsPattern2.matcher(line);
+ if (paramsMatcher2.find() == true && paramsMatcher2.groupCount() > 0) {
+ OAtokenSecret = paramsMatcher2.group(1).toString();
+ }
+
+ if (OAtoken != null && OAtoken.length() > 0 && OAtokenSecret != null && OAtokenSecret.length() > 0) {
+ final SharedPreferences.Editor prefsEdit = getSharedPreferences(cgSettings.preferences, 0).edit();
+ prefsEdit.putString("temp-token-public", OAtoken);
+ prefsEdit.putString("temp-token-secret", OAtokenSecret);
+ prefsEdit.commit();
+
+ try {
+ final HashMap<String, String> paramsPre = new HashMap<String, String>();
+ paramsPre.put("oauth_callback", "oob");
+
+ final String paramsBrowser = cgOAuth.signOAuth(host, pathAuthorize, "GET", true, paramsPre, OAtoken, OAtokenSecret);
+
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://" + host + pathAuthorize + "?" + paramsBrowser)));
+
+ status = 1;
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoauth.requestToken(2): " + e.toString());
+ }
+ }
+ }
+ } catch (IOException eio) {
+ Log.e(cgSettings.tag, "cgeoauth.requestToken(IO): " + eio.toString() + " ~ " + connection.getResponseCode() + ": " + connection.getResponseMessage());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoauth.requestToken(1): " + e.toString());
+ } finally {
+ if (connection != null) {
+ connection.disconnect();
+ }
+ }
+ } catch (Exception e2) {
+ Log.e(cgSettings.tag, "cgeoauth.requestToken(3): " + e2.toString());
+ }
+
+ requestTokenHandler.sendEmptyMessage(status);
+ }
+
+ private void changeToken() {
+ final String host = "twitter.com";
+ final String path = "/oauth/access_token";
+ final String method = "POST";
+
+ int status = 0;
+ String lineOne = null;
+
+ try {
+ final HashMap<String, String> paramsPre = new HashMap<String, String>();
+ paramsPre.put("oauth_verifier", pinEntry.getText().toString());
+
+ int code = -1;
+ int retries = 0;
+
+ final String params = cgOAuth.signOAuth(host, path, method, true, paramsPre, OAtoken, OAtokenSecret);
+ final StringBuilder sb = new StringBuilder();
+ do {
+ // base.trustAllHosts();
+ final URL u = new URL("https://" + host + path);
+ final URLConnection uc = u.openConnection();
+ final HttpsURLConnection connection = (HttpsURLConnection) uc;
+
+ // connection.setHostnameVerifier(base.doNotVerify);
+ connection.setReadTimeout(30000);
+ connection.setRequestMethod(method);
+ HttpsURLConnection.setFollowRedirects(true);
+ connection.setDoOutput(true);
+ connection.setDoInput(true);
+
+ final OutputStream out = connection.getOutputStream();
+ final OutputStreamWriter wr = new OutputStreamWriter(out);
+
+ wr.write(params);
+ wr.flush();
+ wr.close();
+ out.close();
+
+ final InputStream in = connection.getInputStream();
+ final InputStreamReader ins = new InputStreamReader(in);
+ final BufferedReader br = new BufferedReader(ins);
+
+ while ((lineOne = br.readLine()) != null) {
+ sb.append(lineOne);
+ sb.append("\n");
+ }
+
+ code = connection.getResponseCode();
+ retries++;
+
+ Log.i(cgSettings.tag, host + ": " + connection.getResponseCode() + " " + connection.getResponseMessage());
+
+ br.close();
+ ins.close();
+ in.close();
+ connection.disconnect();
+ } while (code == -1 && retries < 5);
+
+ final String line = sb.toString();
+
+ OAtoken = "";
+ OAtokenSecret = "";
+
+ final Matcher paramsMatcher1 = paramsPattern1.matcher(line);
+ if (paramsMatcher1.find() == true && paramsMatcher1.groupCount() > 0) {
+ OAtoken = paramsMatcher1.group(1).toString();
+ }
+ final Matcher paramsMatcher2 = paramsPattern2.matcher(line);
+ if (paramsMatcher2.find() == true && paramsMatcher2.groupCount() > 0) {
+ OAtokenSecret = paramsMatcher2.group(1).toString();
+ }
+
+ if (OAtoken.length() == 0 || OAtokenSecret.length() == 0) {
+ OAtoken = "";
+ OAtokenSecret = "";
+
+ final SharedPreferences.Editor prefs = getSharedPreferences(cgSettings.preferences, 0).edit();
+ prefs.putString("tokenpublic", null);
+ prefs.putString("tokensecret", null);
+ prefs.putInt("twitter", 0);
+ prefs.commit();
+ } else {
+ final SharedPreferences.Editor prefs = getSharedPreferences(cgSettings.preferences, 0).edit();
+ prefs.remove("temp-token-public");
+ prefs.remove("temp-token-secret");
+ prefs.putString("tokenpublic", OAtoken);
+ prefs.putString("tokensecret", OAtokenSecret);
+ prefs.putInt("twitter", 1);
+ prefs.commit();
+
+ status = 1;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoauth.changeToken: " + e.toString());
+ }
+
+ changeTokensHandler.sendEmptyMessage(status);
+ }
+
+ private class startListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ if (requestTokenDialog == null) {
+ requestTokenDialog = new ProgressDialog(activity);
+ requestTokenDialog.setCancelable(false);
+ requestTokenDialog.setMessage(res.getString(R.string.auth_dialog_wait));
+ }
+ requestTokenDialog.show();
+ startButton.setEnabled(false);
+ startButton.setOnTouchListener(null);
+ startButton.setOnClickListener(null);
+
+ final SharedPreferences.Editor prefs = getSharedPreferences(cgSettings.preferences, 0).edit();
+ prefs.putString("temp-token-public", null);
+ prefs.putString("temp-token-secret", null);
+ prefs.commit();
+
+ (new Thread() {
+
+ @Override
+ public void run() {
+ requestToken();
+ }
+ }).start();
+ }
+ }
+
+ private class confirmPINListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ if (((EditText) findViewById(R.id.pin)).getText().toString().length() == 0) {
+ warning.helpDialog(res.getString(R.string.auth_dialog_pin_title), res.getString(R.string.auth_dialog_pin_message));
+ return;
+ }
+
+ if (changeTokensDialog == null) {
+ changeTokensDialog = new ProgressDialog(activity);
+ changeTokensDialog.setCancelable(false);
+ changeTokensDialog.setMessage(res.getString(R.string.auth_dialog_wait));
+ }
+ changeTokensDialog.show();
+ pinEntryButton.setEnabled(false);
+ pinEntryButton.setOnTouchListener(null);
+ pinEntryButton.setOnClickListener(null);
+
+ (new Thread() {
+
+ @Override
+ public void run() {
+ changeToken();
+ }
+ }).start();
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+}
diff --git a/src/cgeo/geocaching/cgeocaches.java b/src/cgeo/geocaching/cgeocaches.java
new file mode 100644
index 0000000..9c730de
--- /dev/null
+++ b/src/cgeo/geocaching/cgeocaches.java
@@ -0,0 +1,2193 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Bundle;
+import android.util.Log;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ListActivity;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.LayoutInflater;
+import android.view.SubMenu;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import cgeo.geocaching.filter.cgFilterBySize;
+import cgeo.geocaching.filter.cgFilterByTrackables;
+import cgeo.geocaching.filter.cgFilterByType;
+
+import com.google.android.apps.analytics.GoogleAnalyticsTracker;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.util.Locale;
+
+public class cgeocaches extends ListActivity {
+
+ private GoogleAnalyticsTracker tracker = null;
+ private String action = null;
+ private String type = null;
+ private Double latitude = null;
+ private Double longitude = null;
+ private String cachetype = null;
+ private String keyword = null;
+ private String address = null;
+ private String username = null;
+ private Long searchId = null;
+ private ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ private cgeoapplication app = null;
+ private Resources res = null;
+ private static Activity activity = null;
+ private cgCacheListAdapter adapter = null;
+ private LayoutInflater inflater = null;
+ private View listFooter = null;
+ private TextView listFooterText = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private ProgressDialog waitDialog = null;
+ private Double northHeading = new Double(0);
+ private cgGeo geo = null;
+ private cgDirection dir = null;
+ private cgUpdateLoc geoUpdate = new update();
+ private cgUpdateDir dirUpdate = new updateDir();
+ private String title = "";
+ private int detailTotal = 0;
+ private int detailProgress = 0;
+ private Long detailProgressTime = 0l;
+ private geocachesLoadDetails threadD = null;
+ private geocachesLoadFromWeb threadW = null;
+ private geocachesDropDetails threadR = null;
+ private int listId = 0;
+ private ArrayList<cgList> lists = null;
+ private String selectedFilter = null;
+ private cgCacheGeocodeComparator gcComparator = new cgCacheGeocodeComparator();
+ private Handler loadCachesHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (searchId != null && searchId > 0) {
+ base.setTitle(activity, title + " [" + app.getCount(searchId) + "]");
+ cacheList.clear();
+
+ final ArrayList<cgCache> cacheListTmp = app.getCaches(searchId);
+ if (cacheListTmp != null && cacheListTmp.isEmpty() == false) {
+ cacheList.addAll(cacheListTmp);
+ cacheListTmp.clear();
+
+ Collections.sort((List<cgCache>)cacheList, gcComparator);
+ }
+ } else {
+ base.setTitle(activity, title);
+ }
+
+ setAdapter();
+
+ if (cacheList == null) {
+ warning.showToast(res.getString(R.string.err_list_load_fail));
+ setMoreCaches(false);
+ } else {
+ final Integer count = app.getTotal(searchId);
+
+ if (count != null && count > 0) {
+ if (cacheList.size() < app.getTotal(searchId) && cacheList.size() < 1000) {
+ setMoreCaches(true);
+ } else {
+ setMoreCaches(false);
+ }
+ } else {
+ setMoreCaches(false);
+ }
+ }
+
+ if (cacheList != null && app.getError(searchId) != null && app.getError(searchId).equalsIgnoreCase(cgBase.errorRetrieve.get(-7)) == true) {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
+ dialog.setTitle(res.getString(R.string.license));
+ dialog.setMessage(res.getString(R.string.err_license));
+ dialog.setCancelable(true);
+ dialog.setNegativeButton(res.getString(R.string.license_dismiss), new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ settings.deleteCookies();
+ dialog.cancel();
+ }
+ });
+ dialog.setPositiveButton(res.getString(R.string.license_show), new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ settings.deleteCookies();
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/software/agreement.aspx?ID=0")));
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ } else if (app != null && app.getError(searchId) != null && app.getError(searchId).length() > 0) {
+ warning.showToast(res.getString(R.string.err_download_fail) + app.getError(searchId) + ".");
+
+ hideLoading();
+ base.showProgress(activity, false);
+
+ finish();
+ return;
+ }
+
+ if (geo != null && geo.latitudeNow != null && geo.longitudeNow != null) {
+ adapter.setActualCoordinates(geo.latitudeNow, geo.longitudeNow);
+ adapter.setActualHeading(northHeading);
+ }
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_detail_cache_find_any));
+ Log.e(cgSettings.tag, "cgeocaches.loadCachesHandler: " + e.toString());
+
+ hideLoading();
+ base.showProgress(activity, false);
+
+ finish();
+ return;
+ }
+
+ try {
+ hideLoading();
+ base.showProgress(activity, false);
+ } catch (Exception e2) {
+ Log.e(cgSettings.tag, "cgeocaches.loadCachesHandler.2: " + e2.toString());
+ }
+
+ if (adapter != null) {
+ adapter.setSelectMode(false, true);
+ }
+ }
+ };
+ private Handler loadNextPageHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (searchId != null && searchId > 0) {
+ base.setTitle(activity, title + " [" + app.getCount(searchId) + "]");
+ cacheList.clear();
+
+ final ArrayList<cgCache> cacheListTmp = app.getCaches(searchId);
+ if (cacheListTmp != null && cacheListTmp.isEmpty() == false) {
+ cacheList.addAll(cacheListTmp);
+ cacheListTmp.clear();
+ Collections.sort((List<cgCache>)cacheList, gcComparator);
+ }
+ if(adapter != null){
+ adapter.reFilter();
+ }
+ } else {
+ base.setTitle(activity, title);
+ }
+
+ setAdapter();
+
+ if (cacheList == null) {
+ warning.showToast(res.getString(R.string.err_list_load_fail));
+ setMoreCaches(false);
+ } else {
+ final Integer count = app.getTotal(searchId);
+ if (count != null && count > 0) {
+ if (cacheList.size() < app.getTotal(searchId) && cacheList.size() < 1000) {
+ setMoreCaches(true);
+ } else {
+ setMoreCaches(false);
+ }
+ } else {
+ setMoreCaches(false);
+ }
+ }
+
+ if (app.getError(searchId) != null && app.getError(searchId).length() > 0) {
+ warning.showToast(res.getString(R.string.err_download_fail) + app.getError(searchId) + ".");
+
+ listFooter.setOnClickListener(new moreCachesListener());
+ hideLoading();
+ base.showProgress(activity, false);
+
+ finish();
+ return;
+ }
+
+ if (geo != null && geo.latitudeNow != null && geo.longitudeNow != null) {
+ adapter.setActualCoordinates(geo.latitudeNow, geo.longitudeNow);
+ adapter.setActualHeading(northHeading);
+ }
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_detail_cache_find_next));
+ Log.e(cgSettings.tag, "cgeocaches.loadNextPageHandler: " + e.toString());
+ }
+
+ listFooter.setOnClickListener(new moreCachesListener());
+
+ hideLoading();
+ base.showProgress(activity, false);
+
+ if (adapter != null) {
+ adapter.setSelectMode(false, true);
+ }
+ }
+ };
+ private Handler loadDetailsHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ setAdapter();
+
+ if (msg.what > -1) {
+ if (waitDialog != null) {
+ cacheList.get(msg.what).statusChecked = false;
+
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
+ }
+
+ Float diffTime = new Float((System.currentTimeMillis() - detailProgressTime) / 1000); // seconds left
+ Float oneCache = diffTime / detailProgress; // left time per cache
+ int etaTime = (int) ((detailTotal - detailProgress) * oneCache / 60); // seconds remaining
+
+ waitDialog.setProgress(detailProgress);
+ if (etaTime < 1) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + res.getString(R.string.caches_eta_ltm));
+ } else if (etaTime == 1) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + etaTime + " " + res.getString(R.string.caches_eta_min));
+ } else {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + etaTime + " " + res.getString(R.string.caches_eta_mins));
+ }
+ }
+ } else {
+ if (cacheList != null && searchId != null) {
+ final ArrayList<cgCache> cacheListTmp = app.getCaches(searchId);
+ if (cacheListTmp != null && cacheListTmp.isEmpty() == false) {
+ cacheList.clear();
+ cacheList.addAll(cacheListTmp);
+ cacheListTmp.clear();
+ Collections.sort((List<cgCache>)cacheList, gcComparator);
+ }
+ }
+
+ if (geo != null && geo.latitudeNow != null && geo.longitudeNow != null) {
+ adapter.setActualCoordinates(geo.latitudeNow, geo.longitudeNow);
+ adapter.setActualHeading(northHeading);
+ }
+
+ base.showProgress(activity, false);
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog.setOnCancelListener(null);
+ }
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.livelist == 1 && settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+ }
+ }
+ };
+ private Handler downloadFromWebHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ setAdapter();
+
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
+ }
+
+ if (msg.what == 0) { //no caches
+ waitDialog.setMessage(res.getString(R.string.web_import_waiting));
+ } else if (msg.what == 1) { //cache downloading
+ waitDialog.setMessage(res.getString(R.string.web_downloading)+" "+(String)msg.obj+"...");
+ } else if (msg.what == 2) { //Cache downloaded
+ waitDialog.setMessage(res.getString(R.string.web_downloaded)+" "+(String)msg.obj+".");
+ //Once a cache is downloaded I used switchList to refresh it.
+ switchList(listId, -1);
+ } else if (msg.what == -2) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog.setOnCancelListener(null);
+ }
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ warning.showToast(res.getString(R.string.gpx_import_no_files));
+ finish();
+ return;
+ } else {
+ if (adapter != null) {
+ adapter.setSelectMode(false, true);
+ }
+
+ cacheList.clear();
+
+ final ArrayList<cgCache> cacheListTmp = app.getCaches(searchId);
+ if (cacheListTmp != null && cacheListTmp.isEmpty() == false) {
+ cacheList.addAll(cacheListTmp);
+ cacheListTmp.clear();
+
+ Collections.sort((List<cgCache>)cacheList, gcComparator);
+ }
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog.setOnCancelListener(null);
+ }
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ }
+ }
+ };
+ private Handler dropDetailsHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ setAdapter();
+
+ if (msg.what > -1) {
+ cacheList.get(msg.what).statusChecked = false;
+ } else {
+ if (adapter != null) {
+ adapter.setSelectMode(false, true);
+ }
+
+ cacheList.clear();
+
+ final ArrayList<cgCache> cacheListTmp = app.getCaches(searchId);
+ if (cacheListTmp != null && cacheListTmp.isEmpty() == false) {
+ cacheList.addAll(cacheListTmp);
+ cacheListTmp.clear();
+
+ Collections.sort((List<cgCache>)cacheList, gcComparator);
+ }
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog.setOnCancelListener(null);
+ }
+ }
+ }
+ };
+ private ContextMenuInfo lastMenuInfo;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ app.setAction(action);
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.caches);
+ base.setTitle(activity, "caches");
+
+ // google analytics
+ tracker = GoogleAnalyticsTracker.getInstance();
+ tracker.start(cgSettings.analytics, this);
+ tracker.dispatch();
+ base.sendAnal(activity, tracker, "/cache/list");
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ type = extras.getString("type");
+ latitude = extras.getDouble("latitude");
+ longitude = extras.getDouble("longitude");
+ cachetype = extras.getString("cachetype");
+ keyword = extras.getString("keyword");
+ address = extras.getString("address");
+ username = extras.getString("username");
+ }
+
+ init();
+
+ Thread threadPure;
+ cgSearchThread thread;
+
+ if (type.equals("offline") == true) {
+ listId = settings.getLastList();
+ if (listId <= 0) {
+ listId = 1;
+ title = res.getString(R.string.caches_stored);
+ } else {
+ final cgList list = app.getList(listId);
+ title = list.title;
+ }
+
+ base.setTitle(activity, title);
+ base.showProgress(activity, true);
+ setLoadingCaches();
+
+ threadPure = new geocachesLoadByOffline(loadCachesHandler, latitude, longitude, listId);
+ threadPure.start();
+ } else if (type.equals("history") == true) {
+ if (adapter != null) {
+ adapter.setHistoric(true);
+ }
+
+ title = res.getString(R.string.caches_history);
+ base.setTitle(activity, title);
+ base.showProgress(activity, true);
+ setLoadingCaches();
+
+ threadPure = new geocachesLoadByHistory(loadCachesHandler);
+ threadPure.start();
+ } else if (type.equals("nearest") == true) {
+ action = "pending";
+ title = res.getString(R.string.caches_nearby);
+ base.setTitle(activity, title);
+ base.showProgress(activity, true);
+ setLoadingCaches();
+
+ thread = new geocachesLoadByCoords(loadCachesHandler, latitude, longitude, cachetype);
+ thread.setRecaptchaHandler(new cgSearchHandler(activity, res, thread));
+ thread.start();
+ } else if (type.equals("coordinate") == true) {
+ action = "planning";
+ title = base.formatCoordinate(latitude, res.getString(R.string.search_lat), true) + " | " + base.formatCoordinate(longitude, res.getString(R.string.search_lon), true);
+ base.setTitle(activity, title);
+ base.showProgress(activity, true);
+ setLoadingCaches();
+
+ thread = new geocachesLoadByCoords(loadCachesHandler, latitude, longitude, cachetype);
+ thread.setRecaptchaHandler(new cgSearchHandler(activity, res, thread));
+ thread.start();
+ } else if (type.equals("keyword") == true) {
+ title = keyword;
+ base.setTitle(activity, title);
+ base.showProgress(activity, true);
+ setLoadingCaches();
+
+ thread = new geocachesLoadByKeyword(loadCachesHandler, keyword, cachetype);
+ thread.setRecaptchaHandler(new cgSearchHandler(activity, res, thread));
+ thread.start();
+ } else if (type.equals("address") == true) {
+ action = "planning";
+ if (address != null && address.length() > 0) {
+ title = address;
+ base.setTitle(activity, title);
+ base.showProgress(activity, true);
+ setLoadingCaches();
+ } else {
+ title = base.formatCoordinate(latitude, res.getString(R.string.search_lat), true) + " | " + base.formatCoordinate(longitude, res.getString(R.string.search_lon), true);
+ base.setTitle(activity, title);
+ base.showProgress(activity, true);
+ setLoadingCaches();
+ }
+
+ thread = new geocachesLoadByCoords(loadCachesHandler, latitude, longitude, cachetype);
+ thread.setRecaptchaHandler(new cgSearchHandler(activity, res, thread));
+ thread.start();
+ } else if (type.equals("username") == true) {
+ title = username;
+ base.setTitle(activity, title);
+ base.showProgress(activity, true);
+ setLoadingCaches();
+
+ thread = new geocachesLoadByUserName(loadCachesHandler, username, cachetype);
+ thread.setRecaptchaHandler(new cgSearchHandler(activity, res, thread));
+ thread.start();
+ } else if (type.equals("owner") == true) {
+ title = username;
+ base.setTitle(activity, title);
+ base.showProgress(activity, true);
+ setLoadingCaches();
+
+ thread = new geocachesLoadByOwner(loadCachesHandler, username, cachetype);
+ thread.setRecaptchaHandler(new cgSearchHandler(activity, res, thread));
+ thread.start();
+ } else {
+ title = "caches";
+ base.setTitle(activity, title);
+ Log.e(cgSettings.tag, "cgeocaches.onCreate: No action or unknown action specified");
+ }
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ init();
+
+ if (adapter != null && geo != null && geo.latitudeNow != null && geo.longitudeNow != null) {
+ adapter.setActualCoordinates(geo.latitudeNow, geo.longitudeNow);
+ adapter.setActualHeading(northHeading);
+ }
+
+ if (adapter != null) {
+ adapter.setSelectMode(false, true);
+ if (geo != null && geo.latitudeNow != null && geo.longitudeNow != null) {
+ adapter.forceSort(geo.latitudeNow, geo.longitudeNow);
+ }
+ }
+
+ if (loadCachesHandler != null && searchId != null) {
+ loadCachesHandler.sendEmptyMessage(0);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ if (adapter != null) {
+ adapter = null;
+ }
+
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+ if (tracker != null) {
+ tracker.stop();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStop() {
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onPause();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ SubMenu subMenuFilter = menu.addSubMenu(0, 105, 0, res.getString(R.string.caches_filter)).setIcon(android.R.drawable.ic_menu_search);
+ subMenuFilter.setHeaderTitle(res.getString(R.string.caches_filter_title));
+ subMenuFilter.add(0, 21, 0, res.getString(R.string.caches_filter_type));
+ subMenuFilter.add(0, 22, 0, res.getString(R.string.caches_filter_size));
+ subMenuFilter.add(0, 23, 0, res.getString(R.string.caches_filter_track));
+ subMenuFilter.add(0, 24, 0, res.getString(R.string.caches_filter_clear));
+
+ SubMenu subMenuSort = menu.addSubMenu(0, 104, 0, res.getString(R.string.caches_sort)).setIcon(android.R.drawable.ic_menu_sort_alphabetically);
+ subMenuSort.setHeaderTitle(res.getString(R.string.caches_sort_title));
+
+ // sort the context menu labels alphabetically for easier reading
+ HashMap<String, Integer> comparators = new HashMap<String, Integer>();
+ comparators.put(res.getString(R.string.caches_sort_distance), 10);
+ comparators.put(res.getString(R.string.caches_sort_difficulty), 11);
+ comparators.put(res.getString(R.string.caches_sort_terrain), 12);
+ comparators.put(res.getString(R.string.caches_sort_size), 13);
+ comparators.put(res.getString(R.string.caches_sort_favorites), 14);
+ comparators.put(res.getString(R.string.caches_sort_name), 15);
+ comparators.put(res.getString(R.string.caches_sort_gccode), 16);
+ comparators.put(res.getString(R.string.caches_sort_rating), 18);
+ comparators.put(res.getString(R.string.caches_sort_vote), 19);
+ comparators.put(res.getString(R.string.caches_sort_inventory), 20);
+
+ ArrayList<String> sortedLabels = new ArrayList<String>(comparators.keySet());
+ Collections.sort(sortedLabels);
+ for (String label : sortedLabels) {
+ Integer id = comparators.get(label);
+ subMenuSort.add(1, id, 0, label).setCheckable(true).setChecked(id == 10);
+ }
+
+ subMenuSort.setGroupCheckable(1, true, true);
+
+ menu.add(0, 0, 0, res.getString(R.string.caches_select_mode)).setIcon(android.R.drawable.ic_menu_agenda);
+ menu.add(0, 9, 0, res.getString(R.string.caches_select_invert)).setIcon(android.R.drawable.ic_menu_agenda);
+ if (type.equals("offline") == true) {
+ SubMenu subMenu = menu.addSubMenu(0, 103, 0, res.getString(R.string.caches_manage)).setIcon(android.R.drawable.ic_menu_save);
+ subMenu.add(0, 5, 0, res.getString(R.string.caches_drop_all)); // delete saved caches
+ subMenu.add(0, 1, 0, res.getString(R.string.cache_offline_refresh)); // download details for all caches
+ if (settings.webDeviceCode == null)
+ {
+ menu.add(0, 6, 0, res.getString(R.string.gpx_import_title)).setIcon(android.R.drawable.ic_menu_upload); // import gpx file
+ } else {
+ SubMenu subMenuImport = menu.addSubMenu(0, 105, 0, res.getString(R.string.import_title)).setIcon(android.R.drawable.ic_menu_upload); // import
+ subMenuImport.add(1, 6, 0, res.getString(R.string.gpx_import_title)).setCheckable(false).setChecked(false);
+ subMenuImport.add(1, 25, 0, res.getString(R.string.web_import_title)).setCheckable(false).setChecked(false);
+ }
+ } else {
+ menu.add(0, 1, 0, res.getString(R.string.caches_store_offline)).setIcon(android.R.drawable.ic_menu_set_as); // download details for all caches
+ }
+
+ final Intent intentTest = new Intent(Intent.ACTION_VIEW);
+ intentTest.setData(Uri.parse("menion.points:x"));
+ if (cgBase.isIntentAvailable(activity, intentTest) == true) {
+ SubMenu subMenu = menu.addSubMenu(0, 101, 0, res.getString(R.string.caches_on_map)).setIcon(android.R.drawable.ic_menu_mapmode);
+ subMenu.add(0, 2, 0, res.getString(R.string.caches_map_cgeo)); // show all caches on map using c:geo
+ subMenu.add(0, 3, 0, res.getString(R.string.caches_map_locus)); // show all caches on map using Locus
+ } else {
+ menu.add(0, 2, 0, res.getString(R.string.caches_on_map)).setIcon(android.R.drawable.ic_menu_mapmode); // show all caches on map
+ }
+
+ if (type.equals("offline") == true) {
+ SubMenu subMenu = menu.addSubMenu(0, 102, 0, res.getString(R.string.list_menu)).setIcon(android.R.drawable.ic_menu_more);
+ subMenu.add(0, 7, 0, res.getString(R.string.list_menu_create));
+ subMenu.add(0, 8, 0, res.getString(R.string.list_menu_drop));
+ subMenu.add(0, 17, 0, res.getString(R.string.list_menu_change));
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+
+ try {
+ if (adapter != null && adapter.getSelectMode() == true) {
+ menu.findItem(0).setTitle(res.getString(R.string.caches_select_mode_exit));
+ menu.findItem(9).setVisible(true);
+ } else {
+ menu.findItem(0).setTitle(res.getString(R.string.caches_select_mode));
+ menu.findItem(9).setVisible(false);
+ }
+
+ if (type != null && type.equals("offline") == true) {
+ if (adapter != null && adapter.getChecked() > 0) {
+ menu.findItem(5).setTitle(res.getString(R.string.caches_drop_selected) + " (" + adapter.getChecked() + ")");
+ } else {
+ menu.findItem(5).setTitle(res.getString(R.string.caches_drop_all));
+ }
+
+ if (adapter != null && adapter.getChecked() > 0) {
+ menu.findItem(1).setTitle(res.getString(R.string.caches_refresh_selected) + " (" + adapter.getChecked() + ")");
+ } else {
+ menu.findItem(1).setTitle(res.getString(R.string.caches_refresh_all));
+ }
+ } else {
+ if (adapter == null) {
+ Log.i(cgSettings.tag, "No adapter");
+ } else {
+ Log.i(cgSettings.tag, "Checked: " + adapter.getChecked());
+ }
+ if (adapter != null && adapter.getChecked() > 0) {
+ menu.findItem(1).setTitle(res.getString(R.string.caches_store_selected) + " (" + adapter.getChecked() + ")");
+ } else {
+ menu.findItem(1).setTitle(res.getString(R.string.caches_store_offline));
+ }
+ }
+
+ if (type != null && type.equals("offline") == false && (cacheList != null && app != null && cacheList.size() >= app.getTotal(searchId))) { // there are no more caches
+ menu.findItem(0).setEnabled(false);
+ } else {
+ menu.findItem(0).setEnabled(true);
+ }
+
+ if (listId == 1) {
+ menu.findItem(8).setVisible(false);
+ } else {
+ menu.findItem(8).setVisible(true);
+ }
+ if (app.getLists().size() < 2) {
+ menu.findItem(17).setVisible(false);
+ } else {
+ menu.findItem(17).setVisible(true);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.onPrepareOptionsMenu: " + e.toString());
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case 0:
+ if (adapter != null) {
+ adapter.switchSelectMode();
+ }
+ return true;
+ case 1:
+ refreshStored();
+ return true;
+ case 2:
+ showOnMap();
+ return false;
+ case 3:
+ showOnLocus();
+ return false;
+ case 5:
+ dropStored();
+ return false;
+ case 6:
+ importGpx();
+ return false;
+ case 7:
+ createList();
+ return false;
+ case 8:
+ removeList();
+ return false;
+ case 9:
+ if (adapter != null) {
+ adapter.invertSelection();
+ }
+ return false;
+ case 10:
+ setComparator(item, null);
+ return false;
+ case 11:
+ setComparator(item, new cgCacheDifficultyComparator());
+ return false;
+ case 12:
+ setComparator(item, new cgCacheTerrainComparator());
+ return false;
+ case 13:
+ setComparator(item, new cgCacheSizeComparator());
+ return false;
+ case 14:
+ setComparator(item, new cgCachePopularityComparator());
+ return false;
+ case 15:
+ setComparator(item, new cgCacheNameComparator());
+ return false;
+ case 16:
+ setComparator(item, new cgCacheGeocodeComparator());
+ return false;
+ case 17:
+ selectList(null);
+ return false;
+ case 18:
+ setComparator(item, new cgCacheRatingComparator());
+ return false;
+ case 19:
+ setComparator(item, new cgCacheVoteComparator());
+ return false;
+ case 20:
+ setComparator(item, new cgCacheInventoryComparator());
+ return false;
+ case 21:
+ selectedFilter = res.getString(R.string.caches_filter_type);
+ openContextMenu(getListView());
+ return false;
+ case 22:
+ selectedFilter = res.getString(R.string.caches_filter_size);
+ openContextMenu(getListView());
+ return false;
+ case 23:
+ adapter.setFilter(new cgFilterByTrackables());
+ return false;
+ case 24:
+ if (adapter != null) {
+ adapter.setFilter(null);
+ }
+ return false;
+ case 25:
+ importWeb();
+ return false;
+ }
+
+ return false;
+ }
+
+ private void setComparator(MenuItem item,
+ Comparator<cgCache> comparator) {
+ if (adapter != null) {
+ adapter.setComparator(comparator);
+ }
+ item.setChecked(true);
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info) {
+ super.onCreateContextMenu(menu, view, info);
+
+ if (adapter == null) {
+ return;
+ }
+
+ AdapterContextMenuInfo adapterInfo = null;
+ try {
+ adapterInfo = (AdapterContextMenuInfo) info;
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgeocaches.onCreateContextMenu: " + e.toString());
+ }
+
+ if ((adapterInfo == null || adapterInfo.position < 0) && selectedFilter != null){
+ // Context menu opened by selecting an option on the filter submenu
+
+ if (selectedFilter.equals(res.getString(R.string.caches_filter_size))) {
+ menu.setHeaderTitle(res.getString(R.string.caches_filter_size_title));
+ menu.add(0, 8, 0, res.getString(R.string.caches_filter_size_micro));
+ menu.add(0, 9, 0, res.getString(R.string.caches_filter_size_small));
+ menu.add(0, 10, 0, res.getString(R.string.caches_filter_size_regular));
+ menu.add(0, 11, 0, res.getString(R.string.caches_filter_size_large));
+ menu.add(0, 12, 0, res.getString(R.string.caches_filter_size_other));
+ menu.add(0, 13, 0, res.getString(R.string.caches_filter_size_virtual));
+ menu.add(0, 14, 0, res.getString(R.string.caches_filter_size_notchosen));
+ } else if (selectedFilter.equals(res.getString(R.string.caches_filter_type))) {
+ menu.setHeaderTitle(res.getString(R.string.caches_filter_type_title));
+ menu.add(0, 15, 0, res.getString(R.string.caches_filter_type_traditional));
+ menu.add(0, 16, 0, res.getString(R.string.caches_filter_type_multi));
+ menu.add(0, 17, 0, res.getString(R.string.caches_filter_type_mystery));
+ menu.add(0, 18, 0, res.getString(R.string.caches_filter_type_letterbox));
+ menu.add(0, 19, 0, res.getString(R.string.caches_filter_type_event));
+ menu.add(0, 20, 0, res.getString(R.string.caches_filter_type_mega));
+ menu.add(0, 21, 0, res.getString(R.string.caches_filter_type_earth));
+ menu.add(0, 22, 0, res.getString(R.string.caches_filter_type_cito));
+ menu.add(0, 23, 0, res.getString(R.string.caches_filter_type_webcam));
+ menu.add(0, 24, 0, res.getString(R.string.caches_filter_type_virtual));
+ menu.add(0, 25, 0, res.getString(R.string.caches_filter_type_wherigo));
+ menu.add(0, 26, 0, res.getString(R.string.caches_filter_type_lostfound));
+ menu.add(0, 27, 0, res.getString(R.string.caches_filter_type_ape));
+ menu.add(0, 28, 0, res.getString(R.string.caches_filter_type_gchq));
+ menu.add(0, 29, 0, res.getString(R.string.caches_filter_type_gps));
+ }
+ } else{
+ final cgCache cache = adapter.getItem(adapterInfo.position);
+
+ if (cache.name != null && cache.name.length() > 0) {
+ menu.setHeaderTitle(cache.name);
+ } else {
+ menu.setHeaderTitle(cache.geocode);
+ }
+
+ if (cache.latitude != null && cache.longitude != null) {
+ menu.add(0, 1, 0, res.getString(R.string.cache_menu_compass));
+ menu.add(0, 2, 0, res.getString(R.string.cache_menu_radar));
+ menu.add(0, 3, 0, res.getString(R.string.cache_menu_map));
+ menu.add(0, 4, 0, res.getString(R.string.cache_menu_map_ext));
+ menu.add(0, 5, 0, res.getString(R.string.cache_menu_tbt));
+ menu.add(0, 6, 0, res.getString(R.string.cache_menu_visit));
+ menu.add(0, 7, 0, res.getString(R.string.cache_menu_details));
+ }
+ }
+
+ ArrayList<cgList> cacheLists = app.getLists();
+ int listCount = cacheLists.size();
+ if (listCount > 1) {
+ SubMenu submenu = menu.addSubMenu(0, 8, 0, res.getString(R.string.cache_menu_move_list));
+ for (int i = 0; i < listCount; i++) {
+ cgList list = cacheLists.get(i);
+ submenu.add(Menu.NONE, 100+list.id, Menu.NONE, list.title);
+ }
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ final int id = item.getItemId();
+ ContextMenu.ContextMenuInfo info = item.getMenuInfo();
+
+ if (info == null) {
+ if(adapter != null){
+ if (id == 8) {
+ adapter.setFilter(new cgFilterBySize(res.getString(R.string.caches_filter_size_micro)));
+ } else if (id == 9) {
+ adapter.setFilter(new cgFilterBySize(res.getString(R.string.caches_filter_size_small)));
+ } else if (id == 10) {
+ adapter.setFilter(new cgFilterBySize(res.getString(R.string.caches_filter_size_regular)));
+ } else if (id == 11) {
+ adapter.setFilter(new cgFilterBySize(res.getString(R.string.caches_filter_size_large)));
+ } else if (id == 12) {
+ adapter.setFilter(new cgFilterBySize(res.getString(R.string.caches_filter_size_other)));
+ } else if (id == 13) {
+ adapter.setFilter(new cgFilterBySize(res.getString(R.string.caches_filter_size_virtual)));
+ } else if (id == 14) {
+ adapter.setFilter(new cgFilterBySize(res.getString(R.string.caches_filter_size_notchosen)));
+ } else if (id == 15) {
+ adapter.setFilter(new cgFilterByType("traditional"));
+ } else if (id == 16) {
+ adapter.setFilter(new cgFilterByType("multi"));
+ } else if (id == 17) {
+ adapter.setFilter(new cgFilterByType("mystery"));
+ } else if (id == 18) {
+ adapter.setFilter(new cgFilterByType("letterbox"));
+ } else if (id == 19) {
+ adapter.setFilter(new cgFilterByType("event"));
+ } else if (id == 20) {
+ adapter.setFilter(new cgFilterByType("mega"));
+ } else if (id == 21) {
+ adapter.setFilter(new cgFilterByType("earth"));
+ } else if (id == 22) {
+ adapter.setFilter(new cgFilterByType("cito"));
+ } else if (id == 23) {
+ adapter.setFilter(new cgFilterByType("webcam"));
+ } else if (id == 24) {
+ adapter.setFilter(new cgFilterByType("virtual"));
+ } else if (id == 25) {
+ adapter.setFilter(new cgFilterByType("wherigo"));
+ } else if (id == 26) {
+ adapter.setFilter(new cgFilterByType("lostfound"));
+ } else if (id == 27) {
+ adapter.setFilter(new cgFilterByType("ape"));
+ } else if (id == 28) {
+ adapter.setFilter(new cgFilterByType("gchq"));
+ } else if (id == 29) {
+ adapter.setFilter(new cgFilterByType("gps"));
+ } else {
+ return false;
+ }
+ return true;
+ } else {
+ // restore menu info for sub menu items, see https://code.google.com/p/android/issues/detail?id=7139
+ info = lastMenuInfo;
+ lastMenuInfo = null;
+ return false;
+ }
+ }
+
+ AdapterContextMenuInfo adapterInfo = null;
+ try {
+ adapterInfo = (AdapterContextMenuInfo) info;
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgeocaches.onContextItemSelected: " + e.toString());
+ }
+
+ final int touchedPos = adapterInfo.position;
+ final cgCache cache = adapter.getItem(touchedPos);
+
+ if (id == 1) { // compass
+ Intent navigateIntent = new Intent(activity, cgeonavigate.class);
+ navigateIntent.putExtra("latitude", cache.latitude);
+ navigateIntent.putExtra("longitude", cache.longitude);
+ navigateIntent.putExtra("geocode", cache.geocode.toUpperCase());
+ navigateIntent.putExtra("name", cache.name);
+
+ activity.startActivity(navigateIntent);
+
+ return true;
+ } else if (id == 2) { // radar
+ try {
+ if (cgBase.isIntentAvailable(activity, "com.google.android.radar.SHOW_RADAR") == true) {
+ Intent radarIntent = new Intent("com.google.android.radar.SHOW_RADAR");
+ radarIntent.putExtra("latitude", new Float(cache.latitude));
+ radarIntent.putExtra("longitude", new Float(cache.longitude));
+ activity.startActivity(radarIntent);
+ } else {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
+ dialog.setTitle(res.getString(R.string.err_radar_title));
+ dialog.setMessage(res.getString(R.string.err_radar_message));
+ dialog.setCancelable(true);
+ dialog.setPositiveButton(getString(android.R.string.yes), new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:com.eclipsim.gpsstatus2")));
+ dialog.cancel();
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_market));
+ Log.e(cgSettings.tag, "cgeocaches.onContextItemSelected.radar.onClick: " + e.toString());
+ }
+ }
+ });
+ dialog.setNegativeButton(getString(android.R.string.no), new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ }
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_generic));
+ Log.e(cgSettings.tag, "cgeocaches.onContextItemSelected.radar: " + e.toString());
+ }
+
+ return true;
+ } else if (id == 3) { // show on map
+ Intent mapIntent = new Intent(activity, settings.getMapFactory().getMapClass());
+ mapIntent.putExtra("detail", false);
+ mapIntent.putExtra("geocode", cache.geocode);
+
+ activity.startActivity(mapIntent);
+
+ return true;
+ } else if (id == 4) { // show on external map
+ base.runExternalMap(0, activity, res, warning, tracker, cache);
+
+ return true;
+ } else if (id == 5) { // turn-by-turn
+ if (geo != null) {
+ base.runNavigation(activity, res, settings, warning, tracker, cache.latitude, cache.longitude, geo.latitudeNow, geo.longitudeNow);
+ } else {
+ base.runNavigation(activity, res, settings, warning, tracker, cache.latitude, cache.longitude);
+ }
+
+ return true;
+ } else if (id == 6) { // log visit
+ if (cache.cacheid == null || cache.cacheid.length() == 0) {
+ warning.showToast(res.getString(R.string.err_cannot_log_visit));
+ return true;
+ }
+
+ Intent logVisitIntent = new Intent(activity, cgeovisit.class);
+ logVisitIntent.putExtra("id", cache.cacheid);
+ logVisitIntent.putExtra("geocode", cache.geocode.toUpperCase());
+ logVisitIntent.putExtra("type", cache.type.toLowerCase());
+
+ activity.startActivity(logVisitIntent);
+
+ return true;
+ } else if (id == 7) { // cache details
+ Intent cachesIntent = new Intent(activity, cgeodetail.class);
+ cachesIntent.putExtra("geocode", cache.geocode.toUpperCase());
+ cachesIntent.putExtra("name", cache.name);
+ activity.startActivity(cachesIntent);
+
+ return true;
+ } else if (id == 8) { // move to list (sub menu)
+ // we must remember the menu info for the sub menu, there is a bug in Android:
+ // https://code.google.com/p/android/issues/detail?id=7139
+ lastMenuInfo = info;
+ return true;
+ } else if (id >= 100) { // move to list
+ int newListId = id - 100;
+ app.moveToList(cache.geocode, newListId);
+ // refresh list by switching to the current list
+ switchListById(listId);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (adapter != null) {
+ if (adapter.resetChecks() == true) {
+ return;
+ } else if (adapter.getSelectMode() == true) {
+ adapter.setSelectMode(false, true);
+
+ return;
+ }
+
+ if (adapter.isFilter()) {
+ adapter.clearFilter();
+
+ return;
+ }
+ }
+
+ super.onBackPressed();
+
+ return;
+ }
+
+ private void setAdapter() {
+ if (listFooter == null) {
+ if (inflater == null) {
+ inflater = activity.getLayoutInflater();
+ }
+ listFooter = inflater.inflate(R.layout.caches_footer, null);
+
+ listFooter.setClickable(true);
+ listFooter.setOnClickListener(new moreCachesListener());
+ }
+ if (listFooterText == null) {
+ listFooterText = (TextView) listFooter.findViewById(R.id.more_caches);
+ }
+
+ if (adapter == null) {
+ final ListView list = getListView();
+
+ registerForContextMenu(list);
+ list.setLongClickable(true);
+ list.addFooterView(listFooter);
+
+ adapter = new cgCacheListAdapter(activity, settings, cacheList, base);
+ setListAdapter(adapter);
+ } else {
+ adapter.notifyDataSetChanged();
+ }
+
+ if (adapter != null && geo != null) {
+ adapter.setActualCoordinates(geo.latitudeNow, geo.longitudeNow);
+ }
+ if (adapter != null && dir != null) {
+ adapter.setActualHeading(dir.directionNow);
+ }
+ }
+
+ private void setLoadingCaches() {
+ if (listFooter == null) {
+ return;
+ }
+ if (listFooterText == null) {
+ return;
+ }
+
+ listFooterText.setText(res.getString(R.string.caches_more_caches_loading));
+ listFooter.setClickable(false);
+ listFooter.setOnClickListener(null);
+ }
+
+ private void setMoreCaches(boolean more) {
+ if (listFooter == null) {
+ return;
+ }
+ if (listFooterText == null) {
+ return;
+ }
+
+ if (more == false) {
+ if (cacheList == null || cacheList.isEmpty()) {
+ listFooterText.setText(res.getString(R.string.caches_no_cache));
+ } else {
+ listFooterText.setText(res.getString(R.string.caches_more_caches_no));
+ }
+ listFooter.setClickable(false);
+ listFooter.setOnClickListener(null);
+ } else {
+ listFooterText.setText(res.getString(R.string.caches_more_caches));
+ listFooter.setClickable(true);
+ listFooter.setOnClickListener(new moreCachesListener());
+ }
+ }
+
+ private void init() {
+ // sensor & geolocation manager
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.livelist == 1 && settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+
+ if (cacheList != null) {
+ base.setTitle(activity, title);
+ }
+
+ if (cacheList != null && cacheList.isEmpty() == false) {
+ final Integer count = app.getTotal(searchId);
+ if (count != null && count > 0) {
+ base.setTitle(activity, title);
+ if (cacheList.size() < app.getTotal(searchId) && cacheList.size() < 1000) {
+ setMoreCaches(true);
+ } else {
+ setMoreCaches(false);
+ }
+ } else {
+ base.setTitle(activity, title);
+ setMoreCaches(false);
+ }
+ } else {
+ base.setTitle(activity, title);
+ }
+
+ setAdapter();
+
+ if (geo != null) {
+ geoUpdate.updateLoc(geo);
+ }
+ if (dir != null) {
+ dirUpdate.updateDir(dir);
+ }
+ }
+
+ private void showOnMap() {
+ if (searchId == null || searchId == 0 || cacheList == null || cacheList.isEmpty() == true) {
+ warning.showToast(res.getString(R.string.warn_no_cache_coord));
+
+ return;
+ }
+
+ Intent mapIntent = new Intent(activity, settings.getMapFactory().getMapClass());
+ mapIntent.putExtra("detail", false);
+ mapIntent.putExtra("searchid", searchId);
+
+ activity.startActivity(mapIntent);
+ }
+
+ private void showOnLocus() {
+ if (cacheList == null || cacheList.isEmpty() == true) {
+ return;
+ }
+
+ try {
+ final Intent intentTest = new Intent(Intent.ACTION_VIEW);
+ intentTest.setData(Uri.parse("menion.points:x"));
+
+ if (cgBase.isIntentAvailable(activity, intentTest) == false) {
+ return;
+ }
+
+ final ArrayList<cgCache> cacheListTemp = (ArrayList<cgCache>) cacheList.clone();
+ final ArrayList<cgCache> cacheListCoord = new ArrayList<cgCache>();
+ for (cgCache cache : cacheListTemp) {
+ if (cache.latitude != null && cache.longitude != null) {
+ cacheListCoord.add(cache);
+ }
+ }
+ cacheListTemp.clear();
+
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ final DataOutputStream dos = new DataOutputStream(baos);
+
+ dos.writeInt(1); // not used
+ dos.writeInt(cacheListCoord.size()); // cache and waypoints
+
+ // cache waypoints
+ if (cacheListCoord != null && cacheListCoord.isEmpty() == false) {
+ for (cgCache cache : cacheListCoord) {
+ final int wpIcon = base.getIcon(true, cache.type, cache.own, cache.found, cache.disabled);
+
+ if (wpIcon > 0) {
+ // load icon
+ Bitmap bitmap = BitmapFactory.decodeResource(res, wpIcon);
+ ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos2);
+ byte[] image = baos2.toByteArray();
+
+ dos.writeInt(image.length);
+ dos.write(image);
+ } else {
+ // no icon
+ dos.writeInt(0); // no image
+ }
+
+ // name
+ if (cache != null && cache.geocode != null && cache.geocode.length() > 0) {
+ dos.writeUTF(cache.geocode.toUpperCase());
+ } else {
+ dos.writeUTF("");
+ }
+
+ // description
+ if (cache != null && cache.name != null && cache.name.length() > 0) {
+ dos.writeUTF(cache.name);
+ } else {
+ dos.writeUTF("");
+ }
+
+ // additional data :: keyword, button title, package, activity, data name, data content
+ if (cache != null && cache.geocode != null && cache.geocode.length() > 0) {
+ dos.writeUTF("intent;c:geo;cgeo.geocaching;cgeo.geocaching.cgeodetail;geocode;" + cache.geocode);
+ } else {
+ dos.writeUTF("");
+ }
+
+ dos.writeDouble(cache.latitude); // latitude
+ dos.writeDouble(cache.longitude); // longitude
+ }
+ }
+
+ final Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse("menion.points:data"));
+ intent.putExtra("data", baos.toByteArray());
+
+ activity.startActivity(intent);
+
+ base.sendAnal(activity, tracker, "/external/locus");
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ private void importGpx() {
+ final Intent intent = new Intent(activity, cgeogpxes.class);
+ intent.putExtra("list", listId);
+ activity.startActivity(intent);
+
+ finish();
+ }
+
+ public void refreshStored() {
+ if (adapter != null && adapter.getChecked() > 0) {
+ // there are some checked caches
+ detailTotal = adapter.getChecked();
+ } else {
+ // no checked caches, download everything (when already stored - refresh them)
+ detailTotal = cacheList.size();
+ }
+ detailProgress = 0;
+
+ base.showProgress(activity, false);
+ waitDialog = new ProgressDialog(this);
+ waitDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+
+ public void onCancel(DialogInterface arg0) {
+ try {
+ if (threadD != null) {
+ threadD.kill();
+ }
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.livelist == 1 && settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.onOptionsItemSelected.onCancel: " + e.toString());
+ }
+ }
+ });
+
+ waitDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ int etaTime = (int) ((detailTotal * 25) / 60);
+ if (etaTime < 1) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + res.getString(R.string.caches_eta_ltm));
+ } else if (etaTime == 1) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + etaTime + " " + res.getString(R.string.caches_eta_min));
+ } else {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + etaTime + " " + res.getString(R.string.caches_eta_mins));
+ }
+ waitDialog.setCancelable(true);
+ waitDialog.setMax(detailTotal);
+ waitDialog.show();
+
+ detailProgressTime = System.currentTimeMillis();
+
+ threadD = new geocachesLoadDetails(loadDetailsHandler, listId);
+ threadD.start();
+ }
+
+ public void importWeb() {
+ detailProgress = 0;
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ base.showProgress(activity, false);
+ waitDialog = new ProgressDialog(this);
+ waitDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+
+ public void onCancel(DialogInterface arg0) {
+ try {
+ if (threadW != null) {
+ threadW.kill();
+ }
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.livelist == 1 && settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.importWeb.onCancel: " + e.toString());
+ }
+ }
+ });
+
+ waitDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
+ waitDialog.setMessage(res.getString(R.string.web_import_waiting));
+ waitDialog.setCancelable(true);
+ waitDialog.show();
+
+ threadW = new geocachesLoadFromWeb(downloadFromWebHandler, listId);
+ threadW.start();
+ }
+
+ public void dropStored() {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
+ dialog.setCancelable(true);
+ dialog.setTitle(res.getString(R.string.caches_drop_stored));
+
+ if (adapter != null && adapter.getChecked() > 0) {
+ dialog.setMessage(res.getString(R.string.caches_drop_selected_ask));
+ dialog.setPositiveButton(getString(android.R.string.yes), new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dropSelected();
+ dialog.cancel();
+ }
+ });
+ } else {
+ dialog.setMessage(res.getString(R.string.caches_drop_all_ask));
+ dialog.setPositiveButton(getString(android.R.string.yes), new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dropSelected();
+ dialog.cancel();
+ }
+ });
+ }
+ dialog.setNegativeButton(getString(android.R.string.no), new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ }
+
+ public void dropSelected() {
+ waitDialog = new ProgressDialog(this);
+ waitDialog.setMessage(res.getString(R.string.caches_drop_progress));
+ waitDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+
+ public void onCancel(DialogInterface arg0) {
+ try {
+ if (threadR != null) {
+ threadR.kill();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.onOptionsItemSelected.onCancel: " + e.toString());
+ }
+ }
+ });
+
+ waitDialog.setCancelable(true);
+ waitDialog.show();
+
+ threadR = new geocachesDropDetails(dropDetailsHandler);
+ threadR.start();
+ }
+
+ private class update extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+ if (adapter == null) {
+ return;
+ }
+
+ try {
+ if (cacheList != null && geo.latitudeNow != null && geo.longitudeNow != null) {
+ adapter.setActualCoordinates(geo.latitudeNow, geo.longitudeNow);
+ }
+
+ if (settings.useCompass == 0 || (geo.speedNow != null && geo.speedNow > 5)) { // use GPS when speed is higher than 18 km/h
+ if (settings.useCompass == 0) {
+ if (geo.bearingNow != null) {
+ adapter.setActualHeading(geo.bearingNow);
+ } else {
+ adapter.setActualHeading(new Double(0));
+ }
+ }
+ if (northHeading != null) {
+ adapter.setActualHeading(northHeading);
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ private class updateDir extends cgUpdateDir {
+
+ @Override
+ public void updateDir(cgDirection dir) {
+ if (settings.livelist == 0) {
+ return;
+ }
+ if (dir == null || dir.directionNow == null) {
+ return;
+ }
+
+ northHeading = dir.directionNow;
+ if (northHeading != null && adapter != null && (geo == null || geo.speedNow == null || geo.speedNow <= 5)) { // use compass when speed is lower than 18 km/h) {
+ adapter.setActualHeading(northHeading);
+ }
+ }
+ }
+
+ private class geocachesLoadByOffline extends Thread {
+
+ private Handler handler = null;
+ private Double latitude = null;
+ private Double longitude = null;
+ private int listId = 1;
+
+ public geocachesLoadByOffline(Handler handlerIn, Double latitudeIn, Double longitudeIn, int listIdIn) {
+ handler = handlerIn;
+ latitude = latitudeIn;
+ longitude = longitudeIn;
+ listId = listIdIn;
+ }
+
+ @Override
+ public void run() {
+ HashMap<String, Object> params = new HashMap<String, Object>();
+ if (latitude != null && longitude != null) {
+ params.put("latitude", latitude);
+ params.put("longitude", longitude);
+ params.put("cachetype", settings.cacheType);
+ params.put("list", listId);
+ }
+
+ searchId = base.searchByOffline(params);
+
+ handler.sendMessage(new Message());
+ }
+ }
+
+ private class geocachesLoadByHistory extends Thread {
+
+ private Handler handler = null;
+
+ public geocachesLoadByHistory(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ HashMap<String, Object> params = new HashMap<String, Object>();
+ if (latitude != null && longitude != null) {
+ params.put("cachetype", settings.cacheType);
+ }
+
+ searchId = base.searchByHistory(params);
+
+ handler.sendMessage(new Message());
+ }
+ }
+
+ private class geocachesLoadNextPage extends cgSearchThread {
+
+ private Handler handler = null;
+
+ public geocachesLoadNextPage(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ searchId = base.searchByNextPage(this, searchId, 0, settings.showCaptcha);
+
+ handler.sendMessage(new Message());
+ }
+ }
+
+ private class geocachesLoadByCoords extends cgSearchThread {
+
+ private Handler handler = null;
+ private Double latitude = null;
+ private Double longitude = null;
+ private String cachetype = null;
+
+ public geocachesLoadByCoords(Handler handlerIn, Double latitudeIn, Double longitudeIn, String cachetypeIn) {
+ setPriority(Thread.MIN_PRIORITY);
+
+ handler = handlerIn;
+ latitude = latitudeIn;
+ longitude = longitudeIn;
+ cachetype = cachetypeIn;
+
+ if (latitude == null || longitude == null) {
+ warning.showToast(res.getString(R.string.warn_no_coordinates));
+
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public void run() {
+ HashMap<String, String> params = new HashMap<String, String>();
+ params.put("latitude", String.format((Locale) null, "%.6f", latitude));
+ params.put("longitude", String.format((Locale) null, "%.6f", longitude));
+ params.put("cachetype", cachetype);
+
+ searchId = base.searchByCoords(this, params, 0, settings.showCaptcha);
+
+ handler.sendMessage(new Message());
+ }
+ }
+
+ private class geocachesLoadByKeyword extends cgSearchThread {
+
+ private Handler handler = null;
+ private String keyword = null;
+ private String cachetype = null;
+
+ public geocachesLoadByKeyword(Handler handlerIn, String keywordIn, String cachetypeIn) {
+ setPriority(Thread.MIN_PRIORITY);
+
+ handler = handlerIn;
+ keyword = keywordIn;
+ cachetype = cachetypeIn;
+
+ if (keyword == null) {
+ warning.showToast(res.getString(R.string.warn_no_keyword));
+
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public void run() {
+ HashMap<String, String> params = new HashMap<String, String>();
+ params.put("keyword", keyword);
+ params.put("cachetype", cachetype);
+
+ searchId = base.searchByKeyword(this, params, 0, settings.showCaptcha);
+
+ handler.sendMessage(new Message());
+ }
+ }
+
+ private class geocachesLoadByUserName extends cgSearchThread {
+
+ private Handler handler = null;
+ private String username = null;
+ private String cachetype = null;
+
+ public geocachesLoadByUserName(Handler handlerIn, String usernameIn, String cachetypeIn) {
+ setPriority(Thread.MIN_PRIORITY);
+
+ handler = handlerIn;
+ username = usernameIn;
+ cachetype = cachetypeIn;
+
+ if (username == null || username.length() == 0) {
+ warning.showToast(res.getString(R.string.warn_no_username));
+
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public void run() {
+ HashMap<String, String> params = new HashMap<String, String>();
+ params.put("username", username);
+ params.put("cachetype", cachetype);
+
+ searchId = base.searchByUsername(this, params, 0, settings.showCaptcha);
+
+ handler.sendMessage(new Message());
+ }
+ }
+
+ private class geocachesLoadByOwner extends cgSearchThread {
+
+ private Handler handler = null;
+ private String username = null;
+ private String cachetype = null;
+
+ public geocachesLoadByOwner(Handler handlerIn, String usernameIn, String cachetypeIn) {
+ setPriority(Thread.MIN_PRIORITY);
+
+ handler = handlerIn;
+ username = usernameIn;
+ cachetype = cachetypeIn;
+
+ if (username == null || username.length() == 0) {
+ warning.showToast(res.getString(R.string.warn_no_username));
+
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public void run() {
+ HashMap<String, String> params = new HashMap<String, String>();
+ params.put("username", username);
+ params.put("cachetype", cachetype);
+
+ searchId = base.searchByOwner(this, params, 0, settings.showCaptcha);
+
+ handler.sendMessage(new Message());
+ }
+ }
+
+ private class geocachesLoadDetails extends Thread {
+
+ private Handler handler = null;
+ private int reason = 1;
+ private volatile boolean needToStop = false;
+ private int checked = 0;
+ private long last = 0l;
+
+ public geocachesLoadDetails(Handler handlerIn, int reasonIn) {
+ setPriority(Thread.MIN_PRIORITY);
+
+ handler = handlerIn;
+ reason = reasonIn;
+
+ if (adapter != null) {
+ checked = adapter.getChecked();
+ }
+ }
+
+ public void kill() {
+ needToStop = true;
+ }
+
+ @Override
+ public void run() {
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ final ArrayList<cgCache> cacheListTemp = (ArrayList<cgCache>) cacheList.clone();
+ for (cgCache cache : cacheListTemp) {
+ if (checked > 0 && cache.statusChecked == false) {
+ handler.sendEmptyMessage(0);
+
+ yield();
+ continue;
+ }
+
+ try {
+ if (needToStop == true) {
+ Log.i(cgSettings.tag, "Stopped storing process.");
+ break;
+ }
+
+ if ((System.currentTimeMillis() - last) < 1500) {
+ try {
+ int delay = 1000 + ((Double) (Math.random() * 1000)).intValue() - (int) (System.currentTimeMillis() - last);
+ if (delay < 0) {
+ delay = 500;
+ }
+
+ Log.i(cgSettings.tag, "Waiting for next cache " + delay + " ms");
+ sleep(delay);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.geocachesLoadDetails.sleep: " + e.toString());
+ }
+ }
+
+ if (needToStop == true) {
+ Log.i(cgSettings.tag, "Stopped storing process.");
+ break;
+ }
+
+ detailProgress++;
+ base.storeCache(app, activity, cache, null, reason, handler);
+
+ handler.sendEmptyMessage(cacheList.indexOf(cache));
+
+ yield();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.geocachesLoadDetails: " + e.toString());
+ }
+
+ last = System.currentTimeMillis();
+ }
+ cacheListTemp.clear();
+
+ handler.sendEmptyMessage(-1);
+ }
+ }
+
+ //tg
+ private class geocachesLoadFromWeb extends Thread {
+
+ private Handler handler = null;
+ private int reason = 1;
+ private volatile boolean needToStop = false;
+ private int checked = 0;
+ private long last = 0l;
+
+ public geocachesLoadFromWeb(Handler handlerIn, int reasonIn) {
+ setPriority(Thread.MIN_PRIORITY);
+
+ handler = handlerIn;
+ reason = reasonIn;
+ }
+
+ public void kill() {
+ needToStop = true;
+ }
+
+ @Override
+ public void run() {
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ int delay=-1;
+ int times=0;
+
+ while (times < 36) //3 minutes max
+ {
+ if (needToStop)
+ {
+ handler.sendEmptyMessage(-1);
+ break;
+ }
+
+ //download new code
+ String deviceCode = settings.webDeviceCode;
+ if (deviceCode==null) deviceCode="";
+ cgResponse responseFromWeb = base.request(false, "send2cgeo.carnero.cc", "/readCode.php", "GET", "d=" + cgBase.urlencode_rfc3986(deviceCode), 0, true);
+
+ if ((responseFromWeb.getStatusCode() == 200)&&(responseFromWeb.getData().length()>2)) {
+
+ String GCcode = responseFromWeb.getData();
+
+ delay=1;
+ Message mes = new Message();
+ mes.what=1;
+ mes.obj=GCcode;
+ handler.sendMessage(mes);
+ yield();
+
+ base.storeCache(app, activity, null, GCcode, reason, null);
+
+ Message mes1 = new Message();
+ mes1.what=2;
+ mes1.obj=GCcode;
+ handler.sendMessage(mes1);
+ yield();
+ } else {
+ delay=0;
+ handler.sendEmptyMessage(0);
+ yield();
+ }
+ if (responseFromWeb.getStatusCode() != 200) {
+ needToStop = true;
+ settings.setWebNameCode(null, null);
+ handler.sendEmptyMessage(-2);
+ return;
+ }
+
+ try {
+ yield();
+ if (delay==0)
+ {
+ sleep(5000); //No caches 5s
+ times++;
+ } else {
+ sleep(500); //Cache was loaded 0.5s
+ times=0;
+ }
+ } catch (InterruptedException e) {
+ Log.e(cgSettings.tag, "cgeocaches.geocachesLoadFromWeb.sleep: " + e.toString());
+ }
+ }
+ handler.sendEmptyMessage(-1);
+ }
+ }
+ //tg
+
+ private class geocachesDropDetails extends Thread {
+
+ private Handler handler = null;
+ private volatile boolean needToStop = false;
+ private int checked = 0;
+
+ public geocachesDropDetails(Handler handlerIn) {
+ setPriority(Thread.MIN_PRIORITY);
+
+ handler = handlerIn;
+
+ if (adapter != null) {
+ checked = adapter.getChecked();
+ }
+ }
+
+ public void kill() {
+ needToStop = true;
+ }
+
+ @Override
+ public void run() {
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ final ArrayList<cgCache> cacheListTemp = (ArrayList<cgCache>) cacheList.clone();
+ for (cgCache cache : cacheListTemp) {
+ if (checked > 0 && cache.statusChecked == false) {
+ handler.sendEmptyMessage(0);
+
+ yield();
+ continue;
+ }
+
+ try {
+ if (needToStop == true) {
+ Log.i(cgSettings.tag, "Stopped dropping process.");
+ break;
+ }
+
+ app.markDropped(cache.geocode);
+
+ handler.sendEmptyMessage(cacheList.indexOf(cache));
+
+ yield();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.geocachesDropDetails: " + e.toString());
+ }
+ }
+ cacheListTemp.clear();
+
+ handler.sendEmptyMessage(-1);
+ }
+ }
+
+ private class moreCachesListener implements View.OnClickListener {
+
+ @Override
+ public void onClick(View arg0) {
+ base.showProgress(activity, true);
+ setLoadingCaches();
+ listFooter.setOnClickListener(null);
+
+ geocachesLoadNextPage thread;
+ thread = new geocachesLoadNextPage(loadNextPageHandler);
+ thread.setRecaptchaHandler(new cgSearchHandler(activity, res, thread));
+ thread.start();
+ }
+ }
+
+ private void hideLoading() {
+ final ListView list = getListView();
+ final RelativeLayout loading = (RelativeLayout) findViewById(R.id.loading);
+
+ if (list.getVisibility() == View.GONE) {
+ list.setVisibility(View.VISIBLE);
+ loading.setVisibility(View.GONE);
+ }
+ }
+
+ public void selectList(View view) {
+ if (type.equals("offline") == false) {
+ return;
+ }
+
+ lists = app.getLists();
+
+ if (lists == null) {
+ return;
+ }
+
+ final ArrayList<CharSequence> listsTitle = new ArrayList<CharSequence>();
+ for (cgList list : lists) {
+ listsTitle.add(list.title);
+ }
+
+ final CharSequence[] items = new CharSequence[listsTitle.size()];
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setTitle(res.getString(R.string.list_title));
+ builder.setItems(listsTitle.toArray(items), new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialogInterface, int item) {
+ switchListByOrder(item);
+
+ return;
+ }
+ });
+ builder.create().show();
+ }
+
+ public void switchListByOrder(int order) {
+ switchList(-1, order);
+ }
+
+ public void switchListById(int id) {
+ switchList(id, -1);
+ }
+
+ public void switchList(int id, int order) {
+ cgList list = null;
+
+ if (id >= 0) {
+ list = app.getList(id);
+ } else if (order >= 0) {
+ lists = app.getLists();
+ list = lists.get(order);
+ } else {
+ return;
+ }
+
+ if (list == null) {
+ return;
+ }
+
+ listId = list.id;
+ title = list.title;
+
+ settings.saveLastList(listId);
+
+ base.showProgress(activity, true);
+ setLoadingCaches();
+
+ Handler handlerMove = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ Thread threadPure = new geocachesLoadByOffline(loadCachesHandler, latitude, longitude, msg.what);
+ threadPure.start();
+ }
+ };
+
+ (new moveCachesToList(listId, handlerMove)).start();
+ }
+
+ private class moveCachesToList extends Thread {
+ int listId = -1;
+ Handler handler = null;
+
+ public moveCachesToList(int listIdIn, Handler handlerIn) {
+ listId = listIdIn;
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ int checked = adapter.getChecked();
+ if (checked > 0) {
+ final ArrayList<cgCache> cacheListTemp = (ArrayList<cgCache>) cacheList.clone();
+ for (cgCache cache : cacheListTemp) {
+ if (cache.statusChecked != false) {
+ app.moveToList(cache.geocode, listId);
+ }
+ }
+ }
+
+ handler.sendEmptyMessage(listId);
+ }
+ }
+
+ private void createList() {
+ final AlertDialog.Builder alert = new AlertDialog.Builder(this);
+ final View view = inflater.inflate(R.layout.list_create_dialog, null);
+ final EditText input = (EditText) view.findViewById(R.id.text);
+
+ alert.setTitle(R.string.list_dialog_create_title);
+ alert.setView(view);
+ alert.setPositiveButton(R.string.list_dialog_create, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ String value = input.getText().toString();
+ // remove whitespaces added by autocompletion of Android keyboard
+ if (value != null) {
+ value = value.trim();
+ }
+
+ if (value != null && value.length() > 0) {
+ int newId = app.createList(value);
+
+ if (newId >= 10) {
+ warning.showToast(res.getString(R.string.list_dialog_create_ok));
+ } else {
+ warning.showToast(res.getString(R.string.list_dialog_create_err));
+ }
+ }
+ }
+ });
+ alert.setNegativeButton(res.getString(R.string.list_dialog_cancel), new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ dialog.dismiss();
+ }
+ });
+
+ alert.show();
+ }
+
+ private void removeList() {
+ final AlertDialog.Builder alert = new AlertDialog.Builder(this);
+
+ alert.setTitle(R.string.list_dialog_remove_title);
+ alert.setMessage(R.string.list_dialog_remove_description);
+ alert.setPositiveButton(R.string.list_dialog_remove, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ boolean status = app.removeList(listId);
+
+ if (status) {
+ warning.showToast(res.getString(R.string.list_dialog_remove_ok));
+ switchListById(1);
+ } else {
+ warning.showToast(res.getString(R.string.list_dialog_remove_err));
+ }
+ }
+ });
+ alert.setNegativeButton(res.getString(R.string.list_dialog_cancel), new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ dialog.dismiss();
+ }
+ });
+
+ alert.show();
+ }
+
+ public void goMap(View view) {
+ showOnMap();
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ if (type != null && type.equals("offline") == true) {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-stored",
+ activity,
+ "http://cgeo.carnero.cc/manual/");
+ } else if (type != null && type.equals("history") == true) {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-history",
+ activity,
+ "http://cgeo.carnero.cc/manual/");
+ } else {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-nearby",
+ activity,
+ "http://cgeo.carnero.cc/manual/");
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgeodate.java b/src/cgeo/geocaching/cgeodate.java
new file mode 100644
index 0000000..b0d5b5b
--- /dev/null
+++ b/src/cgeo/geocaching/cgeodate.java
@@ -0,0 +1,62 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.app.Dialog;
+import android.view.ViewGroup.LayoutParams;
+import android.view.Window;
+import android.widget.DatePicker;
+import java.util.Calendar;
+
+public class cgeodate extends Dialog {
+
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private cgLogForm parent = null;
+ private Calendar date = Calendar.getInstance();
+
+ public cgeodate(Activity contextIn, cgLogForm parentIn, Calendar dateIn) {
+ super(contextIn);
+
+ // init
+ settings = new cgSettings(contextIn, contextIn.getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase((cgeoapplication) contextIn.getApplication(), settings, contextIn.getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(contextIn);
+ date = dateIn;
+
+ parent = parentIn;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ try {
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ getWindow().setLayout(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
+ } catch (Exception e) {
+ // nothing
+ }
+
+ setContentView(R.layout.date);
+
+ // google analytics
+ base.sendAnal(this.getContext(), "/date");
+
+ DatePicker picker = (DatePicker) findViewById(R.id.picker);
+ picker.init(date.get(Calendar.YEAR), date.get(Calendar.MONTH), date.get(Calendar.DATE), new pickerListener());
+ }
+
+ public class pickerListener implements DatePicker.OnDateChangedListener {
+
+ @Override
+ public void onDateChanged(DatePicker picker, int year, int month, int day) {
+ if (parent != null) {
+ date.set(year, month, day);
+
+ parent.setDate(date);
+ }
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgeodetail.java b/src/cgeo/geocaching/cgeodetail.java
new file mode 100644
index 0000000..a786cb3
--- /dev/null
+++ b/src/cgeo/geocaching/cgeodetail.java
@@ -0,0 +1,1902 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Bundle;
+import android.util.Log;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.ContentValues;
+import android.content.Context;
+import android.text.Html;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.method.LinkMovementMethod;
+import android.view.ContextMenu;
+import android.view.View;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.LayoutInflater;
+import android.widget.ScrollView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.widget.ImageView;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.SubMenu;
+import android.view.WindowManager;
+import android.widget.Button;
+
+import com.google.android.apps.analytics.GoogleAnalyticsTracker;
+import java.net.URLEncoder;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map.Entry;
+
+public class cgeodetail extends Activity {
+ public Long searchId = null;
+ public cgCache cache = null;
+ public String geocode = null;
+ public String name = null;
+ public String guid = null;
+ private GoogleAnalyticsTracker tracker = null;
+ private Resources res = null;
+ private Activity activity = null;
+ private LayoutInflater inflater = null;
+ private cgeoapplication app = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private cgGeo geo = null;
+ private cgUpdateLoc geoUpdate = new update();
+ private float pixelRatio = 1;
+ private TextView cacheDistance = null;
+ private String contextMenuUser = null;
+ private ProgressDialog waitDialog = null;
+ private ProgressDialog descDialog = null;
+ private Spanned longDesc = null;
+ private Boolean longDescDisplayed = false;
+ private loadCache threadCache = null;
+ private loadLongDesc threadLongDesc = null;
+ private Thread storeThread = null;
+ private Thread refreshThread = null;
+ private HashMap<String, Integer> gcIcons = new HashMap<String, Integer>();
+ private ProgressDialog storeDialog = null;
+ private ProgressDialog refreshDialog = null;
+ private ProgressDialog dropDialog = null;
+ private HashMap<Integer, String> calendars = new HashMap<Integer, String>();
+ private Handler storeCacheHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ storeThread = null;
+
+ try {
+ cache = app.getCache(searchId); // reload cache details
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_store_failed));
+
+ Log.e(cgSettings.tag, "cgeodetail.storeCacheHandler: " + e.toString());
+ }
+
+ setView();
+ }
+ };
+
+ private Handler refreshCacheHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ refreshThread = null;
+
+ try {
+ cache = app.getCache(searchId); // reload cache details
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_refresh_failed));
+
+ Log.e(cgSettings.tag, "cgeodetail.refreshCacheHandler: " + e.toString());
+ }
+
+ setView();
+ }
+ };
+
+ private Handler dropCacheHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ cache = app.getCache(searchId); // reload cache details
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_drop_failed));
+
+ Log.e(cgSettings.tag, "cgeodetail.dropCacheHandler: " + e.toString());
+ }
+
+ setView();
+ }
+ };
+
+ private Handler loadCacheHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (searchId == null || searchId <= 0) {
+ warning.showToast(res.getString(R.string.err_dwld_details_failed));
+
+ finish();
+ return;
+ }
+
+ if (app.getError(searchId) != null) {
+ warning.showToast(res.getString(R.string.err_dwld_details_failed_reason) + " " + app.getError(searchId) + ".");
+
+ finish();
+ return;
+ }
+
+ setView();
+
+ if (settings.autoLoadDesc == 1) {
+ try {
+ loadLongDesc();
+ } catch (Exception e) {
+ // activity is not visible
+ }
+ }
+
+ (new loadMapPreview(cache, loadMapPreviewHandler)).start();
+ }
+ };
+
+ final Handler loadMapPreviewHandler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ BitmapDrawable image = (BitmapDrawable) message.obj;
+ ScrollView scroll = (ScrollView) findViewById(R.id.details_list_box);
+ ImageView view = (ImageView) findViewById(R.id.map_preview);
+
+ if (image != null && view != null) {
+ view.setImageDrawable(image);
+
+ if (scroll.getScrollY() == 0) {
+ scroll.scrollTo(0, (int) (80 * pixelRatio));
+ }
+ view.setVisibility(View.VISIBLE);
+ }
+ }
+ };
+
+ private Handler loadDescriptionHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (longDesc == null && cache != null && cache.description != null) {
+ longDesc = Html.fromHtml(cache.description.trim(), new cgHtmlImg(activity, settings, geocode, true, cache.reason, false), null);
+ }
+
+ if (longDesc != null) {
+ ((LinearLayout) findViewById(R.id.desc_box)).setVisibility(View.VISIBLE);
+ TextView descView = (TextView) findViewById(R.id.description);
+ if (cache.description.length() > 0) {
+ descView.setVisibility(View.VISIBLE);
+ descView.setText(longDesc, TextView.BufferType.SPANNABLE);
+ descView.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+ else {
+ descView.setVisibility(View.GONE);
+ }
+
+ Button showDesc = (Button) findViewById(R.id.show_description);
+ showDesc.setVisibility(View.GONE);
+ showDesc.setOnTouchListener(null);
+ showDesc.setOnClickListener(null);
+ } else {
+ warning.showToast(res.getString(R.string.err_load_descr_failed));
+ }
+
+ if (descDialog != null && descDialog.isShowing()) {
+ descDialog.dismiss();
+ }
+
+ longDescDisplayed = true;
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.detail);
+ base.setTitle(activity, res.getString(R.string.cache));
+
+ init();
+
+ // get parameters
+ final Bundle extras = getIntent().getExtras();
+ final Uri uri = getIntent().getData();
+
+ // try to get data from extras
+ if (geocode == null && extras != null) {
+ geocode = extras.getString("geocode");
+ name = extras.getString("name");
+ guid = extras.getString("guid");
+ }
+
+ // try to get data from URI
+ if (geocode == null && guid == null && uri != null) {
+ String uriHost = uri.getHost().toLowerCase();
+ String uriPath = uri.getPath().toLowerCase();
+ String uriQuery = uri.getQuery();
+
+ if (uriQuery != null) {
+ Log.i(cgSettings.tag, "Opening URI: " + uriHost + uriPath + "?" + uriQuery);
+ } else {
+ Log.i(cgSettings.tag, "Opening URI: " + uriHost + uriPath);
+ }
+
+ if (uriHost.contains("geocaching.com") == true) {
+ geocode = uri.getQueryParameter("wp");
+ guid = uri.getQueryParameter("guid");
+
+ if (geocode != null && geocode.length() > 0) {
+ geocode = geocode.toUpperCase();
+ guid = null;
+ } else if (guid != null && guid.length() > 0) {
+ geocode = null;
+ guid = guid.toLowerCase();
+ } else {
+ warning.showToast(res.getString(R.string.err_detail_open));
+ finish();
+ return;
+ }
+ } else if (uriHost.contains("coord.info") == true) {
+ if (uriPath != null && uriPath.startsWith("/gc") == true) {
+ geocode = uriPath.substring(1).toUpperCase();
+ } else {
+ warning.showToast(res.getString(R.string.err_detail_open));
+ finish();
+ return;
+ }
+ }
+ }
+
+ // google analytics
+ tracker = GoogleAnalyticsTracker.getInstance();
+ tracker.start(cgSettings.analytics, this);
+ tracker.dispatch();
+ if (geocode != null) {
+ base.sendAnal(activity, tracker, "/cache/detail#" + geocode);
+ }
+
+ // no given data
+ if (geocode == null && guid == null) {
+ warning.showToast(res.getString(R.string.err_detail_cache));
+ finish();
+ return;
+ }
+
+ app.setAction(geocode);
+
+ try {
+ if (name != null && name.length() > 0) {
+ waitDialog = ProgressDialog.show(this, name, res.getString(R.string.cache_dialog_loading_details), true);
+ } else if (geocode != null && geocode.length() > 0) {
+ waitDialog = ProgressDialog.show(this, geocode.toUpperCase(), res.getString(R.string.cache_dialog_loading_details), true);
+ } else {
+ waitDialog = ProgressDialog.show(this, res.getString(R.string.cache), res.getString(R.string.cache_dialog_loading_details), true);
+ }
+ waitDialog.setCancelable(true);
+ } catch (Exception e) {
+ // nothing, we lost the window
+ }
+
+ threadCache = new loadCache(loadCacheHandler, geocode, guid);
+ threadCache.start();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ setView();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ setView();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+ if (tracker != null) tracker.stop();
+
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStop() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onPause();
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info) {
+ super.onCreateContextMenu(menu, view, info);
+ final int viewId = view.getId();
+
+ if (viewId == R.id.author || viewId == R.id.value) {
+ if (viewId == R.id.author) { // Author of a log entry
+ contextMenuUser = ((TextView)view).getText().toString();
+ } else if (viewId == R.id.value) { // The owner of the cache
+ if (cache.ownerReal != null && cache.ownerReal.length() > 0) {
+ contextMenuUser = cache.ownerReal;
+ } else {
+ contextMenuUser = cache.owner;
+ }
+ }
+
+ menu.setHeaderTitle(res.getString(R.string.user_menu_title) + " " + contextMenuUser);
+ menu.add(viewId, 1, 0, res.getString(R.string.user_menu_view_hidden));
+ menu.add(viewId, 2, 0, res.getString(R.string.user_menu_view_found));
+ menu.add(viewId, 3, 0, res.getString(R.string.user_menu_open_browser));
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ final int group = item.getGroupId();
+
+ if (group == R.id.author || group == R.id.value) {
+ final int id = item.getItemId();
+
+ if (id == 1) {
+ final Intent cachesIntent = new Intent(activity, cgeocaches.class);
+
+ cachesIntent.putExtra("type", "owner");
+ cachesIntent.putExtra("username", contextMenuUser);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+
+ activity.startActivity(cachesIntent);
+
+ return true;
+ } else if (id == 2) {
+ final Intent cachesIntent = new Intent(activity, cgeocaches.class);
+
+ cachesIntent.putExtra("type", "username");
+ cachesIntent.putExtra("username", contextMenuUser);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+
+ activity.startActivity(cachesIntent);
+
+ return true;
+ } else if (id == 3) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?u=" + URLEncoder.encode(contextMenuUser))));
+
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ if (cache != null && cache.latitude != null && cache.longitude != null) {
+ menu.add(0, 2, 0, res.getString(R.string.cache_menu_compass)).setIcon(android.R.drawable.ic_menu_compass); // compass
+
+ SubMenu subMenu = menu.addSubMenu(1, 0, 0, res.getString(R.string.cache_menu_navigate)).setIcon(android.R.drawable.ic_menu_more);
+ subMenu.add(0, 8, 0, res.getString(R.string.cache_menu_radar)); // radar
+ if (cache != null && cache.reason >= 1 && settings.storeOfflineMaps == 1) {
+ subMenu.add(1, 6, 0, res.getString(R.string.cache_menu_map_static)); // static maps
+ }
+ subMenu.add(0, 1, 0, res.getString(R.string.cache_menu_map)); // c:geo map
+ if (base.isLocus(activity)) {
+ subMenu.add(0, 20, 0, res.getString(R.string.cache_menu_locus)); // ext.: locus
+ }
+ if (base.isRmaps(activity)) {
+ subMenu.add(0, 21, 0, res.getString(R.string.cache_menu_rmaps)); // ext.: rmaps
+ }
+ subMenu.add(0, 23, 0, res.getString(R.string.cache_menu_map_ext)); // ext.: other
+ subMenu.add(0, 9, 0, res.getString(R.string.cache_menu_tbt)); // turn-by-turn
+ }
+
+ if (cache != null && cache.hidden != null && (cache.type.equalsIgnoreCase("event") == true || cache.type.equalsIgnoreCase("mega") == true || cache.type.equalsIgnoreCase("cito") == true)) {
+ menu.add(1, 11, 0, res.getString(R.string.cache_menu_event)).setIcon(android.R.drawable.ic_menu_agenda); // add event to calendar
+ }
+ if (settings.isLogin() == true) {
+ menu.add(1, 3, 0, res.getString(R.string.cache_menu_visit)).setIcon(android.R.drawable.ic_menu_agenda); // log visit
+ }
+
+ if (cache != null && cache.spoilers != null && cache.spoilers.size() > 0) {
+ menu.add(1, 5, 0, res.getString(R.string.cache_menu_spoilers)).setIcon(android.R.drawable.ic_menu_gallery); // spoiler images
+ }
+
+ if (cache != null && cache.latitude != null && cache.longitude != null) {
+ menu.add(0, 10, 0, res.getString(R.string.cache_menu_around)).setIcon(android.R.drawable.ic_menu_rotate); // caches around
+ }
+
+ menu.add(1, 7, 0, res.getString(R.string.cache_menu_browser)).setIcon(android.R.drawable.ic_menu_info_details); // browser
+ menu.add(0, 12, 0, res.getString(R.string.cache_menu_share)).setIcon(android.R.drawable.ic_menu_share); // share cache
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ final int menuItem = item.getItemId();
+
+ if (menuItem == 1) {
+ showOnMap();
+ return true;
+ } else if (menuItem == 2) {
+ navigateTo();
+ return true;
+ } else if (menuItem == 3) {
+ logVisit();
+ return true;
+ } else if (menuItem == 5) {
+ showSpoilers();
+ return true;
+ } else if (menuItem == 6) {
+ showSmaps();
+ return true;
+ } else if (menuItem == 7) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/seek/cache_details.aspx?wp=" + cache.geocode)));
+ return true;
+ } else if (menuItem == 8) {
+ radarTo();
+ return true;
+ } else if (menuItem == 9) {
+ if (geo != null) {
+ base.runNavigation(activity, res, settings, warning, tracker, cache.latitude, cache.longitude, geo.latitudeNow, geo.longitudeNow);
+ } else {
+ base.runNavigation(activity, res, settings, warning, tracker, cache.latitude, cache.longitude);
+ }
+
+ return true;
+ } else if (menuItem == 10) {
+ cachesAround();
+ return true;
+ } else if (menuItem == 11) {
+ addToCalendar();
+ return true;
+ } else if (menuItem == 12) {
+ shareCache();
+ return true;
+ } else if (menuItem == 20) {
+ base.runExternalMap(cgBase.mapAppLocus, activity, res, warning, tracker, cache); // locus
+ return true;
+ } else if (menuItem == 21) {
+ base.runExternalMap(cgBase.mapAppRmaps, activity, res, warning, tracker, cache); // rmaps
+ return true;
+ } else if (menuItem == 23) {
+ base.runExternalMap(cgBase.mapAppAny, activity, res, warning, tracker, cache); // rmaps
+ return true;
+ }
+
+ return false;
+ }
+
+ private void init() {
+ final DisplayMetrics dm = getResources().getDisplayMetrics();
+ pixelRatio = dm.density;
+
+ if (inflater == null) {
+ inflater = activity.getLayoutInflater();
+ }
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+
+ if (searchId != null && searchId > 0) {
+ cache = app.getCache(searchId);
+ if (cache != null && cache.geocode != null) {
+ geocode = cache.geocode;
+ }
+ }
+
+ if (geocode != null && geocode.length() > 0) {
+ app.setAction(geocode);
+ }
+ }
+
+ private void setView() {
+ RelativeLayout itemLayout;
+ TextView itemName;
+ TextView itemValue;
+
+ if (searchId == null) {
+ return;
+ }
+
+ cache = app.getCache(searchId);
+
+ if (cache == null) {
+ if (waitDialog != null && waitDialog.isShowing()) waitDialog.dismiss();
+
+ if (geocode != null && geocode.length() > 0) {
+ warning.showToast(res.getString(R.string.err_detail_cache_find) + " " + geocode + ".");
+ } else {
+ geocode = null;
+ warning.showToast(res.getString(R.string.err_detail_cache_find_some));
+ }
+
+ finish();
+ return;
+ }
+
+ if (cache.reason >= 1) {
+ base.sendAnal(activity, tracker, "/cache/detail/stored");
+ } else {
+ base.sendAnal(activity, tracker, "/cache/detail/online");
+ }
+
+ try {
+ if (gcIcons == null || gcIcons.isEmpty()) {
+ gcIcons.put("ape", R.drawable.type_ape);
+ gcIcons.put("cito", R.drawable.type_cito);
+ gcIcons.put("earth", R.drawable.type_earth);
+ gcIcons.put("event", R.drawable.type_event);
+ gcIcons.put("letterbox", R.drawable.type_letterbox);
+ gcIcons.put("locationless", R.drawable.type_locationless);
+ gcIcons.put("mega", R.drawable.type_mega);
+ gcIcons.put("multi", R.drawable.type_multi);
+ gcIcons.put("traditional", R.drawable.type_traditional);
+ gcIcons.put("virtual", R.drawable.type_virtual);
+ gcIcons.put("webcam", R.drawable.type_webcam);
+ gcIcons.put("wherigo", R.drawable.type_wherigo);
+ gcIcons.put("gchq", R.drawable.type_hq);
+ gcIcons.put("mystery", R.drawable.type_mystery);
+ }
+
+ if (cache.name != null && cache.name.length() > 0) {
+ base.setTitle(activity, cache.name);
+ } else {
+ base.setTitle(activity, geocode.toUpperCase());
+ }
+
+ inflater = activity.getLayoutInflater();
+ geocode = cache.geocode.toUpperCase();
+
+ ScrollView scroll = (ScrollView) findViewById(R.id.details_list_box);
+ scroll.setVisibility(View.VISIBLE);
+
+ LinearLayout detailsList = (LinearLayout) findViewById(R.id.details_list);
+ detailsList.removeAllViews();
+
+ // actionbar icon
+ if (cache.type != null && gcIcons.containsKey(cache.type) == true) { // cache icon
+ ((TextView) findViewById(R.id.actionbar_title)).setCompoundDrawablesWithIntrinsicBounds((Drawable) activity.getResources().getDrawable(gcIcons.get(cache.type)), null, null, null);
+ } else { // unknown cache type, "mystery" icon
+ ((TextView) findViewById(R.id.actionbar_title)).setCompoundDrawablesWithIntrinsicBounds((Drawable) activity.getResources().getDrawable(gcIcons.get("mystery")), null, null, null);
+ }
+
+ // cache name (full name)
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_name));
+ itemValue.setText(Html.fromHtml(cache.name).toString());
+ detailsList.addView(itemLayout);
+
+ // cache type
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_type));
+
+ String size = null;
+ if (cache.size != null && cache.size.length() > 0) {
+ size = " (" + cache.size + ")";
+ } else {
+ size = "";
+ }
+
+ if (cgBase.cacheTypesInv.containsKey(cache.type) == true) { // cache icon
+ itemValue.setText(cgBase.cacheTypesInv.get(cache.type) + size);
+ } else {
+ itemValue.setText(cgBase.cacheTypesInv.get("mystery") + size);
+ }
+ detailsList.addView(itemLayout);
+
+ // gc-code
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_geocode));
+ itemValue.setText(cache.geocode.toUpperCase());
+ detailsList.addView(itemLayout);
+
+ // cache state
+ if (cache.logOffline == true || cache.archived == true || cache.disabled == true || cache.members == true || cache.found == true) {
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_status));
+
+ StringBuilder state = new StringBuilder();
+ if (cache.logOffline == true) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_offline_log));
+ }
+ if (cache.found == true) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_found));
+ }
+ if (cache.archived == true) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_archived));
+ }
+ if (cache.disabled == true) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_disabled));
+ }
+ if (cache.members == true) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_premium));
+ }
+
+ itemValue.setText(state.toString());
+ detailsList.addView(itemLayout);
+
+ state = null;
+ }
+
+ // distance
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_distance));
+ if (cache.distance != null) {
+ itemValue.setText("~" + base.getHumanDistance(cache.distance));
+ } else {
+ itemValue.setText("--");
+ }
+ detailsList.addView(itemLayout);
+ cacheDistance = itemValue;
+
+ // difficulty
+ if (cache.difficulty != null && cache.difficulty > 0) {
+ addStarRating(detailsList, res.getString(R.string.cache_difficulty), cache.difficulty);
+ }
+
+ // terrain
+ if (cache.terrain != null && cache.terrain > 0) {
+ addStarRating(detailsList, res.getString(R.string.cache_terrain), cache.terrain);
+ }
+
+ // rating
+ if (cache.rating != null && cache.rating > 0) {
+ itemLayout = addStarRating(detailsList, res.getString(R.string.cache_rating), cache.rating);
+ if (cache.votes != null) {
+ final TextView itemAddition = (TextView)itemLayout.findViewById(R.id.addition);
+ itemAddition.setText("(" + cache.votes + ")");
+ itemAddition.setVisibility(View.VISIBLE);
+ }
+ }
+
+ // favourite count
+ if (cache.favouriteCnt != null) {
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_favourite));
+ itemValue.setText(String.format("%d", cache.favouriteCnt) + "×");
+ detailsList.addView(itemLayout);
+ }
+
+ // cache author
+ if ((cache.owner != null && cache.owner.length() > 0) || (cache.ownerReal != null && cache.ownerReal.length() > 0)) {
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_owner));
+ if (cache.owner != null && cache.owner.length() > 0) {
+ itemValue.setText(Html.fromHtml(cache.owner), TextView.BufferType.SPANNABLE);
+ } else if (cache.ownerReal != null && cache.ownerReal.length() > 0) {
+ itemValue.setText(Html.fromHtml(cache.ownerReal), TextView.BufferType.SPANNABLE);
+ }
+ itemValue.setOnClickListener(new userActions());
+ detailsList.addView(itemLayout);
+ }
+
+ // cache hidden
+ if (cache.hidden != null && cache.hidden.getTime() > 0) {
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ if (cache.type != null && (cache.type.equalsIgnoreCase("event") == true || cache.type.equalsIgnoreCase("mega") == true || cache.type.equalsIgnoreCase("cito") == true)) {
+ itemName.setText(res.getString(R.string.cache_event));
+ } else {
+ itemName.setText(res.getString(R.string.cache_hidden));
+ }
+ itemValue.setText(cgBase.dateOut.format(cache.hidden));
+ detailsList.addView(itemLayout);
+ }
+
+ // cache location
+ if (cache.location != null && cache.location.length() > 0) {
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_location));
+ itemValue.setText(cache.location);
+ detailsList.addView(itemLayout);
+ }
+
+ // cache coordinates
+ if (cache.latitude != null && cache.longitude != null) {
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_coordinates));
+ itemValue.setText(cache.latitudeString + " | " + cache.longitudeString);
+ detailsList.addView(itemLayout);
+ }
+
+ // cache attributes
+ if (cache.attributes != null && cache.attributes.size() > 0) {
+ final LinearLayout attribBox = (LinearLayout) findViewById(R.id.attributes_box);
+ final TextView attribView = (TextView) findViewById(R.id.attributes);
+
+ StringBuilder buffer = new StringBuilder();
+ String attribute;
+ for (int i = 0; i < cache.attributes.size(); i++) {
+ attribute = cache.attributes.get(i);
+
+ // dynamically search for a translation of the attribute
+ int id = res.getIdentifier("attribute_" + attribute, "string", base.context.getPackageName());
+ if (id > 0) {
+ String translated = res.getString(id);
+ if (translated != null && translated.length() > 0) {
+ attribute = translated;
+ }
+ }
+ if (buffer.length() > 0) {
+ buffer.append('\n');
+ }
+ buffer.append(attribute);
+ }
+
+ attribView.setText(buffer);
+ attribBox.setVisibility(View.VISIBLE);
+ }
+
+ // cache inventory
+ if (cache.inventory != null && cache.inventory.size() > 0) {
+ final LinearLayout inventBox = (LinearLayout) findViewById(R.id.inventory_box);
+ final TextView inventView = (TextView) findViewById(R.id.inventory);
+
+ StringBuilder inventoryString = new StringBuilder();
+ for (cgTrackable inventoryItem : cache.inventory) {
+ if (inventoryString.length() > 0) {
+ inventoryString.append("\n");
+ }
+ // avoid HTML parsing where possible
+ if (inventoryItem.name.indexOf('<') >= 0 || inventoryItem.name.indexOf('&') >= 0 ) {
+ inventoryString.append(Html.fromHtml(inventoryItem.name).toString());
+ }
+ else {
+ inventoryString.append(inventoryItem.name);
+ }
+ }
+ inventView.setText(inventoryString);
+ inventBox.setClickable(true);
+ inventBox.setOnClickListener(new selectTrackable());
+ inventBox.setVisibility(View.VISIBLE);
+ }
+
+ // offline use
+ final TextView offlineText = (TextView) findViewById(R.id.offline_text);
+ final Button offlineRefresh = (Button) findViewById(R.id.offline_refresh);
+ final Button offlineStore = (Button) findViewById(R.id.offline_store);
+
+ if (cache.reason >= 1) {
+ Long diff = (System.currentTimeMillis() / (60 * 1000)) - (cache.detailedUpdate / (60 * 1000)); // minutes
+
+ String ago = "";
+ if (diff < 15) {
+ ago = res.getString(R.string.cache_offline_time_mins_few);
+ } else if (diff < 50) {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + diff + " " + res.getString(R.string.cache_offline_time_mins);
+ } else if (diff < 90) {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + res.getString(R.string.cache_offline_time_hour);
+ } else if (diff < (48 * 60)) {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + (diff / 60) + " " + res.getString(R.string.cache_offline_time_hours);
+ } else {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + (diff / (24 * 60)) + " " + res.getString(R.string.cache_offline_time_days);
+ }
+
+ offlineText.setText(res.getString(R.string.cache_offline_stored) + "\n" + ago);
+
+ offlineRefresh.setVisibility(View.VISIBLE);
+ offlineRefresh.setClickable(true);
+ offlineRefresh.setOnClickListener(new storeCache());
+
+ offlineStore.setText(res.getString(R.string.cache_offline_drop));
+ offlineStore.setClickable(true);
+ offlineStore.setOnClickListener(new dropCache());
+ } else {
+ offlineText.setText(res.getString(R.string.cache_offline_not_ready));
+
+ offlineRefresh.setVisibility(View.VISIBLE);
+ offlineRefresh.setClickable(true);
+ offlineRefresh.setOnClickListener(new refreshCache());
+
+ offlineStore.setText(res.getString(R.string.cache_offline_store));
+ offlineStore.setClickable(true);
+ offlineStore.setOnClickListener(new storeCache());
+ }
+
+ // cache short desc
+ if (cache.shortdesc != null && cache.shortdesc.length() > 0) {
+ ((LinearLayout) findViewById(R.id.desc_box)).setVisibility(View.VISIBLE);
+
+ TextView descView = (TextView) findViewById(R.id.shortdesc);
+ descView.setVisibility(View.VISIBLE);
+ descView.setText(Html.fromHtml(cache.shortdesc.trim(), new cgHtmlImg(activity, settings, geocode, true, cache.reason, false), null), TextView.BufferType.SPANNABLE);
+ descView.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+
+ // cache long desc
+ if (longDescDisplayed == true) {
+ if (longDesc == null && cache != null && cache.description != null) {
+ longDesc = Html.fromHtml(cache.description.trim(), new cgHtmlImg(activity, settings, geocode, true, cache.reason, false), null);
+ }
+
+ if (longDesc != null && longDesc.length() > 0) {
+ ((LinearLayout) findViewById(R.id.desc_box)).setVisibility(View.VISIBLE);
+
+ TextView descView = (TextView) findViewById(R.id.description);
+ descView.setVisibility(View.VISIBLE);
+ descView.setText(longDesc, TextView.BufferType.SPANNABLE);
+ descView.setMovementMethod(LinkMovementMethod.getInstance());
+
+ Button showDesc = (Button) findViewById(R.id.show_description);
+ showDesc.setVisibility(View.GONE);
+ showDesc.setOnTouchListener(null);
+ showDesc.setOnClickListener(null);
+ }
+ } else if (longDescDisplayed == false && cache.description != null && cache.description.length() > 0) {
+ ((LinearLayout) findViewById(R.id.desc_box)).setVisibility(View.VISIBLE);
+
+ Button showDesc = (Button) findViewById(R.id.show_description);
+ showDesc.setVisibility(View.VISIBLE);
+ showDesc.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View arg0) {
+ loadLongDesc();
+ }
+ });
+ }
+
+ // waypoints
+ LinearLayout waypoints = (LinearLayout) findViewById(R.id.waypoints);
+ waypoints.removeAllViews();
+
+ if (cache.waypoints != null && cache.waypoints.size() > 0) {
+ LinearLayout waypointView;
+
+ // sort waypoints: PP, Sx, FI, OWN
+ ArrayList<cgWaypoint> sortedWaypoints = new ArrayList<cgWaypoint>(cache.waypoints);
+ Collections.sort(sortedWaypoints, new Comparator<cgWaypoint>() {
+
+ @Override
+ public int compare(cgWaypoint wayPoint1, cgWaypoint wayPoint2) {
+
+ return order(wayPoint1) - order(wayPoint2);
+ }
+
+ private int order(cgWaypoint waypoint) {
+ if (waypoint.prefix == null || waypoint.prefix.length() == 0) {
+ return 0;
+ }
+ // check only the first character. sometimes there are inconsistencies like FI or FN for the FINAL
+ char firstLetter = Character.toUpperCase(waypoint.prefix.charAt(0));
+ switch (firstLetter) {
+ case 'P' : return -100; // parking
+ case 'S' : { // stage N
+ try {
+ Integer stageNumber = Integer.valueOf(waypoint.prefix.substring(1));
+ return stageNumber;
+ } catch (NumberFormatException e) {
+ // nothing
+ }
+ return 0;
+ }
+ case 'F' : return 1000; // final
+ case 'O' : return 10000; // own
+ }
+ return 0;
+ }});
+
+ for (cgWaypoint wpt : sortedWaypoints) {
+ waypointView = (LinearLayout) inflater.inflate(R.layout.waypoint_item, null);
+ final TextView identification = (TextView) waypointView.findViewById(R.id.identification);
+
+ ((TextView) waypointView.findViewById(R.id.type)).setText(cgBase.waypointTypes.get(wpt.type));
+ if (wpt.prefix.equalsIgnoreCase("OWN") == false) {
+ identification.setText(wpt.prefix.trim() + "/" + wpt.lookup.trim());
+ } else {
+ identification.setText(res.getString(R.string.waypoint_custom));
+ }
+
+ if (wpt.name.trim().length() == 0) {
+ ((TextView) waypointView.findViewById(R.id.name)).setText(base.formatCoordinate(wpt.latitude, "lat", true) + " | " + base.formatCoordinate(wpt.longitude, "lon", true));
+ } else {
+ // avoid HTML parsing
+ if (wpt.name.indexOf('<') >= 0 || wpt.name.indexOf('&') >= 0) {
+ ((TextView) waypointView.findViewById(R.id.name)).setText(Html.fromHtml(wpt.name.trim()), TextView.BufferType.SPANNABLE);
+ }
+ else {
+ ((TextView) waypointView.findViewById(R.id.name)).setText(wpt.name.trim());
+ }
+ }
+ // avoid HTML parsing
+ if (wpt.note.indexOf('<') >= 0 || wpt.note.indexOf('&') >= 0) {
+ ((TextView) waypointView.findViewById(R.id.note)).setText(Html.fromHtml(wpt.note.trim()), TextView.BufferType.SPANNABLE);
+ }
+ else {
+ ((TextView) waypointView.findViewById(R.id.note)).setText(wpt.note.trim());
+ }
+
+ waypointView.setOnClickListener(new waypointInfo(wpt.id));
+
+ waypoints.addView(waypointView);
+ }
+ }
+
+ Button addWaypoint = (Button) findViewById(R.id.add_waypoint);
+ addWaypoint.setClickable(true);
+ addWaypoint.setOnClickListener(new addWaypoint());
+
+ // cache hint
+ if (cache.hint != null && cache.hint.length() > 0) {
+ ((LinearLayout) findViewById(R.id.hint_box)).setVisibility(View.VISIBLE);
+ TextView hintView = ((TextView) findViewById(R.id.hint));
+ hintView.setText(cgBase.rot13(cache.hint.trim()));
+ hintView.setClickable(true);
+ hintView.setOnClickListener(new codeHint());
+ } else {
+ ((LinearLayout) findViewById(R.id.hint_box)).setVisibility(View.GONE);
+ TextView hintView = ((TextView) findViewById(R.id.hint));
+ hintView.setClickable(false);
+ hintView.setOnClickListener(null);
+ }
+
+ if (geo != null && geo.latitudeNow != null && geo.longitudeNow != null && cache != null && cache.latitude != null && cache.longitude != null) {
+ cacheDistance.setText(base.getHumanDistance(cgBase.getDistance(geo.latitudeNow, geo.longitudeNow, cache.latitude, cache.longitude)));
+ cacheDistance.bringToFront();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeodetail.setView: " + e.toString());
+ }
+
+ if (waitDialog != null && waitDialog.isShowing()) waitDialog.dismiss();
+ if (storeDialog != null && storeDialog.isShowing()) storeDialog.dismiss();
+ if (dropDialog != null && dropDialog.isShowing()) dropDialog.dismiss();
+ if (refreshDialog != null && refreshDialog.isShowing()) refreshDialog.dismiss();
+
+ displayLogs();
+
+ if (geo != null) geoUpdate.updateLoc(geo);
+ }
+
+ private RelativeLayout addStarRating(final LinearLayout detailsList, final String name, final float value) {
+ RelativeLayout itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_layout, null);
+ TextView itemName = (TextView) itemLayout.findViewById(R.id.name);
+ TextView itemValue = (TextView) itemLayout.findViewById(R.id.value);
+ LinearLayout itemStars = (LinearLayout) itemLayout.findViewById(R.id.stars);
+
+ itemName.setText(name);
+ itemValue.setText(String.format(Locale.getDefault(), "%.1f", value) + ' ' + res.getString(R.string.cache_rating_of) + " 5");
+ for (int i = 0; i <= 4; i++) {
+ ImageView star = (ImageView) inflater.inflate(R.layout.star, null);
+ if ((value - i) >= 1.0) {
+ star.setImageResource(R.drawable.star_on);
+ } else if ((value - i) > 0.0) {
+ star.setImageResource(R.drawable.star_half);
+ } else {
+ star.setImageResource(R.drawable.star_off);
+ }
+ itemStars.addView(star, (1 + i));
+ }
+ detailsList.addView(itemLayout);
+ return itemLayout;
+ }
+
+ private void displayLogs() {
+ // cache logs
+ TextView textView = (TextView) findViewById(R.id.logcount);
+ int logCounter = 0;
+ if (cache != null && cache.logCounts != null) {
+ final StringBuffer buff = new StringBuffer();
+ buff.append(res.getString(R.string.cache_log_types));
+ buff.append(": ");
+
+ // sort the log counts by type id ascending. that way the FOUND, DNF log types are the first and most visible ones
+ ArrayList<Entry<Integer, Integer>> sortedLogCounts = new ArrayList<Entry<Integer,Integer>>();
+ sortedLogCounts.addAll(cache.logCounts.entrySet());
+ Collections.sort(sortedLogCounts, new Comparator<Entry<Integer, Integer>>() {
+
+ @Override
+ public int compare(Entry<Integer, Integer> logCountItem1,
+ Entry<Integer, Integer> logCountItem2) {
+ return logCountItem1.getKey().compareTo(logCountItem2.getKey());
+ }});
+ for (Entry<Integer, Integer> pair : sortedLogCounts) {
+ int logTypeId = pair.getKey().intValue();
+ String logTypeLabel = cgBase.logTypes1.get(logTypeId);
+ // it may happen that the label is unknown -> then avoid any output for this type
+ if (logTypeLabel != null) {
+ if (logCounter > 0) {
+ buff.append(", ");
+ }
+ buff.append(pair.getValue().intValue());
+ buff.append("× ");
+ buff.append(logTypeLabel);
+ }
+ logCounter ++;
+ }
+ textView.setText(buff.toString());
+ }
+ // it may happen, that the logCounts map is available, but every log type has zero counts,
+ // therefore check again for the number of counted logs
+ if (logCounter > 0) {
+ textView.setVisibility(View.VISIBLE);
+ } else {
+ textView.setVisibility(View.GONE);
+ }
+
+ // cache logs
+ LinearLayout listView = (LinearLayout) findViewById(R.id.log_list);
+ listView.removeAllViews();
+
+ RelativeLayout rowView;
+
+ if (cache != null && cache.logs != null) {
+ for (cgLog log : cache.logs) {
+ rowView = (RelativeLayout) inflater.inflate(R.layout.log_item, null);
+
+ if (log.date > 0) {
+ final Date logDate = new Date(log.date);
+ ((TextView) rowView.findViewById(R.id.added)).setText(cgBase.dateOutShort.format(logDate));
+ }
+
+ if (cgBase.logTypes1.containsKey(log.type) == true) {
+ ((TextView) rowView.findViewById(R.id.type)).setText(cgBase.logTypes1.get(log.type));
+ } else {
+ ((TextView) rowView.findViewById(R.id.type)).setText(cgBase.logTypes1.get(4)); // note if type is unknown
+ }
+ // avoid parsing HTML if not necessary
+ if (log.author.indexOf('<') >= 0 || log.author.indexOf('&') >= 0) {
+ ((TextView) rowView.findViewById(R.id.author)).setText(Html.fromHtml(log.author), TextView.BufferType.SPANNABLE);
+ }
+ else {
+ ((TextView) rowView.findViewById(R.id.author)).setText(log.author);
+ }
+
+ if (log.found == -1) {
+ ((TextView) rowView.findViewById(R.id.count)).setVisibility(View.GONE);
+ } else if (log.found == 0) {
+ ((TextView) rowView.findViewById(R.id.count)).setText(res.getString(R.string.cache_count_no));
+ } else if (log.found == 1) {
+ ((TextView) rowView.findViewById(R.id.count)).setText(res.getString(R.string.cache_count_one));
+ } else {
+ ((TextView) rowView.findViewById(R.id.count)).setText(log.found + " " + res.getString(R.string.cache_count_more));
+ }
+ // avoid parsing HTML if not necessary
+ if (log.log.indexOf('<') >= 0 || log.log.indexOf('&') >= 0) {
+ ((TextView) rowView.findViewById(R.id.log)).setText(Html.fromHtml(log.log, new cgHtmlImg(activity, settings, null, false, cache.reason, false), null), TextView.BufferType.SPANNABLE);
+ }
+ else {
+ ((TextView) rowView.findViewById(R.id.log)).setText(log.log);
+ }
+
+ final ImageView markFound = (ImageView) rowView.findViewById(R.id.found_mark);
+ final ImageView markDNF = (ImageView) rowView.findViewById(R.id.dnf_mark);
+ final ImageView markDisabled = (ImageView) rowView.findViewById(R.id.disabled_mark);
+ if (log.type == 2 || log.type == 9 || log.type == 10) { // found, will attend, attended
+ markFound.setVisibility(View.VISIBLE);
+ markDNF.setVisibility(View.GONE);
+ markDisabled.setVisibility(View.GONE);
+ } else if (log.type == 3) { // did not find
+ markFound.setVisibility(View.GONE);
+ markDNF.setVisibility(View.VISIBLE);
+ markDisabled.setVisibility(View.GONE);
+ } else if (log.type == 7 || log.type == 8) { // disabled, archived
+ markFound.setVisibility(View.GONE);
+ markDNF.setVisibility(View.GONE);
+ markDisabled.setVisibility(View.VISIBLE);
+ } else {
+ markFound.setVisibility(View.GONE);
+ markDNF.setVisibility(View.GONE);
+ markDisabled.setVisibility(View.GONE);
+ }
+
+ ((TextView) rowView.findViewById(R.id.author)).setOnClickListener(new userActions());
+ ((TextView) rowView.findViewById(R.id.log)).setOnClickListener(new decryptLog());
+
+ listView.addView(rowView);
+ }
+
+ if (cache.logs.size() > 0) {
+ ((LinearLayout) findViewById(R.id.log_box)).setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
+ private class loadCache extends Thread {
+
+ private Handler handler = null;
+ private String geocode = null;
+ private String guid = null;
+
+ public loadCache(Handler handlerIn, String geocodeIn, String guidIn) {
+ handler = handlerIn;
+ geocode = geocodeIn;
+ guid = guidIn;
+
+ if (geocode == null && guid == null) {
+ warning.showToast(res.getString(R.string.err_detail_cache_forgot));
+
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public void run() {
+ HashMap<String, String> params = new HashMap<String, String>();
+ if (geocode != null && geocode.length() > 0) {
+ params.put("geocode", geocode);
+ } else if (guid != null && guid.length() > 0) {
+ params.put("guid", guid);
+ } else {
+ return;
+ }
+
+ searchId = base.searchByGeocode(params, 0, false);
+
+ handler.sendMessage(new Message());
+ }
+ }
+
+ private class loadMapPreview extends Thread {
+ private cgCache cache = null;
+ private Handler handler = null;
+
+ public loadMapPreview(cgCache cacheIn, Handler handlerIn) {
+ cache = cacheIn;
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ if (cache == null || cache.latitude == null || cache.longitude == null) {
+ return;
+ }
+
+ BitmapDrawable image = null;
+
+ try {
+ final String latlonMap = String.format((Locale) null, "%.6f", cache.latitude) + "," + String.format((Locale) null, "%.6f", cache.longitude);
+ final Display display = ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+
+ int width = display.getWidth();
+ int height = (int) (90 * pixelRatio);
+
+ String markerUrl = cgBase.urlencode_rfc3986("http://cgeo.carnero.cc/_markers/my_location_mdpi.png");
+
+ cgHtmlImg mapGetter = new cgHtmlImg(activity, settings, cache.geocode, false, 0, false);
+ image = mapGetter.getDrawable("http://maps.google.com/maps/api/staticmap?center=" + latlonMap + "&zoom=15&size=" + width + "x" + height + "&maptype=terrain&markers=icon%3A" + markerUrl + "%7C" + latlonMap + "&sensor=false");
+ Message message = handler.obtainMessage(0, image);
+ handler.sendMessage(message);
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgeodetail.loadMapPreview.run: " + e.toString());
+ }
+ }
+ }
+
+ public void loadLongDesc() {
+ if (activity != null && (waitDialog == null || waitDialog.isShowing() == false)) {
+ descDialog = ProgressDialog.show(activity, null, res.getString(R.string.cache_dialog_loading_description), true);
+ descDialog.setCancelable(true);
+ }
+
+ threadLongDesc = new loadLongDesc(loadDescriptionHandler);
+ threadLongDesc.start();
+ }
+
+ private class loadLongDesc extends Thread {
+ private Handler handler = null;
+
+ public loadLongDesc(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ if (cache == null || cache.description == null || handler == null) {
+ return;
+ }
+
+ longDesc = Html.fromHtml(cache.description.trim(), new cgHtmlImg(activity, settings, geocode, true, cache.reason, false), null);
+ handler.sendMessage(new Message());
+ }
+ }
+
+ public ArrayList<cgCoord> getCoordinates() {
+ cgCoord coords = null;
+ ArrayList<cgCoord> coordinates = new ArrayList<cgCoord>();
+
+ try {
+ // cache
+ coords = new cgCoord();
+ coords.type = "cache";
+ if (name != null && name.length() > 0) {
+ coords.name = name;
+ } else {
+ coords.name = geocode.toUpperCase();
+ }
+ coords.latitude = cache.latitude;
+ coords.longitude = cache.longitude;
+ coordinates.add(coords);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeodetail.getCoordinates (cache): " + e.toString());
+ }
+
+ try {
+ // waypoints
+ for (cgWaypoint waypoint : cache.waypoints) {
+ if (waypoint.latitude == null || waypoint.longitude == null) {
+ continue;
+ }
+
+ coords = new cgCoord();
+ coords.type = "waypoint";
+ coords.name = waypoint.name;
+ coords.latitude = waypoint.latitude;
+ coords.longitude = waypoint.longitude;
+ coordinates.add(coords);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeodetail.getCoordinates (waypoint): " + e.toString());
+ }
+
+ return coordinates;
+ }
+
+ private void showOnMap() {
+ Intent mapIntent = new Intent(activity, settings.getMapFactory().getMapClass());
+ mapIntent.putExtra("detail", true);
+ mapIntent.putExtra("searchid", searchId);
+
+ activity.startActivity(mapIntent);
+ }
+
+ private void cachesAround() {
+ cgeocaches cachesActivity = new cgeocaches();
+
+ Intent cachesIntent = new Intent(activity, cachesActivity.getClass());
+ cachesIntent.putExtra("type", "coordinate");
+ cachesIntent.putExtra("latitude", cache.latitude);
+ cachesIntent.putExtra("longitude", cache.longitude);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+
+ activity.startActivity(cachesIntent);
+
+ finish();
+ }
+
+ private void addToCalendar() {
+ String[] projection = new String[] { "_id", "displayName" };
+ Uri calendarProvider = null;
+ final int sdk = new Integer(Build.VERSION.SDK).intValue();
+ if (sdk >= 8) {
+ calendarProvider = Uri.parse("content://com.android.calendar/calendars");
+ } else {
+ calendarProvider = Uri.parse("content://calendar/calendars");
+ }
+
+ Cursor cursor = managedQuery(calendarProvider, projection, "selected=1", null, null);
+
+ calendars.clear();
+ int cnt = 0;
+ if (cursor != null) {
+ cnt = cursor.getCount();
+
+ if (cnt > 0) {
+ cursor.moveToFirst();
+
+ int calId = 0;
+ String calIdPre = null;
+ String calName = null;
+ int calIdIn = cursor.getColumnIndex("_id");
+ int calNameIn = cursor.getColumnIndex("displayName");
+
+ do {
+ calIdPre = cursor.getString(calIdIn);
+ if (calIdPre != null) {
+ calId = new Integer(calIdPre);
+ }
+ calName = cursor.getString(calNameIn);
+
+ if (calId > 0 && calName != null) {
+ calendars.put(calId, calName);
+ }
+ } while (cursor.moveToNext() == true);
+ }
+ }
+
+ final CharSequence[] items = calendars.values().toArray(new CharSequence[calendars.size()]);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setTitle(R.string.cache_calendars);
+ builder.setItems(items, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int item) {
+ addToCalendarFn(item);
+ }
+ });
+ AlertDialog alert = builder.create();
+ alert.show();
+ }
+
+ private void addToCalendarFn(int index) {
+ if (calendars == null || calendars.isEmpty() == true) {
+ return;
+ }
+
+ try {
+ Uri calendarProvider = null;
+ final int sdk = new Integer(Build.VERSION.SDK).intValue();
+ if (sdk >= 8) {
+ calendarProvider = Uri.parse("content://com.android.calendar/events");
+ } else {
+ calendarProvider = Uri.parse("content://calendar/events");
+ }
+
+ final Integer[] keys = calendars.keySet().toArray(new Integer[calendars.size()]);
+ final Integer calId = keys[index];
+
+ final Date eventDate = cache.hidden;
+ eventDate.setHours(0);
+ eventDate.setMinutes(0);
+ eventDate.setSeconds(0);
+
+ StringBuilder description = new StringBuilder();
+ description.append("http://coord.info/");
+ description.append(cache.geocode.toUpperCase());
+ description.append("\n\n");
+ if (cache.shortdesc != null && cache.shortdesc.length() > 0) {
+ description.append(Html.fromHtml(cache.shortdesc).toString());
+ }
+
+ ContentValues event = new ContentValues();
+ event.put("calendar_id", calId);
+ event.put("dtstart", eventDate.getTime() + 43200000); // noon
+ event.put("dtend", eventDate.getTime() + 43200000 + 3600000); // + one hour
+ event.put("eventTimezone", "UTC");
+ event.put("title", Html.fromHtml(cache.name).toString());
+ event.put("description", description.toString());
+ String location = "";
+ if (cache.latitudeString != null && cache.latitudeString.length() > 0 && cache.longitudeString != null && cache.longitudeString.length() > 0) {
+ location += cache.latitudeString + " " + cache.longitudeString;
+ }
+ if (cache.location != null && cache.location.length() > 0) {
+ boolean addParenteses = false;
+ if (location.length() > 0) {
+ addParenteses = true;
+ location += " (";
+ }
+
+ location += Html.fromHtml(cache.location).toString();
+ if (addParenteses) {
+ location += ")";
+ }
+ }
+ if (location.length() > 0) {
+ event.put("eventLocation", location);
+ }
+ event.put("allDay", 1);
+ event.put("hasAlarm", 0);
+
+ getContentResolver().insert(calendarProvider, event);
+
+ warning.showToast(res.getString(R.string.event_success));
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.event_fail));
+
+ Log.e(cgSettings.tag, "cgeodetail.addToCalendarFn: " + e.toString());
+ }
+ }
+
+ private void navigateTo() {
+ if (cache == null || cache.latitude == null || cache.longitude == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ cgeonavigate navigateActivity = new cgeonavigate();
+
+ Intent navigateIntent = new Intent(activity, navigateActivity.getClass());
+ navigateIntent.putExtra("latitude", cache.latitude);
+ navigateIntent.putExtra("longitude", cache.longitude);
+ navigateIntent.putExtra("geocode", cache.geocode.toUpperCase());
+ navigateIntent.putExtra("name", cache.name);
+
+ if (cgeonavigate.coordinates != null) {
+ cgeonavigate.coordinates.clear();
+ }
+ cgeonavigate.coordinates = getCoordinates();
+ activity.startActivity(navigateIntent);
+ }
+
+ private void radarTo() {
+ try {
+ if (cgBase.isIntentAvailable(activity, "com.google.android.radar.SHOW_RADAR") == true) {
+ Intent radarIntent = new Intent("com.google.android.radar.SHOW_RADAR");
+ radarIntent.putExtra("latitude", new Float(cache.latitude));
+ radarIntent.putExtra("longitude", new Float(cache.longitude));
+ activity.startActivity(radarIntent);
+ } else {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
+ dialog.setTitle(res.getString(R.string.err_radar_title));
+ dialog.setMessage(res.getString(R.string.err_radar_message));
+ dialog.setCancelable(true);
+ dialog.setPositiveButton("yes", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:com.eclipsim.gpsstatus2")));
+ dialog.cancel();
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_market));
+ Log.e(cgSettings.tag, "cgeodetail.radarTo.onClick: " + e.toString());
+ }
+ }
+ });
+ dialog.setNegativeButton("no", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ }
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_generic));
+ Log.e(cgSettings.tag, "cgeodetail.radarTo: " + e.toString());
+ }
+ }
+
+ public void shareCache() {
+ if (geocode == null && cache == null) {
+ return;
+ }
+
+ final Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setType("text/plain");
+
+ if (cache != null && cache.geocode != null) {
+ String subject = cache.geocode.toUpperCase();
+ if (cache.name != null && cache.name.length() > 0){
+ subject = subject + " - " + cache.name;
+ }
+ intent.putExtra(Intent.EXTRA_SUBJECT, "Geocache " + subject);
+ intent.putExtra(Intent.EXTRA_TEXT, "http://coord.info/" + cache.geocode.toUpperCase());
+ } else if (geocode != null) {
+ intent.putExtra(Intent.EXTRA_SUBJECT, "Geocache " + geocode.toUpperCase());
+ intent.putExtra(Intent.EXTRA_TEXT, "http://coord.info/" + geocode.toUpperCase());
+ }
+
+ startActivity(Intent.createChooser(intent, res.getText(R.string.action_bar_share_title)));
+ }
+
+ private class waypointInfo implements View.OnClickListener {
+ private int id = -1;
+
+ public waypointInfo(int idIn) {
+ id = idIn;
+ }
+
+ public void onClick(View arg0) {
+ Intent waypointIntent = new Intent(activity, cgeowaypoint.class);
+ waypointIntent.putExtra("waypoint", id);
+ waypointIntent.putExtra("geocode", cache.geocode);
+ activity.startActivity(waypointIntent);
+ }
+ }
+
+ private void logVisit() {
+ Intent logVisitIntent = new Intent(activity, cgeovisit.class);
+ logVisitIntent.putExtra("id", cache.cacheid);
+ logVisitIntent.putExtra("geocode", cache.geocode.toUpperCase());
+ logVisitIntent.putExtra("type", cache.type.toLowerCase());
+ logVisitIntent.putExtra("found", cache.found);
+ activity.startActivity(logVisitIntent);
+ }
+
+ private void showSpoilers() {
+ if (cache == null || cache.spoilers == null || cache.spoilers.isEmpty() == true) {
+ warning.showToast(res.getString(R.string.err_detail_no_spoiler));
+ }
+
+ Intent spoilersIntent = new Intent(activity, cgeospoilers.class);
+ spoilersIntent.putExtra("geocode", geocode.toUpperCase());
+ activity.startActivity(spoilersIntent);
+ }
+
+ private void showSmaps() {
+ if (cache == null || cache.reason == 0) {
+ warning.showToast(res.getString(R.string.err_detail_no_map_static));
+ }
+
+ Intent smapsIntent = new Intent(activity, cgeosmaps.class);
+ smapsIntent.putExtra("geocode", geocode.toUpperCase());
+ activity.startActivity(smapsIntent);
+ }
+
+ public class codeHint implements View.OnClickListener {
+ public void onClick(View arg0) {
+ // code hint
+ TextView hintView = ((TextView) findViewById(R.id.hint));
+ hintView.setText(cgBase.rot13(hintView.getText().toString()));
+
+ }
+ }
+
+ private class update extends cgUpdateLoc {
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+
+ try {
+ StringBuilder dist = new StringBuilder();
+
+ if (geo.latitudeNow != null && geo.longitudeNow != null && cache != null && cache.latitude != null && cache.longitude != null) {
+ dist.append(base.getHumanDistance(cgBase.getDistance(geo.latitudeNow, geo.longitudeNow, cache.latitude, cache.longitude)));
+ }
+
+ if (cache.elevation != null) {
+ Double diff = null;
+ if (geo.altitudeNow != null) {
+ diff = (cache.elevation - geo.altitudeNow);
+ }
+
+ if (diff != null && diff >= 0) {
+ dist.append(" ↗");
+ if (settings.units == cgSettings.unitsImperial) {
+ dist.append(String.format(Locale.getDefault(), "%.0f", (Math.abs(diff) * 3.2808399)));
+ dist.append(" ft");
+ } else {
+ dist.append(String.format(Locale.getDefault(), "%.0f", (Math.abs(diff))));
+ dist.append(" m");
+ }
+ } else if (diff != null && diff < 0) {
+ dist.append(" ↘");
+ if (settings.units == cgSettings.unitsImperial) {
+ dist.append(String.format(Locale.getDefault(), "%.0f", (Math.abs(diff) * 3.2808399)));
+ dist.append(" ft");
+ } else {
+ dist.append(String.format(Locale.getDefault(), "%.0f", (Math.abs(diff))));
+ dist.append(" m");
+ }
+ }
+ }
+
+ cacheDistance.setText(dist.toString());
+ cacheDistance.bringToFront();
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ private class selectTrackable implements View.OnClickListener {
+ public void onClick(View arg0) {
+ // show list of trackables
+ try {
+ Intent trackablesIntent = new Intent(activity, cgeotrackables.class);
+ trackablesIntent.putExtra("geocode", geocode.toUpperCase());
+ activity.startActivity(trackablesIntent);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeodetail.selectTrackable: " + e.toString());
+ }
+ }
+ }
+
+ private class storeCache implements View.OnClickListener {
+ public void onClick(View arg0) {
+ if (dropDialog != null && dropDialog.isShowing() == true) {
+ warning.showToast(res.getString(R.string.err_detail_still_removing));
+ return;
+ }
+ if (refreshDialog != null && refreshDialog.isShowing() == true) {
+ warning.showToast(res.getString(R.string.err_detail_still_refreshing));
+ return;
+ }
+
+ storeDialog = ProgressDialog.show(activity, res.getString(R.string.cache_dialog_offline_save_title), res.getString(R.string.cache_dialog_offline_save_message), true);
+ storeDialog.setCancelable(true);
+
+ if (storeThread != null) {
+ storeThread.interrupt();
+ }
+
+ storeThread = new storeCacheThread(storeCacheHandler);
+ storeThread.start();
+ }
+ }
+
+ private class refreshCache implements View.OnClickListener {
+ public void onClick(View arg0) {
+ if (dropDialog != null && dropDialog.isShowing() == true) {
+ warning.showToast(res.getString(R.string.err_detail_still_removing));
+ return;
+ }
+ if (storeDialog != null && storeDialog.isShowing() == true) {
+ warning.showToast(res.getString(R.string.err_detail_still_saving));
+ return;
+ }
+
+ refreshDialog = ProgressDialog.show(activity, res.getString(R.string.cache_dialog_refresh_title), res.getString(R.string.cache_dialog_refresh_message), true);
+ refreshDialog.setCancelable(true);
+
+ if (refreshThread != null) {
+ refreshThread.interrupt();
+ }
+
+ refreshThread = new refreshCacheThread(refreshCacheHandler);
+ refreshThread.start();
+ }
+ }
+
+ private class storeCacheThread extends Thread {
+ private Handler handler = null;
+
+ public storeCacheThread(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ int reason = 1;
+ if (cache.reason > 1) {
+ reason = cache.reason;
+ }
+ base.storeCache(app, activity, cache, null, reason, handler);
+ }
+ }
+
+ private class refreshCacheThread extends Thread {
+ private Handler handler = null;
+
+ public refreshCacheThread(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ app.removeCacheFromCache(geocode);
+
+ final HashMap<String, String> params = new HashMap<String, String>();
+ params.put("geocode", cache.geocode);
+ searchId = base.searchByGeocode(params, 0, true);
+
+ handler.sendEmptyMessage(0);
+ }
+ }
+
+ private class dropCache implements View.OnClickListener {
+ public void onClick(View arg0) {
+ if (storeDialog != null && storeDialog.isShowing() == true) {
+ warning.showToast(res.getString(R.string.err_detail_still_saving));
+ return;
+ }
+ if (refreshDialog != null && refreshDialog.isShowing() == true) {
+ warning.showToast(res.getString(R.string.err_detail_still_refreshing));
+ return;
+ }
+
+ dropDialog = ProgressDialog.show(activity, res.getString(R.string.cache_dialog_offline_drop_title), res.getString(R.string.cache_dialog_offline_drop_message), true);
+ dropDialog.setCancelable(false);
+ Thread thread = new dropCacheThread(dropCacheHandler);
+ thread.start();
+ }
+ }
+
+ private class dropCacheThread extends Thread {
+
+ private Handler handler = null;
+
+ public dropCacheThread(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ base.dropCache(app, activity, cache, handler);
+ }
+ }
+
+ private class addWaypoint implements View.OnClickListener {
+
+ public void onClick(View view) {
+ Intent addWptIntent = new Intent(activity, cgeowaypointadd.class);
+
+ addWptIntent.putExtra("geocode", geocode);
+ int wpCount = 0;
+ if (cache.waypoints != null) {
+ wpCount = cache.waypoints.size();
+ }
+ addWptIntent.putExtra("count", wpCount);
+
+ activity.startActivity(addWptIntent);
+ }
+ }
+
+ private class decryptLog implements View.OnClickListener {
+
+ public void onClick(View view) {
+ if (view == null) {
+ return;
+ }
+
+ try {
+ final TextView logView = (TextView)view;
+ Spannable span = (Spannable) logView.getText();
+
+ // I needed to re-implement the base.rot13() encryption here because we must work on
+ // a SpannableStringBuilder instead of the pure text and we must replace each character inline.
+ // Otherwise we loose all the images, colors and so on...
+ SpannableStringBuilder buffer = new SpannableStringBuilder(span);
+ boolean plaintext = false;
+
+ int length = span.length();
+ for (int index = 0; index < length; index++) {
+ int c = span.charAt(index);
+ if (c == '[') {
+ plaintext = true;
+ } else if (c == ']') {
+ plaintext = false;
+ } else if (!plaintext) {
+ int capitalized = c & 32;
+ c &= ~capitalized;
+ c = ((c >= 'A') && (c <= 'Z') ? ((c - 'A' + 13) % 26 + 'A') : c)
+ | capitalized;
+ }
+ buffer.replace(index, index + 1, String.valueOf((char) c));
+ }
+ logView.setText(buffer);
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ }
+
+ private class userActions implements View.OnClickListener {
+
+ public void onClick(View view) {
+ if (view == null) {
+ return;
+ }
+
+ try {
+ registerForContextMenu(view);
+ openContextMenu(view);
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ }
+
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goCompass(View view) {
+ if (cache == null || cache.latitude == null || cache.longitude == null) {
+ warning.showToast(res.getString(R.string.cache_coordinates_no));
+
+ return;
+ }
+
+ Intent navigateIntent = new Intent(activity, cgeonavigate.class);
+ navigateIntent.putExtra("latitude", cache.latitude);
+ navigateIntent.putExtra("longitude", cache.longitude);
+ navigateIntent.putExtra("geocode", cache.geocode.toUpperCase());
+ navigateIntent.putExtra("name", cache.name);
+
+ if (cgeonavigate.coordinates != null) {
+ cgeonavigate.coordinates.clear();
+ }
+ cgeonavigate.coordinates = getCoordinates();
+ activity.startActivity(navigateIntent);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-cache-details",
+ activity,
+ "http://cgeo.carnero.cc/manual/"
+ );
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgeogpxes.java b/src/cgeo/geocaching/cgeogpxes.java
new file mode 100644
index 0000000..f64100d
--- /dev/null
+++ b/src/cgeo/geocaching/cgeogpxes.java
@@ -0,0 +1,292 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import android.app.ListActivity;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.View;
+import java.io.File;
+import java.util.ArrayList;
+
+public class cgeogpxes extends ListActivity {
+
+ private ArrayList<File> files = new ArrayList<File>();
+ private cgeoapplication app = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private Activity activity = null;
+ private cgGPXListAdapter adapter = null;
+ private ProgressDialog waitDialog = null;
+ private ProgressDialog parseDialog = null;
+ private Resources res = null;
+ private loadFiles searchingThread = null;
+ private boolean endSearching = false;
+ private int listId = 1;
+ private int imported = 0;
+ final private Handler changeWaitDialogHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.obj != null && waitDialog != null) {
+ waitDialog.setMessage(res.getString(R.string.gpx_import_searching_in) + " " + (String) msg.obj);
+ }
+ }
+ };
+ final private Handler changeParseDialogHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.obj != null && parseDialog != null) {
+ parseDialog.setMessage(res.getString(R.string.gpx_import_loading_stored) + " " + (Integer) msg.obj);
+ }
+ }
+ };
+ final private Handler loadFilesHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (files == null || files.isEmpty()) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ warning.showToast(res.getString(R.string.gpx_import_no_files));
+
+ finish();
+ return;
+ } else {
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
+ }
+ }
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ } catch (Exception e) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ Log.e(cgSettings.tag, "cgeogpxes.loadFilesHandler: " + e.toString());
+ }
+ }
+ };
+ final private Handler loadCachesHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (parseDialog != null) {
+ parseDialog.dismiss();
+ }
+
+ warning.helpDialog(res.getString(R.string.gpx_import_title_caches_imported), imported + " " + res.getString(R.string.gpx_import_caches_imported));
+ imported = 0;
+ } catch (Exception e) {
+ if (parseDialog != null) {
+ parseDialog.dismiss();
+ }
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.gpx);
+ base.setTitle(activity, res.getString(R.string.gpx_import_title));
+
+ // google analytics
+ base.sendAnal(activity, "/gpx-import");
+
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ listId = extras.getInt("list");
+ }
+ if (listId <= 0) {
+ listId = 1;
+ }
+
+ setAdapter();
+
+ waitDialog = ProgressDialog.show(
+ this,
+ res.getString(R.string.gpx_import_title_searching),
+ res.getString(R.string.gpx_import_searching),
+ true,
+ true,
+ new DialogInterface.OnCancelListener() {
+ public void onCancel(DialogInterface arg0) {
+ if (searchingThread != null && searchingThread.isAlive()) {
+ searchingThread.notifyEnd();
+ }
+ if (files.isEmpty() == true) {
+ finish();
+ }
+ }
+ }
+ );
+
+ endSearching = false;
+ searchingThread = new loadFiles();
+ searchingThread.start();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ private void setAdapter() {
+ if (adapter == null) {
+ adapter = new cgGPXListAdapter(this, settings, files);
+ setListAdapter(adapter);
+ }
+ }
+
+ private class loadFiles extends Thread {
+ public void notifyEnd() {
+ endSearching = true;
+ }
+
+ @Override
+ public void run() {
+ ArrayList<File> list = new ArrayList<File>();
+
+ try {
+ if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) == true) {
+ final File gpx = new File(Environment.getExternalStorageDirectory().toString() + "/gpx");
+
+ if (gpx.exists() && gpx.isDirectory()) {
+ listDir(list, gpx);
+ } else {
+ listDir(list, Environment.getExternalStorageDirectory());
+ }
+ } else {
+ Log.w(cgSettings.tag, "No external media mounted.");
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeogpxes.loadFiles.run: " + e.toString());
+ }
+
+ final Message msg = new Message();
+ msg.obj = "loaded directories";
+ changeWaitDialogHandler.sendMessage(msg);
+
+ files.addAll(list);
+ list.clear();
+
+ loadFilesHandler.sendMessage(new Message());
+ }
+ }
+
+ private void listDir(ArrayList<File> list, File directory) {
+ if (directory == null || directory.isDirectory() == false || directory.canRead() == false) {
+ return;
+ }
+
+ final File[] listPre = directory.listFiles();
+
+ if (listPre != null && listPre.length > 0) {
+ final int listCnt = listPre.length;
+
+ for (int i = 0; i < listCnt; i++) {
+ if (endSearching == true) {
+ return;
+ }
+
+ if (listPre[i].canRead() == true && listPre[i].isFile() == true) {
+ final String[] nameParts = listPre[i].getName().split("\\.");
+ if (nameParts.length > 1) {
+ final String extension = nameParts[(nameParts.length - 1)].toLowerCase();
+
+ if (extension.equals("gpx") == false) {
+ continue;
+ }
+ } else {
+ continue; // file has no extension
+ }
+
+ list.add(listPre[i]); // add file to list
+ } else if (listPre[i].canRead() == true && listPre[i].isDirectory() == true) {
+ final Message msg = new Message();
+ String name = listPre[i].getName();
+ if (name.substring(0, 1).equals(".") == true) {
+ continue; // skip hidden directories
+ }
+ if (name.length() > 16) {
+ name = name.substring(0, 14) + "...";
+ }
+ msg.obj = name;
+ changeWaitDialogHandler.sendMessage(msg);
+
+ listDir(list, listPre[i]); // go deeper
+ }
+ }
+ }
+
+ return;
+ }
+
+ public void loadGPX(File file) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ parseDialog = ProgressDialog.show(
+ activity,
+ res.getString(R.string.gpx_import_title_reading_file),
+ res.getString(R.string.gpx_import_loading),
+ true,
+ false);
+
+ new loadCaches(file).start();
+ }
+
+ private class loadCaches extends Thread {
+
+ File file = null;
+
+ public loadCaches(File fileIn) {
+ file = fileIn;
+ }
+
+ @Override
+ public void run() {
+ final long searchId = base.parseGPX(app, file, listId, changeParseDialogHandler);
+
+ imported = app.getCount(searchId);
+
+ loadCachesHandler.sendMessage(new Message());
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+}
diff --git a/src/cgeo/geocaching/cgeohelpers.java b/src/cgeo/geocaching/cgeohelpers.java
new file mode 100644
index 0000000..cb38b64
--- /dev/null
+++ b/src/cgeo/geocaching/cgeohelpers.java
@@ -0,0 +1,107 @@
+package cgeo.geocaching;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.content.Intent;
+import android.view.View;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.net.Uri;
+import java.util.Locale;
+
+public class cgeohelpers extends Activity {
+
+ private cgeoapplication app = null;
+ private Resources res = null;
+ private Activity activity = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private SharedPreferences prefs = null;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ prefs = getSharedPreferences(cgSettings.preferences, 0);
+ settings = new cgSettings(this, prefs);
+ base = new cgBase(app, settings, prefs);
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.helpers);
+ base.setTitle(activity, res.getString(R.string.helpers));
+
+ // google analytics
+ base.sendAnal(activity, "/helpers");
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ public void installManual(View view) {
+ final Locale loc = Locale.getDefault();
+ final String lng = loc.getLanguage();
+
+ try {
+ if (lng.equalsIgnoreCase("de")) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:gnu.android.app.cgeomanual.de")));
+ } else {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:gnu.android.app.cgeomanual.en")));
+ }
+ } catch (Exception e) {
+ // market not available in standard emulator
+ }
+
+
+ finish();
+ }
+
+ public void installLocus(View view) {
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:menion.android.locus")));
+ } catch (Exception e) {
+ // market not available in standard emulator
+ }
+
+
+ finish();
+ }
+
+ public void installGpsStatus(View view) {
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:com.eclipsim.gpsstatus2")));
+ } catch (Exception e) {
+ // market not available in standard emulator
+ }
+
+ finish();
+ }
+
+ public void installBluetoothGps(View view) {
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:googoo.android.btgps")));
+ } catch (Exception e) {
+ // market not available in standard emulator
+ }
+
+ finish();
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+}
diff --git a/src/cgeo/geocaching/cgeoinit.java b/src/cgeo/geocaching/cgeoinit.java
new file mode 100644
index 0000000..0be2093
--- /dev/null
+++ b/src/cgeo/geocaching/cgeoinit.java
@@ -0,0 +1,965 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.view.View;
+import android.widget.EditText;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.util.Log;
+import android.os.Handler;
+import android.os.Message;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.AdapterView.OnItemSelectedListener;
+
+import java.io.File;
+
+import cgeo.geocaching.cgSettings.mapSourceEnum;
+
+public class cgeoinit extends Activity {
+
+ private cgeoapplication app = null;
+ private Resources res = null;
+ private Activity activity = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private SharedPreferences prefs = null;
+ private ProgressDialog loginDialog = null;
+ private ProgressDialog webDialog = null;
+ private Handler logInHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (loginDialog != null && loginDialog.isShowing() == true) {
+ loginDialog.dismiss();
+ }
+
+ if (msg.what == 1) {
+ warning.helpDialog(res.getString(R.string.init_login_popup), res.getString(R.string.init_login_popup_ok));
+ } else {
+ if (cgBase.errorRetrieve.containsKey(msg.what) == true) {
+ warning.helpDialog(res.getString(R.string.init_login_popup),
+ res.getString(R.string.init_login_popup_failed_reason) + " " + cgBase.errorRetrieve.get(msg.what) + ".");
+ } else {
+ warning.helpDialog(res.getString(R.string.init_login_popup), res.getString(R.string.init_login_popup_failed));
+ }
+ }
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_login_failed));
+
+ Log.e(cgSettings.tag, "cgeoinit.logInHandler: " + e.toString());
+ }
+
+ if (loginDialog != null && loginDialog.isShowing() == true) {
+ loginDialog.dismiss();
+ }
+
+ init();
+ }
+ };
+
+ private Handler webAuthHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (webDialog != null && webDialog.isShowing() == true) {
+ webDialog.dismiss();
+ }
+
+ if (msg.what > 0) {
+ warning.helpDialog(res.getString(R.string.init_sendToCgeo), res.getString(R.string.init_sendToCgeo_register_ok).replace("####", ""+msg.what));
+ } else {
+ warning.helpDialog(res.getString(R.string.init_sendToCgeo), res.getString(R.string.init_sendToCgeo_register_fail));
+ }
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.init_sendToCgeo_register_fail));
+
+ Log.e(cgSettings.tag, "cgeoinit.webHandler: " + e.toString());
+ }
+
+ if (webDialog != null && webDialog.isShowing() == true) {
+ webDialog.dismiss();
+ }
+
+ init();
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ prefs = getSharedPreferences(cgSettings.preferences, 0);
+ settings = new cgSettings(this, prefs);
+ base = new cgBase(app, settings, prefs);
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.init);
+ base.setTitle(activity, res.getString(R.string.settings));
+
+ // google analytics
+ base.sendAnal(activity, "/init");
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ init();
+ }
+
+ @Override
+ public void onPause() {
+ saveValues();
+ super.onPause();
+ }
+
+ @Override
+ public void onStop() {
+ saveValues();
+ super.onStop();
+ }
+
+ @Override
+ public void onDestroy() {
+ saveValues();
+
+ super.onDestroy();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(0, 0, 0, res.getString(R.string.init_clear)).setIcon(android.R.drawable.ic_menu_delete);
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == 0) {
+ boolean status = false;
+
+ ((EditText) findViewById(R.id.username)).setText("");
+ ((EditText) findViewById(R.id.password)).setText("");
+ ((EditText) findViewById(R.id.passvote)).setText("");
+
+ status = saveValues();
+ if (status == true) {
+ warning.showToast(res.getString(R.string.init_cleared));
+ } else {
+ warning.showToast(res.getString(R.string.err_init_cleared));
+ }
+
+ finish();
+ }
+
+ return false;
+ }
+
+ public void init() {
+
+ // geocaching.com settings
+ String usernameNow = prefs.getString("username", null);
+ if (usernameNow != null) {
+ ((EditText) findViewById(R.id.username)).setText(usernameNow);
+ }
+ String passwordNow = prefs.getString("password", null);
+ if (usernameNow != null) {
+ ((EditText) findViewById(R.id.password)).setText(passwordNow);
+ }
+
+ Button logMeIn = (Button) findViewById(R.id.log_me_in);
+ logMeIn.setOnClickListener(new logIn());
+
+ TextView legalNote = (TextView) findViewById(R.id.legal_note);
+ legalNote.setClickable(true);
+ legalNote.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View arg0) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/about/termsofuse.aspx")));
+ }
+ });
+
+ // gcvote settings
+ String passvoteNow = prefs.getString("pass-vote", null);
+ if (passvoteNow != null) {
+ ((EditText) findViewById(R.id.passvote)).setText(passvoteNow);
+ }
+
+ // go4cache settings
+ TextView go4cache = (TextView) findViewById(R.id.about_go4cache);
+ go4cache.setClickable(true);
+ go4cache.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View arg0) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://go4cache.com/")));
+ }
+ });
+
+ CheckBox publicButton = (CheckBox) findViewById(R.id.publicloc);
+ if (prefs.getInt("publicloc", 0) == 0) {
+ publicButton.setChecked(false);
+ } else {
+ publicButton.setChecked(true);
+ }
+ publicButton.setOnClickListener(new cgeoChangePublic());
+
+ // Twitter settings
+ Button authorizeTwitter = (Button) findViewById(R.id.authorize_twitter);
+ authorizeTwitter.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View arg0) {
+ Intent authIntent = new Intent(activity, cgeoauth.class);
+ activity.startActivity(authIntent);
+ }
+ });
+
+ CheckBox twitterButton = (CheckBox) findViewById(R.id.twitter_option);
+ if (prefs.getInt("twitter", 0) == 0 || settings.tokenPublic == null || settings.tokenPublic.length() == 0 || settings.tokenSecret == null || settings.tokenSecret.length() == 0) {
+ twitterButton.setChecked(false);
+ } else {
+ twitterButton.setChecked(true);
+ }
+ twitterButton.setOnClickListener(new cgeoChangeTwitter());
+
+ // Signature settings
+ EditText sigEdit = (EditText) findViewById(R.id.signature);
+ if (sigEdit.getText().length() == 0) {
+ sigEdit.setText(settings.getSignature());
+ }
+ Button sigBtn = (Button) findViewById(R.id.signature_help);
+ sigBtn.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ warning.helpDialog(res.getString(R.string.init_signature_help_title), res.getString(R.string.init_signature_help_text));
+ }
+ });
+
+ // Other settings
+ CheckBox skinButton = (CheckBox) findViewById(R.id.skin);
+ if (prefs.getInt("skin", 0) == 0) {
+ skinButton.setChecked(false);
+ } else {
+ skinButton.setChecked(true);
+ }
+ skinButton.setOnClickListener(new cgeoChangeSkin());
+
+ CheckBox addressButton = (CheckBox) findViewById(R.id.address);
+ if (prefs.getInt("showaddress", 1) == 0) {
+ addressButton.setChecked(false);
+ } else {
+ addressButton.setChecked(true);
+ }
+ addressButton.setOnClickListener(new cgeoChangeAddress());
+
+ CheckBox captchaButton = (CheckBox) findViewById(R.id.captcha);
+ if (prefs.getBoolean("showcaptcha", false) == false) {
+ captchaButton.setChecked(false);
+ } else {
+ captchaButton.setChecked(true);
+ }
+ captchaButton.setOnClickListener(new cgeoChangeCaptcha());
+
+ CheckBox useEnglishButton = (CheckBox) findViewById(R.id.useenglish);
+ if (prefs.getBoolean("useenglish", false) == false) {
+ useEnglishButton.setChecked(false);
+ } else {
+ useEnglishButton.setChecked(true);
+ }
+ useEnglishButton.setOnClickListener(new cgeoChangeUseEnglish());
+
+ CheckBox excludeButton = (CheckBox) findViewById(R.id.exclude);
+ if (prefs.getInt("excludemine", 0) == 0) {
+ excludeButton.setChecked(false);
+ } else {
+ excludeButton.setChecked(true);
+ }
+ excludeButton.setOnClickListener(new cgeoChangeExclude());
+
+ CheckBox disabledButton = (CheckBox) findViewById(R.id.disabled);
+ if (prefs.getInt("excludedisabled", 0) == 0) {
+ disabledButton.setChecked(false);
+ } else {
+ disabledButton.setChecked(true);
+ }
+ disabledButton.setOnClickListener(new cgeoChangeDisabled());
+
+ CheckBox offlineButton = (CheckBox) findViewById(R.id.offline);
+ if (prefs.getInt("offlinemaps", 1) == 0) {
+ offlineButton.setChecked(false);
+ } else {
+ offlineButton.setChecked(true);
+ }
+ offlineButton.setOnClickListener(new cgeoChangeOffline());
+
+ CheckBox autoloadButton = (CheckBox) findViewById(R.id.autoload);
+ if (prefs.getInt("autoloaddesc", 0) == 0) {
+ autoloadButton.setChecked(false);
+ } else {
+ autoloadButton.setChecked(true);
+ }
+ autoloadButton.setOnClickListener(new cgeoChangeAutoload());
+
+ CheckBox livelistButton = (CheckBox) findViewById(R.id.livelist);
+ if (prefs.getInt("livelist", 1) == 0) {
+ livelistButton.setChecked(false);
+ } else {
+ livelistButton.setChecked(true);
+ }
+ livelistButton.setOnClickListener(new cgeoChangeLivelist());
+
+ CheckBox unitsButton = (CheckBox) findViewById(R.id.units);
+ if (prefs.getInt("units", cgSettings.unitsMetric) == cgSettings.unitsMetric) {
+ unitsButton.setChecked(false);
+ } else {
+ unitsButton.setChecked(true);
+ }
+ unitsButton.setOnClickListener(new cgeoChangeUnits());
+
+ CheckBox gnavButton = (CheckBox) findViewById(R.id.gnav);
+ if (prefs.getInt("usegnav", 1) == 1) {
+ gnavButton.setChecked(true);
+ } else {
+ gnavButton.setChecked(false);
+ }
+ gnavButton.setOnClickListener(new cgeoChangeGNav());
+
+ CheckBox browserButton = (CheckBox) findViewById(R.id.browser);
+ if (prefs.getInt("asbrowser", 1) == 0) {
+ browserButton.setChecked(false);
+ } else {
+ browserButton.setChecked(true);
+ }
+ browserButton.setOnClickListener(new cgeoChangeBrowser());
+
+ // Altitude settings
+ EditText altitudeEdit = (EditText) findViewById(R.id.altitude);
+ altitudeEdit.setText("" + prefs.getInt("altcorrection", 0));
+
+ //Send2cgeo settings
+ String webDeviceName = prefs.getString("webDeviceName", null);
+
+ if ((webDeviceName != null) &&(webDeviceName.length() > 0)) {
+ ((EditText) findViewById(R.id.webDeviceName)).setText(webDeviceName);
+ } else {
+ String s = android.os.Build.MODEL;
+ ((EditText) findViewById(R.id.webDeviceName)).setText(s);
+ }
+
+ Button webAuth = (Button) findViewById(R.id.sendToCgeo_register);
+ webAuth.setOnClickListener(new webAuth());
+
+ /*TextView webText = (TextView) findViewById(R.id.sendToCgeo);
+ webText.setClickable(true);
+ webText.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View arg0) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://send2cgeo.carnero.cc/")));
+ }
+ });*/
+
+ // Map source settings
+ Spinner mapSourceSelector = (Spinner) findViewById(R.id.mapsource);
+ ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
+ this, R.array.map_sources, android.R.layout.simple_spinner_item);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mapSourceSelector.setAdapter(adapter);
+ int mapsource = prefs.getInt("mapsource", 0);
+ mapSourceSelector.setSelection(mapsource);
+ mapSourceSelector.setOnItemSelectedListener(new cgeoChangeMapSource());
+
+ EditText mfmapFileEdit = (EditText) findViewById(R.id.mapfile);
+ mfmapFileEdit.setText(prefs.getString("mfmapfile", ""));
+
+ setMapFileEditState();
+
+ // Cache db backup
+ TextView lastBackup = (TextView) findViewById(R.id.backup_last);
+ File lastBackupFile = app.isRestoreFile();
+ if (lastBackupFile != null) {
+ lastBackup.setText(res.getString(R.string.init_backup_last) + " " + cgBase.timeOut.format(lastBackupFile.lastModified()) + ", " + cgBase.dateOut.format(lastBackupFile.lastModified()));
+ } else {
+ lastBackup.setText(res.getString(R.string.init_backup_last_no));
+ }
+
+ }
+
+ public void backup(View view) {
+ final String file = app.backupDatabase();
+
+ if (file != null) {
+ warning.helpDialog(res.getString(R.string.init_backup_backup), res.getString(R.string.init_backup_success) + "\n" + file);
+ } else {
+ warning.helpDialog(res.getString(R.string.init_backup_backup), res.getString(R.string.init_backup_failed));
+ }
+
+ TextView lastBackup = (TextView) findViewById(R.id.backup_last);
+ File lastBackupFile = app.isRestoreFile();
+ if (lastBackupFile != null) {
+ lastBackup.setText(res.getString(R.string.init_backup_last) + " " + cgBase.timeOut.format(lastBackupFile.lastModified()) + ", " + cgBase.dateOut.format(lastBackupFile.lastModified()));
+ } else {
+ lastBackup.setText(res.getString(R.string.init_backup_last_no));
+ }
+ }
+
+ public void restore(View view) {
+ final boolean status = app.restoreDatabase();
+
+ if (status) {
+ warning.helpDialog(res.getString(R.string.init_backup_restore), res.getString(R.string.init_restore_success));
+ } else {
+ warning.helpDialog(res.getString(R.string.init_backup_restore), res.getString(R.string.init_restore_failed));
+ }
+ }
+
+ private void setMapFileEditState() {
+ EditText mapFileEdit = (EditText) findViewById(R.id.mapfile);
+ if (settings.mapProvider == mapSourceEnum.mapsforgeOffline) {
+ mapFileEdit.setVisibility(View.VISIBLE);
+ } else {
+ mapFileEdit.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ public boolean saveValues() {
+ String usernameNew = ((EditText) findViewById(R.id.username)).getText().toString();
+ String passwordNew = ((EditText) findViewById(R.id.password)).getText().toString();
+ String passvoteNew = ((EditText) findViewById(R.id.passvote)).getText().toString();
+ String signatureNew = ((EditText) findViewById(R.id.signature)).getText().toString();
+ String altitudeNew = ((EditText) findViewById(R.id.altitude)).getText().toString();
+ String mfmapFileNew = ((EditText) findViewById(R.id.mapfile)).getText().toString();
+
+ if (usernameNew == null) {
+ usernameNew = "";
+ }
+ if (passwordNew == null) {
+ passwordNew = "";
+ }
+ if (passvoteNew == null) {
+ passvoteNew = "";
+ }
+ if (signatureNew == null) {
+ signatureNew = "";
+ }
+
+ int altitudeNewInt = 0;
+ if (altitudeNew == null) {
+ altitudeNewInt = 0;
+ } else {
+ altitudeNewInt = new Integer(altitudeNew);
+ }
+
+ if (mfmapFileNew == null) {
+ mfmapFileNew = "";
+ }
+
+ final boolean status1 = settings.setLogin(usernameNew, passwordNew);
+ final boolean status2 = settings.setGCvoteLogin(passvoteNew);
+ final boolean status3 = settings.setSignature(signatureNew);
+ final boolean status4 = settings.setAltCorrection(altitudeNewInt);
+ final boolean status5 = settings.setMapFile(mfmapFileNew);
+
+ if (status1 && status2 && status3 && status4 && status5) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private class cgeoChangeTwitter implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ CheckBox twitterButton = (CheckBox) findViewById(R.id.twitter_option);
+
+ if (twitterButton.isChecked() == true) {
+ settings.reloadTwitterTokens();
+
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("twitter", 0) == 0) {
+ edit.putInt("twitter", 1);
+ settings.twitter = 1;
+ } else {
+ edit.putInt("twitter", 0);
+ settings.twitter = 0;
+ }
+ edit.commit();
+
+ if (settings.twitter == 1 && (settings.tokenPublic == null || settings.tokenPublic.length() == 0 || settings.tokenSecret == null || settings.tokenSecret.length() == 0)) {
+ Intent authIntent = new Intent(activity, cgeoauth.class);
+ activity.startActivity(authIntent);
+ }
+
+ if (prefs.getInt("twitter", 0) == 0) {
+ twitterButton.setChecked(false);
+ } else {
+ twitterButton.setChecked(true);
+ }
+ } else {
+ SharedPreferences.Editor edit = prefs.edit();
+ edit.putInt("twitter", 0);
+ settings.twitter = 0;
+ edit.commit();
+
+ twitterButton.setChecked(false);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeSkin implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("skin", 0) == 0) {
+ edit.putInt("skin", 1);
+ settings.setSkin(1);
+ } else {
+ edit.putInt("skin", 0);
+ settings.setSkin(0);
+ }
+ edit.commit();
+
+ CheckBox skinButton = (CheckBox) findViewById(R.id.skin);
+ if (prefs.getInt("skin", 0) == 0) {
+ skinButton.setChecked(false);
+ } else {
+ skinButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeAddress implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("showaddress", 1) == 0) {
+ edit.putInt("showaddress", 1);
+ } else {
+ edit.putInt("showaddress", 0);
+ }
+ edit.commit();
+
+ CheckBox transparentButton = (CheckBox) findViewById(R.id.address);
+ if (prefs.getInt("showaddress", 1) == 0) {
+ transparentButton.setChecked(false);
+ } else {
+ transparentButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangePublic implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("publicloc", 0) == 0) {
+ edit.putInt("publicloc", 1);
+ settings.publicLoc = 1;
+ } else {
+ edit.putInt("publicloc", 0);
+ settings.publicLoc = 0;
+ }
+ edit.commit();
+
+ CheckBox publicloc = (CheckBox) findViewById(R.id.publicloc);
+ if (prefs.getInt("publicloc", 0) == 0) {
+ publicloc.setChecked(false);
+ } else {
+ publicloc.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeCaptcha implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getBoolean("showcaptcha", false) == false) {
+ edit.putBoolean("showcaptcha", true);
+ settings.showCaptcha = true;
+ } else {
+ edit.putBoolean("showcaptcha", false);
+ settings.showCaptcha = false;
+ }
+ edit.commit();
+
+ CheckBox captchaButton = (CheckBox) findViewById(R.id.captcha);
+ if (prefs.getBoolean("showcaptcha", false) == false) {
+ captchaButton.setChecked(false);
+ } else {
+ captchaButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeUseEnglish implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getBoolean("useenglish", false) == false) {
+ edit.putBoolean("useenglish", true);
+ settings.useEnglish = true;
+ settings.setLanguage(true);
+ } else {
+ edit.putBoolean("useenglish", false);
+ settings.useEnglish = false;
+ settings.setLanguage(false);
+ }
+ edit.commit();
+
+ CheckBox useEnglishButton = (CheckBox) findViewById(R.id.useenglish);
+ if (prefs.getBoolean("useenglish", false) == false) {
+ useEnglishButton.setChecked(false);
+ } else {
+ useEnglishButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeExclude implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("excludemine", 0) == 0) {
+ edit.putInt("excludemine", 1);
+ settings.excludeMine = 1;
+ } else {
+ edit.putInt("excludemine", 0);
+ settings.excludeMine = 0;
+ }
+ edit.commit();
+
+ CheckBox excludeButton = (CheckBox) findViewById(R.id.exclude);
+ if (prefs.getInt("excludemine", 0) == 0) {
+ excludeButton.setChecked(false);
+ } else {
+ excludeButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeDisabled implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("excludedisabled", 0) == 0) {
+ edit.putInt("excludedisabled", 1);
+ settings.excludeDisabled = 1;
+ } else {
+ edit.putInt("excludedisabled", 0);
+ settings.excludeDisabled = 0;
+ }
+ edit.commit();
+
+ CheckBox disabledButton = (CheckBox) findViewById(R.id.disabled);
+ if (prefs.getInt("excludedisabled", 0) == 0) {
+ disabledButton.setChecked(false);
+ } else {
+ disabledButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeOffline implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("offlinemaps", 1) == 0) {
+ edit.putInt("offlinemaps", 1);
+ settings.excludeDisabled = 1;
+ } else {
+ edit.putInt("offlinemaps", 0);
+ settings.excludeDisabled = 0;
+ }
+ edit.commit();
+
+ CheckBox offlineButton = (CheckBox) findViewById(R.id.offline);
+ if (prefs.getInt("offlinemaps", 0) == 0) {
+ offlineButton.setChecked(false);
+ } else {
+ offlineButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeLivelist implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("livelist", 1) == 0) {
+ edit.putInt("livelist", 1);
+ settings.livelist = 1;
+ } else {
+ edit.putInt("livelist", 0);
+ settings.livelist = 0;
+ }
+ edit.commit();
+
+ CheckBox livelistButton = (CheckBox) findViewById(R.id.livelist);
+ if (prefs.getInt("livelist", 1) == 0) {
+ livelistButton.setChecked(false);
+ } else {
+ livelistButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeAutoload implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("autoloaddesc", 0) == 0) {
+ edit.putInt("autoloaddesc", 1);
+ settings.autoLoadDesc = 1;
+ } else {
+ edit.putInt("autoloaddesc", 0);
+ settings.autoLoadDesc = 0;
+ }
+ edit.commit();
+
+ CheckBox autoloadButton = (CheckBox) findViewById(R.id.autoload);
+ if (prefs.getInt("autoloaddesc", 0) == 0) {
+ autoloadButton.setChecked(false);
+ } else {
+ autoloadButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeUnits implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("units", cgSettings.unitsMetric) == cgSettings.unitsMetric) {
+ edit.putInt("units", cgSettings.unitsImperial);
+ settings.units = cgSettings.unitsImperial;
+ } else {
+ edit.putInt("units", cgSettings.unitsMetric);
+ settings.units = cgSettings.unitsMetric;
+ }
+ edit.commit();
+
+ CheckBox unitsButton = (CheckBox) findViewById(R.id.units);
+ if (prefs.getInt("units", cgSettings.unitsMetric) == cgSettings.unitsMetric) {
+ unitsButton.setChecked(false);
+ } else {
+ unitsButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeGNav implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("usegnav", 1) == 1) {
+ edit.putInt("usegnav", 0);
+ settings.useGNavigation = 0;
+ } else {
+ edit.putInt("usegnav", 1);
+ settings.useGNavigation = 1;
+ }
+ edit.commit();
+
+ CheckBox gnavButton = (CheckBox) findViewById(R.id.gnav);
+ if (prefs.getInt("usegnav", 1) == 1) {
+ gnavButton.setChecked(true);
+ } else {
+ gnavButton.setChecked(false);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeBrowser implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("asbrowser", 1) == 0) {
+ edit.putInt("asbrowser", 1);
+ settings.asBrowser = 1;
+ } else {
+ edit.putInt("asbrowser", 0);
+ settings.asBrowser = 0;
+ }
+ edit.commit();
+
+ CheckBox browserButton = (CheckBox) findViewById(R.id.browser);
+ if (prefs.getInt("asbrowser", 1) == 0) {
+ browserButton.setChecked(false);
+ } else {
+ browserButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeMapSource implements OnItemSelectedListener {
+
+ @Override
+ public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
+ long arg3) {
+ settings.mapProvider = mapSourceEnum.fromInt(arg2);
+ SharedPreferences.Editor edit = prefs.edit();
+ edit.putInt("mapsource", arg2);
+ edit.commit();
+ setMapFileEditState();
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> arg0) {
+ arg0.setSelection(settings.mapProvider.ordinal());
+ setMapFileEditState();
+ }
+ }
+
+ private class logIn implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ final String username = ((EditText) findViewById(R.id.username)).getText().toString();
+ final String password = ((EditText) findViewById(R.id.password)).getText().toString();
+
+ if (username == null || username.length() == 0 || password == null || password.length() == 0) {
+ warning.showToast(res.getString(R.string.err_missing_auth));
+ return;
+ }
+
+ loginDialog = ProgressDialog.show(activity, res.getString(R.string.init_login_popup), res.getString(R.string.init_login_popup_working), true);
+ loginDialog.setCancelable(false);
+
+ settings.setLogin(username, password);
+ settings.deleteCookies();
+
+ (new Thread() {
+
+ @Override
+ public void run() {
+ logInHandler.sendEmptyMessage(base.login());
+ }
+ }).start();
+ }
+ }
+
+ private class webAuth implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ final String deviceName = ((EditText) findViewById(R.id.webDeviceName)).getText().toString();
+ final String deviceCode = prefs.getString("webDeviceCode", null);
+
+
+ if (deviceName == null || deviceName.length() == 0) {
+ warning.showToast(res.getString(R.string.err_missing_device_name));
+ return;
+ }
+
+ webDialog = ProgressDialog.show(activity, res.getString(R.string.init_sendToCgeo), res.getString(R.string.init_sendToCgeo_registering), true);
+ webDialog.setCancelable(false);
+
+ (new Thread() {
+
+ @Override
+ public void run() {
+ int pin = 0;
+
+ String nam = deviceName==null?"":deviceName;
+ String cod = deviceCode==null?"":deviceCode;
+
+ String params = "name="+cgBase.urlencode_rfc3986(nam)+"&code="+cgBase.urlencode_rfc3986(cod);
+
+ cgResponse response = base.request(false, "send2cgeo.carnero.cc", "/authDev.php", "GET", params, 0, true);
+
+ if (response.getStatusCode() == 200)
+ {
+ //response was OK
+ String[] strings = response.getData().split(",");
+ try {
+ pin=Integer.parseInt(strings[1].trim());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "webDialog: " + e.toString());
+ }
+ String code = strings[0];
+ settings.setWebNameCode(nam, code);
+ }
+
+ webAuthHandler.sendEmptyMessage(pin);
+ }
+ }).start();
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-configuration",
+ activity,
+ "http://cgeo.carnero.cc/manual/"
+ );
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgeonavigate.java b/src/cgeo/geocaching/cgeonavigate.java
new file mode 100644
index 0000000..65afa17
--- /dev/null
+++ b/src/cgeo/geocaching/cgeonavigate.java
@@ -0,0 +1,503 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import java.util.ArrayList;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.util.Log;
+import android.app.Activity;
+import android.view.Menu;
+import android.view.SubMenu;
+import android.view.MenuItem;
+import android.widget.TextView;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.view.View;
+import android.view.WindowManager;
+import java.util.HashMap;
+import java.util.Locale;
+
+
+public class cgeonavigate extends Activity {
+
+ public static ArrayList<cgCoord> coordinates = new ArrayList<cgCoord>();
+ private Resources res = null;
+ private cgeoapplication app = null;
+ private Activity activity = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private PowerManager pm = null;
+ private cgGeo geo = null;
+ private cgDirection dir = null;
+ private cgUpdateLoc geoUpdate = new update();
+ private cgUpdateDir dirUpdate = new updateDir();
+ private Double dstLatitude = null;
+ private Double dstLongitude = null;
+ private Double cacheHeading = new Double(0);
+ private Double northHeading = new Double(0);
+ private String title = null;
+ private String name = null;
+ private TextView navType = null;
+ private TextView navAccuracy = null;
+ private TextView navSatellites = null;
+ private TextView navLocation = null;
+ private TextView distanceView = null;
+ private TextView headingView = null;
+ private cgCompass compassView = null;
+ private updaterThread updater = null;
+ private Handler updaterHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (compassView != null) {
+ compassView.updateNorth(northHeading, cacheHeading);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeonavigate.updaterHandler: " + e.toString());
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // class init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.navigate);
+ base.setTitle(activity, res.getString(R.string.compass_title));
+
+ // google analytics
+ base.sendAnal(activity, "/navigate");
+
+ // sensor & geolocation manager
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ title = extras.getString("geocode");
+ name = extras.getString("name");
+ dstLatitude = extras.getDouble("latitude");
+ dstLongitude = extras.getDouble("longitude");
+
+ if (name != null && name.length() > 0) {
+ if (title != null && title.length() > 0) {
+ title = title + ": " + name;
+ } else {
+ title = name;
+ }
+ }
+ } else {
+ Intent pointIntent = new Intent(activity, cgeopoint.class);
+ activity.startActivity(pointIntent);
+
+ finish();
+ return;
+ }
+
+ if (title != null && title.length() > 0) {
+ app.setAction(title);
+ } else if (name != null && name.length() > 0) {
+ app.setAction(name);
+ }
+
+ // set header
+ setTitle();
+ setDestCoords();
+
+ // get textviews once
+ compassView = (cgCompass) findViewById(R.id.rose);
+
+ // start updater thread
+ updater = new updaterThread(updaterHandler);
+ updater.start();
+
+ if (geo != null) {
+ geoUpdate.updateLoc(geo);
+ }
+ if (dir != null) {
+ dirUpdate.updateDir(dir);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+
+ if (title != null && title.length() > 0) {
+ app.setAction(title);
+ } else if (name != null && name.length() > 0) {
+ app.setAction(name);
+ }
+
+ // sensor & geolocation manager
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+
+ // keep backlight on
+ if (pm == null) {
+ pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ }
+
+ // updater thread
+ if (updater == null) {
+ updater = new updaterThread(updaterHandler);
+ updater.start();
+ }
+ }
+
+ @Override
+ public void onStop() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+
+ super.onPause();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+
+ compassView.destroyDrawingCache();
+ compassView = null;
+
+ super.onDestroy();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ if (settings.useCompass == 1) {
+ menu.add(0, 1, 0, res.getString(R.string.use_gps)).setIcon(android.R.drawable.ic_menu_compass);
+ } else {
+ menu.add(0, 1, 0, res.getString(R.string.use_compass)).setIcon(android.R.drawable.ic_menu_compass);
+ }
+ menu.add(0, 0, 0, res.getString(R.string.caches_on_map)).setIcon(android.R.drawable.ic_menu_mapmode);
+ menu.add(0, 2, 0, res.getString(R.string.destination_set)).setIcon(android.R.drawable.ic_menu_edit);
+ if (coordinates != null && coordinates.size() > 1) {
+ SubMenu subMenu = menu.addSubMenu(0, 3, 0, res.getString(R.string.destination_select)).setIcon(android.R.drawable.ic_menu_myplaces);
+
+ int cnt = 4;
+ for (cgCoord coordinate : coordinates) {
+ subMenu.add(0, cnt, 0, coordinate.name + " (" + coordinate.type + ")");
+ cnt++;
+ }
+
+ return true;
+ } else {
+ menu.add(0, 3, 0, res.getString(R.string.destination_select)).setIcon(android.R.drawable.ic_menu_myplaces).setEnabled(false);
+
+ return true;
+ }
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+
+ MenuItem item;
+ item = menu.findItem(1);
+ if (settings.useCompass == 1) {
+ item.setTitle(res.getString(R.string.use_gps));
+ } else {
+ item.setTitle(res.getString(R.string.use_compass));
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int id = item.getItemId();
+
+ if (id == 0) {
+ Intent mapIntent = new Intent(activity, settings.getMapFactory().getMapClass());
+ mapIntent.putExtra("detail", false);
+ mapIntent.putExtra("latitude", dstLatitude);
+ mapIntent.putExtra("longitude", dstLongitude);
+
+ activity.startActivity(mapIntent);
+ } else if (id == 1) {
+ if (settings.useCompass == 1) {
+ settings.useCompass = 0;
+
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+
+ SharedPreferences.Editor prefsEdit = getSharedPreferences(cgSettings.preferences, 0).edit();
+ prefsEdit.putInt("usecompass", settings.useCompass);
+ prefsEdit.commit();
+ } else {
+ settings.useCompass = 1;
+
+ if (dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+
+ SharedPreferences.Editor prefsEdit = getSharedPreferences(cgSettings.preferences, 0).edit();
+ prefsEdit.putInt("usecompass", settings.useCompass);
+ prefsEdit.commit();
+ }
+ } else if (id == 2) {
+ Intent pointIntent = new Intent(activity, cgeopoint.class);
+ activity.startActivity(pointIntent);
+
+ finish();
+ return true;
+ } else if (id > 3 && coordinates != null && coordinates.get(id - 4) != null) {
+ cgCoord coordinate = coordinates.get(id - 4);
+
+ title = coordinate.name;
+ dstLatitude = coordinate.latitude;
+ dstLongitude = coordinate.longitude;
+ setTitle();
+ setDestCoords();
+ updateDistanceInfo();
+
+ Log.d(cgSettings.tag, "destination set: " + title + " (" + String.format(Locale.getDefault(), "%.8f", dstLatitude) + " | " + String.format(Locale.getDefault(), "%.8f", dstLatitude) + ")");
+ return true;
+ }
+
+ return false;
+ }
+
+ private void setTitle() {
+ if (title != null && title.length() > 0) {
+ base.setTitle(activity, title);
+ } else {
+ base.setTitle(activity, res.getString(R.string.navigation));
+ }
+ }
+
+ private void setDestCoords() {
+ if (dstLatitude == null || dstLatitude == null) {
+ return;
+ }
+
+ ((TextView) findViewById(R.id.destination)).setText(base.formatCoordinate(dstLatitude, "lat", true) + " | " + base.formatCoordinate(dstLongitude, "lon", true));
+ }
+
+ public void setDest(Double lat, Double lon) {
+ if (lat == null || lon == null) {
+ return;
+ }
+
+ title = "some place";
+ setTitle();
+ setDestCoords();
+
+ dstLatitude = lat;
+ dstLongitude = lon;
+ updateDistanceInfo();
+ }
+
+ public HashMap<String, Double> getCoordinatesNow() {
+ HashMap<String, Double> coordsNow = new HashMap<String, Double>();
+ if (geo != null) {
+ coordsNow.put("latitude", geo.latitudeNow);
+ coordsNow.put("longitude", geo.longitudeNow);
+ }
+ return coordsNow;
+ }
+
+ private void updateDistanceInfo() {
+ if (geo == null || geo.latitudeNow == null || geo.longitudeNow == null || dstLatitude == null || dstLongitude == null) {
+ return;
+ }
+
+ if (distanceView == null) {
+ distanceView = (TextView) findViewById(R.id.distance);
+ }
+ if (headingView == null) {
+ headingView = (TextView) findViewById(R.id.heading);
+ }
+
+ cacheHeading = cgBase.getHeading(geo.latitudeNow, geo.longitudeNow, dstLatitude, dstLongitude);
+ distanceView.setText(base.getHumanDistance(cgBase.getDistance(geo.latitudeNow, geo.longitudeNow, dstLatitude, dstLongitude)));
+ headingView.setText(String.format(Locale.getDefault(), "%.0f", cacheHeading) + "°");
+ }
+
+ private class update extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+
+ try {
+ if (navType == null || navLocation == null || navAccuracy == null) {
+ navType = (TextView) findViewById(R.id.nav_type);
+ navAccuracy = (TextView) findViewById(R.id.nav_accuracy);
+ navSatellites = (TextView) findViewById(R.id.nav_satellites);
+ navLocation = (TextView) findViewById(R.id.nav_location);
+ }
+
+ if (geo.latitudeNow != null && geo.longitudeNow != null) {
+ String satellites = null;
+ if (geo.satellitesVisible != null && geo.satellitesFixed != null && geo.satellitesFixed > 0) {
+ satellites = res.getString(R.string.loc_sat) + ": " + geo.satellitesFixed + "/" + geo.satellitesVisible;
+ } else if (geo.satellitesVisible != null) {
+ satellites = res.getString(R.string.loc_sat) + ": 0/" + geo.satellitesVisible;
+ } else {
+ satellites = "";
+ }
+ navSatellites.setText(satellites);
+
+ if (geo.gps == -1) {
+ navType.setText(res.getString(R.string.loc_last));
+ } else if (geo.gps == 0) {
+ navType.setText(res.getString(R.string.loc_net));
+ } else {
+ navType.setText(res.getString(R.string.loc_gps));
+ }
+
+ if (geo.accuracyNow != null) {
+ if (settings.units == cgSettings.unitsImperial) {
+ navAccuracy.setText("±" + String.format(Locale.getDefault(), "%.0f", (geo.accuracyNow * 3.2808399)) + " ft");
+ } else {
+ navAccuracy.setText("±" + String.format(Locale.getDefault(), "%.0f", geo.accuracyNow) + " m");
+ }
+ } else {
+ navAccuracy.setText(null);
+ }
+
+ if (geo.altitudeNow != null) {
+ String humanAlt;
+ if (settings.units == cgSettings.unitsImperial) {
+ humanAlt = String.format("%.0f", (geo.altitudeNow * 3.2808399)) + " ft";
+ } else {
+ humanAlt = String.format("%.0f", geo.altitudeNow) + " m";
+ }
+ navLocation.setText(base.formatCoordinate(geo.latitudeNow, "lat", true) + " | " + base.formatCoordinate(geo.longitudeNow, "lon", true) + " | " + humanAlt);
+ } else {
+ navLocation.setText(base.formatCoordinate(geo.latitudeNow, "lat", true) + " | " + base.formatCoordinate(geo.longitudeNow, "lon", true));
+ }
+
+ updateDistanceInfo();
+ } else {
+ navType.setText(null);
+ navAccuracy.setText(null);
+ navLocation.setText(res.getString(R.string.loc_trying));
+ }
+
+ if (settings.useCompass == 0 || (geo.speedNow != null && geo.speedNow > 5)) { // use GPS when speed is higher than 18 km/h
+ if (geo != null && geo.bearingNow != null) {
+ northHeading = geo.bearingNow;
+ } else {
+ northHeading = new Double(0);
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ private class updateDir extends cgUpdateDir {
+
+ @Override
+ public void updateDir(cgDirection dir) {
+ if (dir == null || dir.directionNow == null) {
+ return;
+ }
+
+ if (geo == null || geo.speedNow == null || geo.speedNow <= 5) { // use compass when speed is lower than 18 km/h
+ northHeading = dir.directionNow;
+ }
+ }
+ }
+
+ private class updaterThread extends Thread {
+
+ private Handler handler = null;
+
+ public updaterThread(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ while (!Thread.currentThread().isInterrupted()) {
+ if (handler != null) {
+ handler.sendMessage(new Message());
+ }
+
+ try {
+ Thread.sleep(20);
+ } catch (Exception e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-compass",
+ activity,
+ "http://cgeo.carnero.cc/manual/");
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgeopoint.java b/src/cgeo/geocaching/cgeopoint.java
new file mode 100644
index 0000000..142bf53
--- /dev/null
+++ b/src/cgeo/geocaching/cgeopoint.java
@@ -0,0 +1,535 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+
+import com.google.android.apps.analytics.GoogleAnalyticsTracker;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class cgeopoint extends Activity {
+
+ private Resources res = null;
+ private cgeoapplication app = null;
+ private cgSettings settings = null;
+ private SharedPreferences prefs = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private Activity activity = null;
+ private GoogleAnalyticsTracker tracker = null;
+ private cgGeo geo = null;
+ private cgUpdateLoc geoUpdate = new update();
+ private EditText latEdit = null;
+ private EditText lonEdit = null;
+ private boolean changed = false;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ app = (cgeoapplication) this.getApplication();
+ res = this.getResources();
+ settings = new cgSettings(activity, activity.getSharedPreferences(cgSettings.preferences, 0));
+ prefs = getSharedPreferences(cgSettings.preferences, 0);
+ base = new cgBase(app, settings, activity.getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(activity);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.point);
+ base.setTitle(activity, res.getString(R.string.search_destination));
+
+ // google analytics
+ tracker = GoogleAnalyticsTracker.getInstance();
+ tracker.start(cgSettings.analytics, this);
+ tracker.dispatch();
+ base.sendAnal(activity, tracker, "/point");
+
+ init();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ init();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+ if (tracker != null) {
+ tracker.stop();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStop() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onPause();
+ }
+
+ private void init() {
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+
+ EditText latitudeEdit = (EditText) findViewById(R.id.latitude);
+ latitudeEdit.setOnKeyListener(new View.OnKeyListener() {
+
+ public boolean onKey(View v, int i, KeyEvent k) {
+ changed = true;
+
+ return false;
+ }
+ });
+
+ EditText longitudeEdit = (EditText) findViewById(R.id.longitude);
+ longitudeEdit.setOnKeyListener(new View.OnKeyListener() {
+
+ public boolean onKey(View v, int i, KeyEvent k) {
+ changed = true;
+
+ return false;
+ }
+ });
+
+ if (prefs.contains("anylatitude") == true && prefs.contains("anylongitude") == true) {
+ latitudeEdit.setText(base.formatCoordinate(new Double(prefs.getFloat("anylatitude", 0f)), "lat", true));
+ longitudeEdit.setText(base.formatCoordinate(new Double(prefs.getFloat("anylongitude", 0f)), "lon", true));
+ }
+
+ Button buttonCurrent = (Button) findViewById(R.id.current);
+ buttonCurrent.setOnClickListener(new currentListener());
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(0, 2, 0, res.getString(R.string.cache_menu_compass)).setIcon(android.R.drawable.ic_menu_compass); // compass
+
+ SubMenu subMenu = menu.addSubMenu(1, 0, 0, res.getString(R.string.cache_menu_navigate)).setIcon(android.R.drawable.ic_menu_more);
+ subMenu.add(0, 3, 0, res.getString(R.string.cache_menu_radar)); // radar
+ subMenu.add(0, 1, 0, res.getString(R.string.cache_menu_map)); // c:geo map
+ if (base.isLocus(activity)) {
+ subMenu.add(0, 20, 0, res.getString(R.string.cache_menu_locus)); // ext.: locus
+ }
+ if (base.isRmaps(activity)) {
+ subMenu.add(0, 21, 0, res.getString(R.string.cache_menu_rmaps)); // ext.: rmaps
+ }
+ subMenu.add(0, 23, 0, res.getString(R.string.cache_menu_map_ext)); // ext.: other
+ subMenu.add(0, 4, 0, res.getString(R.string.cache_menu_tbt)); // turn-by-turn
+
+ menu.add(0, 5, 0, res.getString(R.string.cache_menu_around)).setIcon(android.R.drawable.ic_menu_rotate); // caches around
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+
+ try {
+ ArrayList<Double> coords = getDestination();
+
+ if (coords != null && coords.get(0) != null && coords.get(1) != null) {
+ menu.findItem(0).setVisible(true);
+ menu.findItem(2).setVisible(true);
+ menu.findItem(5).setVisible(true);
+ } else {
+ menu.findItem(0).setVisible(false);
+ menu.findItem(2).setVisible(false);
+ menu.findItem(5).setVisible(false);
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ final int menuItem = item.getItemId();
+
+ ArrayList<Double> coords = getDestination();
+
+ if (menuItem == 1) {
+ showOnMap();
+ return true;
+ } else if (menuItem == 2) {
+ navigateTo();
+ return true;
+ } else if (menuItem == 3) {
+ radarTo();
+ return true;
+ } else if (menuItem == 4) {
+ if (geo != null) {
+ base.runNavigation(activity, res, settings, warning, tracker, coords.get(0), coords.get(1), geo.latitudeNow, geo.longitudeNow);
+ } else {
+ base.runNavigation(activity, res, settings, warning, tracker, coords.get(0), coords.get(1));
+ }
+
+ return true;
+ } else if (menuItem == 5) {
+ cachesAround();
+ return true;
+ } else if (menuItem == 20) {
+ base.runExternalMap(cgBase.mapAppLocus, activity, res, warning, tracker, coords.get(0), coords.get(1)); // locus
+ return true;
+ } else if (menuItem == 21) {
+ base.runExternalMap(cgBase.mapAppRmaps, activity, res, warning, tracker, coords.get(0), coords.get(1)); // rmaps
+ return true;
+ } else if (menuItem == 23) {
+ base.runExternalMap(cgBase.mapAppAny, activity, res, warning, tracker, coords.get(0), coords.get(1)); // rmaps
+ return true;
+ }
+
+ return false;
+ }
+
+ private void showOnMap() {
+ ArrayList<Double> coords = getDestination();
+
+ if (coords == null || coords.get(0) == null || coords.get(1) == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ Intent mapIntent = new Intent(activity, settings.getMapFactory().getMapClass());
+
+ mapIntent.putExtra("latitude", coords.get(0));
+ mapIntent.putExtra("longitude", coords.get(1));
+
+ activity.startActivity(mapIntent);
+ }
+
+ private void navigateTo() {
+ ArrayList<Double> coords = getDestination();
+
+ if (coords == null || coords.get(0) == null || coords.get(1) == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ cgeonavigate navigateActivity = new cgeonavigate();
+
+ Intent navigateIntent = new Intent(activity, navigateActivity.getClass());
+ navigateIntent.putExtra("latitude", coords.get(0));
+ navigateIntent.putExtra("longitude", coords.get(1));
+ navigateIntent.putExtra("geocode", "");
+ navigateIntent.putExtra("name", "Some destination");
+
+ activity.startActivity(navigateIntent);
+ }
+
+ private void radarTo() {
+ ArrayList<Double> coords = getDestination();
+
+ if (coords == null || coords.get(0) == null || coords.get(1) == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ try {
+ if (cgBase.isIntentAvailable(activity, "com.google.android.radar.SHOW_RADAR") == true) {
+ Intent radarIntent = new Intent("com.google.android.radar.SHOW_RADAR");
+ radarIntent.putExtra("latitude", new Float(coords.get(0)));
+ radarIntent.putExtra("longitude", new Float(coords.get(1)));
+ activity.startActivity(radarIntent);
+ } else {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
+ dialog.setTitle(res.getString(R.string.err_radar_title));
+ dialog.setMessage(res.getString(R.string.err_radar_message));
+ dialog.setCancelable(true);
+ dialog.setPositiveButton("yes", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:com.eclipsim.gpsstatus2")));
+ dialog.cancel();
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_market));
+ Log.e(cgSettings.tag, "cgeopoint.radarTo.onClick: " + e.toString());
+ }
+ }
+ });
+ dialog.setNegativeButton("no", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ }
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_generic));
+ Log.e(cgSettings.tag, "cgeopoint.radarTo: " + e.toString());
+ }
+ }
+
+ private void cachesAround() {
+ ArrayList<Double> coords = getDestination();
+
+ if (coords == null || coords.get(0) == null || coords.get(1) == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ cgeocaches cachesActivity = new cgeocaches();
+
+ Intent cachesIntent = new Intent(activity, cachesActivity.getClass());
+
+ cachesIntent.putExtra("type", "coordinate");
+ cachesIntent.putExtra("latitude", coords.get(0));
+ cachesIntent.putExtra("longitude", coords.get(1));
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+
+ activity.startActivity(cachesIntent);
+
+ finish();
+ }
+
+ private class update extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+
+ try {
+ if (latEdit == null) {
+ latEdit = (EditText) findViewById(R.id.latitude);
+ }
+ if (lonEdit == null) {
+ lonEdit = (EditText) findViewById(R.id.longitude);
+ }
+
+ latEdit.setHint(base.formatCoordinate(geo.latitudeNow, "lat", false));
+ lonEdit.setHint(base.formatCoordinate(geo.longitudeNow, "lon", false));
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ private class currentListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ if (geo == null || geo.latitudeNow == null || geo.longitudeNow == null) {
+ warning.showToast(res.getString(R.string.err_point_unknown_position));
+ return;
+ }
+
+ ((EditText) findViewById(R.id.latitude)).setText(base.formatCoordinate(geo.latitudeNow, "lat", true));
+ ((EditText) findViewById(R.id.longitude)).setText(base.formatCoordinate(geo.longitudeNow, "lon", true));
+
+ changed = false;
+ }
+ }
+
+ private ArrayList<Double> getDestination() {
+ ArrayList<Double> coords = new ArrayList<Double>();
+ Double latitude = null;
+ Double longitude = null;
+
+ String bearingText = ((EditText) findViewById(R.id.bearing)).getText().toString();
+ String distanceText = ((EditText) findViewById(R.id.distance)).getText().toString();
+ String latText = ((EditText) findViewById(R.id.latitude)).getText().toString();
+ String lonText = ((EditText) findViewById(R.id.longitude)).getText().toString();
+
+ if ((bearingText == null || bearingText.length() == 0) && (distanceText == null || distanceText.length() == 0)
+ && (latText == null || latText.length() == 0) && (lonText == null || lonText.length() == 0)) {
+ warning.helpDialog(res.getString(R.string.err_point_no_position_given_title), res.getString(R.string.err_point_no_position_given));
+ return null;
+ }
+
+ if (latText != null && latText.length() > 0 && lonText != null && lonText.length() > 0) {
+ // latitude & longitude
+ HashMap<String, Object> latParsed = base.parseCoordinate(latText, "lat");
+ HashMap<String, Object> lonParsed = base.parseCoordinate(lonText, "lat");
+
+ if (latParsed == null || latParsed.get("coordinate") == null || latParsed.get("string") == null) {
+ warning.showToast(res.getString(R.string.err_parse_lat));
+ return null;
+ }
+
+ if (lonParsed == null || lonParsed.get("coordinate") == null || lonParsed.get("string") == null) {
+ warning.showToast(res.getString(R.string.err_parse_lon));
+ return null;
+ }
+
+ latitude = (Double) latParsed.get("coordinate");
+ longitude = (Double) lonParsed.get("coordinate");
+ } else {
+ if (geo == null || geo.latitudeNow == null || geo.longitudeNow == null) {
+ warning.showToast(res.getString(R.string.err_point_curr_position_unavailable));
+ return null;
+ }
+
+ latitude = geo.latitudeNow;
+ longitude = geo.longitudeNow;
+ }
+
+ if (bearingText != null && bearingText.length() > 0 && distanceText != null && distanceText.length() > 0) {
+ // bearing & distance
+ Double bearing = null;
+ try {
+ bearing = new Double(bearingText);
+ } catch (Exception e) {
+ // probably not a number
+ }
+ if (bearing == null) {
+ warning.helpDialog(res.getString(R.string.err_point_bear_and_dist_title), res.getString(R.string.err_point_bear_and_dist));
+ return null;
+ }
+
+ Double distance = null; // km
+
+ final Pattern patternA = Pattern.compile("^([0-9\\.\\,]+)[ ]*m$", Pattern.CASE_INSENSITIVE); // m
+ final Pattern patternB = Pattern.compile("^([0-9\\.\\,]+)[ ]*km$", Pattern.CASE_INSENSITIVE); // km
+ final Pattern patternC = Pattern.compile("^([0-9\\.\\,]+)[ ]*ft$", Pattern.CASE_INSENSITIVE); // ft - 0.3048m
+ final Pattern patternD = Pattern.compile("^([0-9\\.\\,]+)[ ]*yd$", Pattern.CASE_INSENSITIVE); // yd - 0.9144m
+ final Pattern patternE = Pattern.compile("^([0-9\\.\\,]+)[ ]*mi$", Pattern.CASE_INSENSITIVE); // mi - 1609.344m
+
+ Matcher matcherA = patternA.matcher(distanceText);
+ Matcher matcherB = patternB.matcher(distanceText);
+ Matcher matcherC = patternC.matcher(distanceText);
+ Matcher matcherD = patternD.matcher(distanceText);
+ Matcher matcherE = patternE.matcher(distanceText);
+
+ if (matcherA.find() == true && matcherA.groupCount() > 0) {
+ distance = (new Double(matcherA.group(1))) * 0.001;
+ } else if (matcherB.find() == true && matcherB.groupCount() > 0) {
+ distance = new Double(matcherB.group(1));
+ } else if (matcherC.find() == true && matcherC.groupCount() > 0) {
+ distance = (new Double(matcherC.group(1))) * 0.0003048;
+ } else if (matcherD.find() == true && matcherD.groupCount() > 0) {
+ distance = (new Double(matcherD.group(1))) * 0.0009144;
+ } else if (matcherE.find() == true && matcherE.groupCount() > 0) {
+ distance = (new Double(matcherE.group(1))) * 1.609344;
+ } else {
+ try {
+ if (settings.units == cgSettings.unitsImperial) {
+ distance = (new Double(distanceText)) * 0.0003048; // considering it feet
+ } else {
+ distance = (new Double(distanceText)) * 0.001; // considering it meters
+ }
+ } catch (Exception e) {
+ // probably not a number
+ }
+ }
+
+ if (distance == null) {
+ warning.showToast(res.getString(R.string.err_parse_dist));
+ return null;
+ }
+
+ Double latParsed = null;
+ Double lonParsed = null;
+
+ HashMap<String, Double> coordsDst = base.getRadialDistance(latitude, longitude, bearing, distance);
+
+ latParsed = coordsDst.get("latitude");
+ lonParsed = coordsDst.get("longitude");
+
+ if (latParsed == null || lonParsed == null) {
+ warning.showToast(res.getString(R.string.err_point_location_error));
+ return null;
+ }
+
+ coords.add(0, (Double) latParsed);
+ coords.add(1, (Double) lonParsed);
+ } else if (latitude != null && longitude != null) {
+ coords.add(0, latitude);
+ coords.add(1, longitude);
+ } else {
+ return null;
+ }
+
+ saveCoords(coords.get(0), coords.get(1));
+
+ return coords;
+ }
+
+ private void saveCoords(Double latitude, Double longitude) {
+ if (changed == true && latitude == null || longitude == null) {
+ SharedPreferences.Editor edit = prefs.edit();
+
+ edit.putFloat("anylatitude", new Float(latitude));
+ edit.putFloat("anylongitude", new Float(longitude));
+
+ edit.commit();
+ } else {
+ SharedPreferences.Editor edit = prefs.edit();
+
+ edit.remove("anylatitude");
+ edit.remove("anylongitude");
+
+ edit.commit();
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-navigate-any",
+ activity,
+ "http://cgeo.carnero.cc/manual/");
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgeopopup.java b/src/cgeo/geocaching/cgeopopup.java
new file mode 100644
index 0000000..92d1338
--- /dev/null
+++ b/src/cgeo/geocaching/cgeopopup.java
@@ -0,0 +1,834 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import com.google.android.apps.analytics.GoogleAnalyticsTracker;
+import java.util.HashMap;
+import java.util.Locale;
+
+public class cgeopopup extends Activity {
+
+ private GoogleAnalyticsTracker tracker = null;
+ private Activity activity = null;
+ private Resources res = null;
+ private cgeoapplication app = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private Boolean fromDetail = false;
+ private LayoutInflater inflater = null;
+ private String geocode = null;
+ private cgCache cache = null;
+ private cgGeo geo = null;
+ private cgUpdateLoc geoUpdate = new update();
+ private ProgressDialog storeDialog = null;
+ private ProgressDialog dropDialog = null;
+ private TextView cacheDistance = null;
+ private HashMap<String, Integer> gcIcons = new HashMap<String, Integer>();
+ private Handler ratingHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ final Bundle data = msg.getData();
+
+ setRating(data.getFloat("rating"), data.getInt("votes"));
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ };
+ private Handler storeCacheHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (storeDialog != null) {
+ storeDialog.dismiss();
+ }
+
+ finish();
+ return;
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_store));
+
+ Log.e(cgSettings.tag, "cgeopopup.storeCacheHandler: " + e.toString());
+ }
+
+ if (storeDialog != null) {
+ storeDialog.dismiss();
+ }
+ init();
+ }
+ };
+ private Handler dropCacheHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (dropDialog != null) {
+ dropDialog.dismiss();
+ }
+
+ finish();
+ return;
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_drop));
+
+ Log.e(cgSettings.tag, "cgeopopup.dropCacheHandler: " + e.toString());
+ }
+
+ if (dropDialog != null) {
+ dropDialog.dismiss();
+ }
+ init();
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ setTheme(R.style.transparent);
+ setContentView(R.layout.popup);
+ base.setTitle(activity, res.getString(R.string.detail));
+
+ // google analytics
+ tracker = GoogleAnalyticsTracker.getInstance();
+ tracker.start(cgSettings.analytics, this);
+ tracker.dispatch();
+ base.sendAnal(activity, tracker, "/popup");
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ fromDetail = extras.getBoolean("fromdetail");
+ geocode = extras.getString("geocode");
+ }
+
+ if (geocode == null || geocode.length() == 0) {
+ warning.showToast(res.getString(R.string.err_detail_cache_find));
+
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(0, 2, 0, res.getString(R.string.cache_menu_compass)).setIcon(android.R.drawable.ic_menu_compass); // compass
+
+ SubMenu subMenu = menu.addSubMenu(1, 0, 0, res.getString(R.string.cache_menu_navigate)).setIcon(android.R.drawable.ic_menu_more);
+ subMenu.add(0, 3, 0, res.getString(R.string.cache_menu_radar)); // radar
+ subMenu.add(0, 1, 0, res.getString(R.string.cache_menu_map)); // c:geo map
+ if (base.isLocus(activity)) {
+ subMenu.add(0, 20, 0, res.getString(R.string.cache_menu_locus)); // ext.: locus
+ }
+ if (base.isRmaps(activity)) {
+ subMenu.add(0, 21, 0, res.getString(R.string.cache_menu_rmaps)); // ext.: rmaps
+ }
+ subMenu.add(0, 23, 0, res.getString(R.string.cache_menu_map_ext)); // ext.: other
+ subMenu.add(0, 4, 0, res.getString(R.string.cache_menu_tbt)); // turn-by-turn
+
+ menu.add(0, 6, 0, res.getString(R.string.cache_menu_visit)).setIcon(android.R.drawable.ic_menu_agenda); // log visit
+ menu.add(0, 5, 0, res.getString(R.string.cache_menu_around)).setIcon(android.R.drawable.ic_menu_rotate); // caches around
+ menu.add(0, 7, 0, res.getString(R.string.cache_menu_browser)).setIcon(android.R.drawable.ic_menu_info_details); // browser
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+
+ try {
+ if (cache != null && cache.latitude != null && cache.longitude != null) {
+ menu.findItem(0).setVisible(true);
+ menu.findItem(2).setVisible(true);
+ menu.findItem(5).setVisible(true);
+ } else {
+ menu.findItem(0).setVisible(false);
+ menu.findItem(2).setVisible(false);
+ menu.findItem(5).setVisible(false);
+ }
+
+ if (fromDetail == false && settings.isLogin() == true) {
+ menu.findItem(6).setEnabled(true);
+ } else {
+ menu.findItem(6).setEnabled(false);
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ final int menuItem = item.getItemId();
+
+ if (menuItem == 1) {
+ showOnMap();
+ return true;
+ } else if (menuItem == 2) {
+ navigateTo();
+ return true;
+ } else if (menuItem == 3) {
+ radarTo();
+ return true;
+ } else if (menuItem == 4) {
+ if (geo != null) {
+ base.runNavigation(activity, res, settings, warning, tracker, cache.latitude, cache.longitude, geo.latitudeNow, geo.longitudeNow);
+ } else {
+ base.runNavigation(activity, res, settings, warning, tracker, cache.latitude, cache.longitude);
+ }
+
+ return true;
+ } else if (menuItem == 5) {
+ cachesAround();
+ return true;
+ } else if (menuItem == 6) {
+ if (cache.cacheid == null || cache.cacheid.length() == 0) {
+ warning.showToast(res.getString(R.string.err_cannot_log_visit));
+ return false;
+ }
+
+ Intent logVisitIntent = new Intent(activity, cgeovisit.class);
+ logVisitIntent.putExtra("id", cache.cacheid);
+ logVisitIntent.putExtra("geocode", cache.geocode.toUpperCase());
+ logVisitIntent.putExtra("type", cache.type.toLowerCase());
+ activity.startActivity(logVisitIntent);
+
+ activity.finish();
+
+ return true;
+ } else if (menuItem == 7) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/seek/cache_details.aspx?wp=" + cache.geocode)));
+ return true;
+ } else if (menuItem == 20) {
+ base.runExternalMap(cgBase.mapAppLocus, activity, res, warning, tracker, cache.latitude, cache.longitude); // locus
+ return true;
+ } else if (menuItem == 21) {
+ base.runExternalMap(cgBase.mapAppRmaps, activity, res, warning, tracker, cache.latitude, cache.longitude); // rmaps
+ return true;
+ } else if (menuItem == 23) {
+ base.runExternalMap(cgBase.mapAppAny, activity, res, warning, tracker, cache.latitude, cache.longitude); // rmaps
+ return true;
+ }
+
+ return false;
+ }
+
+ private void init() {
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+
+ app.setAction(geocode);
+
+ cache = app.getCacheByGeocode(geocode);
+
+ if (cache == null) {
+ warning.showToast(res.getString(R.string.err_detail_cache_find));
+
+ finish();
+ return;
+ }
+
+ try {
+ RelativeLayout itemLayout;
+ TextView itemName;
+ TextView itemValue;
+ LinearLayout itemStars;
+
+ if (gcIcons == null || gcIcons.isEmpty()) {
+ gcIcons.put("ape", R.drawable.type_ape);
+ gcIcons.put("cito", R.drawable.type_cito);
+ gcIcons.put("earth", R.drawable.type_earth);
+ gcIcons.put("event", R.drawable.type_event);
+ gcIcons.put("letterbox", R.drawable.type_letterbox);
+ gcIcons.put("locationless", R.drawable.type_locationless);
+ gcIcons.put("mega", R.drawable.type_mega);
+ gcIcons.put("multi", R.drawable.type_multi);
+ gcIcons.put("traditional", R.drawable.type_traditional);
+ gcIcons.put("virtual", R.drawable.type_virtual);
+ gcIcons.put("webcam", R.drawable.type_webcam);
+ gcIcons.put("wherigo", R.drawable.type_wherigo);
+ gcIcons.put("mystery", R.drawable.type_mystery);
+ gcIcons.put("gchq", R.drawable.type_hq);
+ }
+
+ if (cache.name != null && cache.name.length() > 0) {
+ base.setTitle(activity, cache.name);
+ } else {
+ base.setTitle(activity, geocode.toUpperCase());
+ }
+
+ inflater = activity.getLayoutInflater();
+ geocode = cache.geocode.toUpperCase();
+
+ ((ScrollView) findViewById(R.id.details_list_box)).setVisibility(View.VISIBLE);
+ LinearLayout detailsList = (LinearLayout) findViewById(R.id.details_list);
+ detailsList.removeAllViews();
+
+ // actionbar icon
+ if (cache.type != null && gcIcons.containsKey(cache.type) == true) { // cache icon
+ ((TextView) findViewById(R.id.actionbar_title)).setCompoundDrawablesWithIntrinsicBounds((Drawable) activity.getResources().getDrawable(gcIcons.get(cache.type)), null, null, null);
+ } else { // unknown cache type, "mystery" icon
+ ((TextView) findViewById(R.id.actionbar_title)).setCompoundDrawablesWithIntrinsicBounds((Drawable) activity.getResources().getDrawable(gcIcons.get("mystery")), null, null, null);
+ }
+
+ // cache type
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_type));
+ if (cgBase.cacheTypesInv.containsKey(cache.type) == true) { // cache icon
+ if (cache.size != null && cache.size.length() > 0) {
+ itemValue.setText(cgBase.cacheTypesInv.get(cache.type) + " (" + cache.size + ")");
+ } else {
+ itemValue.setText(cgBase.cacheTypesInv.get(cache.type));
+ }
+ } else {
+ if (cache.size != null && cache.size.length() > 0) {
+ itemValue.setText(cgBase.cacheTypesInv.get("mystery") + " (" + cache.size + ")");
+ } else {
+ itemValue.setText(cgBase.cacheTypesInv.get("mystery"));
+ }
+ }
+ detailsList.addView(itemLayout);
+
+ // gc-code
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_geocode));
+ itemValue.setText(cache.geocode.toUpperCase());
+ detailsList.addView(itemLayout);
+
+ // cache state
+ if (cache.archived == true || cache.disabled == true || cache.members == true || cache.found == true) {
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_status));
+
+ StringBuilder state = new StringBuilder();
+ if (cache.found == true) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_found));
+ }
+ if (cache.archived == true) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_archived));
+ }
+ if (cache.disabled == true) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_disabled));
+ }
+ if (cache.members == true) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_premium));
+ }
+
+ itemValue.setText(state.toString());
+ detailsList.addView(itemLayout);
+
+ state = null;
+ }
+
+ // distance
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_distance));
+ itemValue.setText("--");
+ detailsList.addView(itemLayout);
+ cacheDistance = itemValue;
+
+ // difficulty
+ if (cache.difficulty > 0f) {
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_layout, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+ itemStars = (LinearLayout) itemLayout.findViewById(R.id.stars);
+
+ itemName.setText(res.getString(R.string.cache_difficulty));
+ itemValue.setText(String.format(Locale.getDefault(), "%.1f", cache.difficulty) + " of 5");
+ for (int i = 0; i <= 4; i++) {
+ ImageView star = (ImageView) inflater.inflate(R.layout.star, null);
+ if ((cache.difficulty - i) >= 1.0) {
+ star.setImageResource(R.drawable.star_on);
+ } else if ((cache.difficulty - i) > 0.0) {
+ star.setImageResource(R.drawable.star_half);
+ } else {
+ star.setImageResource(R.drawable.star_off);
+ }
+ itemStars.addView(star);
+ }
+ detailsList.addView(itemLayout);
+ }
+
+ // terrain
+ if (cache.terrain > 0f) {
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_layout, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+ itemStars = (LinearLayout) itemLayout.findViewById(R.id.stars);
+
+ itemName.setText(res.getString(R.string.cache_terrain));
+ itemValue.setText(String.format(Locale.getDefault(), "%.1f", cache.terrain) + " of 5");
+ for (int i = 0; i <= 4; i++) {
+ ImageView star = (ImageView) inflater.inflate(R.layout.star, null);
+ if ((cache.terrain - i) >= 1.0) {
+ star.setImageResource(R.drawable.star_on);
+ } else if ((cache.terrain - i) > 0.0) {
+ star.setImageResource(R.drawable.star_half);
+ } else {
+ star.setImageResource(R.drawable.star_off);
+ }
+ itemStars.addView(star);
+ }
+ detailsList.addView(itemLayout);
+ }
+
+ // rating
+ if (cache.rating != null && cache.rating > 0) {
+ setRating(cache.rating, cache.votes);
+ } else {
+ (new Thread() {
+
+ public void run() {
+ cgRating rating = base.getRating(cache.guid, geocode);
+
+ Message msg = new Message();
+ Bundle bundle = new Bundle();
+
+ if (rating == null || rating.rating == null) {
+ return;
+ }
+
+ bundle.putFloat("rating", rating.rating);
+ bundle.putInt("votes", rating.votes);
+ msg.setData(bundle);
+
+ ratingHandler.sendMessage(msg);
+ }
+ }).start();
+ }
+
+ // more details
+ if (fromDetail == false) {
+ ((LinearLayout) findViewById(R.id.more_details_box)).setVisibility(View.VISIBLE);
+
+ Button buttonMore = (Button) findViewById(R.id.more_details);
+ buttonMore.setOnClickListener(new OnClickListener() {
+
+ public void onClick(View arg0) {
+ Intent cachesIntent = new Intent(activity, cgeodetail.class);
+ cachesIntent.putExtra("geocode", geocode.toUpperCase());
+ activity.startActivity(cachesIntent);
+
+ activity.finish();
+ return;
+ }
+ });
+ } else {
+ ((LinearLayout) findViewById(R.id.more_details_box)).setVisibility(View.GONE);
+ }
+
+ if (fromDetail == false) {
+ ((LinearLayout) findViewById(R.id.offline_box)).setVisibility(View.VISIBLE);
+
+ // offline use
+ final TextView offlineText = (TextView) findViewById(R.id.offline_text);
+ final Button offlineRefresh = (Button) findViewById(R.id.offline_refresh);
+ final Button offlineStore = (Button) findViewById(R.id.offline_store);
+
+ if (cache.reason > 0) {
+ Long diff = (System.currentTimeMillis() / (60 * 1000)) - (cache.detailedUpdate / (60 * 1000)); // minutes
+
+ String ago = "";
+ if (diff < 15) {
+ ago = res.getString(R.string.cache_offline_time_mins_few);
+ } else if (diff < 50) {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + diff + " " + res.getString(R.string.cache_offline_time_mins);
+ } else if (diff < 90) {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + res.getString(R.string.cache_offline_time_hour);
+ } else if (diff < (48 * 60)) {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + (diff / 60) + " " + res.getString(R.string.cache_offline_time_hours);
+ } else {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + (diff / (24 * 60)) + " " + res.getString(R.string.cache_offline_time_days);
+ }
+
+ offlineText.setText(res.getString(R.string.cache_offline_stored) + "\n" + ago);
+
+ offlineRefresh.setVisibility(View.VISIBLE);
+ offlineRefresh.setEnabled(true);
+ offlineRefresh.setOnClickListener(new storeCache());
+
+ offlineStore.setText(res.getString(R.string.cache_offline_drop));
+ offlineStore.setEnabled(true);
+ offlineStore.setOnClickListener(new dropCache());
+ } else {
+ offlineText.setText(res.getString(R.string.cache_offline_not_ready));
+
+ offlineRefresh.setVisibility(View.GONE);
+ offlineRefresh.setEnabled(false);
+ offlineRefresh.setOnTouchListener(null);
+ offlineRefresh.setOnClickListener(null);
+
+ offlineStore.setText(res.getString(R.string.cache_offline_store));
+ offlineStore.setEnabled(true);
+ offlineStore.setOnClickListener(new storeCache());
+ }
+ } else {
+ ((LinearLayout) findViewById(R.id.offline_box)).setVisibility(View.GONE);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeopopup.init: " + e.toString());
+ }
+
+ if (geo != null) {
+ geoUpdate.updateLoc(geo);
+ }
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ init();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+ if (tracker != null) {
+ tracker.stop();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStop() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onPause();
+ }
+
+ private class update extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+
+ try {
+ if (geo.latitudeNow != null && geo.longitudeNow != null && cache != null && cache.latitude != null && cache.longitude != null) {
+ cacheDistance.setText(base.getHumanDistance(cgBase.getDistance(geo.latitudeNow, geo.longitudeNow, cache.latitude, cache.longitude)));
+ cacheDistance.bringToFront();
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ private void showOnMap() {
+ if (cache == null || cache.latitude == null || cache.longitude == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ Intent mapIntent = new Intent(activity, settings.getMapFactory().getMapClass());
+
+ mapIntent.putExtra("latitude", cache.latitude);
+ mapIntent.putExtra("longitude", cache.longitude);
+
+ activity.startActivity(mapIntent);
+ }
+
+ private void navigateTo() {
+ if (cache == null || cache.latitude == null || cache.longitude == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ cgeonavigate navigateActivity = new cgeonavigate();
+
+ Intent navigateIntent = new Intent(activity, navigateActivity.getClass());
+ navigateIntent.putExtra("latitude", cache.latitude);
+ navigateIntent.putExtra("longitude", cache.longitude);
+ navigateIntent.putExtra("geocode", "");
+ navigateIntent.putExtra("name", "Some destination");
+
+ activity.startActivity(navigateIntent);
+ }
+
+ private void radarTo() {
+ if (cache == null || cache.latitude == null || cache.longitude == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ try {
+ if (cgBase.isIntentAvailable(activity, "com.google.android.radar.SHOW_RADAR") == true) {
+ Intent radarIntent = new Intent("com.google.android.radar.SHOW_RADAR");
+ radarIntent.putExtra("latitude", new Float(cache.latitude));
+ radarIntent.putExtra("longitude", new Float(cache.longitude));
+ activity.startActivity(radarIntent);
+ } else {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
+ dialog.setTitle(res.getString(R.string.err_radar_title));
+ dialog.setMessage(res.getString(R.string.err_radar_message));
+ dialog.setCancelable(true);
+ dialog.setPositiveButton("yes", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:com.eclipsim.gpsstatus2")));
+ dialog.cancel();
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_market));
+ Log.e(cgSettings.tag, "cgeopoint.radarTo.onClick: " + e.toString());
+ }
+ }
+ });
+ dialog.setNegativeButton("no", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ }
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_generic));
+ Log.e(cgSettings.tag, "cgeopoint.radarTo: " + e.toString());
+ }
+ }
+
+ private void cachesAround() {
+ if (cache == null || cache.latitude == null || cache.longitude == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ cgeocaches cachesActivity = new cgeocaches();
+
+ Intent cachesIntent = new Intent(activity, cachesActivity.getClass());
+
+ cachesIntent.putExtra("type", "coordinate");
+ cachesIntent.putExtra("latitude", cache.latitude);
+ cachesIntent.putExtra("longitude", cache.longitude);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+
+ activity.startActivity(cachesIntent);
+
+ finish();
+ }
+
+ private class storeCache implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ if (dropDialog != null && dropDialog.isShowing() == true) {
+ warning.showToast("Still removing this cache.");
+ return;
+ }
+
+ storeDialog = ProgressDialog.show(activity, res.getString(R.string.cache_dialog_offline_save_title), res.getString(R.string.cache_dialog_offline_save_message), true);
+ storeDialog.setCancelable(false);
+ Thread thread = new storeCacheThread(storeCacheHandler);
+ thread.start();
+ }
+ }
+
+ private class storeCacheThread extends Thread {
+
+ private Handler handler = null;
+
+ public storeCacheThread(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ base.storeCache(app, activity, cache, null, 1, handler);
+ }
+ }
+
+ private class dropCache implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ if (storeDialog != null && storeDialog.isShowing() == true) {
+ warning.showToast("Still saving this cache.");
+ return;
+ }
+
+ dropDialog = ProgressDialog.show(activity, res.getString(R.string.cache_dialog_offline_drop_title), res.getString(R.string.cache_dialog_offline_drop_message), true);
+ dropDialog.setCancelable(false);
+ Thread thread = new dropCacheThread(dropCacheHandler);
+ thread.start();
+ }
+ }
+
+ private class dropCacheThread extends Thread {
+
+ private Handler handler = null;
+
+ public dropCacheThread(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ base.dropCache(app, activity, cache, handler);
+ }
+ }
+
+ private void setRating(Float rating, Integer votes) {
+ if (rating == null || rating <= 0) {
+ return;
+ }
+
+ RelativeLayout itemLayout;
+ TextView itemName;
+ TextView itemValue;
+ LinearLayout itemStars;
+ LinearLayout detailsList = (LinearLayout) findViewById(R.id.details_list);
+
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_layout, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+ itemStars = (LinearLayout) itemLayout.findViewById(R.id.stars);
+
+ itemName.setText(res.getString(R.string.cache_rating));
+ itemValue.setText(String.format(Locale.getDefault(), "%.1f", rating) + " of 5");
+ for (int i = 0; i <= 4; i++) {
+ ImageView star = (ImageView) inflater.inflate(R.layout.star, null);
+ if ((rating - i) >= 1.0) {
+ star.setImageResource(R.drawable.star_on);
+ } else if ((rating - i) > 0.0) {
+ star.setImageResource(R.drawable.star_half);
+ } else {
+ star.setImageResource(R.drawable.star_off);
+ }
+ itemStars.addView(star, (1 + i));
+ }
+ if (votes != null) {
+ final TextView itemAddition = (TextView) itemLayout.findViewById(R.id.addition);
+ itemAddition.setText("(" + votes + ")");
+ itemAddition.setVisibility(View.VISIBLE);
+ }
+ detailsList.addView(itemLayout);
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goCompass(View view) {
+ if (cache == null || cache.latitude == null || cache.longitude == null) {
+ warning.showToast(res.getString(R.string.cache_coordinates_no));
+
+ return;
+ }
+
+ cgeonavigate navigateActivity = new cgeonavigate();
+
+ Intent navigateIntent = new Intent(activity, navigateActivity.getClass());
+ navigateIntent.putExtra("latitude", cache.latitude);
+ navigateIntent.putExtra("longitude", cache.longitude);
+ navigateIntent.putExtra("geocode", cache.geocode.toUpperCase());
+ navigateIntent.putExtra("name", cache.name);
+
+ activity.startActivity(navigateIntent);
+
+ finish();
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-cache-info",
+ activity,
+ "http://cgeo.carnero.cc/manual/"
+ );
+ } catch (Exception e) {
+ // nothing
+ }
+
+ finish();
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgeosmaps.java b/src/cgeo/geocaching/cgeosmaps.java
new file mode 100644
index 0000000..9979ab5
--- /dev/null
+++ b/src/cgeo/geocaching/cgeosmaps.java
@@ -0,0 +1,172 @@
+package cgeo.geocaching;
+
+import java.util.ArrayList;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+
+public class cgeosmaps extends Activity {
+
+ private ArrayList<Bitmap> maps = new ArrayList<Bitmap>();
+ private String geocode = null;
+ private Resources res = null;
+ private cgeoapplication app = null;
+ private Activity activity = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private LayoutInflater inflater = null;
+ private ProgressDialog waitDialog = null;
+ private LinearLayout smapsView = null;
+ private BitmapFactory factory = null;
+ private Handler loadMapsHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (maps == null || maps.isEmpty()) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ warning.showToast(res.getString(R.string.err_detail_not_load_map_static));
+
+ finish();
+ return;
+ } else {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ if (inflater == null) {
+ inflater = activity.getLayoutInflater();
+ }
+
+ if (smapsView == null) {
+ smapsView = (LinearLayout) findViewById(R.id.maps_list);
+ }
+ smapsView.removeAllViews();
+
+ int cnt = 1;
+ for (Bitmap image : maps) {
+ if (image != null) {
+ final ImageView map = (ImageView) inflater.inflate(R.layout.map_static_item, null);
+ map.setImageBitmap(image);
+ smapsView.addView(map);
+
+ cnt++;
+ }
+ }
+ }
+ } catch (Exception e) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ Log.e(cgSettings.tag, "cgeosmaps.loadMapsHandler: " + e.toString());
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.map_static);
+ base.setTitle(activity, res.getString(R.string.map_static_title));
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+
+ // try to get data from extras
+ if (extras != null) {
+ geocode = extras.getString("geocode");
+ }
+
+ if (geocode == null) {
+ warning.showToast("Sorry, c:geo forgot for what cache you want to load static maps.");
+ finish();
+ return;
+ }
+
+ waitDialog = ProgressDialog.show(this, null, res.getString(R.string.map_static_loading), true);
+ waitDialog.setCancelable(true);
+
+ (new loadMaps()).start();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ private class loadMaps extends Thread {
+
+ @Override
+ public void run() {
+ try {
+ if (factory == null) {
+ factory = new BitmapFactory();
+ }
+
+ for (int level = 1; level <= 5; level++) {
+ try {
+ Bitmap image = BitmapFactory.decodeFile(settings.getStorage() + geocode + "/map_" + level);
+ if (image != null) {
+ maps.add(image);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeosmaps.loadMaps.run.1: " + e.toString());
+ }
+ }
+
+ if (maps.isEmpty() == true) {
+ for (int level = 1; level <= 5; level++) {
+ try {
+ Bitmap image = BitmapFactory.decodeFile(settings.getStorageSec() + geocode + "/map_" + level);
+ if (image != null) {
+ maps.add(image);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeosmaps.loadMaps.run.2: " + e.toString());
+ }
+ }
+ }
+
+ loadMapsHandler.sendMessage(new Message());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeosmaps.loadMaps.run: " + e.toString());
+ }
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgeospoilers.java b/src/cgeo/geocaching/cgeospoilers.java
new file mode 100644
index 0000000..4d2bd58
--- /dev/null
+++ b/src/cgeo/geocaching/cgeospoilers.java
@@ -0,0 +1,231 @@
+package cgeo.geocaching;
+
+import java.util.ArrayList;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.net.Uri;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.util.Log;
+import android.text.Html;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.LinearLayout;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.view.ViewGroup.LayoutParams;
+
+public class cgeospoilers extends Activity {
+ private ArrayList<cgSpoiler> spoilers = new ArrayList<cgSpoiler>();
+ private Resources res = null;
+ private String geocode = null;
+ private cgeoapplication app = null;
+ private Activity activity = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private LayoutInflater inflater = null;
+ private ProgressDialog progressDialog = null;
+ private ProgressDialog waitDialog = null;
+ private LinearLayout spoilerView = null;
+ private int offline = 0;
+ private int count = 0;
+ private int countDone = 0;
+ private Handler loadSpoilersHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (spoilers.isEmpty()) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ warning.showToast("Sorry, c:geo failed to load spoiler images.");
+
+ finish();
+ return;
+ } else {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ if (app.isOffline(geocode, null) == true) {
+ offline = 1;
+ } else {
+ offline = 0;
+ }
+
+ count = spoilers.size();
+ progressDialog = new ProgressDialog(activity);
+ progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ progressDialog.setMessage(res.getString(R.string.cache_spoiler_images_loading));
+ progressDialog.setCancelable(true);
+ progressDialog.setMax(count);
+ progressDialog.show();
+
+ LinearLayout rowView = null;
+ for (final cgSpoiler spl : spoilers) {
+ rowView = (LinearLayout) inflater.inflate(R.layout.spoiler_item, null);
+
+ ((TextView) rowView.findViewById(R.id.title)).setText(Html.fromHtml(spl.title));
+
+ if (spl.description != null && spl.description.length() > 0) {
+ final TextView descView = (TextView) rowView.findViewById(R.id.description);
+ descView.setText(Html.fromHtml(spl.description), TextView.BufferType.SPANNABLE);
+ descView.setVisibility(View.VISIBLE);
+ }
+
+ final Handler handler = new onLoadHandler(rowView, spl);
+
+ new Thread() {
+
+ @Override
+ public void run() {
+ BitmapDrawable image = null;
+ try {
+ cgHtmlImg imgGetter = new cgHtmlImg(activity, settings, geocode, true, offline, false);
+
+ image = imgGetter.getDrawable(spl.url);
+ Message message = handler.obtainMessage(0, image);
+ handler.sendMessage(message);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeospoilers.onCreate.onClick.run: " + e.toString());
+ }
+
+ }
+ }.start();
+
+ spoilerView.addView(rowView);
+ }
+ }
+ } catch (Exception e) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ Log.e(cgSettings.tag, "cgeospoilers.loadSpoilersHandler: " + e.toString());
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.spoilers);
+ base.setTitle(activity, res.getString(R.string.cache_spoiler_images_title));
+
+ // google analytics
+ base.sendAnal(activity, "/spoilers");
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+
+ // try to get data from extras
+ if (extras != null) {
+ geocode = extras.getString("geocode");
+ }
+
+ if (geocode == null) {
+ warning.showToast("Sorry, c:geo forgot for what cache you want to load spoiler images.");
+ finish();
+ return;
+ }
+
+ inflater = activity.getLayoutInflater();
+ if (spoilerView == null) {
+ spoilerView = (LinearLayout) findViewById(R.id.spoiler_list);
+ }
+
+ waitDialog = ProgressDialog.show(this, null, res.getString(R.string.cache_spoiler_images_loading), true);
+ waitDialog.setCancelable(true);
+
+ (new loadSpoilers()).start();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ private class loadSpoilers extends Thread {
+
+ @Override
+ public void run() {
+ try {
+ spoilers = app.loadSpoilers(geocode);
+
+ loadSpoilersHandler.sendMessage(new Message());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeospoilers.loadSpoilers.run: " + e.toString());
+ }
+ }
+ }
+
+ private class onLoadHandler extends Handler {
+
+ LinearLayout view = null;
+ cgSpoiler spoiler = null;
+
+ public onLoadHandler(LinearLayout view, cgSpoiler spoiler) {
+ this.view = view;
+ this.spoiler = spoiler;
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ BitmapDrawable image = (BitmapDrawable) message.obj;
+ if (image != null) {
+ ImageView spoilerImage = null;
+ spoilerImage = (ImageView) inflater.inflate(R.layout.image_item, null);
+
+ Rect bounds = image.getBounds();
+
+ spoilerImage.setImageResource(R.drawable.image_not_loaded);
+ spoilerImage.setClickable(true);
+ spoilerImage.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View arg0) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(spoiler.url)));
+ }
+ });
+ spoilerImage.setImageDrawable((BitmapDrawable) message.obj);
+ spoilerImage.setScaleType(ImageView.ScaleType.CENTER_CROP);
+ spoilerImage.setLayoutParams(new LayoutParams(bounds.width(), bounds.height()));
+
+ view.addView(spoilerImage);
+ }
+
+ countDone++;
+ progressDialog.setProgress(countDone);
+ if (progressDialog.getProgress() >= count) {
+ progressDialog.dismiss();
+ }
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+}
diff --git a/src/cgeo/geocaching/cgeotouch.java b/src/cgeo/geocaching/cgeotouch.java
new file mode 100644
index 0000000..07f83d5
--- /dev/null
+++ b/src/cgeo/geocaching/cgeotouch.java
@@ -0,0 +1,487 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.view.View;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+public class cgeotouch extends cgLogForm {
+ private cgeoapplication app = null;
+ private Activity activity = null;
+ private Resources res = null;
+ private LayoutInflater inflater = null;
+ private cgBase base = null;
+ private cgSettings settings = null;
+ private cgWarning warning = null;
+ private cgTrackable trackable = null;
+ private ArrayList<Integer> types = new ArrayList<Integer>();
+ private ProgressDialog waitDialog = null;
+ private String guid = null;
+ private String geocode = null;
+ private String text = null;
+ private String viewstate = null;
+ private String viewstate1 = null;
+ private Boolean gettingViewstate = true;
+ private Calendar date = Calendar.getInstance();
+ private int typeSelected = -1;
+ private int attempts = 0;
+ private CheckBox tweetCheck = null;
+ private LinearLayout tweetBox = null;
+
+ private Handler showProgressHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ base.showProgress(activity, true);
+ }
+ };
+
+ private Handler loadDataHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if ((viewstate == null || viewstate.length() == 0) && attempts < 2) {
+ warning.showToast(res.getString(R.string.err_log_load_data_again));
+
+ loadData thread;
+ thread = new loadData(guid);
+ thread.start();
+
+ return;
+ } else if ((viewstate == null || viewstate.length() == 0) && attempts >= 2) {
+ warning.showToast(res.getString(R.string.err_log_load_data));
+ base.showProgress(activity, false);
+
+ return;
+ }
+
+ gettingViewstate = false; // we're done, user can post log
+
+ Button buttonPost = (Button)findViewById(R.id.post);
+ buttonPost.setEnabled(true);
+ buttonPost.setOnClickListener(new postListener());
+
+ base.showProgress(activity, false);
+ }
+ };
+
+ private Handler postLogHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == 1) {
+ warning.showToast(res.getString(R.string.info_log_posted));
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ finish();
+ return;
+ } else if (msg.what >= 1000) {
+ if (msg.what == 1001) {
+ warning.showToast(res.getString(R.string.warn_log_text_fill));
+ } else if(msg.what == 1002) {
+ warning.showToast(res.getString(R.string.err_log_failed_server));
+ } else {
+ warning.showToast(res.getString(R.string.err_log_post_failed));
+ }
+ } else {
+ if (cgBase.errorRetrieve.get(msg.what) != null) {
+ warning.showToast(res.getString(R.string.err_log_post_failed_because) + cgBase.errorRetrieve.get(msg.what) + ".");
+ } else {
+ warning.showToast(res.getString(R.string.err_log_post_failed));
+ }
+ }
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication)this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.touch);
+ base.setTitle(activity, res.getString(R.string.trackable_touch));
+
+ // google analytics
+ base.sendAnal(activity, "/trackable/touch");
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ geocode = extras.getString("geocode");
+ guid = extras.getString("guid");
+ text = extras.getString("text");
+ }
+
+ trackable = app.getTrackableByGeocode("logging trackable");
+
+ if (trackable.name != null && trackable.name.length() > 0) {
+ base.setTitle(activity, res.getString(R.string.trackable_touch) + trackable.name);
+ } else {
+ base.setTitle(activity, res.getString(R.string.trackable_touch) + trackable.geocode.toUpperCase());
+ }
+
+ app.setAction("logging trackable");
+
+ if (trackable == null || guid == null) {
+ warning.showToast(res.getString(R.string.err_tb_forgot_saw));
+
+ finish();
+ return;
+ }
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ init();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ SubMenu subMenu = menu.addSubMenu(0, 0, 0, res.getString(R.string.log_add)).setIcon(android.R.drawable.ic_menu_add);
+
+ subMenu.add(0, 0x6, 0, res.getString(R.string.log_date_time));
+ subMenu.add(0, 0x4, 0, res.getString(R.string.log_date));
+ subMenu.add(0, 0x2, 0, res.getString(R.string.log_time));
+ subMenu.add(0, 0x1, 0, res.getString(R.string.init_signature));
+ subMenu.add(0, 0x7, 0, res.getString(R.string.log_date_time) + " & " + res.getString(R.string.init_signature));
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ if (settings.getSignature() == null) {
+ menu.findItem(0x1).setVisible(false);
+ menu.findItem(0x7).setVisible(false);
+ } else {
+ menu.findItem(0x1).setVisible(true);
+ menu.findItem(0x7).setVisible(true);
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int id = item.getItemId();
+
+ EditText text = null;
+ String textContent = null;
+ String dateString = null;
+ String timeString = null;
+ String addText = "";
+
+ if ((id >= 0x1 && id <= 0x7)) {
+ text = (EditText) findViewById(R.id.log);
+ textContent = text.getText().toString();
+ dateString = cgBase.dateOut.format(new Date());
+ timeString = cgBase.timeOut.format(new Date());
+
+ if ((id & 0x4) == 0x4) {
+ addText += dateString;
+ if ((id & 0x2) == 0x2) {
+ addText += " | ";
+ }
+ }
+ if ((id & 0x2) == 0x2) {
+ addText += timeString;
+ }
+ if ((id & 0x1) == 0x1 && settings.getSignature() != null) {
+ if (addText.length() > 0) {
+ addText += "\n";
+ }
+ addText += settings.getSignature()
+ .replaceAll("\\[DATE\\]", dateString)
+ .replaceAll("\\[TIME\\]", timeString)
+ .replaceAll("\\[USER\\]", settings.getUsername())
+ .replaceAll("\\[NUMBER\\]", "");
+ }
+ if (textContent.length() > 0 && addText.length() > 0 ) {
+ addText = "\n" + addText;
+ }
+ text.setText(textContent + addText, TextView.BufferType.NORMAL);
+ text.setSelection(text.getText().toString().length());
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info) {
+ super.onCreateContextMenu(menu, view, info);
+ final int viewId = view.getId();
+
+ if (viewId == R.id.type) {
+ for (final int typeOne : types) menu.add(viewId, typeOne, 0, cgBase.logTypes2.get(typeOne));
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ final int group = item.getGroupId();
+ final int id = item.getItemId();
+
+ if (group == R.id.type) {
+ setType(id);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public void init() {
+ if (geocode != null) app.setAction("logging trackable");
+
+ types.clear();
+ types.add(cgBase.LOG_RETRIEVED_IT);
+ types.add(cgBase.LOG_GRABBED_IT);
+ types.add(cgBase.LOG_NOTE);
+ types.add(cgBase.LOG_DISCOVERED_IT);
+
+ if (typeSelected < 0 && cgBase.logTypes2.get(typeSelected) == null) typeSelected = types.get(2);
+ setType(typeSelected);
+
+ Button typeButton = (Button)findViewById(R.id.type);
+ registerForContextMenu(typeButton);
+ typeButton.setText(cgBase.logTypes2.get(typeSelected));
+ typeButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View view) {
+ openContextMenu(view);
+ }
+ });
+
+ Button dateButton = (Button)findViewById(R.id.date);
+ dateButton.setText(cgBase.dateOutShort.format(date.getTime()));
+ dateButton.setOnClickListener(new cgeotouchDateListener());
+
+ if (tweetBox == null) tweetBox = (LinearLayout)findViewById(R.id.tweet_box);
+ if (tweetCheck == null) tweetCheck = (CheckBox)findViewById(R.id.tweet);
+ tweetCheck.setChecked(true);
+
+ Button buttonPost = (Button)findViewById(R.id.post);
+ if (viewstate == null || viewstate.length() == 0) {
+ buttonPost.setEnabled(false);
+ buttonPost.setOnTouchListener(null);
+ buttonPost.setOnClickListener(null);
+
+ loadData thread;
+ thread = new loadData(guid);
+ thread.start();
+ } else {
+ buttonPost.setEnabled(true);
+ buttonPost.setOnClickListener(new postListener());
+ }
+ }
+
+ public void setDate(Calendar dateIn) {
+ date = dateIn;
+
+ final Button dateButton = (Button)findViewById(R.id.date);
+ dateButton.setText(cgBase.dateOutShort.format(date.getTime()));
+ }
+
+ public void setType(int type) {
+ final Button typeButton = (Button)findViewById(R.id.type);
+
+ if (cgBase.logTypes2.get(type) != null) typeSelected = type;
+ if (cgBase.logTypes2.get(typeSelected) == null) typeSelected = 0;
+ typeButton.setText(cgBase.logTypes2.get(typeSelected));
+
+ if (tweetBox == null) tweetBox = (LinearLayout)findViewById(R.id.tweet_box);
+ if (settings.twitter == 1) tweetBox.setVisibility(View.VISIBLE);
+ else tweetBox.setVisibility(View.GONE);
+ }
+
+ private class cgeotouchDateListener implements View.OnClickListener {
+ public void onClick(View arg0) {
+ Dialog dateDialog = new cgeodate(activity, (cgeotouch)activity, date);
+ dateDialog.setCancelable(true);
+ dateDialog.show();
+ }
+ }
+
+ private class postListener implements View.OnClickListener {
+ public void onClick(View arg0) {
+ if (gettingViewstate == false) {
+ waitDialog = ProgressDialog.show(activity, null, res.getString(R.string.log_saving), true);
+ waitDialog.setCancelable(true);
+
+ String tracking = ((EditText)findViewById(R.id.tracking)).getText().toString();
+ String log = ((EditText)findViewById(R.id.log)).getText().toString();
+ Thread thread = new postLog(postLogHandler, tracking, log);
+ thread.start();
+ } else {
+ warning.showToast(res.getString(R.string.err_log_load_data_still));
+ }
+ }
+ }
+
+ private class loadData extends Thread {
+ private String guid = null;
+
+ public loadData(String guidIn) {
+ guid = guidIn;
+
+ if (guid == null) {
+ warning.showToast(res.getString(R.string.err_tb_forgot_saw));
+
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public void run() {
+ final HashMap<String, String> params = new HashMap<String, String>();
+
+ showProgressHandler.sendEmptyMessage(0);
+ gettingViewstate = true;
+ attempts ++;
+
+ try {
+ if (guid != null && guid.length() > 0) {
+ params.put("wid", guid);
+ } else {
+ loadDataHandler.sendEmptyMessage(0);
+ return;
+ }
+
+ final String page = base.request(false, "www.geocaching.com", "/track/log.aspx", "GET", params, false, false, false).getData();
+
+ viewstate = base.findViewstate(page, 0);
+ viewstate1 = base.findViewstate(page, 1);
+
+ final ArrayList<Integer> typesPre = base.parseTypes(page);
+ if (typesPre.size() > 0) {
+ types.clear();
+ types.addAll(typesPre);
+ }
+ typesPre.clear();
+
+ if (types.contains(typeSelected) == false) {
+ typeSelected = types.get(0);
+ setType(typeSelected);
+ warning.showToast(res.getString(R.string.info_log_type_changed));
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeotouch.loadData.run: " + e.toString());
+ }
+
+ loadDataHandler.sendEmptyMessage(0);
+ }
+ }
+
+ private class postLog extends Thread {
+ Handler handler = null;
+ String tracking = null;
+ String log = null;
+
+ public postLog(Handler handlerIn, String trackingIn, String logIn) {
+ handler = handlerIn;
+ tracking = trackingIn;
+ log = logIn;
+ }
+
+ @Override
+ public void run() {
+ int ret = -1;
+
+ ret = postLogFn(tracking, log);
+
+ handler.sendEmptyMessage(ret);
+ }
+ }
+
+ public int postLogFn(String tracking, String log) {
+ int status = -1;
+
+ try {
+ if (tweetBox == null) tweetBox = (LinearLayout)findViewById(R.id.tweet_box);
+ if (tweetCheck == null) tweetCheck = (CheckBox)findViewById(R.id.tweet);
+
+ status = base.postLogTrackable(guid, tracking, viewstate, viewstate1, typeSelected, date.get(Calendar.YEAR), (date.get(Calendar.MONTH ) + 1), date.get(Calendar.DATE), log);
+
+ if (
+ status == 1 && settings.twitter == 1 &&
+ settings.tokenPublic != null && settings.tokenPublic.length() > 0 && settings.tokenSecret != null && settings.tokenSecret.length() > 0 &&
+ tweetCheck.isChecked() == true && tweetBox.getVisibility() == View.VISIBLE
+ ) {
+ base.postTweetTrackable(app, settings, geocode);
+ }
+
+ return status;
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeotouch.postLogFn: " + e.toString());
+ }
+
+ return 1000;
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-log-trackable",
+ activity,
+ "http://cgeo.carnero.cc/manual/"
+ );
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgeotrackable.java b/src/cgeo/geocaching/cgeotrackable.java
new file mode 100644
index 0000000..98b8cbc
--- /dev/null
+++ b/src/cgeo/geocaching/cgeotrackable.java
@@ -0,0 +1,671 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import java.net.URLEncoder;
+import java.util.Date;
+import java.util.HashMap;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Bundle;
+import android.util.Log;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.text.Html;
+import android.text.method.LinkMovementMethod;
+import android.view.ContextMenu;
+import android.view.View;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.LayoutInflater;
+import android.widget.ScrollView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.widget.ImageView;
+
+public class cgeotrackable extends Activity {
+ public cgTrackable trackable = null;
+ public String geocode = null;
+ public String name = null;
+ public String guid = null;
+ public String id = null;
+ private String contextMenuUser = null;
+ private Resources res = null;
+ private cgeoapplication app = null;
+ private Activity activity = null;
+ private LayoutInflater inflater = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private ProgressDialog waitDialog = null;
+ private Handler loadTrackableHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ RelativeLayout itemLayout;
+ TextView itemName;
+ TextView itemValue;
+
+ if (trackable != null && trackable.errorRetrieve != 0) {
+ warning.showToast(res.getString(R.string.err_tb_details_download) + " " + cgBase.errorRetrieve.get(trackable.errorRetrieve) + ".");
+
+ finish();
+ return;
+ }
+
+ if (trackable != null && trackable.error.length() > 0) {
+ warning.showToast(res.getString(R.string.err_tb_details_download) + " " + trackable.error + ".");
+
+ finish();
+ return;
+ }
+
+ if (trackable == null) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ if (geocode != null && geocode.length() > 0) {
+ warning.showToast(res.getString(R.string.err_tb_find) + " " + geocode + ".");
+ } else {
+ warning.showToast(res.getString(R.string.err_tb_find_that));
+ }
+
+ finish();
+ return;
+ }
+
+ try {
+ inflater = activity.getLayoutInflater();
+ geocode = trackable.geocode.toUpperCase();
+
+ if (trackable.name != null && trackable.name.length() > 0) {
+ base.setTitle(activity, Html.fromHtml(trackable.name).toString());
+ } else {
+ base.setTitle(activity, trackable.name.toUpperCase());
+ }
+
+ ((ScrollView) findViewById(R.id.details_list_box)).setVisibility(View.VISIBLE);
+ LinearLayout detailsList = (LinearLayout) findViewById(R.id.details_list);
+
+ // actiobar icon
+ if (trackable.iconUrl != null && trackable.iconUrl.length() > 0) {
+ final tbIconHandler iconHandler = new tbIconHandler(((TextView) findViewById(R.id.actionbar_title)));
+ final tbIconThread iconThread = new tbIconThread(trackable.iconUrl, iconHandler);
+ iconThread.start();
+ }
+
+ // trackable name
+ itemLayout = (RelativeLayout)inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.trackable_name));
+ if (trackable.name != null) {
+ itemValue.setText(Html.fromHtml(trackable.name).toString());
+ } else {
+ itemValue.setText(res.getString(R.string.trackable_unknown));
+ }
+ detailsList.addView(itemLayout);
+
+ // trackable type
+ itemLayout = (RelativeLayout)inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ String tbType = null;
+ if (trackable.type != null && trackable.type.length() > 0) {
+ tbType = Html.fromHtml(trackable.type).toString();
+ } else {
+ tbType = res.getString(R.string.trackable_unknown);
+ }
+ itemName.setText(res.getString(R.string.trackable_type));
+ itemValue.setText(tbType);
+ detailsList.addView(itemLayout);
+
+ // trackable geocode
+ itemLayout = (RelativeLayout)inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.trackable_code));
+ itemValue.setText(trackable.geocode.toUpperCase());
+ detailsList.addView(itemLayout);
+
+ // trackable owner
+ itemLayout = (RelativeLayout)inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.trackable_owner));
+ if (trackable.owner != null) {
+ itemValue.setText(Html.fromHtml(trackable.owner), TextView.BufferType.SPANNABLE);
+ itemLayout.setOnClickListener(new userActions());
+ } else {
+ itemValue.setText(res.getString(R.string.trackable_unknown));
+ }
+ detailsList.addView(itemLayout);
+
+ // trackable spotted
+ if (
+ (trackable.spottedName != null && trackable.spottedName.length() > 0) ||
+ trackable.spottedType == cgTrackable.SPOTTED_UNKNOWN ||
+ trackable.spottedType == cgTrackable.SPOTTED_OWNER
+ ) {
+ itemLayout = (RelativeLayout)inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.trackable_spotted));
+ String text = null;
+
+ if (trackable.spottedType == cgTrackable.SPOTTED_CACHE) {
+ text = res.getString(R.string.trackable_spotted_in_cache) + " " + Html.fromHtml(trackable.spottedName).toString();
+ } else if (trackable.spottedType == cgTrackable.SPOTTED_USER) {
+ text = res.getString(R.string.trackable_spotted_at_user) + " " + Html.fromHtml(trackable.spottedName).toString();
+ } else if (trackable.spottedType == cgTrackable.SPOTTED_UNKNOWN) {
+ text = res.getString(R.string.trackable_spotted_unknown_location);
+ } else if (trackable.spottedType == cgTrackable.SPOTTED_OWNER) {
+ text = res.getString(R.string.trackable_spotted_owner);
+ } else {
+ text = "N/A";
+ }
+
+ itemValue.setText(text);
+ itemLayout.setClickable(true);
+ if (cgTrackable.SPOTTED_CACHE == trackable.spottedType) {
+ itemLayout.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View arg0) {
+ Intent cacheIntent = new Intent(activity, cgeodetail.class);
+ cacheIntent.putExtra("guid", (String) trackable.spottedGuid);
+ cacheIntent.putExtra("name", (String) trackable.spottedName);
+ activity.startActivity(cacheIntent);
+ }
+ });
+ } else if (cgTrackable.SPOTTED_USER == trackable.spottedType) {
+ itemLayout.setOnClickListener(new userActions());
+ //activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?guid=" + trackable.spottedGuid)));
+ }
+
+ detailsList.addView(itemLayout);
+ }
+
+ // trackable origin
+ if (trackable.origin != null && trackable.origin.length() > 0) {
+ itemLayout = (RelativeLayout)inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.trackable_origin));
+ itemValue.setText(Html.fromHtml(trackable.origin), TextView.BufferType.SPANNABLE);
+ detailsList.addView(itemLayout);
+ }
+
+ // trackable released
+ if (trackable.released != null) {
+ itemLayout = (RelativeLayout)inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.trackable_released));
+ itemValue.setText(cgBase.dateOut.format(trackable.released));
+ detailsList.addView(itemLayout);
+ }
+
+ // trackable distance
+ if (trackable.distance != null) {
+ itemLayout = (RelativeLayout)inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.trackable_distance));
+ itemValue.setText(base.getHumanDistance(trackable.distance));
+ detailsList.addView(itemLayout);
+ }
+
+
+ // trackable goal
+ if (trackable.goal != null && trackable.goal.length() > 0) {
+ ((LinearLayout) findViewById(R.id.goal_box)).setVisibility(View.VISIBLE);
+ TextView descView = (TextView) findViewById(R.id.goal);
+ descView.setVisibility(View.VISIBLE);
+ descView.setText(Html.fromHtml(trackable.goal, new cgHtmlImg(activity, settings, geocode, true, 0, false), null), TextView.BufferType.SPANNABLE);
+ descView.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+
+ // trackable details
+ if (trackable.details != null && trackable.details.length() > 0) {
+ ((LinearLayout) findViewById(R.id.details_box)).setVisibility(View.VISIBLE);
+ TextView descView = (TextView) findViewById(R.id.details);
+ descView.setVisibility(View.VISIBLE);
+ descView.setText(Html.fromHtml(trackable.details, new cgHtmlImg(activity, settings, geocode, true, 0, false), null), TextView.BufferType.SPANNABLE);
+ descView.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+
+ // trackable image
+ if (trackable.image != null && trackable.image.length() > 0) {
+ ((LinearLayout) findViewById(R.id.image_box)).setVisibility(View.VISIBLE);
+ LinearLayout imgView = (LinearLayout) findViewById(R.id.image);
+
+ final ImageView trackableImage = (ImageView) inflater.inflate(R.layout.trackable_image, null);
+
+ trackableImage.setImageResource(R.drawable.image_not_loaded);
+ trackableImage.setClickable(true);
+ trackableImage.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View arg0) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(trackable.image)));
+ }
+ });
+
+ // try to load image
+ final Handler handler = new Handler() {
+
+ @Override
+ public void handleMessage(Message message) {
+ BitmapDrawable image = (BitmapDrawable) message.obj;
+ if (image != null) {
+ trackableImage.setImageDrawable((BitmapDrawable) message.obj);
+ }
+ }
+ };
+
+ new Thread() {
+
+ @Override
+ public void run() {
+ BitmapDrawable image = null;
+ try {
+ cgHtmlImg imgGetter = new cgHtmlImg(activity, settings, geocode, true, 0, false);
+
+ image = imgGetter.getDrawable(trackable.image);
+ Message message = handler.obtainMessage(0, image);
+ handler.sendMessage(message);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeospoilers.onCreate.onClick.run: " + e.toString());
+ }
+ }
+ }.start();
+
+ imgView.addView(trackableImage);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeotrackable.loadTrackableHandler: " + e.toString() + e.getStackTrace());
+ }
+
+ displayLogs();
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.trackable_detail);
+ base.setTitle(activity, res.getString(R.string.trackable));
+
+ // google analytics
+ base.sendAnal(activity, "/trackable/detail");
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+ Uri uri = getIntent().getData();
+
+ // try to get data from extras
+ if (extras != null) {
+ geocode = extras.getString("geocode");
+ name = extras.getString("name");
+ guid = extras.getString("guid");
+ id = extras.getString("id");
+ }
+
+ // try to get data from URI
+ if (geocode == null && guid == null && id == null && uri != null) {
+ String uriHost = uri.getHost().toLowerCase();
+ if (uriHost.contains("geocaching.com") == true) {
+ geocode = uri.getQueryParameter("tracker");
+ guid = uri.getQueryParameter("guid");
+ id = uri.getQueryParameter("id");
+
+ if (geocode != null && geocode.length() > 0) {
+ geocode = geocode.toUpperCase();
+ guid = null;
+ id = null;
+ } else if (guid != null && guid.length() > 0) {
+ geocode = null;
+ guid = guid.toLowerCase();
+ id = null;
+ } else if (id != null && id.length() > 0) {
+ geocode = null;
+ guid = null;
+ id = id.toLowerCase();
+ } else {
+ warning.showToast(res.getString(R.string.err_tb_details_open));
+ finish();
+ return;
+ }
+ } else if (uriHost.contains("coord.info") == true) {
+ String uriPath = uri.getPath().toLowerCase();
+ if (uriPath != null && uriPath.startsWith("/tb") == true) {
+ geocode = uriPath.substring(1).toUpperCase();
+ guid = null;
+ id = null;
+ } else {
+ warning.showToast(res.getString(R.string.err_tb_details_open));
+ finish();
+ return;
+ }
+ }
+ }
+
+ // no given data
+ if (geocode == null && guid == null && id == null) {
+ warning.showToast(res.getString(R.string.err_tb_display));
+ finish();
+ return;
+ }
+
+ if (name != null && name.length() > 0) {
+ waitDialog = ProgressDialog.show(this, Html.fromHtml(name).toString(), res.getString(R.string.trackable_details_loading), true);
+ } else if (geocode != null && geocode.length() > 0) {
+ waitDialog = ProgressDialog.show(this, geocode.toUpperCase(), res.getString(R.string.trackable_details_loading), true);
+ } else {
+ waitDialog = ProgressDialog.show(this, res.getString(R.string.trackable), res.getString(R.string.trackable_details_loading), true);
+ }
+ waitDialog.setCancelable(true);
+
+ loadTrackable thread;
+ thread = new loadTrackable(loadTrackableHandler, geocode, guid, id);
+ thread.start();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info) {
+ super.onCreateContextMenu(menu, view, info);
+ final int viewId = view.getId();
+
+ if (viewId == R.id.author) { // Log item author
+ contextMenuUser = ((TextView)view).getText().toString();
+ } else { // Trackable owner, and user holding trackable now
+ RelativeLayout itemLayout = (RelativeLayout)view;
+ TextView itemName = (TextView) itemLayout.findViewById(R.id.name);
+
+ String selectedName = itemName.getText().toString();
+ if (selectedName.equals(res.getString(R.string.trackable_owner))) {
+ contextMenuUser = trackable.owner;
+ } else if (selectedName.equals(res.getString(R.string.trackable_spotted))) {
+ contextMenuUser = trackable.spottedName;
+ }
+ }
+
+ menu.setHeaderTitle(res.getString(R.string.user_menu_title) + " " + contextMenuUser);
+ menu.add(viewId, 1, 0, res.getString(R.string.user_menu_view_hidden));
+ menu.add(viewId, 2, 0, res.getString(R.string.user_menu_view_found));
+ menu.add(viewId, 3, 0, res.getString(R.string.user_menu_open_browser));
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ final int id = item.getItemId();
+
+ if (id == 1) {
+ final Intent cachesIntent = new Intent(activity, cgeocaches.class);
+
+ cachesIntent.putExtra("type", "owner");
+ cachesIntent.putExtra("username", contextMenuUser);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+
+ activity.startActivity(cachesIntent);
+
+ return true;
+ } else if (id == 2) {
+ final Intent cachesIntent = new Intent(activity, cgeocaches.class);
+
+ cachesIntent.putExtra("type", "username");
+ cachesIntent.putExtra("username", contextMenuUser);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+
+ activity.startActivity(cachesIntent);
+
+ return true;
+ } else if (id == 3) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?u=" + URLEncoder.encode(contextMenuUser))));
+
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(0, 1, 0, res.getString(R.string.trackable_log_touch)).setIcon(android.R.drawable.ic_menu_agenda); // log touch
+
+ menu.add(0, 2, 0, res.getString(R.string.trackable_browser_open)).setIcon(android.R.drawable.ic_menu_info_details); // browser
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case 1:
+ logTouch();
+ return true;
+ case 2:
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/track/details.aspx?tracker=" + trackable.geocode)));
+ return true;
+ }
+
+ return false;
+ }
+
+ private class loadTrackable extends Thread {
+
+ private Handler handler = null;
+ private String geocode = null;
+ private String guid = null;
+ private String id = null;
+
+ public loadTrackable(Handler handlerIn, String geocodeIn, String guidIn, String idIn) {
+ handler = handlerIn;
+ geocode = geocodeIn;
+ guid = guidIn;
+ id = idIn;
+
+ if (geocode == null && guid == null && id == null) {
+ warning.showToast(res.getString(R.string.err_tb_forgot));
+
+ stop();
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public void run() {
+ loadTrackableFn(geocode, guid, id);
+ handler.sendMessage(new Message());
+ }
+ }
+
+ public void loadTrackableFn(String geocode, String guid, String id) {
+ HashMap<String, String> params = new HashMap<String, String>();
+ if (geocode != null && geocode.length() > 0) {
+ params.put("geocode", geocode);
+ } else if (guid != null && guid.length() > 0) {
+ params.put("guid", guid);
+ } else if (id != null && id.length() > 0) {
+ params.put("id", id);
+ } else {
+ return;
+ }
+
+ trackable = base.searchTrackable(params);
+ }
+
+ private void displayLogs() {
+ // trackable logs
+ LinearLayout listView = (LinearLayout) findViewById(R.id.log_list);
+ listView.removeAllViews();
+
+ RelativeLayout rowView;
+
+ if (trackable != null && trackable.logs != null) {
+ for (cgLog log : trackable.logs) {
+ rowView = (RelativeLayout) inflater.inflate(R.layout.trackable_logitem, null);
+
+ if (log.date > 0) {
+ final Date logDate = new Date(log.date);
+ ((TextView) rowView.findViewById(R.id.added)).setText(cgBase.dateOutShort.format(logDate));
+ }
+
+
+ if (cgBase.logTypes1.containsKey(log.type) == true) {
+ ((TextView) rowView.findViewById(R.id.type)).setText(cgBase.logTypes1.get(log.type));
+ } else {
+ ((TextView) rowView.findViewById(R.id.type)).setText(cgBase.logTypes1.get(4)); // note if type is unknown
+ }
+ ((TextView) rowView.findViewById(R.id.author)).setText(Html.fromHtml(log.author), TextView.BufferType.SPANNABLE);
+
+ if (log.cacheName == null || log.cacheName.length() == 0) {
+ ((TextView) rowView.findViewById(R.id.location)).setVisibility(View.GONE);
+ } else {
+ ((TextView) rowView.findViewById(R.id.location)).setText(Html.fromHtml(log.cacheName));
+ final String cacheGuid = log.cacheGuid;
+ final String cacheName = log.cacheName;
+ ((TextView) rowView.findViewById(R.id.location)).setOnClickListener(new View.OnClickListener() {
+ public void onClick(View arg0) {
+ Intent cacheIntent = new Intent(activity, cgeodetail.class);
+ cacheIntent.putExtra("guid", (String) cacheGuid);
+ cacheIntent.putExtra("name", (String) Html.fromHtml(cacheName).toString());
+ activity.startActivity(cacheIntent);
+ }
+ });
+ }
+
+ ((TextView) rowView.findViewById(R.id.log)).setText(Html.fromHtml(log.log, new cgHtmlImg(activity, settings, null, false, 0, false), null), TextView.BufferType.SPANNABLE);
+
+ ((TextView) rowView.findViewById(R.id.author)).setOnClickListener(new userActions());
+ listView.addView(rowView);
+ }
+
+ if (trackable.logs.size() > 0) {
+ ((LinearLayout) findViewById(R.id.log_box)).setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
+ private class userActions implements View.OnClickListener {
+
+ public void onClick(View view) {
+ if (view == null) {
+ return;
+ }
+
+ try {
+ registerForContextMenu(view);
+ openContextMenu(view);
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ }
+
+ private void logTouch() {
+ Intent logTouchIntent = new Intent(activity, cgeotouch.class);
+ logTouchIntent.putExtra("geocode", trackable.geocode.toUpperCase());
+ logTouchIntent.putExtra("guid", trackable.guid);
+ activity.startActivity(logTouchIntent);
+ }
+
+ private class tbIconThread extends Thread {
+ String url = null;
+ Handler handler = null;
+
+ public tbIconThread(String urlIn, Handler handlerIn) {
+ url = urlIn;
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ if (url == null || handler == null) {
+ return;
+ }
+
+ BitmapDrawable image = null;
+ try {
+ cgHtmlImg imgGetter = new cgHtmlImg(activity, settings, trackable.geocode, false, 0, false);
+
+ image = imgGetter.getDrawable(url);
+ Message message = handler.obtainMessage(0, image);
+ handler.sendMessage(message);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeotrackable.tbIconThread.run: " + e.toString());
+ }
+ }
+ }
+
+ private class tbIconHandler extends Handler {
+ TextView view = null;
+
+ public tbIconHandler(TextView viewIn) {
+ view = viewIn;
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ BitmapDrawable image = (BitmapDrawable) message.obj;
+ if (image != null && view != null) {
+ view.setCompoundDrawablesWithIntrinsicBounds((Drawable) image, null, null, null);
+ }
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-trackable-details",
+ activity,
+ "http://cgeo.carnero.cc/manual/"
+ );
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgeotrackables.java b/src/cgeo/geocaching/cgeotrackables.java
new file mode 100644
index 0000000..d414e16
--- /dev/null
+++ b/src/cgeo/geocaching/cgeotrackables.java
@@ -0,0 +1,186 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import java.util.ArrayList;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.text.Html;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+public class cgeotrackables extends Activity {
+ private ArrayList<cgTrackable> trackables = new ArrayList<cgTrackable>();
+ private String geocode = null;
+ private cgeoapplication app = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private Activity activity = null;
+ private LayoutInflater inflater = null;
+ private LinearLayout addList = null;
+ private ProgressDialog waitDialog = null;
+ private Handler loadInventoryHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (inflater == null) {
+ inflater = activity.getLayoutInflater();
+ }
+
+ if (addList == null) {
+ addList = (LinearLayout) findViewById(R.id.trackable_list);
+ }
+
+ if (trackables.isEmpty()) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ warning.showToast("Sorry, c:geo failed to load cache inventory.");
+
+ finish();
+ return;
+ } else {
+ LinearLayout oneTbPre = null;
+ for (cgTrackable trackable : trackables) {
+ oneTbPre = (LinearLayout) inflater.inflate(R.layout.trackable_button, null);
+
+ Button oneTb = (Button) oneTbPre.findViewById(R.id.button);
+
+ if (trackable.name != null) {
+ oneTb.setText(Html.fromHtml(trackable.name).toString());
+ } else {
+ oneTb.setText("some trackable");
+ }
+ oneTb.setClickable(true);
+ oneTb.setOnClickListener(new buttonListener(trackable.guid, trackable.geocode, trackable.name));
+ addList.addView(oneTbPre);
+ }
+ }
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ } catch (Exception e) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ Log.e(cgSettings.tag, "cgeotrackables.loadInventoryHandler: " + e.toString());
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.trackables);
+ base.setTitle(activity, "Trackables");
+
+ // google analytics
+ base.sendAnal(activity, "/trackable/list");
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+
+ // try to get data from extras
+ if (extras != null) {
+ geocode = extras.getString("geocode");
+ }
+
+ if (geocode == null) {
+ warning.showToast("Sorry, c:geo forgot for what cache you want to load trackables.");
+ finish();
+ return;
+ }
+
+ waitDialog = ProgressDialog.show(this, null, "loading cache inventory...", true);
+ waitDialog.setCancelable(true);
+
+ (new loadInventory()).start();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ private class loadInventory extends Thread {
+
+ @Override
+ public void run() {
+ try {
+ trackables = app.loadInventory(geocode);
+
+ loadInventoryHandler.sendMessage(new Message());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeotrackables.loadInventory.run: " + e.toString());
+ }
+ }
+ }
+
+ private class buttonListener implements View.OnClickListener {
+
+ private String guid = null;
+ private String geocode = null;
+ private String name = null;
+
+ public buttonListener(String guidIn, String geocodeIn, String nameIn) {
+ guid = guidIn;
+ geocode = geocodeIn;
+ name = nameIn;
+ }
+
+ public void onClick(View arg0) {
+ Intent trackableIntent = new Intent(activity, cgeotrackable.class);
+ trackableIntent.putExtra("guid", guid);
+ trackableIntent.putExtra("geocode", geocode);
+ trackableIntent.putExtra("name", name);
+ activity.startActivity(trackableIntent);
+
+ finish();
+ return;
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-trackable-list",
+ activity,
+ "http://cgeo.carnero.cc/manual/"
+ );
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgeovisit.java b/src/cgeo/geocaching/cgeovisit.java
new file mode 100644
index 0000000..d99b581
--- /dev/null
+++ b/src/cgeo/geocaching/cgeovisit.java
@@ -0,0 +1,912 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Message;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.widget.CheckBox;
+import android.widget.LinearLayout;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+
+public class cgeovisit extends cgLogForm {
+ private cgeoapplication app = null;
+ private Activity activity = null;
+ private Resources res = null;
+ private LayoutInflater inflater = null;
+ private cgBase base = null;
+ private cgSettings settings = null;
+ private cgWarning warning = null;
+ private cgCache cache = null;
+ private ArrayList<Integer> types = new ArrayList<Integer>();
+ private ProgressDialog waitDialog = null;
+ private String cacheid = null;
+ private String geocode = null;
+ private String text = null;
+ private boolean alreadyFound = false;
+ private String viewstate = null;
+ private String viewstate1 = null;
+ private Boolean gettingViewstate = true;
+ private ArrayList<cgTrackableLog> trackables = null;
+ private Calendar date = Calendar.getInstance();
+ private int typeSelected = 1;
+ private int attempts = 0;
+ private boolean progressBar = false;
+ private Button post = null;
+ private Button save = null;
+ private Button clear = null;
+ private CheckBox tweetCheck = null;
+ private LinearLayout tweetBox = null;
+ private int rating = 0;
+ private boolean tbChanged = false;
+ // constants
+ private final static int LOG_SIGNATURE = 0x1;
+ private final static int LOG_TIME = 0x2;
+ private final static int LOG_DATE = 0x4;
+ private final static int LOG_DATE_TIME = 0x6;
+ private final static int LOG_SIGNATURE_DATE_TIME = 0x7;
+ // handlers
+ private Handler showProgressHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (progressBar == true) {
+ base.showProgress(activity, true);
+ }
+ }
+ };
+ private Handler loadDataHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (types.contains(typeSelected) == false) {
+ typeSelected = types.get(0);
+ setType(typeSelected);
+
+ warning.showToast(res.getString(R.string.info_log_type_changed));
+ }
+
+ if ((viewstate == null || viewstate.length() == 0) && attempts < 2) {
+ warning.showToast(res.getString(R.string.err_log_load_data_again));
+
+ loadData thread;
+ thread = new loadData(cacheid);
+ thread.start();
+
+ return;
+ } else if ((viewstate == null || viewstate.length() == 0) && attempts >= 2) {
+ warning.showToast(res.getString(R.string.err_log_load_data));
+ base.showProgress(activity, false);
+
+ return;
+ }
+
+ gettingViewstate = false; // we're done, user can post log
+
+ if (post == null) {
+ post = (Button) findViewById(R.id.post);
+ }
+ post.setEnabled(true);
+ post.setOnClickListener(new postListener());
+
+ // add trackables
+ if (trackables != null && trackables.isEmpty() == false) {
+ if (inflater == null) {
+ inflater = activity.getLayoutInflater();
+ }
+
+ final LinearLayout inventoryView = (LinearLayout) findViewById(R.id.inventory);
+ inventoryView.removeAllViews();
+
+ for (cgTrackableLog tb : trackables) {
+ LinearLayout inventoryItem = (LinearLayout) inflater.inflate(R.layout.visit_trackable, null);
+
+ ((TextView) inventoryItem.findViewById(R.id.trackcode)).setText(tb.trackCode);
+ ((TextView) inventoryItem.findViewById(R.id.name)).setText(tb.name);
+ ((TextView) inventoryItem.findViewById(R.id.action)).setText(cgBase.logTypesTrackable.get(0));
+
+ inventoryItem.setId(tb.id);
+ final String tbCode = tb.trackCode;
+ inventoryItem.setClickable(true);
+ registerForContextMenu(inventoryItem);
+ inventoryItem.findViewById(R.id.info).setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View view) {
+ final Intent trackablesIntent = new Intent(activity, cgeotrackable.class);
+ trackablesIntent.putExtra("geocode", tbCode);
+ activity.startActivity(trackablesIntent);
+ }
+ });
+ inventoryItem.findViewById(R.id.action).setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View view) {
+ openContextMenu(view);
+ }
+ });
+
+ inventoryView.addView(inventoryItem);
+ }
+
+ if (inventoryView.getChildCount() > 0) {
+ ((LinearLayout) findViewById(R.id.inventory_box)).setVisibility(View.VISIBLE);
+ }
+ if (inventoryView.getChildCount() > 1 && inventoryView.getChildCount() <= 20) {
+ final LinearLayout inventoryChangeAllView = (LinearLayout) findViewById(R.id.inventory_changeall);
+
+ Button changeButton = (Button) inventoryChangeAllView.findViewById(R.id.changebutton);
+ registerForContextMenu(changeButton);
+ changeButton.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View view) {
+ openContextMenu(view);
+ }
+ });
+
+ ((LinearLayout) findViewById(R.id.inventory_changeall)).setVisibility(View.VISIBLE);
+ }
+ }
+
+ base.showProgress(activity, false);
+ }
+ };
+
+ private Handler postLogHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == 1) {
+ warning.showToast(res.getString(R.string.info_log_posted));
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ finish();
+ return;
+ } else if (msg.what == 2) {
+ warning.showToast(res.getString(R.string.info_log_saved));
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ finish();
+ return;
+ } else if (msg.what >= 1000) {
+ if (msg.what == 1001) {
+ warning.showToast(res.getString(R.string.warn_log_text_fill));
+ } else if (msg.what == 1002) {
+ warning.showToast(res.getString(R.string.err_log_failed_server));
+ } else {
+ warning.showToast(res.getString(R.string.err_log_post_failed));
+ }
+ } else {
+ if (cgBase.errorRetrieve.get(msg.what) != null) {
+ warning.showToast(res.getString(R.string.err_log_post_failed_because) + " " + cgBase.errorRetrieve.get(msg.what) + ".");
+ } else {
+ warning.showToast(res.getString(R.string.err_log_post_failed));
+ }
+ }
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.visit);
+ base.setTitle(activity, res.getString(R.string.log_new_log));
+
+ // google analytics
+ base.sendAnal(activity, "/visit");
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ cacheid = extras.getString("id");
+ geocode = extras.getString("geocode");
+ text = extras.getString("text");
+ alreadyFound = extras.getBoolean("found");
+ }
+
+ if ((cacheid == null || cacheid.length() == 0) && geocode != null && geocode.length() > 0) {
+ cacheid = app.getCacheid(geocode);
+ }
+ if ((geocode == null || geocode.length() == 0) && cacheid != null && cacheid.length() > 0) {
+ geocode = app.getGeocode(cacheid);
+ }
+
+ cache = app.getCacheByGeocode(geocode);
+
+ if (cache.name != null && cache.name.length() > 0) {
+ base.setTitle(activity, res.getString(R.string.log_new_log) + " " + cache.name);
+ } else {
+ base.setTitle(activity, res.getString(R.string.log_new_log) + " " + cache.geocode.toUpperCase());
+ }
+
+ app.setAction(geocode);
+
+ if (cache == null) {
+ warning.showToast(res.getString(R.string.err_detail_cache_forgot_visit));
+
+ finish();
+ return;
+ }
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ init();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ SubMenu subMenu = null;
+
+ subMenu = menu.addSubMenu(0, 0, 0, res.getString(R.string.log_add)).setIcon(android.R.drawable.ic_menu_add);
+ subMenu.add(0, LOG_DATE_TIME, 0, res.getString(R.string.log_date_time));
+ subMenu.add(0, LOG_DATE, 0, res.getString(R.string.log_date));
+ subMenu.add(0, LOG_TIME, 0, res.getString(R.string.log_time));
+ subMenu.add(0, LOG_SIGNATURE, 0, res.getString(R.string.init_signature));
+ subMenu.add(0, LOG_SIGNATURE_DATE_TIME, 0, res.getString(R.string.log_date_time) + " & " + res.getString(R.string.init_signature));
+
+ subMenu = menu.addSubMenu(0, 9, 0, res.getString(R.string.log_rating)).setIcon(android.R.drawable.ic_menu_sort_by_size);
+ subMenu.add(0, 10, 0, res.getString(R.string.log_no_rating));
+ subMenu.add(0, 15, 0, res.getString(R.string.log_stars_5));
+ subMenu.add(0, 14, 0, res.getString(R.string.log_stars_4));
+ subMenu.add(0, 13, 0, res.getString(R.string.log_stars_3));
+ subMenu.add(0, 12, 0, res.getString(R.string.log_stars_2));
+ subMenu.add(0, 11, 0, res.getString(R.string.log_stars_1));
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ if (settings.getSignature() == null) {
+ menu.findItem(LOG_SIGNATURE).setVisible(false);
+ menu.findItem(LOG_SIGNATURE_DATE_TIME).setVisible(false);
+ } else {
+ menu.findItem(LOG_SIGNATURE).setVisible(true);
+ menu.findItem(LOG_SIGNATURE_DATE_TIME).setVisible(true);
+ }
+
+ if (settings.isGCvoteLogin() && typeSelected == cgBase.LOG_FOUND_IT && cache.guid != null && cache.guid.length() > 0) {
+ menu.findItem(9).setVisible(true);
+ } else {
+ menu.findItem(9).setVisible(false);
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int id = item.getItemId();
+
+ if ((id >= LOG_SIGNATURE && id <= LOG_SIGNATURE_DATE_TIME)) {
+ addSignature(id);
+
+ return true;
+ } else if (id >= 10 && id <= 15) {
+ rating = id - 10;
+
+ if (post == null) {
+ post = (Button) findViewById(R.id.post);
+ }
+ if (rating == 0) {
+ post.setText(res.getString(R.string.log_post_no_rate));
+ } else {
+ post.setText(res.getString(R.string.log_post_rate) + " " + rating + "*");
+ }
+ }
+
+ return false;
+ }
+
+ public void addSignature(int id) {
+ EditText text = null;
+ String textContent = null;
+ String dateString = null;
+ String timeString = null;
+ StringBuilder addText = new StringBuilder();
+
+ text = (EditText) findViewById(R.id.log);
+ textContent = text.getText().toString();
+ dateString = cgBase.dateOut.format(new Date());
+ timeString = cgBase.timeOut.format(new Date());
+
+ if ((id & LOG_DATE) == LOG_DATE) {
+ addText.append(dateString);
+ if ((id & LOG_TIME) == LOG_TIME) {
+ addText.append(" | ");
+ }
+ }
+
+ if ((id & LOG_TIME) == LOG_TIME) {
+ addText.append(timeString);
+ }
+
+ if ((id & LOG_SIGNATURE) == LOG_SIGNATURE && settings.getSignature() != null) {
+ String findCount = "";
+ if (addText.length() > 0) {
+ addText.append("\n");
+ }
+
+ if (settings.getSignature().contains("[NUMBER]") == true) {
+ final HashMap<String, String> params = new HashMap<String, String>();
+ final String page = base.request(false, "www.geocaching.com", "/my/", "GET", params, false, false, false).getData();
+ int current = base.parseFindCount(page);
+
+ if (current >= 0) {
+ findCount = "" + (current + 1);
+ }
+ }
+
+ String signature = settings.getSignature()
+ .replaceAll("\\[DATE\\]", dateString)
+ .replaceAll("\\[TIME\\]", timeString)
+ .replaceAll("\\[USER\\]", settings.getUsername())
+ .replaceAll("\\[NUMBER\\]", findCount);
+
+ addText.append(signature);
+ }
+
+ final String addTextDone;
+ if (textContent.length() > 0 && addText.length() > 0 ) {
+ addTextDone = textContent + "\n" + addText.toString();
+ } else {
+ addTextDone = textContent + addText.toString();
+ }
+
+ text.setText(addTextDone, TextView.BufferType.NORMAL);
+ text.setSelection(text.getText().toString().length());
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info) {
+ super.onCreateContextMenu(menu, view, info);
+ final int viewId = view.getId();
+
+ if (viewId == R.id.type) {
+ for (final int typeOne : types) {
+ menu.add(viewId, typeOne, 0, cgBase.logTypes2.get(typeOne));
+ Log.w(cgSettings.tag, "Addig " + typeOne + " " + cgBase.logTypes2.get(typeOne));
+ }
+ } else if (viewId == R.id.changebutton) {
+ final int textId = ((TextView) findViewById(viewId)).getId();
+
+ menu.setHeaderTitle(res.getString(R.string.log_tb_changeall));
+ for (final int logTbAction : cgBase.logTypesTrackable.keySet()) {
+ menu.add(textId, logTbAction, 0, cgBase.logTypesTrackable.get(logTbAction));
+ }
+ } else {
+ final int realViewId = ((LinearLayout) findViewById(viewId)).getId();
+
+ for (final cgTrackableLog tb : trackables) {
+ if (tb.id == realViewId) {
+ menu.setHeaderTitle(tb.name);
+ }
+ }
+ for (final int logTbAction : cgBase.logTypesTrackable.keySet()) {
+ menu.add(realViewId, logTbAction, 0, cgBase.logTypesTrackable.get(logTbAction));
+ }
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ final int group = item.getGroupId();
+ final int id = item.getItemId();
+
+ if (group == R.id.type) {
+ setType(id);
+
+ return true;
+ } else if (group == R.id.changebutton) {
+ try {
+ final String logTbAction = cgBase.logTypesTrackable.get(id);
+ if (logTbAction != null) {
+ final LinearLayout inventView = (LinearLayout) findViewById(R.id.inventory);
+ for (int count = 0; count < inventView.getChildCount(); count++) {
+ final LinearLayout tbView = (LinearLayout) inventView.getChildAt(count);
+ if (tbView == null) {
+ return false;
+ }
+
+ final TextView tbText = (TextView) tbView.findViewById(R.id.action);
+ if (tbText == null) {
+ return false;
+ }
+ tbText.setText(logTbAction);
+ }
+ for (cgTrackableLog tb : trackables) {
+ tb.action = id;
+ }
+ tbChanged = true;
+ return true;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeovisit.onContextItemSelected: " + e.toString());
+ }
+ } else {
+ try {
+ final String logTbAction = cgBase.logTypesTrackable.get(id);
+ if (logTbAction != null) {
+ final LinearLayout tbView = (LinearLayout) findViewById(group);
+ if (tbView == null) {
+ return false;
+ }
+
+ final TextView tbText = (TextView) tbView.findViewById(R.id.action);
+ if (tbText == null) {
+ return false;
+ }
+
+ for (cgTrackableLog tb : trackables) {
+ if (tb.id == group) {
+ tbChanged = true;
+
+ tb.action = id;
+ tbText.setText(logTbAction);
+
+ Log.i(cgSettings.tag, "Trackable " + tb.trackCode + " (" + tb.name + ") has new action: #" + id);
+ }
+ }
+
+ return true;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeovisit.onContextItemSelected: " + e.toString());
+ }
+ }
+
+ return false;
+ }
+
+ public void init() {
+ if (geocode != null) {
+ app.setAction(geocode);
+ }
+
+ types.clear();
+
+ if (cache.type.equals("event") || cache.type.equals("mega") || cache.type.equals("cito") || cache.type.equals("lostfound")) {
+ types.add(cgBase.LOG_WILL_ATTEND);
+ types.add(cgBase.LOG_NOTE);
+ types.add(cgBase.LOG_ATTENDED);
+ types.add(cgBase.LOG_NEEDS_ARCHIVE);
+ } else if (cache.type.equals("earth")) {
+ types.add(cgBase.LOG_FOUND_IT);
+ types.add(cgBase.LOG_DIDNT_FIND_IT);
+ types.add(cgBase.LOG_NOTE);
+ types.add(cgBase.LOG_NEEDS_MAINTENANCE);
+ types.add(cgBase.LOG_NEEDS_ARCHIVE);
+ } else if (cache.type.equals("webcam")) {
+ types.add(cgBase.LOG_WEBCAM_PHOTO_TAKEN);
+ types.add(cgBase.LOG_DIDNT_FIND_IT);
+ types.add(cgBase.LOG_NOTE);
+ types.add(cgBase.LOG_NEEDS_ARCHIVE);
+ types.add(cgBase.LOG_NEEDS_MAINTENANCE);
+ } else {
+ types.add(cgBase.LOG_FOUND_IT);
+ types.add(cgBase.LOG_DIDNT_FIND_IT);
+ types.add(cgBase.LOG_NOTE);
+ types.add(cgBase.LOG_NEEDS_ARCHIVE);
+ types.add(cgBase.LOG_NEEDS_MAINTENANCE);
+ }
+ if (cache.owner.equalsIgnoreCase(settings.getUsername()) == true) {
+ types.add(cgBase.LOG_OWNER_MAINTENANCE);
+ types.add(cgBase.LOG_TEMP_DISABLE_LISTING);
+ types.add(cgBase.LOG_ENABLE_LISTING);
+ types.add(cgBase.LOG_ARCHIVE);
+ types.remove(new Integer(cgBase.LOG_UPDATE_COORDINATES));
+ if (cache.type.equals("event") || cache.type.equals("mega") || cache.type.equals("cito") || cache.type.equals("lostfound")) {
+ types.add(cgBase.LOG_ANNOUNCEMENT);
+ }
+ }
+
+ final cgLog log = app.loadLogOffline(geocode);
+ if (log != null) {
+ typeSelected = log.type;
+ date.setTime(new Date(log.date));
+ text = log.log;
+ if (typeSelected == cgBase.LOG_FOUND_IT && settings.isGCvoteLogin() == true) {
+ if (post == null) {
+ post = (Button) findViewById(R.id.post);
+ }
+ post.setText(res.getString(R.string.log_post_no_rate));
+ }
+ } else if (settings.getSignature() != null && settings.getSignature().length() > 0) {
+ addSignature(LOG_SIGNATURE);
+ }
+
+ if (types.contains(typeSelected) == false) {
+ if (alreadyFound == true) {
+ typeSelected = cgBase.LOG_NOTE;
+ } else {
+ typeSelected = types.get(0);
+ }
+ setType(typeSelected);
+ }
+
+ Button typeButton = (Button) findViewById(R.id.type);
+ registerForContextMenu(typeButton);
+ typeButton.setText(cgBase.logTypes2.get(typeSelected));
+ typeButton.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View view) {
+ openContextMenu(view);
+ }
+ });
+
+ Button dateButton = (Button) findViewById(R.id.date);
+ dateButton.setText(cgBase.dateOutShort.format(date.getTime()));
+ dateButton.setOnClickListener(new cgeovisitDateListener());
+
+ EditText logView = (EditText) findViewById(R.id.log);
+ if (logView.getText().length() == 0 && text != null && text.length() > 0) {
+ logView.setText(text);
+ }
+
+
+ if (tweetBox == null) {
+ tweetBox = (LinearLayout) findViewById(R.id.tweet_box);
+ }
+ if (tweetCheck == null) {
+ tweetCheck = (CheckBox) findViewById(R.id.tweet);
+ }
+ tweetCheck.setChecked(true);
+
+ if (post == null) {
+ post = (Button) findViewById(R.id.post);
+ }
+ if (viewstate == null || viewstate.length() == 0) {
+ post.setEnabled(false);
+ post.setOnTouchListener(null);
+ post.setOnClickListener(null);
+
+ loadData thread;
+ thread = new loadData(cacheid);
+ thread.start();
+ } else {
+ post.setEnabled(true);
+ post.setOnClickListener(new postListener());
+ }
+
+ if (save == null) {
+ save = (Button) findViewById(R.id.save);
+ }
+ save.setOnClickListener(new saveListener());
+
+ if (clear == null) {
+ clear = (Button) findViewById(R.id.clear);
+ }
+ clear.setOnClickListener(new clearListener());
+ }
+
+ public void setDate(Calendar dateIn) {
+ date = dateIn;
+
+ final Button dateButton = (Button) findViewById(R.id.date);
+ dateButton.setText(cgBase.dateOutShort.format(date.getTime()));
+ }
+
+ public void setType(int type) {
+ final Button typeButton = (Button) findViewById(R.id.type);
+
+ if (cgBase.logTypes2.get(type) != null) {
+ typeSelected = type;
+ }
+ if (cgBase.logTypes2.get(typeSelected) == null) {
+ typeSelected = 1;
+ }
+ typeButton.setText(cgBase.logTypes2.get(typeSelected));
+
+ if (tweetBox == null) {
+ tweetBox = (LinearLayout) findViewById(R.id.tweet_box);
+ }
+
+ if (type == 2 && tbChanged == false) {
+ // TODO: change action
+ } else if (type != 2 && tbChanged == false) {
+ // TODO: change action
+ }
+
+ if (type == cgBase.LOG_FOUND_IT && settings.twitter == 1) {
+ tweetBox.setVisibility(View.VISIBLE);
+ } else {
+ tweetBox.setVisibility(View.GONE);
+ }
+
+ if (post == null) {
+ post = (Button) findViewById(R.id.post);
+ }
+
+ if (type == cgBase.LOG_FOUND_IT && settings.isGCvoteLogin() == true) {
+ if (rating == 0) {
+ post.setText(res.getString(R.string.log_post_no_rate));
+ } else {
+ post.setText(res.getString(R.string.log_post_rate) + " " + rating + "*");
+ }
+ } else {
+ post.setText(res.getString(R.string.log_post));
+ }
+ }
+
+ private class cgeovisitDateListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ Dialog dateDialog = new cgeodate(activity, (cgeovisit) activity, date);
+ dateDialog.setCancelable(true);
+ dateDialog.show();
+ }
+ }
+
+ private class postListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ if (gettingViewstate == false) {
+ waitDialog = ProgressDialog.show(activity, null, res.getString(R.string.log_saving), true);
+ waitDialog.setCancelable(true);
+
+ String log = ((EditText) findViewById(R.id.log)).getText().toString();
+ Thread thread = new postLog(postLogHandler, log);
+ thread.start();
+ } else {
+ warning.showToast(res.getString(R.string.err_log_load_data_still));
+ }
+ }
+ }
+
+ private class saveListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ String log = ((EditText) findViewById(R.id.log)).getText().toString();
+ final boolean status = app.saveLogOffline(geocode, date.getTime(), typeSelected, log);
+ if (save == null) {
+ save = (Button) findViewById(R.id.save);
+ }
+ save.setOnClickListener(new saveListener());
+
+ if (status == true) {
+ warning.showToast(res.getString(R.string.info_log_saved));
+ app.saveVisitDate(geocode);
+ } else {
+ warning.showToast(res.getString(R.string.err_log_post_failed));
+ }
+ }
+ }
+
+ private class clearListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ app.clearLogOffline(geocode);
+
+ if (alreadyFound == true) {
+ typeSelected = cgBase.LOG_NOTE;
+ } else {
+ typeSelected = types.get(0);
+ }
+ date.setTime(new Date());
+ text = null;
+
+ setType(typeSelected);
+
+ Button dateButton = (Button) findViewById(R.id.date);
+ dateButton.setText(cgBase.dateOutShort.format(date.getTime()));
+ dateButton.setOnClickListener(new cgeovisitDateListener());
+
+ EditText logView = (EditText) findViewById(R.id.log);
+ if (text != null && text.length() > 0) {
+ logView.setText(text);
+ } else {
+ logView.setText("");
+ }
+
+ if (clear == null) {
+ clear = (Button) findViewById(R.id.clear);
+ }
+ clear.setOnClickListener(new clearListener());
+
+ warning.showToast(res.getString(R.string.info_log_cleared));
+ }
+ }
+
+ private class loadData extends Thread {
+
+ private String cacheid = null;
+
+ public loadData(String cacheidIn) {
+ cacheid = cacheidIn;
+
+ if (cacheid == null) {
+ warning.showToast(res.getString(R.string.err_detail_cache_forgot_visit));
+
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public void run() {
+ final HashMap<String, String> params = new HashMap<String, String>();
+
+ showProgressHandler.sendEmptyMessage(0);
+ gettingViewstate = true;
+ attempts++;
+
+ try {
+ if (cacheid != null && cacheid.length() > 0) {
+ params.put("ID", cacheid);
+ } else {
+ loadDataHandler.sendEmptyMessage(0);
+ return;
+ }
+
+ final String page = base.request(false, "www.geocaching.com", "/seek/log.aspx", "GET", params, false, false, false).getData();
+
+ viewstate = base.findViewstate(page, 0);
+ viewstate1 = base.findViewstate(page, 1);
+ trackables = base.parseTrackableLog(page);
+
+ final ArrayList<Integer> typesPre = base.parseTypes(page);
+ if (typesPre.size() > 0) {
+ types.clear();
+ types.addAll(typesPre);
+ types.remove(new Integer(cgBase.LOG_UPDATE_COORDINATES));
+ }
+ typesPre.clear();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeovisit.loadData.run: " + e.toString());
+ }
+
+ loadDataHandler.sendEmptyMessage(0);
+ }
+ }
+
+ private class postLog extends Thread {
+
+ Handler handler = null;
+ String log = null;
+
+ public postLog(Handler handlerIn, String logIn) {
+ handler = handlerIn;
+ log = logIn;
+ }
+
+ @Override
+ public void run() {
+ int ret = -1;
+
+ ret = postLogFn(log);
+
+ handler.sendEmptyMessage(ret);
+ }
+ }
+
+ public int postLogFn(String log) {
+ int status = -1;
+
+ try {
+ if (tweetBox == null) {
+ tweetBox = (LinearLayout) findViewById(R.id.tweet_box);
+ }
+ if (tweetCheck == null) {
+ tweetCheck = (CheckBox) findViewById(R.id.tweet);
+ }
+
+ status = base.postLog(app, geocode, cacheid, viewstate, viewstate1, typeSelected, date.get(Calendar.YEAR), (date.get(Calendar.MONTH) + 1), date.get(Calendar.DATE), log, trackables);
+
+ if (status == 1) {
+ cgLog logNow = new cgLog();
+ logNow.author = settings.getUsername();
+ logNow.date = date.getTimeInMillis();
+ logNow.type = typeSelected;
+ logNow.log = log;
+
+ cache.logs.add(0, logNow);
+ app.addLog(geocode, logNow);
+
+ if (typeSelected == cgBase.LOG_FOUND_IT) {
+ app.markFound(geocode);
+ if (cache != null) {
+ cache.found = true;
+ }
+ }
+
+ if (cache != null) {
+ app.putCacheInCache(cache);
+ } else {
+ app.removeCacheFromCache(geocode);
+ }
+ }
+
+ if (status == 1) {
+ app.clearLogOffline(geocode);
+ }
+
+ if (
+ status == 1 && typeSelected == cgBase.LOG_FOUND_IT && settings.twitter == 1
+ && settings.tokenPublic != null && settings.tokenPublic.length() > 0 && settings.tokenSecret != null
+ && settings.tokenSecret.length() > 0 && tweetCheck.isChecked() == true && tweetBox.getVisibility() == View.VISIBLE
+ ) {
+ base.postTweetCache(app, settings, geocode);
+ }
+
+ if (status == 1 && typeSelected == cgBase.LOG_FOUND_IT && settings.isGCvoteLogin() == true) {
+ base.setRating(cache.guid, rating);
+ }
+
+ return status;
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeovisit.postLogFn: " + e.toString());
+ }
+
+ return 1000;
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-log",
+ activity,
+ "http://cgeo.carnero.cc/manual/"
+ );
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgeowaypoint.java b/src/cgeo/geocaching/cgeowaypoint.java
new file mode 100644
index 0000000..5121a38
--- /dev/null
+++ b/src/cgeo/geocaching/cgeowaypoint.java
@@ -0,0 +1,465 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.util.Log;
+import android.text.Html;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.widget.Button;
+
+import com.google.android.apps.analytics.GoogleAnalyticsTracker;
+import java.util.ArrayList;
+
+public class cgeowaypoint extends Activity {
+
+ private static final int MENU_ID_EXTERN = 23;
+ private static final int MENU_ID_RMAPS = 21;
+ private static final int MENU_ID_LOCUS = 20;
+ private static final int MENU_ID_NAVIGATION = 0;
+ private static final int MENU_ID_CACHES_AROUND = 5;
+ private static final int MENU_ID_TURNBYTURN = 4;
+ private static final int MENU_ID_MAP = 1;
+ private static final int MENU_ID_RADAR = 3;
+ private static final int MENU_ID_COMPASS = 2;
+ private GoogleAnalyticsTracker tracker = null;
+ private cgWaypoint waypoint = null;
+ private String geocode = null;
+ private int id = -1;
+ private cgeoapplication app = null;
+ private Resources res = null;
+ private Activity activity = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private ProgressDialog waitDialog = null;
+ private cgGeo geo = null;
+ private cgUpdateLoc geoUpdate = new update();
+ private Handler loadWaypointHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (waypoint == null) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog = null;
+ }
+
+ warning.showToast(res.getString(R.string.err_waypoint_load_failed));
+
+ finish();
+ return;
+ } else {
+ final TextView identification = (TextView) findViewById(R.id.identification);
+ final TextView coords = (TextView) findViewById(R.id.coordinates);
+ final TextView note = (TextView) findViewById(R.id.note);
+ final ImageView compass = (ImageView) findViewById(R.id.compass);
+ final View separator = (View) findViewById(R.id.separator);
+
+ if (waypoint.name != null && waypoint.name.length() > 0) {
+ base.setTitle(activity, Html.fromHtml(waypoint.name.trim()).toString());
+ } else {
+ base.setTitle(activity, res.getString(R.string.waypoint_title));
+ }
+
+ if (waypoint.prefix.equalsIgnoreCase("OWN") == false) {
+ identification.setText(waypoint.prefix.trim() + "/" + waypoint.lookup.trim());
+ } else {
+ identification.setText(res.getString(R.string.waypoint_custom));
+ }
+
+ if (waypoint.latitude != null && waypoint.longitude != null) {
+ coords.setText(Html.fromHtml(base.formatCoordinate(waypoint.latitude, "lat", true) + " | " + base.formatCoordinate(waypoint.longitude, "lon", true)), TextView.BufferType.SPANNABLE);
+ compass.setVisibility(View.VISIBLE);
+ separator.setVisibility(View.VISIBLE);
+ } else {
+ coords.setText(res.getString(R.string.waypoint_unknown_coordinates));
+ compass.setVisibility(View.GONE);
+ separator.setVisibility(View.GONE);
+ }
+
+ if (waypoint.note != null && waypoint.note.length() > 0) {
+ note.setText(Html.fromHtml(waypoint.note.trim()), TextView.BufferType.SPANNABLE);
+ }
+
+ Button buttonEdit = (Button) findViewById(R.id.edit);
+ buttonEdit.setOnClickListener(new editWaypointListener(waypoint.id));
+
+ Button buttonDelete = (Button) findViewById(R.id.delete);
+ if (waypoint.type != null && waypoint.type.equalsIgnoreCase("own") == true) {
+ buttonDelete.setOnClickListener(new deleteWaypointListener(waypoint.id));
+ buttonDelete.setVisibility(View.VISIBLE);
+ }
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog = null;
+ }
+ }
+ } catch (Exception e) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog = null;
+ }
+ Log.e(cgSettings.tag, "cgeowaypoint.loadWaypointHandler: " + e.toString());
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.waypoint);
+ base.setTitle(activity, "waypoint");
+
+ // google analytics
+ tracker = GoogleAnalyticsTracker.getInstance();
+ tracker.start(cgSettings.analytics, this);
+ tracker.dispatch();
+ base.sendAnal(activity, tracker, "/waypoint/detail");
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+
+ // try to get data from extras
+ if (extras != null) {
+ id = extras.getInt("waypoint");
+ geocode = extras.getString("geocode");
+ }
+
+ if (id <= 0) {
+ warning.showToast(res.getString(R.string.err_waypoint_unknown));
+ finish();
+ return;
+ }
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+
+ waitDialog = ProgressDialog.show(this, null, res.getString(R.string.waypoint_loading), true);
+ waitDialog.setCancelable(true);
+
+ (new loadWaypoint()).start();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+
+ if (waitDialog == null) {
+ waitDialog = ProgressDialog.show(this, null, res.getString(R.string.waypoint_loading), true);
+ waitDialog.setCancelable(true);
+
+ (new loadWaypoint()).start();
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+ if (tracker != null) {
+ tracker.stop();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStop() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onPause();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(0, MENU_ID_COMPASS, 0, res.getString(R.string.cache_menu_compass)).setIcon(android.R.drawable.ic_menu_compass); // compass
+
+ SubMenu subMenu = menu.addSubMenu(1, MENU_ID_NAVIGATION, 0, res.getString(R.string.cache_menu_navigate)).setIcon(android.R.drawable.ic_menu_more);
+ subMenu.add(0, MENU_ID_RADAR, 0, res.getString(R.string.cache_menu_radar)); // radar
+ subMenu.add(0, MENU_ID_MAP, 0, res.getString(R.string.cache_menu_map)); // c:geo map
+ if (base.isLocus(activity)) {
+ subMenu.add(0, MENU_ID_LOCUS, 0, res.getString(R.string.cache_menu_locus)); // ext.: locus
+ }
+ if (base.isRmaps(activity)) {
+ subMenu.add(0, MENU_ID_RMAPS, 0, res.getString(R.string.cache_menu_rmaps)); // ext.: rmaps
+ }
+ subMenu.add(0, MENU_ID_EXTERN, 0, res.getString(R.string.cache_menu_map_ext)); // ext.: other
+ subMenu.add(0, MENU_ID_TURNBYTURN, 0, res.getString(R.string.cache_menu_tbt)); // turn-by-turn
+
+ menu.add(0, MENU_ID_CACHES_AROUND, 0, res.getString(R.string.cache_menu_around)).setIcon(android.R.drawable.ic_menu_rotate); // caches around
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+
+ try {
+ boolean visible = waypoint != null && waypoint.latitude != null && waypoint.longitude != null;
+ menu.findItem(MENU_ID_NAVIGATION).setVisible(visible);
+ menu.findItem(MENU_ID_COMPASS).setVisible(visible);
+ menu.findItem(MENU_ID_CACHES_AROUND).setVisible(visible);
+ } catch (Exception e) {
+ // nothing
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ final int menuItem = item.getItemId();
+
+ if (menuItem == MENU_ID_MAP) {
+ showOnMap();
+ return true;
+ } else if (menuItem == MENU_ID_COMPASS) {
+ goCompass(null);
+ return true;
+ } else if (menuItem == MENU_ID_RADAR) {
+ radarTo();
+ return true;
+ } else if (menuItem == MENU_ID_TURNBYTURN) {
+ if (geo != null) {
+ base.runNavigation(activity, res, settings, warning, tracker, waypoint.latitude, waypoint.longitude, geo.latitudeNow, geo.longitudeNow);
+ } else {
+ base.runNavigation(activity, res, settings, warning, tracker, waypoint.latitude, waypoint.longitude);
+ }
+
+ return true;
+ } else if (menuItem == MENU_ID_CACHES_AROUND) {
+ cachesAround();
+ return true;
+ } else if (menuItem == MENU_ID_LOCUS) {
+ base.runExternalMap(cgBase.mapAppLocus, activity, res, warning, tracker, waypoint); // locus
+ return true;
+ } else if (menuItem == MENU_ID_RMAPS) {
+ base.runExternalMap(cgBase.mapAppRmaps, activity, res, warning, tracker, waypoint); // rmaps
+ return true;
+ } else if (menuItem == MENU_ID_EXTERN) {
+ base.runExternalMap(cgBase.mapAppAny, activity, res, warning, tracker, waypoint); // extern
+ return true;
+ }
+
+ return false;
+ }
+
+ private void showOnMap() {
+ if (waypoint == null || waypoint.latitude == null || waypoint.longitude == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ Intent mapIntent = new Intent(activity, settings.getMapFactory().getMapClass());
+ mapIntent.putExtra("latitude", waypoint.latitude);
+ mapIntent.putExtra("longitude", waypoint.longitude);
+ mapIntent.putExtra("wpttype", waypoint.type);
+
+ activity.startActivity(mapIntent);
+ }
+
+ private void radarTo() {
+ if (waypoint == null || waypoint.latitude == null || waypoint.longitude == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ try {
+ if (cgBase.isIntentAvailable(activity, "com.google.android.radar.SHOW_RADAR") == true) {
+ Intent radarIntent = new Intent("com.google.android.radar.SHOW_RADAR");
+ radarIntent.putExtra("latitude", new Float(waypoint.latitude));
+ radarIntent.putExtra("longitude", new Float(waypoint.longitude));
+ activity.startActivity(radarIntent);
+ } else {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
+ dialog.setTitle(res.getString(R.string.err_radar_title));
+ dialog.setMessage(res.getString(R.string.err_radar_message));
+ dialog.setCancelable(true);
+ dialog.setPositiveButton("yes", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:com.eclipsim.gpsstatus2")));
+ dialog.cancel();
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_market));
+ Log.e(cgSettings.tag, "cgeowaypoint.radarTo.onClick: " + e.toString());
+ }
+ }
+ });
+ dialog.setNegativeButton("no", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ }
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_generic));
+ Log.e(cgSettings.tag, "cgeowaypoint.radarTo: " + e.toString());
+ }
+ }
+
+ private void cachesAround() {
+ if (waypoint == null || waypoint.latitude == null || waypoint.longitude == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ cgeocaches cachesActivity = new cgeocaches();
+
+ Intent cachesIntent = new Intent(activity, cachesActivity.getClass());
+ cachesIntent.putExtra("type", "coordinate");
+ cachesIntent.putExtra("latitude", waypoint.latitude);
+ cachesIntent.putExtra("longitude", waypoint.longitude);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+
+ activity.startActivity(cachesIntent);
+
+ finish();
+ }
+
+ private class loadWaypoint extends Thread {
+
+ @Override
+ public void run() {
+ try {
+ waypoint = app.loadWaypoint(id);
+
+ loadWaypointHandler.sendMessage(new Message());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeowaypoint.loadWaypoint.run: " + e.toString());
+ }
+ }
+ }
+
+ private class update extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ // nothing
+ }
+ }
+
+ private class editWaypointListener implements View.OnClickListener {
+
+ private int id = -1;
+
+ public editWaypointListener(int idIn) {
+ id = idIn;
+ }
+
+ public void onClick(View arg0) {
+ Intent editIntent = new Intent(activity, cgeowaypointadd.class);
+ editIntent.putExtra("waypoint", id);
+ activity.startActivity(editIntent);
+ }
+ }
+
+ private class deleteWaypointListener implements View.OnClickListener {
+
+ private Integer id = null;
+
+ public deleteWaypointListener(int idIn) {
+ id = idIn;
+ }
+
+ public void onClick(View arg0) {
+ if (app.deleteWaypoint(id) == false) {
+ warning.showToast(res.getString(R.string.err_waypoint_delete_failed));
+ } else {
+ app.removeCacheFromCache(geocode);
+
+ finish();
+ return;
+ }
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-waypoint-details",
+ activity,
+ "http://cgeo.carnero.cc/manual/");
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ public void goCompass(View view) {
+ if (waypoint == null || waypoint.latitude == null || waypoint.longitude == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ Intent navigateIntent = new Intent(activity, cgeonavigate.class);
+ navigateIntent.putExtra("latitude", waypoint.latitude);
+ navigateIntent.putExtra("longitude", waypoint.longitude);
+ navigateIntent.putExtra("geocode", waypoint.prefix.trim() + "/" + waypoint.lookup.trim());
+ navigateIntent.putExtra("name", waypoint.name);
+
+ if (cgeonavigate.coordinates != null) {
+ cgeonavigate.coordinates.clear();
+ }
+ cgeonavigate.coordinates = new ArrayList<cgCoord>();
+ cgeonavigate.coordinates.add(new cgCoord(waypoint));
+ activity.startActivity(navigateIntent);
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgeowaypointadd.java b/src/cgeo/geocaching/cgeowaypointadd.java
new file mode 100644
index 0000000..ec58257
--- /dev/null
+++ b/src/cgeo/geocaching/cgeowaypointadd.java
@@ -0,0 +1,434 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.os.Bundle;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Message;
+import android.text.Html;
+import android.util.Log;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import android.widget.Button;
+import android.widget.EditText;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class cgeowaypointadd extends Activity {
+
+ private cgeoapplication app = null;
+ private Resources res = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private Activity activity = null;
+ private String geocode = null;
+ private int id = -1;
+ private cgGeo geo = null;
+ private cgUpdateLoc geoUpdate = new update();
+ private EditText latEdit = null;
+ private EditText lonEdit = null;
+ private ProgressDialog waitDialog = null;
+ private cgWaypoint waypoint = null;
+ private String type = "own";
+ private String prefix = "OWN";
+ private String lookup = "---";
+ /**
+ * number of waypoints that the corresponding cache has until now
+ */
+ private int wpCount = 0;
+ private Handler loadWaypointHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (waypoint == null) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog = null;
+ }
+
+ id = -1;
+ } else {
+ geocode = waypoint.geocode;
+ type = waypoint.type;
+ prefix = waypoint.prefix;
+ lookup = waypoint.lookup;
+
+ app.setAction(geocode);
+
+ ((EditText) findViewById(R.id.latitude)).setText(base.formatCoordinate(waypoint.latitude, "lat", true));
+ ((EditText) findViewById(R.id.longitude)).setText(base.formatCoordinate(waypoint.longitude, "lon", true));
+ ((EditText) findViewById(R.id.name)).setText(Html.fromHtml(waypoint.name.trim()).toString());
+ ((EditText) findViewById(R.id.note)).setText(Html.fromHtml(waypoint.note.trim()).toString());
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog = null;
+ }
+ }
+ } catch (Exception e) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog = null;
+ }
+ Log.e(cgSettings.tag, "cgeowaypointadd.loadWaypointHandler: " + e.toString());
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(activity, activity.getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, activity.getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(activity);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.waypoint_new);
+ base.setTitle(activity, "waypoint");
+
+ // google analytics
+ base.sendAnal(activity, "/waypoint/new");
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ geocode = extras.getString("geocode");
+ wpCount = extras.getInt("count", 0);
+ id = extras.getInt("waypoint");
+ }
+
+ if ((geocode == null || geocode.length() == 0) && id <= 0) {
+ warning.showToast(res.getString(R.string.err_waypoint_cache_unknown));
+
+ finish();
+ return;
+ }
+
+ if (id <= 0) {
+ base.setTitle(activity, res.getString(R.string.waypoint_add_title));
+ } else {
+ base.setTitle(activity, res.getString(R.string.waypoint_edit_title));
+ }
+
+ if (geocode != null) {
+ app.setAction(geocode);
+ }
+
+ Button buttonCurrent = (Button) findViewById(R.id.current);
+ buttonCurrent.setOnClickListener(new currentListener());
+
+ Button addWaypoint = (Button) findViewById(R.id.add_waypoint);
+ addWaypoint.setOnClickListener(new coordsListener());
+
+ ArrayList<String> wayPointNames = new ArrayList<String>(cgBase.waypointTypes.values());
+ AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.name);
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, wayPointNames);
+ textView.setAdapter(adapter);
+
+
+ if (id > 0) {
+ waitDialog = ProgressDialog.show(this, null, res.getString(R.string.waypoint_loading), true);
+ waitDialog.setCancelable(true);
+
+ (new loadWaypoint()).start();
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+
+ if (id > 0) {
+ if (waitDialog == null) {
+ waitDialog = ProgressDialog.show(this, null, res.getString(R.string.waypoint_loading), true);
+ waitDialog.setCancelable(true);
+
+ (new loadWaypoint()).start();
+ }
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStop() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onPause();
+ }
+
+ private class update extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+
+ try {
+ if (latEdit == null) {
+ latEdit = (EditText) findViewById(R.id.latitude);
+ }
+ if (lonEdit == null) {
+ lonEdit = (EditText) findViewById(R.id.longitude);
+ }
+
+ latEdit.setHint(base.formatCoordinate(geo.latitudeNow, "lat", false));
+ lonEdit.setHint(base.formatCoordinate(geo.longitudeNow, "lon", false));
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ private class loadWaypoint extends Thread {
+
+ @Override
+ public void run() {
+ try {
+ waypoint = app.loadWaypoint(id);
+
+ loadWaypointHandler.sendMessage(new Message());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeowaypoint.loadWaypoint.run: " + e.toString());
+ }
+ }
+ }
+
+ private class currentListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ if (geo == null || geo.latitudeNow == null || geo.longitudeNow == null) {
+ warning.showToast(res.getString(R.string.err_point_unknown_position));
+ return;
+ }
+
+ ((EditText) findViewById(R.id.latitude)).setText(base.formatCoordinate(geo.latitudeNow, "lat", true));
+ ((EditText) findViewById(R.id.longitude)).setText(base.formatCoordinate(geo.longitudeNow, "lon", true));
+ }
+ }
+
+ private class coordsListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ ArrayList<Double> coords = new ArrayList<Double>();
+ Double latitude = null;
+ Double longitude = null;
+
+ final String bearingText = ((EditText) findViewById(R.id.bearing)).getText().toString();
+ final String distanceText = ((EditText) findViewById(R.id.distance)).getText().toString();
+ final String latText = ((EditText) findViewById(R.id.latitude)).getText().toString();
+ final String lonText = ((EditText) findViewById(R.id.longitude)).getText().toString();
+
+ if ((bearingText == null || bearingText.length() == 0) && (distanceText == null || distanceText.length() == 0)
+ && (latText == null || latText.length() == 0) && (lonText == null || lonText.length() == 0)) {
+ warning.helpDialog(res.getString(R.string.err_point_no_position_given_title), res.getString(R.string.err_point_no_position_given));
+ return;
+ }
+
+ if (latText != null && latText.length() > 0 && lonText != null && lonText.length() > 0) {
+ // latitude & longitude
+ HashMap<String, Object> latParsed = base.parseCoordinate(latText, "lat");
+ HashMap<String, Object> lonParsed = base.parseCoordinate(lonText, "lat");
+
+ if (latParsed == null || latParsed.get("coordinate") == null || latParsed.get("string") == null) {
+ warning.showToast(res.getString(R.string.err_parse_lat));
+ return;
+ }
+
+ if (lonParsed == null || lonParsed.get("coordinate") == null || lonParsed.get("string") == null) {
+ warning.showToast(res.getString(R.string.err_parse_lon));
+ return;
+ }
+
+ latitude = (Double) latParsed.get("coordinate");
+ longitude = (Double) lonParsed.get("coordinate");
+ } else {
+ if (geo == null || geo.latitudeNow == null || geo.longitudeNow == null) {
+ warning.showToast(res.getString(R.string.err_point_curr_position_unavailable));
+ return;
+ }
+
+ latitude = geo.latitudeNow;
+ longitude = geo.longitudeNow;
+ }
+
+ if (bearingText != null && bearingText.length() > 0 && distanceText != null && distanceText.length() > 0) {
+ // bearing & distance
+ Double bearing = null;
+ try {
+ bearing = new Double(bearingText);
+ } catch (Exception e) {
+ // probably not a number
+ }
+ if (bearing == null) {
+ warning.helpDialog(res.getString(R.string.err_point_bear_and_dist_title), res.getString(R.string.err_point_bear_and_dist));
+ return;
+ }
+
+ Double distance = null; // km
+
+ final Pattern patternA = Pattern.compile("^([0-9\\.\\,]+)[ ]*m$", Pattern.CASE_INSENSITIVE); // m
+ final Pattern patternB = Pattern.compile("^([0-9\\.\\,]+)[ ]*km$", Pattern.CASE_INSENSITIVE); // km
+ final Pattern patternC = Pattern.compile("^([0-9\\.\\,]+)[ ]*ft$", Pattern.CASE_INSENSITIVE); // ft - 0.3048m
+ final Pattern patternD = Pattern.compile("^([0-9\\.\\,]+)[ ]*yd$", Pattern.CASE_INSENSITIVE); // yd - 0.9144m
+ final Pattern patternE = Pattern.compile("^([0-9\\.\\,]+)[ ]*mi$", Pattern.CASE_INSENSITIVE); // mi - 1609.344m
+
+ Matcher matcherA = patternA.matcher(distanceText);
+ Matcher matcherB = patternB.matcher(distanceText);
+ Matcher matcherC = patternC.matcher(distanceText);
+ Matcher matcherD = patternD.matcher(distanceText);
+ Matcher matcherE = patternE.matcher(distanceText);
+
+ if (matcherA.find() == true && matcherA.groupCount() > 0) {
+ distance = (new Double(matcherA.group(1))) * 0.001;
+ } else if (matcherB.find() == true && matcherB.groupCount() > 0) {
+ distance = new Double(matcherB.group(1));
+ } else if (matcherC.find() == true && matcherC.groupCount() > 0) {
+ distance = (new Double(matcherC.group(1))) * 0.0003048;
+ } else if (matcherD.find() == true && matcherD.groupCount() > 0) {
+ distance = (new Double(matcherD.group(1))) * 0.0009144;
+ } else if (matcherE.find() == true && matcherE.groupCount() > 0) {
+ distance = (new Double(matcherE.group(1))) * 1.609344;
+ } else {
+ try {
+ if (settings.units == cgSettings.unitsImperial) {
+ distance = (new Double(distanceText)) * 1.609344; // considering it miles
+ } else {
+ distance = (new Double(distanceText)) * 0.001; // considering it meters
+ }
+ } catch (Exception e) {
+ // probably not a number
+ }
+ }
+
+ if (distance == null) {
+ warning.showToast(res.getString(R.string.err_parse_dist));
+ return;
+ }
+
+ Double latParsed = null;
+ Double lonParsed = null;
+
+ HashMap<String, Double> coordsDst = base.getRadialDistance(latitude, longitude, bearing, distance);
+
+ latParsed = coordsDst.get("latitude");
+ lonParsed = coordsDst.get("longitude");
+
+ if (latParsed == null || lonParsed == null) {
+ warning.showToast(res.getString(R.string.err_point_location_error));
+ return;
+ }
+
+ coords.add(0, (Double) latParsed);
+ coords.add(1, (Double) lonParsed);
+ } else if (latitude != null && longitude != null) {
+ coords.add(0, latitude);
+ coords.add(1, longitude);
+ } else {
+ warning.showToast(res.getString(R.string.err_point_location_error));
+ return;
+ }
+
+ String name = ((EditText) findViewById(R.id.name)).getText().toString().trim();
+ // if no name is given, just give the waypoint its number as name
+ if (name.length() == 0) {
+ name = res.getString(R.string.waypoint) + " " + String.valueOf(wpCount + 1);
+ }
+ final String note = ((EditText) findViewById(R.id.note)).getText().toString().trim();
+
+ final cgWaypoint waypoint = new cgWaypoint();
+ waypoint.type = type;
+ waypoint.geocode = geocode;
+ waypoint.prefix = prefix;
+ waypoint.lookup = lookup;
+ waypoint.name = name;
+ waypoint.latitude = coords.get(0);
+ waypoint.longitude = coords.get(1);
+ waypoint.latitudeString = base.formatCoordinate(coords.get(0), "lat", true);
+ waypoint.longitudeString = base.formatCoordinate(coords.get(1), "lon", true);
+ waypoint.note = note;
+
+ if (app.saveOwnWaypoint(id, geocode, waypoint) == true) {
+ app.removeCacheFromCache(geocode);
+
+ finish();
+ return;
+ } else {
+ warning.showToast(res.getString(R.string.err_waypoint_add_failed));
+ }
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ if (id >= 0) {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-waypoint-edit",
+ activity,
+ "http://cgeo.carnero.cc/manual/"
+ );
+ } else {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-waypoint-new",
+ activity,
+ "http://cgeo.carnero.cc/manual/"
+ );
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/filter/cgFilter.java b/src/cgeo/geocaching/filter/cgFilter.java
new file mode 100644
index 0000000..20f04c9
--- /dev/null
+++ b/src/cgeo/geocaching/filter/cgFilter.java
@@ -0,0 +1,20 @@
+package cgeo.geocaching.filter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import cgeo.geocaching.cgCache;
+
+public abstract class cgFilter {
+ abstract boolean applyFilter(cgCache cache);
+
+ public void filter(List<cgCache> list){
+ List<cgCache> itemsToRemove = new ArrayList<cgCache>();
+ for(cgCache item : list){
+ if(!applyFilter(item)){
+ itemsToRemove.add(item);
+ }
+ }
+ list.removeAll(itemsToRemove);
+ }
+}
diff --git a/src/cgeo/geocaching/filter/cgFilterBySize.java b/src/cgeo/geocaching/filter/cgFilterBySize.java
new file mode 100644
index 0000000..b32afc0
--- /dev/null
+++ b/src/cgeo/geocaching/filter/cgFilterBySize.java
@@ -0,0 +1,17 @@
+package cgeo.geocaching.filter;
+
+import cgeo.geocaching.cgCache;
+
+public class cgFilterBySize extends cgFilter {
+ private String size;
+
+ public cgFilterBySize(String size){
+ this.size = size;
+ }
+
+ @Override
+ boolean applyFilter(cgCache cache) {
+ return cache.size.equals(size);
+ }
+
+}
diff --git a/src/cgeo/geocaching/filter/cgFilterByTrackables.java b/src/cgeo/geocaching/filter/cgFilterByTrackables.java
new file mode 100644
index 0000000..44c85c1
--- /dev/null
+++ b/src/cgeo/geocaching/filter/cgFilterByTrackables.java
@@ -0,0 +1,12 @@
+package cgeo.geocaching.filter;
+
+import cgeo.geocaching.cgCache;
+
+public class cgFilterByTrackables extends cgFilter {
+
+ @Override
+ boolean applyFilter(cgCache cache) {
+ return cache.hasTrackables();
+ }
+
+}
diff --git a/src/cgeo/geocaching/filter/cgFilterByType.java b/src/cgeo/geocaching/filter/cgFilterByType.java
new file mode 100644
index 0000000..8ba177b
--- /dev/null
+++ b/src/cgeo/geocaching/filter/cgFilterByType.java
@@ -0,0 +1,17 @@
+package cgeo.geocaching.filter;
+
+import cgeo.geocaching.cgCache;
+
+public class cgFilterByType extends cgFilter {
+ private String type;
+
+ public cgFilterByType(String type){
+ this.type = type;
+ }
+
+ @Override
+ boolean applyFilter(cgCache cache) {
+ return cache.type.equals(type);
+ }
+
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleCacheOverlay.java b/src/cgeo/geocaching/googlemaps/googleCacheOverlay.java
new file mode 100644
index 0000000..68929cf
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleCacheOverlay.java
@@ -0,0 +1,101 @@
+package cgeo.geocaching.googlemaps;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.mapcommon.cgMapOverlay;
+import cgeo.geocaching.mapinterfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+
+import com.google.android.maps.ItemizedOverlay;
+import com.google.android.maps.MapView;
+
+/**
+ * Google specific implementation of the itemized cache overlay
+ * @author rsudev
+ *
+ */
+public class googleCacheOverlay extends ItemizedOverlay<googleCacheOverlayItem> implements ItemizedOverlayImpl {
+
+ private cgMapOverlay base;
+
+ public googleCacheOverlay(cgSettings settingsIn, Context contextIn, Drawable markerIn, Boolean fromDetailIn) {
+ super(boundCenterBottom(markerIn));
+ base = new cgMapOverlay(settingsIn, this, contextIn, fromDetailIn);
+ }
+
+ @Override
+ public cgMapOverlay getBase() {
+ return base;
+ }
+
+ @Override
+ protected googleCacheOverlayItem createItem(int i) {
+ if (base == null)
+ return null;
+
+ return (googleCacheOverlayItem) base.createItem(i);
+ }
+
+ @Override
+ public int size() {
+ if (base == null)
+ return 0;
+
+ return base.size();
+ }
+
+ @Override
+ protected boolean onTap(int arg0) {
+ if (base == null)
+ return false;
+
+ return base.onTap(arg0);
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapView mapView, boolean shadow) {
+ base.draw(canvas, (MapViewImpl) mapView, shadow);
+ }
+
+ @Override
+ public void superPopulate() {
+ populate();
+ }
+
+ @Override
+ public Drawable superBoundCenter(Drawable markerIn) {
+ return super.boundCenter(markerIn);
+ }
+
+ @Override
+ public Drawable superBoundCenterBottom(Drawable marker) {
+ return super.boundCenterBottom(marker);
+ }
+
+ @Override
+ public void superSetLastFocusedItemIndex(int i) {
+ super.setLastFocusedIndex(i);
+ }
+
+ @Override
+ public boolean superOnTap(int index) {
+ return super.onTap(index);
+ }
+
+ @Override
+ public void superDraw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ super.draw(canvas, (MapView) mapView, shadow);
+ }
+
+ @Override
+ public void superDrawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+ // Nothing to do here...
+ }
+
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleCacheOverlayItem.java b/src/cgeo/geocaching/googlemaps/googleCacheOverlayItem.java
new file mode 100644
index 0000000..5546077
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleCacheOverlayItem.java
@@ -0,0 +1,28 @@
+package cgeo.geocaching.googlemaps;
+
+import com.google.android.maps.GeoPoint;
+import com.google.android.maps.OverlayItem;
+
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.mapinterfaces.CacheOverlayItemImpl;
+
+public class googleCacheOverlayItem extends OverlayItem implements CacheOverlayItemImpl {
+ private String cacheType = null;
+ private cgCoord coord;
+
+ public googleCacheOverlayItem(cgCoord coordinate, String type) {
+ super(new GeoPoint((int)(coordinate.latitude * 1e6), (int)(coordinate.longitude * 1e6)), coordinate.name, "");
+
+ this.cacheType = type;
+ this.coord = coordinate;
+ }
+
+ public cgCoord getCoord() {
+ return coord;
+ }
+
+ public String getType() {
+ return cacheType;
+ }
+
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleGeoPoint.java b/src/cgeo/geocaching/googlemaps/googleGeoPoint.java
new file mode 100644
index 0000000..a22e7d4
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleGeoPoint.java
@@ -0,0 +1,13 @@
+package cgeo.geocaching.googlemaps;
+
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+
+import com.google.android.maps.GeoPoint;
+
+public class googleGeoPoint extends GeoPoint implements GeoPointImpl {
+
+ public googleGeoPoint(int latitudeE6, int longitudeE6) {
+ super(latitudeE6, longitudeE6);
+ }
+
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleMapActivity.java b/src/cgeo/geocaching/googlemaps/googleMapActivity.java
new file mode 100644
index 0000000..a95b741
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleMapActivity.java
@@ -0,0 +1,101 @@
+package cgeo.geocaching.googlemaps;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import cgeo.geocaching.mapcommon.MapBase;
+import cgeo.geocaching.mapcommon.cgeomap;
+import cgeo.geocaching.mapinterfaces.ActivityImpl;
+
+import com.google.android.maps.MapActivity;
+
+public class googleMapActivity extends MapActivity implements ActivityImpl {
+
+ private MapBase mapBase;
+
+ public googleMapActivity() {
+ mapBase = new cgeomap(this);
+ }
+
+ @Override
+ protected boolean isRouteDisplayed() {
+ return false;
+ }
+
+ @Override
+ public Activity getActivity() {
+ return this;
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ mapBase.onCreate(icicle);
+ }
+
+ @Override
+ protected void onDestroy() {
+ mapBase.onDestroy();
+ }
+
+ @Override
+ protected void onPause() {
+ mapBase.onPause();
+ }
+
+ @Override
+ protected void onResume() {
+ mapBase.onResume();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ return mapBase.onCreateOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ return mapBase.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ return mapBase.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ protected void onStop() {
+ mapBase.onStop();
+ }
+
+ @Override
+ public void superOnCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public boolean superOnCreateOptionsMenu(Menu menu) {
+ return superOnCreateOptionsMenu(menu);
+ }
+
+ @Override
+ public void superOnDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ public boolean superOnOptionsItemSelected(MenuItem item) {
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void superOnResume() {
+ super.onResume();
+ }
+
+ @Override
+ public boolean superOnPrepareOptionsMenu(Menu menu) {
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleMapController.java b/src/cgeo/geocaching/googlemaps/googleMapController.java
new file mode 100644
index 0000000..c779b32
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleMapController.java
@@ -0,0 +1,37 @@
+package cgeo.geocaching.googlemaps;
+
+import com.google.android.maps.GeoPoint;
+import com.google.android.maps.MapController;
+
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapControllerImpl;
+
+public class googleMapController implements MapControllerImpl {
+
+ private MapController mapController;
+
+ public googleMapController(MapController mapControllerIn) {
+ mapController = mapControllerIn;
+ }
+
+ @Override
+ public void animateTo(GeoPointImpl geoPoint) {
+ mapController.animateTo((GeoPoint)geoPoint);
+ }
+
+ @Override
+ public void setCenter(GeoPointImpl geoPoint) {
+ mapController.setCenter((GeoPoint)geoPoint);
+ }
+
+ @Override
+ public void setZoom(int mapzoom) {
+ mapController.setZoom(mapzoom);
+ }
+
+ @Override
+ public void zoomToSpan(int latSpanE6, int lonSpanE6) {
+ mapController.zoomToSpan(latSpanE6, lonSpanE6);
+ }
+
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleMapFactory.java b/src/cgeo/geocaching/googlemaps/googleMapFactory.java
new file mode 100644
index 0000000..86e75a0
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleMapFactory.java
@@ -0,0 +1,54 @@
+package cgeo.geocaching.googlemaps;
+
+import android.content.Context;
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.mapinterfaces.CacheOverlayItemImpl;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapFactory;
+import cgeo.geocaching.mapinterfaces.OverlayImpl;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.UserOverlayItemImpl;
+
+public class googleMapFactory implements MapFactory{
+
+ @Override
+ public Class getMapClass() {
+ return googleMapActivity.class;
+ }
+
+ @Override
+ public int getMapViewId() {
+ return R.id.map;
+ }
+
+ @Override
+ public int getMapLayoutId() {
+ return R.layout.googlemap;
+ }
+
+ @Override
+ public GeoPointImpl getGeoPointBase(int latE6, int lonE6) {
+ return new googleGeoPoint(latE6, lonE6);
+ }
+
+ @Override
+ public OverlayImpl getOverlayBaseWrapper(OverlayBase ovlIn) {
+ googleOverlay baseOvl = new googleOverlay(ovlIn);
+ return baseOvl;
+ }
+
+ @Override
+ public CacheOverlayItemImpl getCacheOverlayItem(cgCoord coordinate, String type) {
+ googleCacheOverlayItem baseItem = new googleCacheOverlayItem(coordinate, type);
+ return baseItem;
+ }
+
+ @Override
+ public UserOverlayItemImpl getUserOverlayItemBase(Context context, cgUser userOne) {
+ googleUsersOverlayItem baseItem = new googleUsersOverlayItem(context, userOne);
+ return baseItem;
+ }
+
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleMapProjection.java b/src/cgeo/geocaching/googlemaps/googleMapProjection.java
new file mode 100644
index 0000000..476d78d
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleMapProjection.java
@@ -0,0 +1,28 @@
+package cgeo.geocaching.googlemaps;
+
+import com.google.android.maps.GeoPoint;
+import com.google.android.maps.Projection;
+
+import android.graphics.Point;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+
+public class googleMapProjection implements MapProjectionImpl {
+
+ private Projection projection;
+
+ public googleMapProjection(Projection projectionIn) {
+ projection = projectionIn;
+ }
+
+ @Override
+ public void toPixels(GeoPointImpl leftGeo, Point left) {
+ projection.toPixels((GeoPoint) leftGeo, left);
+ }
+
+ @Override
+ public Object getImpl() {
+ return projection;
+ }
+
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleMapView.java b/src/cgeo/geocaching/googlemaps/googleMapView.java
new file mode 100644
index 0000000..b63ca2e
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleMapView.java
@@ -0,0 +1,118 @@
+package cgeo.geocaching.googlemaps;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.mapcommon.cgMapOverlay;
+import cgeo.geocaching.mapcommon.cgUsersOverlay;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapControllerImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+import cgeo.geocaching.mapinterfaces.OverlayImpl;
+
+import com.google.android.maps.GeoPoint;
+import com.google.android.maps.MapView;
+import com.google.android.maps.Overlay;
+
+public class googleMapView extends MapView implements MapViewImpl{
+
+ public googleMapView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public googleMapView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public googleMapView(Context context, String apiKey) {
+ super(context, apiKey);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ try {
+ if (getMapZoomLevel() >= 22) { // to avoid too close zoom level (mostly on Samsung Galaxy S series)
+ getController().setZoom(22);
+ }
+
+ super.draw(canvas);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapView.draw: " + e.toString());
+ }
+ }
+
+ @Override
+ public void displayZoomControls(boolean takeFocus) {
+ try {
+ super.displayZoomControls(takeFocus);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapView.displayZoomControls: " + e.toString());
+ }
+ }
+
+ @Override
+ public MapControllerImpl getMapController() {
+ return new googleMapController(getController());
+ }
+
+ @Override
+ public GeoPointImpl getMapViewCenter() {
+ GeoPoint point = getMapCenter();
+ return new googleGeoPoint(point.getLatitudeE6(), point.getLongitudeE6());
+ }
+
+ @Override
+ public void addOverlay(OverlayImpl ovl) {
+ getOverlays().add((Overlay)ovl);
+ }
+
+ @Override
+ public void clearOverlays() {
+ getOverlays().clear();
+ }
+
+ @Override
+ public MapProjectionImpl getMapProjection() {
+ return new googleMapProjection(getProjection());
+ }
+
+ @Override
+ public cgMapOverlay createAddMapOverlay(cgSettings settings,
+ Context context, Drawable drawable, boolean fromDetailIntent) {
+
+ googleCacheOverlay ovl = new googleCacheOverlay(settings, context, drawable, fromDetailIntent);
+ getOverlays().add(ovl);
+ return ovl.getBase();
+ }
+
+ @Override
+ public cgUsersOverlay createAddUsersOverlay(Context context, Drawable markerIn) {
+ googleUsersOverlay ovl = new googleUsersOverlay(context, markerIn);
+ getOverlays().add(ovl);
+ return ovl.getBase();
+ }
+
+ @Override
+ public int getMapZoomLevel() {
+ return getZoomLevel();
+ }
+
+ @Override
+ public void setMapSource(cgSettings settings) {
+ // nothing to do for google maps...
+ }
+
+ @Override
+ public boolean needsScaleOverlay() {
+ return true;
+ }
+
+ @Override
+ public void setBuiltinScale(boolean b) {
+ //Nothing to do for google maps...
+ }
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleOverlay.java b/src/cgeo/geocaching/googlemaps/googleOverlay.java
new file mode 100644
index 0000000..3847d9f
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleOverlay.java
@@ -0,0 +1,26 @@
+package cgeo.geocaching.googlemaps;
+
+import android.graphics.Canvas;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.OverlayImpl;
+
+import com.google.android.maps.MapView;
+import com.google.android.maps.Overlay;
+
+public class googleOverlay extends Overlay implements OverlayImpl {
+
+ private OverlayBase overlayBase;
+
+ public googleOverlay(OverlayBase overlayBaseIn) {
+ overlayBase = overlayBaseIn;
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapView mapView, boolean shadow) {
+ super.draw(canvas, mapView, shadow);
+
+ overlayBase.draw(canvas, (MapViewImpl) mapView, shadow);
+ }
+
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleUsersOverlay.java b/src/cgeo/geocaching/googlemaps/googleUsersOverlay.java
new file mode 100644
index 0000000..5019e6e
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleUsersOverlay.java
@@ -0,0 +1,94 @@
+package cgeo.geocaching.googlemaps;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+import cgeo.geocaching.mapcommon.cgUsersOverlay;
+import cgeo.geocaching.mapinterfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+
+import com.google.android.maps.ItemizedOverlay;
+import com.google.android.maps.MapView;
+
+public class googleUsersOverlay extends ItemizedOverlay<googleUsersOverlayItem> implements ItemizedOverlayImpl {
+
+ private cgUsersOverlay base;
+
+ public googleUsersOverlay(Context contextIn, Drawable markerIn) {
+ super(boundCenter(markerIn));
+ base = new cgUsersOverlay(this, contextIn);
+ }
+
+ @Override
+ public cgUsersOverlay getBase() {
+ return base;
+ }
+
+ @Override
+ protected googleUsersOverlayItem createItem(int i) {
+ if (base == null)
+ return null;
+
+ return (googleUsersOverlayItem) base.createItem(i);
+ }
+
+ @Override
+ public int size() {
+ if (base == null)
+ return 0;
+
+ return base.size();
+ }
+
+ @Override
+ protected boolean onTap(int arg0) {
+ if (base == null)
+ return false;
+
+ return base.onTap(arg0);
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapView mapView, boolean shadow) {
+ base.draw(canvas, (MapViewImpl) mapView, shadow);
+ }
+
+ @Override
+ public void superPopulate() {
+ populate();
+ }
+
+ @Override
+ public Drawable superBoundCenter(Drawable markerIn) {
+ return super.boundCenter(markerIn);
+ }
+
+ @Override
+ public Drawable superBoundCenterBottom(Drawable marker) {
+ return super.boundCenterBottom(marker);
+ }
+
+ @Override
+ public void superSetLastFocusedItemIndex(int i) {
+ super.setLastFocusedIndex(i);
+ }
+
+ @Override
+ public boolean superOnTap(int index) {
+ return super.onTap(index);
+ }
+
+ @Override
+ public void superDraw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ super.draw(canvas, (MapView) mapView, shadow);
+ }
+
+ @Override
+ public void superDrawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+ // Nothing to do here
+ }
+
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/googlemaps/googleUsersOverlayItem.java b/src/cgeo/geocaching/googlemaps/googleUsersOverlayItem.java
new file mode 100644
index 0000000..c3d404e
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleUsersOverlayItem.java
@@ -0,0 +1,43 @@
+package cgeo.geocaching.googlemaps;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.mapinterfaces.UserOverlayItemImpl;
+
+import com.google.android.maps.GeoPoint;
+import com.google.android.maps.OverlayItem;
+
+public class googleUsersOverlayItem extends OverlayItem implements UserOverlayItemImpl {
+ private Context context = null;
+ private cgUser user = null;
+
+ public googleUsersOverlayItem(Context contextIn, cgUser userIn) {
+ super(new GeoPoint((int)(userIn.latitude * 1e6), (int)(userIn.longitude * 1e6)), userIn.username, "");
+
+ context = contextIn;
+ user = userIn;
+ }
+
+ @Override
+ public Drawable getMarker(int state) {
+ Drawable marker = null;
+
+ if (user != null && user.located != null && user.located.getTime() >= (System.currentTimeMillis() - (20 * 60 * 1000))) {
+ marker = context.getResources().getDrawable(R.drawable.user_location_active);
+ } else {
+ marker = context.getResources().getDrawable(R.drawable.user_location);
+ }
+
+ marker.setBounds(0, 0, marker.getIntrinsicWidth(), marker.getIntrinsicHeight());
+ marker.setAlpha(190);
+ setMarker(marker);
+
+ return marker;
+ }
+
+ public cgUser getUser() {
+ return user;
+ }
+}
diff --git a/src/cgeo/geocaching/mapcommon/ItemizedOverlayBase.java b/src/cgeo/geocaching/mapcommon/ItemizedOverlayBase.java
new file mode 100644
index 0000000..41739e2
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/ItemizedOverlayBase.java
@@ -0,0 +1,57 @@
+package cgeo.geocaching.mapcommon;
+
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+import cgeo.geocaching.mapinterfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+import cgeo.geocaching.mapinterfaces.OverlayItemImpl;
+
+/**
+ * Base class for itemized overlays. Delegates calls from deriving classes to the contained
+ * provider-specific implementation.
+ * @author rsudev
+ *
+ */
+public abstract class ItemizedOverlayBase {
+
+ private ItemizedOverlayImpl ovlImpl;
+
+ public ItemizedOverlayBase(ItemizedOverlayImpl ovlImplIn) {
+ ovlImpl = ovlImplIn;
+ }
+
+ void populate() {
+ ovlImpl.superPopulate();
+ }
+
+ public boolean onTap(int index) {
+ return ovlImpl.superOnTap(index);
+ }
+
+ Drawable boundCenter(Drawable markerIn) {
+ return ovlImpl.superBoundCenter(markerIn);
+ }
+
+ Drawable boundCenterBottom(Drawable markerIn) {
+ return ovlImpl.superBoundCenterBottom(markerIn);
+ }
+
+ void setLastFocusedItemIndex(int index){
+ ovlImpl.superSetLastFocusedItemIndex(index);
+ }
+
+ public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ ovlImpl.superDraw(canvas, mapView, shadow);
+ }
+
+ public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+ ovlImpl.superDrawOverlayBitmap(canvas, drawPosition, projection, drawZoomLevel);
+ }
+
+ public abstract OverlayItemImpl createItem(int index);
+
+ public abstract int size();
+}
diff --git a/src/cgeo/geocaching/mapcommon/MapBase.java b/src/cgeo/geocaching/mapcommon/MapBase.java
new file mode 100644
index 0000000..2340998
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/MapBase.java
@@ -0,0 +1,64 @@
+package cgeo.geocaching.mapcommon;
+
+import cgeo.geocaching.mapinterfaces.ActivityImpl;
+import android.app.Activity;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+
+/**
+ * Base class for the map activity. Delegates base class calls to the
+ * provider-specific implementation.
+ * @author rsudev
+ *
+ */
+public class MapBase {
+
+ ActivityImpl mapActivity;
+
+ public MapBase(ActivityImpl activity) {
+ mapActivity = activity;
+ }
+
+ public Resources getResources() {
+ return mapActivity.getResources();
+ }
+
+ public Activity getActivity() {
+ return mapActivity.getActivity();
+ }
+
+ public void onCreate(Bundle savedInstanceState) {
+ mapActivity.superOnCreate(savedInstanceState);
+ }
+
+ public void onResume() {
+ mapActivity.superOnResume();
+ }
+
+ public void onStop() {
+ mapActivity.superOnResume();
+ }
+
+ public void onPause() {
+ mapActivity.superOnResume();
+ }
+
+ public void onDestroy() {
+ mapActivity.superOnDestroy();
+ }
+
+ public boolean onCreateOptionsMenu(Menu menu) {
+ return mapActivity.superOnCreateOptionsMenu(menu);
+ }
+
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ return mapActivity.superOnPrepareOptionsMenu(menu);
+ }
+
+ public boolean onOptionsItemSelected(MenuItem item) {
+ return mapActivity.superOnOptionsItemSelected(item);
+ }
+
+}
diff --git a/src/cgeo/geocaching/mapcommon/cgMapMyOverlay.java b/src/cgeo/geocaching/mapcommon/cgMapMyOverlay.java
new file mode 100644
index 0000000..3951c14
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/cgMapMyOverlay.java
@@ -0,0 +1,198 @@
+package cgeo.geocaching.mapcommon;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Paint.Style;
+import android.graphics.PaintFlagsDrawFilter;
+import android.location.Location;
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgBase;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapFactory;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+
+import java.util.ArrayList;
+
+public class cgMapMyOverlay implements OverlayBase {
+ private cgSettings settings = null;
+ private Location coordinates = null;
+ private GeoPointImpl location = null;
+ private Double heading = new Double(0);
+ private Paint accuracyCircle = null;
+ private Paint historyLine = null;
+ private Paint historyLineShadow = null;
+ private Point center = new Point();
+ private Point left = new Point();
+ private Bitmap arrow = null;
+ private int widthArrow = 0;
+ private int heightArrow = 0;
+ private PaintFlagsDrawFilter setfil = null;
+ private PaintFlagsDrawFilter remfil = null;
+ private Location historyRecent = null;
+ private ArrayList<Location> history = new ArrayList<Location>();
+ private Point historyPointN = new Point();
+ private Point historyPointP = new Point();
+
+ public cgMapMyOverlay(cgSettings settingsIn) {
+ settings = settingsIn;
+ }
+
+ public void setCoordinates(Location coordinatesIn) {
+ coordinates = coordinatesIn;
+ location = settings.getMapFactory().getGeoPointBase((int)(coordinatesIn.getLatitude() * 1e6), (int)(coordinatesIn.getLongitude() * 1e6));
+ }
+
+ public void setHeading(Double headingIn) {
+ heading = headingIn;
+ }
+
+ @Override
+ public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+
+ drawInternal(canvas, projection);
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+
+ drawInternal(canvas, mapView.getMapProjection());
+ }
+
+ private void drawInternal(Canvas canvas, MapProjectionImpl projection) {
+
+ if (coordinates == null || location == null) return;
+
+ MapFactory mapFactory = settings.getMapFactory();
+
+ if (accuracyCircle == null) {
+ accuracyCircle = new Paint();
+ accuracyCircle.setAntiAlias(true);
+ accuracyCircle.setStrokeWidth(1.0f);
+ }
+
+ if (historyLine == null) {
+ historyLine = new Paint();
+ historyLine.setAntiAlias(true);
+ historyLine.setStrokeWidth(3.0f);
+ historyLine.setColor(0xFFFFFFFF);
+ }
+
+ if (historyLineShadow == null) {
+ historyLineShadow = new Paint();
+ historyLineShadow.setAntiAlias(true);
+ historyLineShadow.setStrokeWidth(7.0f);
+ historyLineShadow.setColor(0x66000000);
+ }
+
+ if (setfil == null) setfil = new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG);
+ if (remfil == null) remfil = new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0);
+
+ canvas.setDrawFilter(setfil);
+
+ double latitude = coordinates.getLatitude();
+ double longitude = coordinates.getLongitude();
+ float accuracy = coordinates.getAccuracy();
+
+ float[] result = new float[1];
+
+ Location.distanceBetween(latitude, longitude, latitude, longitude + 1, result);
+ float longitudeLineDistance = result[0];
+
+ GeoPointImpl leftGeo = mapFactory.getGeoPointBase((int)(latitude * 1e6), (int)((longitude - accuracy / longitudeLineDistance) * 1e6));
+ projection.toPixels(leftGeo, left);
+ projection.toPixels(location, center);
+ int radius = center.x - left.x;
+
+ accuracyCircle.setColor(0x66000000);
+ accuracyCircle.setStyle(Style.STROKE);
+ canvas.drawCircle(center.x, center.y, radius, accuracyCircle);
+
+ accuracyCircle.setColor(0x08000000);
+ accuracyCircle.setStyle(Style.FILL);
+ canvas.drawCircle(center.x, center.y, radius, accuracyCircle);
+
+ if (coordinates.getAccuracy() < 50f && ((historyRecent != null && cgBase.getDistance(historyRecent.getLatitude(), historyRecent.getLongitude(), coordinates.getLatitude(), coordinates.getLongitude()) > 0.005) || historyRecent == null)) {
+ if (historyRecent != null) history.add(historyRecent);
+ historyRecent = coordinates;
+
+ int toRemove = history.size() - 700;
+
+ if (toRemove > 0) {
+ for (int cnt = 0; cnt < toRemove; cnt ++) {
+ history.remove(cnt);
+ }
+ }
+ }
+
+ if (settings.maptrail == 1) {
+ int size = history.size();
+ if (size > 1) {
+ int alpha = 0;
+ int alphaCnt = size - 201;
+ if (alphaCnt < 1) alphaCnt = 1;
+
+ for (int cnt = 1; cnt < size; cnt ++) {
+ Location prev = history.get(cnt - 1);
+ Location now = history.get(cnt);
+
+ if (prev != null && now != null) {
+ projection.toPixels(mapFactory.getGeoPointBase((int)(prev.getLatitude() * 1e6), (int)(prev.getLongitude() * 1e6)), historyPointP);
+ projection.toPixels(mapFactory.getGeoPointBase((int)(now.getLatitude() * 1e6), (int)(now.getLongitude() * 1e6)), historyPointN);
+
+ if ((alphaCnt - cnt) > 0) alpha = Math.round(255 / (alphaCnt - cnt));
+ else alpha = 255;
+
+ historyLineShadow.setAlpha(alpha);
+ historyLine.setAlpha(alpha);
+
+ canvas.drawLine(historyPointP.x, historyPointP.y, historyPointN.x, historyPointN.y, historyLineShadow);
+ canvas.drawLine(historyPointP.x, historyPointP.y, historyPointN.x, historyPointN.y, historyLine);
+ }
+ }
+ }
+
+ if (size > 0) {
+ Location prev = history.get(size - 1);
+ Location now = coordinates;
+
+ if (prev != null && now != null) {
+ projection.toPixels(mapFactory.getGeoPointBase((int)(prev.getLatitude() * 1e6), (int)(prev.getLongitude() * 1e6)), historyPointP);
+ projection.toPixels(mapFactory.getGeoPointBase((int)(now.getLatitude() * 1e6), (int)(now.getLongitude() * 1e6)), historyPointN);
+
+ historyLineShadow.setAlpha(255);
+ historyLine.setAlpha(255);
+
+ canvas.drawLine(historyPointP.x, historyPointP.y, historyPointN.x, historyPointN.y, historyLineShadow);
+ canvas.drawLine(historyPointP.x, historyPointP.y, historyPointN.x, historyPointN.y, historyLine);
+ }
+ }
+ }
+
+ if (arrow == null) {
+ arrow = BitmapFactory.decodeResource(settings.getContext().getResources(), R.drawable.my_location_chevron);
+ widthArrow = arrow.getWidth();
+ heightArrow = arrow.getHeight();
+ }
+
+ int marginLeft;
+ int marginTop;
+
+ marginLeft = center.x - (widthArrow / 2);
+ marginTop = center.y - (heightArrow / 2);
+
+ canvas.rotate(new Float(heading), center.x, center.y);
+ canvas.drawBitmap(arrow, marginLeft, marginTop, null);
+ canvas.rotate(-(new Float(heading)), center.x, center.y);
+
+ canvas.setDrawFilter(remfil);
+
+ //super.draw(canvas, mapView, shadow);
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/mapcommon/cgMapOverlay.java b/src/cgeo/geocaching/mapcommon/cgMapOverlay.java
new file mode 100644
index 0000000..7433ccb
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/cgMapOverlay.java
@@ -0,0 +1,322 @@
+package cgeo.geocaching.mapcommon;
+
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.content.DialogInterface;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.Point;
+import android.location.Location;
+import android.text.Html;
+import android.util.Log;
+import cgeo.geocaching.cgBase;
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.cgeodetail;
+import cgeo.geocaching.cgeonavigate;
+import cgeo.geocaching.cgeopopup;
+import cgeo.geocaching.cgeowaypoint;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.mapinterfaces.MapFactory;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+import cgeo.geocaching.mapinterfaces.CacheOverlayItemImpl;
+
+import java.util.ArrayList;
+
+import org.mapsforge.android.maps.Projection;
+
+public class cgMapOverlay extends ItemizedOverlayBase implements OverlayBase {
+
+ private ArrayList<CacheOverlayItemImpl> items = new ArrayList<CacheOverlayItemImpl>();
+ private Context context = null;
+ private Boolean fromDetail = false;
+ private boolean displayCircles = false;
+ private ProgressDialog waitDialog = null;
+ private Point center = new Point();
+ private Point left = new Point();
+ private Paint blockedCircle = null;
+ private PaintFlagsDrawFilter setfil = null;
+ private PaintFlagsDrawFilter remfil = null;
+ private cgSettings settings;
+
+ public cgMapOverlay(cgSettings settingsIn, ItemizedOverlayImpl ovlImpl, Context contextIn, Boolean fromDetailIn) {
+ super(ovlImpl);
+
+ populate();
+ settings = settingsIn;
+
+ context = contextIn;
+ fromDetail = fromDetailIn;
+ }
+
+ public void updateItems(CacheOverlayItemImpl item) {
+ ArrayList<CacheOverlayItemImpl> itemsPre = new ArrayList<CacheOverlayItemImpl>();
+ itemsPre.add(item);
+
+ updateItems(itemsPre);
+ }
+
+ public void updateItems(ArrayList<CacheOverlayItemImpl> itemsPre) {
+ if (itemsPre == null) {
+ return;
+ }
+
+ for (CacheOverlayItemImpl item : itemsPre) {
+ item.setMarker(boundCenterBottom(item.getMarker(0)));
+ }
+
+// items.clear();
+
+// if (itemsPre.size() > 0) {
+ items = (ArrayList<CacheOverlayItemImpl>) itemsPre.clone();
+// }
+
+ setLastFocusedItemIndex(-1); // to reset tap during data change
+ populate();
+ }
+
+ public boolean getCircles() {
+ return displayCircles;
+ }
+
+ public void switchCircles() {
+ displayCircles = !displayCircles;
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+
+ drawInternal(canvas, mapView.getMapProjection());
+
+ super.draw(canvas, mapView, false);
+ }
+
+ @Override
+ public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+
+ drawInternal(canvas, projection);
+
+ super.drawOverlayBitmap(canvas, drawPosition, projection, drawZoomLevel);
+ }
+
+ private void drawInternal(Canvas canvas, MapProjectionImpl projection) {
+
+ MapFactory mapFactory = settings.getMapFactory();
+
+ if (displayCircles) {
+ if (blockedCircle == null) {
+ blockedCircle = new Paint();
+ blockedCircle.setAntiAlias(true);
+ blockedCircle.setStrokeWidth(1.0f);
+ }
+
+ if (setfil == null) setfil = new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG);
+ if (remfil == null) remfil = new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0);
+
+ canvas.setDrawFilter(setfil);
+
+ for (CacheOverlayItemImpl item : items) {
+ final cgCoord itemCoord = item.getCoord();
+ float[] result = new float[1];
+
+ Location.distanceBetween(itemCoord.latitude, itemCoord.longitude, itemCoord.latitude, itemCoord.longitude + 1, result);
+ final float longitudeLineDistance = result[0];
+
+ GeoPointImpl itemGeo = mapFactory.getGeoPointBase((int)(itemCoord.latitude * 1e6), (int)(itemCoord.longitude * 1e6));
+ GeoPointImpl leftGeo = mapFactory.getGeoPointBase((int)(itemCoord.latitude * 1e6), (int)((itemCoord.longitude - 161 / longitudeLineDistance) * 1e6));
+
+ projection.toPixels(itemGeo, center);
+ projection.toPixels(leftGeo, left);
+ int radius = center.x - left.x;
+
+ final String type = item.getType();
+ if (type == null || "multi".equals(type) || "mystery".equals(type) || "virtual".equals(type)) {
+ blockedCircle.setColor(0x66000000);
+ blockedCircle.setStyle(Style.STROKE);
+ canvas.drawCircle(center.x, center.y, radius, blockedCircle);
+ } else {
+ blockedCircle.setColor(0x66BB0000);
+ blockedCircle.setStyle(Style.STROKE);
+ canvas.drawCircle(center.x, center.y, radius, blockedCircle);
+
+ blockedCircle.setColor(0x44BB0000);
+ blockedCircle.setStyle(Style.FILL);
+ canvas.drawCircle(center.x, center.y, radius, blockedCircle);
+ }
+ }
+
+ canvas.setDrawFilter(remfil);
+ }
+ }
+
+ @Override
+ public boolean onTap(int index) {
+ try {
+ if (items.size() <= index) {
+ return false;
+ }
+
+ if (waitDialog == null) {
+ waitDialog = new ProgressDialog(context);
+ waitDialog.setMessage("loading details...");
+ waitDialog.setCancelable(false);
+ }
+ waitDialog.show();
+
+ CacheOverlayItemImpl item = items.get(index);
+ cgCoord coordinate = item.getCoord();
+
+ if (coordinate.type != null && coordinate.type.equalsIgnoreCase("cache") == true && coordinate.geocode != null && coordinate.geocode.length() > 0) {
+ Intent popupIntent = new Intent(context, cgeopopup.class);
+
+ popupIntent.putExtra("fromdetail", fromDetail);
+ popupIntent.putExtra("geocode", coordinate.geocode);
+
+ context.startActivity(popupIntent);
+ } else if (coordinate.type != null && coordinate.type.equalsIgnoreCase("waypoint") == true && coordinate.id != null && coordinate.id > 0) {
+ Intent popupIntent = new Intent(context, cgeowaypoint.class);
+
+ popupIntent.putExtra("waypoint", coordinate.id);
+ popupIntent.putExtra("geocode", coordinate.geocode);
+
+ context.startActivity(popupIntent);
+ } else {
+ waitDialog.dismiss();
+ return false;
+ }
+
+ waitDialog.dismiss();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapOverlay.onTap: " + e.toString());
+ }
+
+ return false;
+ }
+
+ @Override
+ public CacheOverlayItemImpl createItem(int index) {
+ try {
+ return items.get(index);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapOverlay.createItem: " + e.toString());
+ }
+
+ return null;
+ }
+
+ @Override
+ public int size() {
+ try {
+ return items.size();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapOverlay.size: " + e.toString());
+ }
+
+ return 0;
+ }
+
+ public void infoDialog(int index) {
+ final CacheOverlayItemImpl item = items.get(index);
+ final cgCoord coordinate = item.getCoord();
+
+ if (coordinate == null) {
+ Log.e(cgSettings.tag, "cgMapOverlay:infoDialog: No coordinates given");
+ return;
+ }
+
+ try {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(context);
+ dialog.setCancelable(true);
+
+ if (coordinate.type.equalsIgnoreCase("cache")) {
+ dialog.setTitle("cache");
+
+ String cacheType;
+ if (cgBase.cacheTypesInv.containsKey(coordinate.typeSpec) == true) {
+ cacheType = cgBase.cacheTypesInv.get(coordinate.typeSpec);
+ } else {
+ cacheType = cgBase.cacheTypesInv.get("mystery");
+ }
+
+ dialog.setMessage(Html.fromHtml(item.getTitle()) + "\n\ngeocode: " + coordinate.geocode.toUpperCase() + "\ntype: " + cacheType);
+ if (fromDetail == false) {
+ dialog.setPositiveButton("detail", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ Intent cachesIntent = new Intent(context, cgeodetail.class);
+ cachesIntent.putExtra("geocode", coordinate.geocode.toUpperCase());
+ context.startActivity(cachesIntent);
+
+ dialog.cancel();
+ }
+ });
+ } else {
+ dialog.setPositiveButton("navigate", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ cgeonavigate navigateActivity = new cgeonavigate();
+
+ cgeonavigate.coordinates = new ArrayList<cgCoord>();
+ cgeonavigate.coordinates.add(coordinate);
+
+ Intent navigateIntent = new Intent(context, navigateActivity.getClass());
+ navigateIntent.putExtra("latitude", coordinate.latitude);
+ navigateIntent.putExtra("longitude", coordinate.longitude);
+ navigateIntent.putExtra("geocode", coordinate.geocode.toUpperCase());
+ context.startActivity(navigateIntent);
+ dialog.cancel();
+ }
+ });
+ }
+ } else {
+ dialog.setTitle("waypoint");
+
+ String waypointType;
+ if (cgBase.cacheTypesInv.containsKey(coordinate.typeSpec) == true) {
+ waypointType = cgBase.waypointTypes.get(coordinate.typeSpec);
+ } else {
+ waypointType = cgBase.waypointTypes.get("waypoint");
+ }
+
+ dialog.setMessage(Html.fromHtml(item.getTitle()) + "\n\ntype: " + waypointType);
+ dialog.setPositiveButton("navigate", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ cgeonavigate navigateActivity = new cgeonavigate();
+
+ cgeonavigate.coordinates = new ArrayList<cgCoord>();
+ cgeonavigate.coordinates.add(coordinate);
+
+ Intent navigateIntent = new Intent(context, navigateActivity.getClass());
+ navigateIntent.putExtra("latitude", coordinate.latitude);
+ navigateIntent.putExtra("longitude", coordinate.longitude);
+ navigateIntent.putExtra("geocode", coordinate.name);
+
+ context.startActivity(navigateIntent);
+ dialog.cancel();
+ }
+ });
+ }
+
+ dialog.setNegativeButton("dismiss", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapOverlay.infoDialog: " + e.toString());
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/mapcommon/cgOverlayScale.java b/src/cgeo/geocaching/mapcommon/cgOverlayScale.java
new file mode 100644
index 0000000..1e4a6e6
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/cgOverlayScale.java
@@ -0,0 +1,140 @@
+package cgeo.geocaching.mapcommon;
+
+import android.app.Activity;
+import android.graphics.BlurMaskFilter;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Typeface;
+import android.util.DisplayMetrics;
+import cgeo.geocaching.cgBase;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+
+public class cgOverlayScale implements OverlayBase {
+ private cgSettings settings = null;
+ private Paint scale = null;
+ private Paint scaleShadow = null;
+ private BlurMaskFilter blur = null;
+ private float pixelDensity = 0l;
+ private double pixels = 0d;
+ private int bottom = 0;
+ private double distance = 0d;
+ private double distanceRound = 0d;
+ private String units = null;
+
+ public cgOverlayScale(Activity activity, cgSettings settingsIn) {
+ settings = settingsIn;
+
+ DisplayMetrics metrics = new DisplayMetrics();
+ activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ pixelDensity = metrics.density;
+ }
+
+ @Override
+ public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ //super.draw(canvas, mapView, shadow);
+
+ final double span = mapView.getLongitudeSpan() / 1e6;
+ final GeoPointImpl center = mapView.getMapViewCenter();
+
+ pixels = mapView.getWidth() / 2; // pixels related to following latitude span
+ bottom = mapView.getHeight() - 14; // pixels from bottom side of screen
+ distance = cgBase.getDistance((center.getLatitudeE6() / 1e6), ((center.getLongitudeE6() / 1e6) - (span /2)), (center.getLatitudeE6() / 1e6), ((center.getLongitudeE6() / 1e6) + (span /2)));
+ distance = distance / 2;
+ distanceRound = 0d;
+
+ if(settings.units == cgSettings.unitsImperial) {
+ distance *= cgBase.kmInMiles;
+
+ if (distance > 100) { // 100+ mi > 1xx mi
+ distanceRound = Math.floor(distance / 100) * 100;
+ units = "mi";
+ } else if (distance > 10) { // 10 - 100 mi > 1x mi
+ distanceRound = Math.floor(distance / 10) * 10;
+ units = "mi";
+ } else if (distance > 1) { // 1 - 10 mi > 1.x mi
+ distanceRound = Math.floor(distance);
+ units = "mi";
+ } else if (distance > 0.1) { // 0.1 mi - 1.0 mi > 1xx ft
+ distance *= 5280;
+ distanceRound = Math.floor(distance / 100) * 100;
+ units = "ft";
+ } else { // 1 - 100 ft > 1x ft
+ distance *= 5280;
+ distanceRound = Math.round(distance / 10) * 10;
+ units = "ft";
+ }
+ } else {
+ if (distance > 100) { // 100+ km > 1xx km
+ distanceRound = Math.floor(distance / 100) * 100;
+ units = "km";
+ } else if (distance > 10) { // 10 - 100 km > 1x km
+ distanceRound = Math.floor(distance / 10) * 10;
+ units = "km";
+ } else if (distance > 1) { // 1 - 10 km > 1.x km
+ distanceRound = Math.floor(distance);
+ units = "km";
+ } else if (distance > 0.1) { // 100 m - 1 km > 1xx m
+ distance *= 1000;
+ distanceRound = Math.floor(distance / 100) * 100;
+ units = "m";
+ } else { // 1 - 100 m > 1x m
+ distance *= 1000;
+ distanceRound = Math.round(distance / 10) * 10;
+ units = "m";
+ }
+ }
+
+ pixels = Math.round((pixels / distance) * distanceRound);
+
+ if (blur == null) {
+ blur = new BlurMaskFilter(3, BlurMaskFilter.Blur.NORMAL);
+ }
+
+ if (scaleShadow == null) {
+ scaleShadow = new Paint();
+ scaleShadow.setAntiAlias(true);
+ scaleShadow.setStrokeWidth(4 * pixelDensity);
+ scaleShadow.setMaskFilter(blur);
+ scaleShadow.setTextSize(14 * pixelDensity);
+ scaleShadow.setTypeface(Typeface.DEFAULT_BOLD);
+ }
+
+ if (scale == null) {
+ scale = new Paint();
+ scale.setAntiAlias(true);
+ scale.setStrokeWidth(2 * pixelDensity);
+ scale.setTextSize(14 * pixelDensity);
+ scale.setTypeface(Typeface.DEFAULT_BOLD);
+ }
+
+ if (mapView.isSatellite()) {
+ scaleShadow.setColor(0xFF000000);
+ scale.setColor(0xFFFFFFFF);
+ } else {
+ scaleShadow.setColor(0xFFFFFFFF);
+ scale.setColor(0xFF000000);
+ }
+
+ canvas.drawLine(10, bottom, 10, (bottom - (8 * pixelDensity)), scaleShadow);
+ canvas.drawLine((int)(pixels + 10), bottom, (int)(pixels + 10), (bottom - (8 * pixelDensity)), scaleShadow);
+ canvas.drawLine(8, bottom, (int)(pixels + 12), bottom, scaleShadow);
+ canvas.drawText(String.format("%.0f", distanceRound) + " " + units, (float)(pixels - (10 * pixelDensity)), (bottom - (10 * pixelDensity)), scaleShadow);
+
+ canvas.drawLine(11, bottom, 11, (bottom - (6 * pixelDensity)), scale);
+ canvas.drawLine((int)(pixels + 9), bottom, (int)(pixels + 9), (bottom - (6 * pixelDensity)), scale);
+ canvas.drawLine(10, bottom, (int)(pixels + 10), bottom, scale);
+ canvas.drawText(String.format("%.0f", distanceRound) + " " + units, (float)(pixels - (10 * pixelDensity)), (bottom - (10 * pixelDensity)), scale);
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/mapcommon/cgUsersOverlay.java b/src/cgeo/geocaching/mapcommon/cgUsersOverlay.java
new file mode 100644
index 0000000..8eb76cd
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/cgUsersOverlay.java
@@ -0,0 +1,185 @@
+package cgeo.geocaching.mapcommon;
+
+import java.util.ArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.util.Log;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.cgeodetail;
+import cgeo.geocaching.mapinterfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.UserOverlayItemImpl;
+
+public class cgUsersOverlay extends ItemizedOverlayBase implements OverlayBase {
+
+ private ArrayList<UserOverlayItemImpl> items = new ArrayList<UserOverlayItemImpl>();
+ private Context context = null;
+ private final Pattern patternGeocode = Pattern.compile("^(GC[A-Z0-9]+)(\\: ?(.+))?$", Pattern.CASE_INSENSITIVE);
+
+ public cgUsersOverlay(ItemizedOverlayImpl ovlImplIn, Context contextIn) {
+ super(ovlImplIn);
+ populate();
+
+ context = contextIn;
+ }
+
+ protected void updateItems(UserOverlayItemImpl item) {
+ ArrayList<UserOverlayItemImpl> itemsPre = new ArrayList<UserOverlayItemImpl>();
+ itemsPre.add(item);
+
+ updateItems(itemsPre);
+ }
+
+ public void updateItems(ArrayList<UserOverlayItemImpl> itemsPre) {
+ if (itemsPre == null) {
+ return;
+ }
+
+ for (UserOverlayItemImpl item : itemsPre) {
+ item.setMarker(boundCenter(item.getMarker(0)));
+ }
+
+ items.clear();
+
+ if (itemsPre.size() > 0) {
+ items = (ArrayList<UserOverlayItemImpl>) itemsPre.clone();
+ }
+
+ setLastFocusedItemIndex(-1); // to reset tap during data change
+ populate();
+ }
+
+ @Override
+ public boolean onTap(int index) {
+ try {
+ if (items.size() <= index) {
+ return false;
+ }
+
+ final UserOverlayItemImpl item = items.get(index);
+ final cgUser user = item.getUser();
+
+ // set action
+ String action = null;
+ String geocode = null;
+ final Matcher matcherGeocode = patternGeocode.matcher(user.action.trim());
+
+ if (user.action.length() == 0 || user.action.equalsIgnoreCase("pending")) {
+ action = "Looking around";
+ } else if (user.action.equalsIgnoreCase("tweeting")) {
+ action = "Tweeting";
+ } else if (matcherGeocode.find() == true) {
+ if (matcherGeocode.group(1) != null) {
+ geocode = matcherGeocode.group(1).trim().toUpperCase();
+ }
+ if (matcherGeocode.group(3) != null) {
+ action = "Heading to " + geocode + " (" + matcherGeocode.group(3).trim() + ")";
+ } else {
+ action = "Heading to " + geocode;
+ }
+ } else {
+ action = user.action;
+ }
+
+ // set icon
+ int icon = -1;
+ if (user.client.equalsIgnoreCase("c:geo") == true) {
+ icon = R.drawable.client_cgeo;
+ } else if (user.client.equalsIgnoreCase("preCaching") == true) {
+ icon = R.drawable.client_precaching;
+ } else if (user.client.equalsIgnoreCase("Handy Geocaching") == true) {
+ icon = R.drawable.client_handygeocaching;
+ }
+
+ final AlertDialog.Builder dialog = new AlertDialog.Builder(context);
+ if (icon > -1) {
+ dialog.setIcon(icon);
+ }
+ dialog.setTitle(user.username);
+ dialog.setMessage(action);
+ dialog.setCancelable(true);
+ if (geocode != null && geocode.length() > 0) {
+ dialog.setPositiveButton(geocode + "?", new cacheDetails(geocode));
+ }
+ dialog.setNeutralButton("Dismiss", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+
+ return true;
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgUsersOverlay.onTap: " + e.toString());
+ }
+
+ return false;
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ super.draw(canvas, mapView, false);
+ }
+
+ @Override
+ public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+ super.drawOverlayBitmap(canvas, drawPosition, projection, drawZoomLevel);
+ }
+
+ @Override
+ public UserOverlayItemImpl createItem(int index) {
+ try {
+ return items.get(index);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgUsersOverlay.createItem: " + e.toString());
+ }
+
+ return null;
+ }
+
+ @Override
+ public int size() {
+ try {
+ return items.size();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgUsersOverlay.size: " + e.toString());
+ }
+
+ return 0;
+ }
+
+ private class cacheDetails implements DialogInterface.OnClickListener {
+
+ private String geocode = null;
+
+ public cacheDetails(String geocodeIn) {
+ geocode = geocodeIn;
+ }
+
+ public void onClick(DialogInterface dialog, int id) {
+ if (geocode != null) {
+ Intent detailIntent = new Intent(context, cgeodetail.class);
+ detailIntent.putExtra("geocode", geocode);
+ context.startActivity(detailIntent);
+ }
+
+ dialog.cancel();
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/mapcommon/cgeomap.java b/src/cgeo/geocaching/mapcommon/cgeomap.java
new file mode 100644
index 0000000..7ba7532
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/cgeomap.java
@@ -0,0 +1,1686 @@
+package cgeo.geocaching.mapcommon;
+
+import gnu.android.app.appmanualclient.*;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import java.util.ArrayList;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgBase;
+import cgeo.geocaching.cgCache;
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.cgDirection;
+import cgeo.geocaching.cgGeo;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.cgUpdateDir;
+import cgeo.geocaching.cgUpdateLoc;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.cgWarning;
+import cgeo.geocaching.cgWaypoint;
+import cgeo.geocaching.cgeoapplication;
+import cgeo.geocaching.mapinterfaces.ActivityImpl;
+import cgeo.geocaching.mapinterfaces.CacheOverlayItemImpl;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapControllerImpl;
+import cgeo.geocaching.mapinterfaces.MapFactory;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+import cgeo.geocaching.mapinterfaces.UserOverlayItemImpl;
+
+import android.util.Log;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.ImageView;
+import cgeo.geocaching.cgSearch;
+
+import java.util.HashMap;
+import java.util.Locale;
+
+public class cgeomap extends MapBase {
+
+ private Resources res = null;
+ private Activity activity = null;
+ private MapViewImpl mapView = null;
+ private MapControllerImpl mapController = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private cgeoapplication app = null;
+ private SharedPreferences.Editor prefsEdit = null;
+ private cgGeo geo = null;
+ private cgDirection dir = null;
+ private cgUpdateLoc geoUpdate = new UpdateLoc();
+ private cgUpdateDir dirUpdate = new UpdateDir();
+ // from intent
+ private boolean fromDetailIntent = false;
+ private Long searchIdIntent = null;
+ private String geocodeIntent = null;
+ private Double latitudeIntent = null;
+ private Double longitudeIntent = null;
+ private String waypointTypeIntent = null;
+ // status data
+ private Long searchId = null;
+ private String token = null;
+ private boolean noMapTokenShowed = false;
+ // map status data
+ private boolean followMyLocation = false;
+ private Integer centerLatitude = null;
+ private Integer centerLongitude = null;
+ private Integer spanLatitude = null;
+ private Integer spanLongitude = null;
+ private Integer centerLatitudeUsers = null;
+ private Integer centerLongitudeUsers = null;
+ private Integer spanLatitudeUsers = null;
+ private Integer spanLongitudeUsers = null;
+ // thread
+ private LoadTimer loadTimer = null;
+ private UsersTimer usersTimer = null;
+ private LoadThread loadThread = null;
+ private DownloadThread downloadThread = null;
+ private DisplayThread displayThread = null;
+ private UsersThread usersThread = null;
+ private DisplayUsersThread displayUsersThread = null;
+ private LoadDetails loadDetailsThread = null;
+ private volatile long loadThreadRun = 0l;
+ private volatile long downloadThreadRun = 0l;
+ private volatile long usersThreadRun = 0l;
+ private volatile boolean downloaded = false;
+ // overlays
+ private cgMapOverlay overlayCaches = null;
+ private cgUsersOverlay overlayUsers = null;
+ private cgOverlayScale overlayScale = null;
+ private cgMapMyOverlay overlayMyLoc = null;
+ // data for overlays
+ private int cachesCnt = 0;
+ private HashMap<Integer, Drawable> iconsCache = new HashMap<Integer, Drawable>();
+ private ArrayList<cgCache> caches = new ArrayList<cgCache>();
+ private ArrayList<cgUser> users = new ArrayList<cgUser>();
+ private ArrayList<cgCoord> coordinates = new ArrayList<cgCoord>();
+ // storing for offline
+ private ProgressDialog waitDialog = null;
+ private int detailTotal = 0;
+ private int detailProgress = 0;
+ private Long detailProgressTime = 0l;
+ // views
+ private ImageView myLocSwitch = null;
+ // other things
+ private boolean live = true; // live map (live, dead) or rest (displaying caches on map)
+ private boolean liveChanged = false; // previous state for loadTimer
+ private boolean centered = false; // if map is already centered
+ private boolean alreadyCentered = false; // -""- for setting my location
+ // handlers
+ final private Handler displayHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ final int what = msg.what;
+
+ if (what == 0) {
+ // set title
+ final StringBuilder title = new StringBuilder();
+
+ if (live == true) {
+ title.append(res.getString(R.string.map_live));
+ } else {
+ title.append(res.getString(R.string.map_map));
+ }
+
+ if (caches != null && cachesCnt > 0) {
+ title.append(" ");
+ title.append("[");
+ title.append(caches.size());
+ title.append("]");
+ }
+
+ base.setTitle(activity, title.toString());
+ } else if (what == 1 && mapView != null) {
+ mapView.invalidate();
+ }
+ }
+ };
+ final private Handler showProgressHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ final int what = msg.what;
+
+ if (what == 0) {
+ base.showProgress(activity, false);
+ } else if (what == 1) {
+ base.showProgress(activity, true);
+ }
+ }
+ };
+ final private Handler loadDetailsHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == 0) {
+ if (waitDialog != null) {
+ Float diffTime = new Float((System.currentTimeMillis() - detailProgressTime) / 1000); // seconds left
+ Float oneCache = diffTime / detailProgress; // left time per cache
+ Float etaTime = (detailTotal - detailProgress) * oneCache; // seconds remaining
+
+ waitDialog.setProgress(detailProgress);
+ if (etaTime < 40) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + res.getString(R.string.caches_eta_ltm));
+ } else if (etaTime < 90) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + String.format(Locale.getDefault(), "%.0f", (etaTime / 60)) + " " + res.getString(R.string.caches_eta_min));
+ } else {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + String.format(Locale.getDefault(), "%.0f", (etaTime / 60)) + " " + res.getString(R.string.caches_eta_mins));
+ }
+ }
+ } else {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog.setOnCancelListener(null);
+ }
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+ }
+ }
+ };
+ final private Handler noMapTokenHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (!noMapTokenShowed) {
+ warning.showToast(res.getString(R.string.map_token_err));
+
+ noMapTokenShowed = true;
+ }
+ }
+ };
+
+ public cgeomap(ActivityImpl activity) {
+ super(activity);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // class init
+ res = this.getResources();
+ activity = this.getActivity();
+ app = (cgeoapplication) activity.getApplication();
+ app.setAction(null);
+ settings = new cgSettings(activity, activity.getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, activity.getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(activity);
+ prefsEdit = activity.getSharedPreferences(cgSettings.preferences, 0).edit();
+ MapFactory mapFactory = settings.getMapFactory();
+
+ // reset status
+ noMapTokenShowed = false;
+
+ // set layout
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ // set layout
+ if (settings.skin == 1) {
+ activity.setTheme(R.style.light);
+ } else {
+ activity.setTheme(R.style.dark);
+ }
+ activity.setContentView(settings.getMapFactory().getMapLayoutId());
+ base.setTitle(activity, res.getString(R.string.map_map));
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+
+ mapView = (MapViewImpl) activity.findViewById(mapFactory.getMapViewId());
+ mapView.setMapSource(settings);
+ if (!mapView.needsScaleOverlay()) {
+ mapView.setBuiltinScale(true);
+ }
+
+ // initialize map
+ if (settings.maptype == cgSettings.mapSatellite) {
+ mapView.setSatellite(true);
+ } else {
+ mapView.setSatellite(false);
+ }
+ mapView.setBuiltInZoomControls(true);
+ mapView.displayZoomControls(true);
+ mapView.preLoad();
+
+ // initialize overlays
+ mapView.clearOverlays();
+
+ if (overlayMyLoc == null) {
+ overlayMyLoc = new cgMapMyOverlay(settings);
+ mapView.addOverlay(mapFactory.getOverlayBaseWrapper(overlayMyLoc));
+ }
+
+ if (settings.publicLoc > 0 && overlayUsers == null) {
+ overlayUsers = mapView.createAddUsersOverlay(activity, getResources().getDrawable(R.drawable.user_location));
+ }
+
+ if (overlayCaches == null) {
+ overlayCaches = mapView.createAddMapOverlay(settings, mapView.getContext(), getResources().getDrawable(R.drawable.marker), fromDetailIntent);
+ }
+
+ if (overlayScale == null && mapView.needsScaleOverlay()) {
+ overlayScale = new cgOverlayScale(activity, settings);
+ mapView.addOverlay(mapFactory.getOverlayBaseWrapper(overlayScale));
+ }
+
+ mapView.invalidate();
+
+ mapController = mapView.getMapController();
+ mapController.setZoom(settings.mapzoom);
+
+ // start location and directory services
+ if (geo != null) {
+ geoUpdate.updateLoc(geo);
+ }
+ if (dir != null) {
+ dirUpdate.updateDir(dir);
+ }
+
+ // get parameters
+ Bundle extras = activity.getIntent().getExtras();
+ if (extras != null) {
+ fromDetailIntent = extras.getBoolean("detail");
+ searchIdIntent = extras.getLong("searchid");
+ geocodeIntent = extras.getString("geocode");
+ latitudeIntent = extras.getDouble("latitude");
+ longitudeIntent = extras.getDouble("longitude");
+ waypointTypeIntent = extras.getString("wpttype");
+
+ if (searchIdIntent == 0l) {
+ searchIdIntent = null;
+ }
+ if (latitudeIntent == 0.0) {
+ latitudeIntent = null;
+ }
+ if (longitudeIntent == 0.0) {
+ longitudeIntent = null;
+ }
+ }
+
+ // live or death
+ if (searchIdIntent == null && geocodeIntent == null && (latitudeIntent == null || longitudeIntent == null)) {
+ live = true;
+ } else {
+ live = false;
+ }
+
+ // google analytics
+ if (live) {
+ base.sendAnal(activity, "/map/live");
+
+ followMyLocation = true;
+ } else {
+ base.sendAnal(activity, "/map/normal");
+
+ followMyLocation = false;
+
+ if (geocodeIntent != null || searchIdIntent != null || (latitudeIntent != null && longitudeIntent != null)) {
+ centerMap(geocodeIntent, searchIdIntent, latitudeIntent, longitudeIntent);
+ }
+ }
+ setMyLoc(null);
+ startTimer();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+
+ app.setAction(null);
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+
+ if (geo != null) {
+ geoUpdate.updateLoc(geo);
+ }
+ if (dir != null) {
+ dirUpdate.updateDir(dir);
+ }
+
+ startTimer();
+ }
+
+ @Override
+ public void onStop() {
+ if (loadTimer != null) {
+ loadTimer.stopIt();
+ loadTimer = null;
+ }
+
+ if (usersTimer != null) {
+ usersTimer.stopIt();
+ usersTimer = null;
+ }
+
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ savePrefs();
+
+ if (mapView != null) {
+ mapView.destroyDrawingCache();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (loadTimer != null) {
+ loadTimer.stopIt();
+ loadTimer = null;
+ }
+
+ if (usersTimer != null) {
+ usersTimer.stopIt();
+ usersTimer = null;
+ }
+
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ savePrefs();
+
+ if (mapView != null) {
+ mapView.destroyDrawingCache();
+ }
+
+ super.onPause();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (loadTimer != null) {
+ loadTimer.stopIt();
+ loadTimer = null;
+ }
+
+ if (usersTimer != null) {
+ usersTimer.stopIt();
+ usersTimer = null;
+ }
+
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ savePrefs();
+
+ if (mapView != null) {
+ mapView.destroyDrawingCache();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(0, 1, 0, res.getString(R.string.caches_on_map)).setIcon(android.R.drawable.ic_menu_mapmode);
+ menu.add(0, 3, 0, res.getString(R.string.map_live_disable)).setIcon(android.R.drawable.ic_menu_close_clear_cancel);
+ menu.add(0, 4, 0, res.getString(R.string.caches_store_offline)).setIcon(android.R.drawable.ic_menu_set_as).setEnabled(false);
+ menu.add(0, 2, 0, res.getString(R.string.map_trail_hide)).setIcon(android.R.drawable.ic_menu_recent_history);
+ menu.add(0, 5, 0, res.getString(R.string.map_circles_hide)).setIcon(android.R.drawable.ic_menu_view);
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+
+ MenuItem item;
+ try {
+ item = menu.findItem(1); // view
+ if (mapView != null && mapView.isSatellite() == false) {
+ item.setTitle(res.getString(R.string.map_view_satellite));
+ } else {
+ item.setTitle(res.getString(R.string.map_view_map));
+ }
+
+ item = menu.findItem(2); // show trail
+ if (settings.maptrail == 1) {
+ item.setTitle(res.getString(R.string.map_trail_hide));
+ } else {
+ item.setTitle(res.getString(R.string.map_trail_show));
+ }
+
+ item = menu.findItem(3); // live map
+ if (live == false) {
+ item.setEnabled(false);
+ item.setTitle(res.getString(R.string.map_live_enable));
+ } else {
+ if (settings.maplive == 1) {
+ item.setTitle(res.getString(R.string.map_live_disable));
+ } else {
+ item.setTitle(res.getString(R.string.map_live_enable));
+ }
+ }
+
+ item = menu.findItem(4); // store loaded
+ if (live && !isLoading() && app.getNotOfflineCount(searchId) > 0 && caches != null && caches.size() > 0) {
+ item.setEnabled(true);
+ } else {
+ item.setEnabled(false);
+ }
+
+ item = menu.findItem(5); // show circles
+ if (overlayCaches != null && overlayCaches.getCircles()) {
+ item.setTitle(res.getString(R.string.map_circles_hide));
+ } else {
+ item.setTitle(res.getString(R.string.map_circles_show));
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeomap.onPrepareOptionsMenu: " + e.toString());
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ final int id = item.getItemId();
+
+ if (id == 1) {
+ if (mapView != null && mapView.isSatellite() == false) {
+ mapView.setSatellite(true);
+
+ prefsEdit.putInt("maptype", cgSettings.mapSatellite);
+ prefsEdit.commit();
+ } else {
+ mapView.setSatellite(false);
+
+ prefsEdit.putInt("maptype", cgSettings.mapClassic);
+ prefsEdit.commit();
+ }
+
+ return true;
+ } else if (id == 2) {
+ if (settings.maptrail == 1) {
+ prefsEdit.putInt("maptrail", 0);
+ prefsEdit.commit();
+
+ settings.maptrail = 0;
+ } else {
+ prefsEdit.putInt("maptrail", 1);
+ prefsEdit.commit();
+
+ settings.maptrail = 1;
+ }
+ } else if (id == 3) {
+ if (settings.maplive == 1) {
+ settings.liveMapDisable();
+ } else {
+ settings.liveMapEnable();
+ }
+ liveChanged = true;
+ searchId = null;
+ searchIdIntent = null;
+ } else if (id == 4) {
+ if (live && !isLoading() && caches != null && !caches.isEmpty()) {
+ final ArrayList<String> geocodes = new ArrayList<String>();
+
+ ArrayList<cgCache> cachesProtected = (ArrayList<cgCache>) caches.clone();
+ try {
+ if (cachesProtected != null && cachesProtected.size() > 0) {
+ final GeoPointImpl mapCenter = mapView.getMapViewCenter();
+ final int mapCenterLat = mapCenter.getLatitudeE6();
+ final int mapCenterLon = mapCenter.getLongitudeE6();
+ final int mapSpanLat = mapView.getLatitudeSpan();
+ final int mapSpanLon = mapView.getLongitudeSpan();
+
+ for (cgCache oneCache : cachesProtected) {
+ if (oneCache != null && oneCache.latitude != null && oneCache.longitude != null) {
+ if (base.isCacheInViewPort(mapCenterLat, mapCenterLon, mapSpanLat, mapSpanLon, oneCache.latitude, oneCache.longitude) && app.isOffline(oneCache.geocode, null) == false) {
+ geocodes.add(oneCache.geocode);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeomap.onOptionsItemSelected.#4: " + e.toString());
+ }
+
+ detailTotal = geocodes.size();
+
+ if (detailTotal == 0) {
+ warning.showToast(res.getString(R.string.warn_save_nothing));
+
+ return true;
+ }
+
+ waitDialog = new ProgressDialog(activity);
+ waitDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ waitDialog.setCancelable(true);
+ waitDialog.setMax(detailTotal);
+ waitDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+
+ public void onCancel(DialogInterface arg0) {
+ try {
+ if (loadDetailsThread != null) {
+ loadDetailsThread.stopIt();
+ }
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.onPrepareOptionsMenu.onCancel: " + e.toString());
+ }
+ }
+ });
+
+ Float etaTime = new Float((detailTotal * (float) 7) / 60);
+ if (etaTime < 0.4) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + res.getString(R.string.caches_eta_ltm));
+ } else if (etaTime < 1.5) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + String.format(Locale.getDefault(), "%.0f", etaTime) + " " + res.getString(R.string.caches_eta_min));
+ } else {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + String.format(Locale.getDefault(), "%.0f", etaTime) + " " + res.getString(R.string.caches_eta_mins));
+ }
+ waitDialog.show();
+
+ detailProgressTime = System.currentTimeMillis();
+
+ loadDetailsThread = new LoadDetails(loadDetailsHandler, geocodes);
+ loadDetailsThread.start();
+
+ return true;
+ }
+ } else if (id == 5) {
+ if (overlayCaches == null) {
+ return false;
+ }
+
+ overlayCaches.switchCircles();
+ }
+
+ return false;
+ }
+
+ private void savePrefs() {
+ if (mapView == null) {
+ return;
+ }
+
+ if (mapView.isSatellite()) {
+ prefsEdit.putInt("maptype", cgSettings.mapSatellite);
+ settings.maptype = cgSettings.mapSatellite;
+ } else {
+ prefsEdit.putInt("maptype", cgSettings.mapClassic);
+ settings.maptype = cgSettings.mapClassic;
+ }
+
+ if (prefsEdit == null) {
+ prefsEdit = activity.getSharedPreferences(cgSettings.preferences, 0).edit();
+ }
+ prefsEdit.putInt("mapzoom", mapView.getMapZoomLevel());
+ prefsEdit.commit();
+ }
+
+ // set center of map to my location
+ private void myLocationInMiddle() {
+ if (geo == null) {
+ return;
+ }
+ if (!followMyLocation) {
+ return;
+ }
+
+ centerMap(geo.latitudeNow, geo.longitudeNow);
+ }
+
+ // class: update location
+ private class UpdateLoc extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+
+ try {
+ if (overlayMyLoc == null && mapView != null) {
+ overlayMyLoc = new cgMapMyOverlay(settings);
+ mapView.addOverlay(settings.getMapFactory().getOverlayBaseWrapper(overlayMyLoc));
+ }
+
+ if (overlayMyLoc != null && geo.location != null) {
+ overlayMyLoc.setCoordinates(geo.location);
+ }
+
+ if (geo.latitudeNow != null && geo.longitudeNow != null) {
+ if (followMyLocation == true) {
+ myLocationInMiddle();
+ }
+ }
+
+ if (settings.useCompass == 0 || (geo.speedNow != null && geo.speedNow > 5)) { // use GPS when speed is higher than 18 km/h
+ if (geo.bearingNow != null) {
+ overlayMyLoc.setHeading(geo.bearingNow);
+ } else {
+ overlayMyLoc.setHeading(new Double(0));
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ // class: update direction
+ private class UpdateDir extends cgUpdateDir {
+
+ @Override
+ public void updateDir(cgDirection dir) {
+ if (dir == null || dir.directionNow == null) {
+ return;
+ }
+
+ if (overlayMyLoc != null && mapView != null && (geo == null || geo.speedNow == null || geo.speedNow <= 5)) { // use compass when speed is lower than 18 km/h
+ overlayMyLoc.setHeading(dir.directionNow);
+ mapView.invalidate();
+ }
+ }
+ }
+
+ public void startTimer() {
+ if (latitudeIntent != null && longitudeIntent != null) {
+ // display just one point
+ (new DisplayPointThread()).start();
+ } else {
+ // start timer
+ if (loadTimer != null) {
+ loadTimer.stopIt();
+ loadTimer = null;
+ }
+ loadTimer = new LoadTimer();
+ loadTimer.start();
+ }
+
+ if (settings.publicLoc > 0) {
+ if (usersTimer != null) {
+ usersTimer.stopIt();
+ usersTimer = null;
+ }
+ usersTimer = new UsersTimer();
+ usersTimer.start();
+ }
+ }
+
+ // loading timer
+ private class LoadTimer extends Thread {
+
+ private volatile boolean stop = false;
+
+ public void stopIt() {
+ stop = true;
+
+ if (loadThread != null) {
+ loadThread.stopIt();
+ loadThread = null;
+ }
+
+ if (downloadThread != null) {
+ downloadThread.stopIt();
+ downloadThread = null;
+ }
+
+ if (displayThread != null) {
+ displayThread.stopIt();
+ displayThread = null;
+ }
+ }
+
+ @Override
+ public void run() {
+ GeoPointImpl mapCenterNow;
+ int centerLatitudeNow;
+ int centerLongitudeNow;
+ int spanLatitudeNow;
+ int spanLongitudeNow;
+ boolean moved = false;
+ boolean force = false;
+ long currentTime = 0;
+
+ while (!stop) {
+ try {
+ sleep(250);
+
+ if (mapView != null) {
+ // get current viewport
+ mapCenterNow = mapView.getMapViewCenter();
+ centerLatitudeNow = mapCenterNow.getLatitudeE6();
+ centerLongitudeNow = mapCenterNow.getLongitudeE6();
+ spanLatitudeNow = mapView.getLatitudeSpan();
+ spanLongitudeNow = mapView.getLongitudeSpan();
+
+ // check if map moved or zoomed
+ moved = false;
+ force = false;
+
+ if (liveChanged) {
+ moved = true;
+ force = true;
+ } else if (live && settings.maplive == 1 && downloaded == false) {
+ moved = true;
+ } else if (centerLatitude == null || centerLongitude == null) {
+ moved = true;
+ } else if (spanLatitude == null || spanLongitude == null) {
+ moved = true;
+ } else if (((Math.abs(spanLatitudeNow - spanLatitude) > 50) || (Math.abs(spanLongitudeNow - spanLongitude) > 50) || // changed zoom
+ (Math.abs(centerLatitudeNow - centerLatitude) > (spanLatitudeNow / 4)) || (Math.abs(centerLongitudeNow - centerLongitude) > (spanLongitudeNow / 4)) // map moved
+ ) && (cachesCnt <= 0 || caches == null || caches.isEmpty()
+ || !base.isInViewPort(centerLatitude, centerLongitude, centerLatitudeNow, centerLongitudeNow, spanLatitude, spanLongitude, spanLatitudeNow, spanLongitudeNow))) {
+ moved = true;
+ }
+
+ if (moved && caches != null && centerLatitude != null && centerLongitude != null && ((Math.abs(centerLatitudeNow - centerLatitude) > (spanLatitudeNow * 1.2)) || (Math.abs(centerLongitudeNow - centerLongitude) > (spanLongitudeNow * 1.2)))) {
+ force = true;
+ }
+
+ //LeeB
+ // save new values
+ if (moved) {
+ liveChanged = false;
+
+ currentTime = System.currentTimeMillis();
+
+ if (1000 < (currentTime - loadThreadRun)) {
+ // from web
+ if (20000 < (currentTime - loadThreadRun)) {
+ force = true; // probably stucked thread
+ }
+
+ if (force && loadThread != null && loadThread.isWorking()) {
+ loadThread.stopIt();
+
+ try {
+ sleep(100);
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ if (loadThread != null && loadThread.isWorking()) {
+ continue;
+ }
+
+ centerLatitude = centerLatitudeNow;
+ centerLongitude = centerLongitudeNow;
+ spanLatitude = spanLatitudeNow;
+ spanLongitude = spanLongitudeNow;
+
+ showProgressHandler.sendEmptyMessage(1); // show progress
+
+ loadThread = new LoadThread(centerLatitude, centerLongitude, spanLatitude, spanLongitude);
+ loadThread.setName("loadThread");
+ loadThread.start(); //loadThread will kick off downloadThread once it's done
+ }
+ }
+ }
+
+ if (!isLoading()) {
+ showProgressHandler.sendEmptyMessage(0); // hide progress
+ }
+
+ yield();
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgeomap.LoadTimer.run: " + e.toString());
+ }
+ };
+ }
+ }
+
+ // loading timer
+ private class UsersTimer extends Thread {
+
+ private volatile boolean stop = false;
+
+ public void stopIt() {
+ stop = true;
+
+ if (usersThread != null) {
+ usersThread.stopIt();
+ usersThread = null;
+ }
+
+ if (displayUsersThread != null) {
+ displayUsersThread.stopIt();
+ displayUsersThread = null;
+ }
+ }
+
+ @Override
+ public void run() {
+ GeoPointImpl mapCenterNow;
+ int centerLatitudeNow;
+ int centerLongitudeNow;
+ int spanLatitudeNow;
+ int spanLongitudeNow;
+ boolean moved = false;
+ long currentTime = 0;
+
+ while (!stop) {
+ try {
+ sleep(250);
+
+ if (mapView != null) {
+ // get current viewport
+ mapCenterNow = mapView.getMapViewCenter();
+ centerLatitudeNow = mapCenterNow.getLatitudeE6();
+ centerLongitudeNow = mapCenterNow.getLongitudeE6();
+ spanLatitudeNow = mapView.getLatitudeSpan();
+ spanLongitudeNow = mapView.getLongitudeSpan();
+
+ // check if map moved or zoomed
+ moved = false;
+
+ currentTime = System.currentTimeMillis();
+
+ if (60000 < (currentTime - usersThreadRun)) {
+ moved = true;
+ } else if (centerLatitudeUsers == null || centerLongitudeUsers == null) {
+ moved = true;
+ } else if (spanLatitudeUsers == null || spanLongitudeUsers == null) {
+ moved = true;
+ } else if (((Math.abs(spanLatitudeNow - spanLatitudeUsers) > 50) || (Math.abs(spanLongitudeNow - spanLongitudeUsers) > 50) || // changed zoom
+ (Math.abs(centerLatitudeNow - centerLatitudeUsers) > (spanLatitudeNow / 4)) || (Math.abs(centerLongitudeNow - centerLongitudeUsers) > (spanLongitudeNow / 4)) // map moved
+ ) && !base.isInViewPort(centerLatitudeUsers, centerLongitudeUsers, centerLatitudeNow, centerLongitudeNow, spanLatitudeUsers, spanLongitudeUsers, spanLatitudeNow, spanLongitudeNow)) {
+ moved = true;
+ }
+
+ // save new values
+ if (moved && (1000 < (currentTime - usersThreadRun))) {
+ if (usersThread != null && usersThread.isWorking()) {
+ continue;
+ }
+
+ centerLatitudeUsers = centerLatitudeNow;
+ centerLongitudeUsers = centerLongitudeNow;
+ spanLatitudeUsers = spanLatitudeNow;
+ spanLongitudeUsers = spanLongitudeNow;
+
+ usersThread = new UsersThread(centerLatitude, centerLongitude, spanLatitude, spanLongitude);
+ usersThread.start();
+ }
+ }
+
+ yield();
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgeomap.LoadUsersTimer.run: " + e.toString());
+ }
+ };
+ }
+ }
+
+ // load caches from database
+ private class LoadThread extends DoThread {
+
+ public LoadThread(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) {
+ super(centerLatIn, centerLonIn, spanLatIn, spanLonIn);
+ }
+
+ @Override
+ public void run() {
+ try {
+ stop = false;
+ working = true;
+ loadThreadRun = System.currentTimeMillis();
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ //LeeB - I think this can be done better:
+ //1. fetch and draw(in another thread) caches from the db (fast? db read will be the slow bit)
+ //2. fetch and draw(in another thread) and then insert into the db caches from geocaching.com - dont draw/insert if exist in memory?
+
+ // stage 1 - pull and render from the DB only
+ if (settings.maplive == 0) {
+ searchId = app.getStoredInViewport(centerLat, centerLon, spanLat, spanLon, settings.cacheType);
+ } else {
+ searchId = app.getCachedInViewport(centerLat, centerLon, spanLat, spanLon, settings.cacheType);
+ }
+
+ if (searchId != null) {
+ downloaded = true;
+ }
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ caches = app.getCaches(searchId);
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ //render
+ if (displayThread != null && displayThread.isWorking()) {
+ displayThread.stopIt();
+ }
+ displayThread = new DisplayThread(centerLat, centerLon, spanLat, spanLon);
+ displayThread.start();
+
+ if (stop) {
+ displayThread.stopIt();
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ //*** this needs to be in it's own thread
+ // stage 2 - pull and render from geocaching.com
+ //this should just fetch and insert into the db _and_ be cancel-able if the viewport changes
+
+ if (settings.maplive >= 1) {
+ if (downloadThread != null && downloadThread.isWorking()) {
+ downloadThread.stopIt();
+ }
+ downloadThread = new DownloadThread(centerLat, centerLon, spanLat, spanLon);
+ downloadThread.setName("downloadThread");
+ downloadThread.start();
+ }
+ } finally {
+ working = false;
+ }
+ }
+ }
+
+ // load caches from internet
+ private class DownloadThread extends DoThread {
+
+ public DownloadThread(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) {
+ super(centerLatIn, centerLonIn, spanLatIn, spanLonIn);
+ }
+
+ @Override
+ public void run() { //first time we enter we have crappy long/lat....
+ try {
+ stop = false;
+ working = true;
+ downloadThreadRun = System.currentTimeMillis();
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ double latMin = (centerLat / 1e6) - ((spanLat / 1e6) / 2) - ((spanLat / 1e6) / 4);
+ double latMax = (centerLat / 1e6) + ((spanLat / 1e6) / 2) + ((spanLat / 1e6) / 4);
+ double lonMin = (centerLon / 1e6) - ((spanLon / 1e6) / 2) - ((spanLon / 1e6) / 4);
+ double lonMax = (centerLon / 1e6) + ((spanLon / 1e6) / 2) + ((spanLon / 1e6) / 4);
+ double llCache;
+
+ if (latMin > latMax) {
+ llCache = latMax;
+ latMax = latMin;
+ latMin = llCache;
+ }
+ if (lonMin > lonMax) {
+ llCache = lonMax;
+ lonMax = lonMin;
+ lonMin = llCache;
+ }
+
+ //*** this needs to be in it's own thread
+ // stage 2 - pull and render from geocaching.com
+ //this should just fetch and insert into the db _and_ be cancel-able if the viewport changes
+
+ if (token == null) {
+ token = base.getMapUserToken(noMapTokenHandler);
+ }
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ HashMap<String, String> params = new HashMap<String, String>();
+ params.put("usertoken", token);
+ params.put("latitude-min", String.format((Locale) null, "%.6f", latMin));
+ params.put("latitude-max", String.format((Locale) null, "%.6f", latMax));
+ params.put("longitude-min", String.format((Locale) null, "%.6f", lonMin));
+ params.put("longitude-max", String.format((Locale) null, "%.6f", lonMax));
+
+ searchId = base.searchByViewport(params, 0);
+ if (searchId != null) {
+ downloaded = true;
+ }
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ caches = app.getCaches(searchId, centerLat, centerLon, spanLat, spanLon);
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ //render
+ if (displayThread != null && displayThread.isWorking()) {
+ displayThread.stopIt();
+ }
+ displayThread = new DisplayThread(centerLat, centerLon, spanLat, spanLon);
+ displayThread.start();
+
+ } finally {
+ working = false;
+ }
+ }
+ }
+
+ // display (down)loaded caches
+ private class DisplayThread extends DoThread {
+
+ public DisplayThread(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) {
+ super(centerLatIn, centerLonIn, spanLatIn, spanLonIn);
+ }
+
+ @Override
+ public void run() {
+ try {
+ stop = false;
+ working = true;
+
+ if (mapView == null || caches == null) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ // display caches
+ final ArrayList<cgCache> cachesProtected = (ArrayList<cgCache>) caches.clone();
+ final ArrayList<CacheOverlayItemImpl> items = new ArrayList<CacheOverlayItemImpl>();
+
+ if (cachesProtected != null && !cachesProtected.isEmpty()) {
+ int counter = 0;
+ int icon = 0;
+ Drawable pin = null;
+ CacheOverlayItemImpl item = null;
+
+ for (cgCache cacheOne : cachesProtected) {
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ if (cacheOne.latitude == null && cacheOne.longitude == null) {
+ continue;
+ }
+
+ final cgCoord coord = new cgCoord(cacheOne);
+ coordinates.add(coord);
+
+ item = settings.getMapFactory().getCacheOverlayItem(coord, cacheOne.type);
+ icon = base.getIcon(true, cacheOne.type, cacheOne.own, cacheOne.found, cacheOne.disabled || cacheOne.archived);
+ pin = null;
+
+ if (iconsCache.containsKey(icon)) {
+ pin = iconsCache.get(icon);
+ } else {
+ pin = getResources().getDrawable(icon);
+ pin.setBounds(0, 0, pin.getIntrinsicWidth(), pin.getIntrinsicHeight());
+
+ iconsCache.put(icon, pin);
+ }
+ item.setMarker(pin);
+
+ items.add(item);
+
+ /*
+ counter++;
+ if ((counter % 10) == 0) {
+ overlayCaches.updateItems(items);
+ displayHandler.sendEmptyMessage(1);
+ }
+ */
+ }
+
+ overlayCaches.updateItems(items);
+ displayHandler.sendEmptyMessage(1);
+
+ cachesCnt = cachesProtected.size();
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ // display cache waypoints
+ if (cachesCnt == 1 && (geocodeIntent != null || searchIdIntent != null) && !live) {
+ if (cachesCnt == 1 && live == false) {
+ cgCache oneCache = cachesProtected.get(0);
+
+ if (oneCache != null && oneCache.waypoints != null && !oneCache.waypoints.isEmpty()) {
+ for (cgWaypoint oneWaypoint : oneCache.waypoints) {
+ if (oneWaypoint.latitude == null && oneWaypoint.longitude == null) {
+ continue;
+ }
+
+ cgCoord coord = new cgCoord(oneWaypoint);
+
+ coordinates.add(coord);
+ item = settings.getMapFactory().getCacheOverlayItem(coord, null);
+
+ icon = base.getIcon(false, oneWaypoint.type, false, false, false);
+ if (iconsCache.containsKey(icon)) {
+ pin = iconsCache.get(icon);
+ } else {
+ pin = getResources().getDrawable(icon);
+ pin.setBounds(0, 0, pin.getIntrinsicWidth(), pin.getIntrinsicHeight());
+ iconsCache.put(icon, pin);
+ }
+ item.setMarker(pin);
+
+ items.add(item);
+ }
+
+ overlayCaches.updateItems(items);
+ displayHandler.sendEmptyMessage(1);
+ }
+ }
+ }
+ } else {
+ overlayCaches.updateItems(items);
+ displayHandler.sendEmptyMessage(1);
+ }
+
+ cachesProtected.clear();
+
+ displayHandler.sendEmptyMessage(0);
+ } finally {
+ working = false;
+ }
+ }
+ }
+
+ // load users from Go 4 Cache
+ private class UsersThread extends DoThread {
+
+ public UsersThread(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) {
+ super(centerLatIn, centerLonIn, spanLatIn, spanLonIn);
+ }
+
+ @Override
+ public void run() {
+ try {
+ stop = false;
+ working = true;
+ usersThreadRun = System.currentTimeMillis();
+
+ if (stop) {
+ return;
+ }
+
+ double latMin = (centerLat / 1e6) - ((spanLat / 1e6) / 2) - ((spanLat / 1e6) / 4);
+ double latMax = (centerLat / 1e6) + ((spanLat / 1e6) / 2) + ((spanLat / 1e6) / 4);
+ double lonMin = (centerLon / 1e6) - ((spanLon / 1e6) / 2) - ((spanLon / 1e6) / 4);
+ double lonMax = (centerLon / 1e6) + ((spanLon / 1e6) / 2) + ((spanLon / 1e6) / 4);
+ double llCache;
+
+ if (latMin > latMax) {
+ llCache = latMax;
+ latMax = latMin;
+ latMin = llCache;
+ }
+ if (lonMin > lonMax) {
+ llCache = lonMax;
+ lonMax = lonMin;
+ lonMin = llCache;
+ }
+
+ users = base.getGeocachersInViewport(settings.getUsername(), latMin, latMax, lonMin, lonMax);
+
+ if (stop) {
+ return;
+ }
+
+ if (displayUsersThread != null && displayUsersThread.isWorking()) {
+ displayUsersThread.stopIt();
+ }
+ displayUsersThread = new DisplayUsersThread(users, centerLat, centerLon, spanLat, spanLon);
+ displayUsersThread.start();
+ } finally {
+ working = false;
+ }
+ }
+ }
+
+ // display users of Go 4 Cache
+ private class DisplayUsersThread extends DoThread {
+
+ private ArrayList<cgUser> users = null;
+
+ public DisplayUsersThread(ArrayList<cgUser> usersIn, long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) {
+ super(centerLatIn, centerLonIn, spanLatIn, spanLonIn);
+
+ users = usersIn;
+ }
+
+ @Override
+ public void run() {
+ try {
+ stop = false;
+ working = true;
+
+ if (mapView == null || users == null || users.isEmpty()) {
+ return;
+ }
+
+ // display users
+ ArrayList<UserOverlayItemImpl> items = new ArrayList<UserOverlayItemImpl>();
+
+ int counter = 0;
+ UserOverlayItemImpl item = null;
+
+ for (cgUser userOne : users) {
+ if (stop) {
+ return;
+ }
+
+ if (userOne.latitude == null && userOne.longitude == null) {
+ continue;
+ }
+
+ item = settings.getMapFactory().getUserOverlayItemBase(activity, userOne);
+ items.add(item);
+
+ counter++;
+ if ((counter % 10) == 0) {
+ overlayUsers.updateItems(items);
+ displayHandler.sendEmptyMessage(1);
+ }
+ }
+
+ overlayUsers.updateItems(items);
+ } finally {
+ working = false;
+ }
+ }
+ }
+
+ // display one point
+ private class DisplayPointThread extends Thread {
+
+ @Override
+ public void run() {
+ if (mapView == null || caches == null) {
+ return;
+ }
+
+ if (latitudeIntent != null && longitudeIntent != null) {
+ cgCoord coord = new cgCoord();
+ coord.type = "waypoint";
+ coord.latitude = latitudeIntent;
+ coord.longitude = longitudeIntent;
+ coord.name = "some place";
+
+ coordinates.add(coord);
+ CacheOverlayItemImpl item = settings.getMapFactory().getCacheOverlayItem(coord, null);
+
+ final int icon = base.getIcon(false, waypointTypeIntent, false, false, false);
+ Drawable pin = null;
+ if (iconsCache.containsKey(icon)) {
+ pin = iconsCache.get(icon);
+ } else {
+ pin = getResources().getDrawable(icon);
+ pin.setBounds(0, 0, pin.getIntrinsicWidth(), pin.getIntrinsicHeight());
+ iconsCache.put(icon, pin);
+ }
+ item.setMarker(pin);
+
+ overlayCaches.updateItems(item);
+ displayHandler.sendEmptyMessage(1);
+
+ cachesCnt = 1;
+ } else {
+ cachesCnt = 0;
+ }
+
+ displayHandler.sendEmptyMessage(0);
+ }
+ }
+
+ // parent for those above :)
+ private class DoThread extends Thread {
+
+ protected boolean working = true;
+ protected boolean stop = false;
+ protected long centerLat = 0l;
+ protected long centerLon = 0l;
+ protected long spanLat = 0l;
+ protected long spanLon = 0l;
+
+ public DoThread(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) {
+ centerLat = centerLatIn;
+ centerLon = centerLonIn;
+ spanLat = spanLatIn;
+ spanLon = spanLonIn;
+ }
+
+ public synchronized boolean isWorking() {
+ return working;
+ }
+
+ public synchronized void stopIt() {
+ stop = true;
+ }
+ }
+
+ // get if map is loading something
+ private synchronized boolean isLoading() {
+ boolean loading = false;
+
+ if (loadThread != null && loadThread.isWorking()) {
+ loading = true;
+ } else if (downloadThread != null && downloadThread.isWorking()) {
+ loading = true;
+ } else if (displayThread != null && displayThread.isWorking()) {
+ loading = true;
+ }
+
+ return loading;
+ }
+
+ // store caches
+ private class LoadDetails extends Thread {
+
+ private Handler handler = null;
+ private ArrayList<String> geocodes = null;
+ private volatile boolean stop = false;
+ private long last = 0l;
+
+ public LoadDetails(Handler handlerIn, ArrayList<String> geocodesIn) {
+ handler = handlerIn;
+ geocodes = geocodesIn;
+ }
+
+ public void stopIt() {
+ stop = true;
+ }
+
+ @Override
+ public void run() {
+ if (geocodes == null || geocodes.isEmpty()) {
+ return;
+ }
+
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ for (String geocode : geocodes) {
+ try {
+ if (stop == true) {
+ break;
+ }
+
+ if (!app.isOffline(geocode, null)) {
+ if ((System.currentTimeMillis() - last) < 1500) {
+ try {
+ int delay = 1000 + ((Double) (Math.random() * 1000)).intValue() - (int) (System.currentTimeMillis() - last);
+ if (delay < 0) {
+ delay = 500;
+ }
+
+ sleep(delay);
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ if (stop == true) {
+ Log.i(cgSettings.tag, "Stopped storing process.");
+
+ break;
+ }
+
+ base.storeCache(app, activity, null, geocode, 1, handler);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.LoadDetails.run: " + e.toString());
+ } finally {
+ // one more cache over
+ detailProgress++;
+ handler.sendEmptyMessage(0);
+ }
+
+ yield();
+
+ last = System.currentTimeMillis();
+ }
+
+ // we're done
+ handler.sendEmptyMessage(1);
+ }
+ }
+
+ // center map to desired location
+ private void centerMap(Double latitude, Double longitude) {
+ if (latitude == null || longitude == null) {
+ return;
+ }
+ if (mapView == null) {
+ return;
+ }
+
+ if (!alreadyCentered) {
+ alreadyCentered = true;
+
+ mapController.setCenter(makeGeoPoint(latitude, longitude));
+ } else {
+ mapController.animateTo(makeGeoPoint(latitude, longitude));
+ }
+ }
+
+ // move map to view results of searchIdIntent
+ private void centerMap(String geocodeCenter, Long searchIdCenter, Double latitudeCenter, Double longitudeCenter) {
+ if (!centered && (geocodeCenter != null || searchIdIntent != null)) {
+ try {
+ ArrayList<Object> viewport;
+
+ if (geocodeCenter != null) {
+ viewport = app.getBounds(geocodeCenter);
+ } else {
+ viewport = app.getBounds(searchIdCenter);
+ }
+
+ Integer cnt = (Integer) viewport.get(0);
+ Integer minLat = null;
+ Integer maxLat = null;
+ Integer minLon = null;
+ Integer maxLon = null;
+
+ if (viewport.get(1) != null) {
+ minLat = new Double((Double) viewport.get(1) * 1e6).intValue();
+ }
+ if (viewport.get(2) != null) {
+ maxLat = new Double((Double) viewport.get(2) * 1e6).intValue();
+ }
+ if (viewport.get(3) != null) {
+ maxLon = new Double((Double) viewport.get(3) * 1e6).intValue();
+ }
+ if (viewport.get(4) != null) {
+ minLon = new Double((Double) viewport.get(4) * 1e6).intValue();
+ }
+
+ if (cnt == null || cnt <= 0 || minLat == null || maxLat == null || minLon == null || maxLon == null) {
+ return;
+ }
+
+ int centerLat = 0;
+ int centerLon = 0;
+
+ if ((Math.abs(maxLat) - Math.abs(minLat)) != 0) {
+ centerLat = minLat + ((maxLat - minLat) / 2);
+ } else {
+ centerLat = maxLat;
+ }
+ if ((Math.abs(maxLon) - Math.abs(minLon)) != 0) {
+ centerLon = minLon + ((maxLon - minLon) / 2);
+ } else {
+ centerLon = maxLon;
+ }
+
+ if (cnt != null && cnt > 0) {
+ mapController.setCenter(settings.getMapFactory().getGeoPointBase(centerLat, centerLon));
+ if (Math.abs(maxLat - minLat) != 0 && Math.abs(maxLon - minLon) != 0) {
+ mapController.zoomToSpan(Math.abs(maxLat - minLat), Math.abs(maxLon - minLon));
+ }
+ }
+ } catch (Exception e) {
+ // nothing at all
+ }
+
+ centered = true;
+ alreadyCentered = true;
+ } else if (!centered && latitudeCenter != null && longitudeCenter != null) {
+ try {
+ mapController.setCenter(makeGeoPoint(latitudeCenter, longitudeCenter));
+ } catch (Exception e) {
+ // nothing at all
+ }
+
+ centered = true;
+ alreadyCentered = true;
+ }
+ }
+
+ // switch My Location button image
+ private void setMyLoc(Boolean status) {
+ if (myLocSwitch == null) {
+ myLocSwitch = (ImageView) activity.findViewById(R.id.my_position);
+ }
+
+ if (status == null) {
+ if (followMyLocation == true) {
+ myLocSwitch.setImageResource(R.drawable.my_location_on);
+ } else {
+ myLocSwitch.setImageResource(R.drawable.my_location_off);
+ }
+ } else {
+ if (status == true) {
+ myLocSwitch.setImageResource(R.drawable.my_location_on);
+ } else {
+ myLocSwitch.setImageResource(R.drawable.my_location_off);
+ }
+ }
+
+ myLocSwitch.setOnClickListener(new MyLocationListener());
+ }
+
+ // set my location listener
+ private class MyLocationListener implements View.OnClickListener {
+
+ public void onClick(View view) {
+ if (myLocSwitch == null) {
+ myLocSwitch = (ImageView) activity.findViewById(R.id.my_position);
+ }
+
+ if (followMyLocation == true) {
+ followMyLocation = false;
+
+ myLocSwitch.setImageResource(R.drawable.my_location_off);
+ } else {
+ followMyLocation = true;
+ myLocationInMiddle();
+
+ myLocSwitch.setImageResource(R.drawable.my_location_on);
+ }
+ }
+ }
+
+ // make geopoint
+ private GeoPointImpl makeGeoPoint(Double latitude, Double longitude) {
+ return settings.getMapFactory().getGeoPointBase((int) (latitude * 1e6), (int) (longitude * 1e6));
+ }
+
+ // close activity and open homescreen
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ // open manual entry
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-live-map",
+ activity,
+ "http://cgeo.carnero.cc/manual/");
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/ActivityImpl.java b/src/cgeo/geocaching/mapinterfaces/ActivityImpl.java
new file mode 100644
index 0000000..1895744
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/ActivityImpl.java
@@ -0,0 +1,33 @@
+package cgeo.geocaching.mapinterfaces;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+
+/**
+ * Defines the common functions of the provider-specific
+ * MapActivity implementations.
+ * @author rsudev
+ *
+ */
+public interface ActivityImpl {
+
+ Resources getResources();
+
+ Activity getActivity();
+
+ void superOnCreate(Bundle savedInstanceState);
+
+ void superOnResume();
+
+ void superOnDestroy();
+
+ boolean superOnCreateOptionsMenu(Menu menu);
+
+ boolean superOnPrepareOptionsMenu(Menu menu);
+
+ boolean superOnOptionsItemSelected(MenuItem item);
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/CacheOverlayItemImpl.java b/src/cgeo/geocaching/mapinterfaces/CacheOverlayItemImpl.java
new file mode 100644
index 0000000..bdb8511
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/CacheOverlayItemImpl.java
@@ -0,0 +1,17 @@
+package cgeo.geocaching.mapinterfaces;
+
+import cgeo.geocaching.cgCoord;
+
+/**
+ * Covers the common functions of the provider-specific
+ * CacheOverlayItem implementations
+ * @author rsudev
+ *
+ */
+public interface CacheOverlayItemImpl extends OverlayItemImpl {
+
+ public cgCoord getCoord();
+
+ public String getType();
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/GeoPointImpl.java b/src/cgeo/geocaching/mapinterfaces/GeoPointImpl.java
new file mode 100644
index 0000000..c6e80d4
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/GeoPointImpl.java
@@ -0,0 +1,15 @@
+package cgeo.geocaching.mapinterfaces;
+
+/**
+ * Defines the common functions of the provider-specific
+ * GeoPoint implementations
+ * @author rsudev
+ *
+ */
+public interface GeoPointImpl {
+
+ int getLatitudeE6();
+
+ int getLongitudeE6();
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/ItemizedOverlayImpl.java b/src/cgeo/geocaching/mapinterfaces/ItemizedOverlayImpl.java
new file mode 100644
index 0000000..73eed1f
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/ItemizedOverlayImpl.java
@@ -0,0 +1,33 @@
+package cgeo.geocaching.mapinterfaces;
+
+import cgeo.geocaching.mapcommon.ItemizedOverlayBase;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+
+/**
+ * Defines the common functions to access the provider-specific
+ * ItemizedOverlay implementation
+ * @author rsudev
+ *
+ */
+public interface ItemizedOverlayImpl {
+
+ ItemizedOverlayBase getBase();
+
+ void superPopulate();
+
+ void superSetLastFocusedItemIndex(int i);
+
+ Drawable superBoundCenter(Drawable markerIn);
+
+ Drawable superBoundCenterBottom(Drawable marker);
+
+ boolean superOnTap(int index);
+
+ void superDraw(Canvas canvas, MapViewImpl mapView, boolean shadow);
+
+ void superDrawOverlayBitmap(Canvas canvas, Point drawPosition, MapProjectionImpl projection,
+ byte drawZoomLevel);
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/MapControllerImpl.java b/src/cgeo/geocaching/mapinterfaces/MapControllerImpl.java
new file mode 100644
index 0000000..dbdb955
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/MapControllerImpl.java
@@ -0,0 +1,19 @@
+package cgeo.geocaching.mapinterfaces;
+
+/**
+ * Defines the common functions of the provider-specific
+ * MapController implementations
+ * @author rsudev
+ *
+ */
+public interface MapControllerImpl {
+
+ void setZoom(int mapzoom);
+
+ void setCenter(GeoPointImpl geoPoint);
+
+ void animateTo(GeoPointImpl geoPoint);
+
+ void zoomToSpan(int latSpanE6, int lonSpanE6);
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/MapFactory.java b/src/cgeo/geocaching/mapinterfaces/MapFactory.java
new file mode 100644
index 0000000..fe09626
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/MapFactory.java
@@ -0,0 +1,30 @@
+package cgeo.geocaching.mapinterfaces;
+
+import android.content.Context;
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.cgUser;
+
+/**
+ * Defines functions of a factory class to get implementation specific objects
+ * (GeoPoints, OverlayItems, ...)
+ * @author rsudev
+ *
+ */
+public interface MapFactory {
+
+ public Class getMapClass();
+
+ public int getMapViewId();
+
+ public int getMapLayoutId();
+
+ public GeoPointImpl getGeoPointBase(int latE6, int lonE6);
+
+ public OverlayImpl getOverlayBaseWrapper(OverlayBase ovlIn);
+
+ CacheOverlayItemImpl getCacheOverlayItem(cgCoord coordinate, String type);
+
+ public UserOverlayItemImpl getUserOverlayItemBase(Context context,
+ cgUser userOne);
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/MapProjectionImpl.java b/src/cgeo/geocaching/mapinterfaces/MapProjectionImpl.java
new file mode 100644
index 0000000..10d36ee
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/MapProjectionImpl.java
@@ -0,0 +1,17 @@
+package cgeo.geocaching.mapinterfaces;
+
+import android.graphics.Point;
+
+/**
+ * Defines common functions of the provider-specific
+ * MapProjection implementations
+ * @author rsudev
+ *
+ */
+public interface MapProjectionImpl {
+
+ Object getImpl();
+
+ void toPixels(GeoPointImpl leftGeo, Point left);
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/MapViewImpl.java b/src/cgeo/geocaching/mapinterfaces/MapViewImpl.java
new file mode 100644
index 0000000..651b39f
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/MapViewImpl.java
@@ -0,0 +1,64 @@
+package cgeo.geocaching.mapinterfaces;
+
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.mapcommon.cgMapOverlay;
+import cgeo.geocaching.mapcommon.cgUsersOverlay;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+
+/**
+ * Defines common functions of the provider-specific
+ * MapView implementations
+ * @author rsudev
+ *
+ */
+public interface MapViewImpl {
+
+ void invalidate();
+
+ void setSatellite(boolean b);
+
+ void setBuiltInZoomControls(boolean b);
+
+ void displayZoomControls(boolean b);
+
+ void preLoad();
+
+ void clearOverlays();
+
+ void addOverlay(OverlayImpl ovl);
+
+ MapControllerImpl getMapController();
+
+ void destroyDrawingCache();
+
+ boolean isSatellite();
+
+ GeoPointImpl getMapViewCenter();
+
+ int getLatitudeSpan();
+
+ int getLongitudeSpan();
+
+ int getMapZoomLevel();
+
+ int getWidth();
+
+ int getHeight();
+
+ MapProjectionImpl getMapProjection();
+
+ Context getContext();
+
+ cgMapOverlay createAddMapOverlay(cgSettings settings, Context context,
+ Drawable drawable, boolean fromDetailIntent);
+
+ cgUsersOverlay createAddUsersOverlay(Context context, Drawable markerIn);
+
+ boolean needsScaleOverlay();
+
+ void setBuiltinScale(boolean b);
+
+ void setMapSource(cgSettings settings);
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/OverlayBase.java b/src/cgeo/geocaching/mapinterfaces/OverlayBase.java
new file mode 100644
index 0000000..59afb49
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/OverlayBase.java
@@ -0,0 +1,19 @@
+package cgeo.geocaching.mapinterfaces;
+
+import android.graphics.Canvas;
+import android.graphics.Point;
+
+/**
+ * Defines the base functions of the provider-independent
+ * Overlay implementations
+ * @author rsudev
+ *
+ */
+public interface OverlayBase {
+
+ void draw(Canvas canvas, MapViewImpl mapView, boolean shadow);
+
+ void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel);
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/OverlayImpl.java b/src/cgeo/geocaching/mapinterfaces/OverlayImpl.java
new file mode 100644
index 0000000..6680b6a
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/OverlayImpl.java
@@ -0,0 +1,11 @@
+package cgeo.geocaching.mapinterfaces;
+
+/**
+ * Marker interface of the provider-specific
+ * Overlay implementations
+ * @author rsudev
+ *
+ */
+public interface OverlayImpl {
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/OverlayItemImpl.java b/src/cgeo/geocaching/mapinterfaces/OverlayItemImpl.java
new file mode 100644
index 0000000..0f0297e
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/OverlayItemImpl.java
@@ -0,0 +1,18 @@
+package cgeo.geocaching.mapinterfaces;
+
+import android.graphics.drawable.Drawable;
+
+/**
+ * Common functions of the provider-specific
+ * OverlayItem implementations
+ * @author rsudev
+ *
+ */
+public interface OverlayItemImpl {
+
+ public String getTitle();
+
+ public Drawable getMarker(int index);
+
+ public void setMarker(Drawable markerIn);
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/UserOverlayItemImpl.java b/src/cgeo/geocaching/mapinterfaces/UserOverlayItemImpl.java
new file mode 100644
index 0000000..6b1532d
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/UserOverlayItemImpl.java
@@ -0,0 +1,14 @@
+package cgeo.geocaching.mapinterfaces;
+
+import cgeo.geocaching.cgUser;
+
+/**
+ * Common functions of the provider-specific
+ * UserOverlayItem implementations
+ * @author rsudev
+ *
+ */
+public interface UserOverlayItemImpl extends OverlayItemImpl {
+
+ public cgUser getUser();
+}
diff --git a/src/cgeo/geocaching/mapsforge/mfCacheOverlay.java b/src/cgeo/geocaching/mapsforge/mfCacheOverlay.java
new file mode 100644
index 0000000..a7665cb
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfCacheOverlay.java
@@ -0,0 +1,99 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.ItemizedOverlay;
+import org.mapsforge.android.maps.MapView;
+import org.mapsforge.android.maps.Projection;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.mapcommon.cgMapOverlay;
+import cgeo.geocaching.mapinterfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+
+
+public class mfCacheOverlay extends ItemizedOverlay<mfCacheOverlayItem> implements ItemizedOverlayImpl {
+
+ private cgMapOverlay base;
+
+ public mfCacheOverlay(cgSettings settingsIn, Context contextIn, Drawable markerIn, Boolean fromDetailIn) {
+ super(boundCenterBottom(markerIn));
+ base = new cgMapOverlay(settingsIn, this, contextIn, fromDetailIn);
+ }
+
+ @Override
+ public cgMapOverlay getBase() {
+ return base;
+ }
+
+ @Override
+ protected mfCacheOverlayItem createItem(int i) {
+ if (base == null)
+ return null;
+
+ return (mfCacheOverlayItem) base.createItem(i);
+ }
+
+ @Override
+ public int size() {
+ if (base == null)
+ return 0;
+
+ return base.size();
+ }
+
+ @Override
+ protected boolean onTap(int arg0) {
+ if (base == null)
+ return false;
+
+ return base.onTap(arg0);
+ }
+
+ @Override
+ protected void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ Projection projection, byte drawZoomLevel) {
+ base.drawOverlayBitmap(canvas, drawPosition, new mfMapProjection(projection), drawZoomLevel);
+ }
+
+ @Override
+ public void superPopulate() {
+ populate();
+ }
+
+ @Override
+ public Drawable superBoundCenter(Drawable markerIn) {
+ return super.boundCenter(markerIn);
+ }
+
+ @Override
+ public Drawable superBoundCenterBottom(Drawable marker) {
+ return super.boundCenterBottom(marker);
+ }
+
+ @Override
+ public void superSetLastFocusedItemIndex(int i) {
+ // nothing to do
+ }
+
+ @Override
+ public boolean superOnTap(int index) {
+ return super.onTap(index);
+ }
+
+ @Override
+ public void superDraw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ // nothing to do here...
+ }
+
+ @Override
+ public void superDrawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+ super.drawOverlayBitmap(canvas, drawPosition, (Projection) projection.getImpl(), drawZoomLevel);
+ }
+
+}
+
diff --git a/src/cgeo/geocaching/mapsforge/mfCacheOverlayItem.java b/src/cgeo/geocaching/mapsforge/mfCacheOverlayItem.java
new file mode 100644
index 0000000..b6b7d62
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfCacheOverlayItem.java
@@ -0,0 +1,35 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.GeoPoint;
+import org.mapsforge.android.maps.OverlayItem;
+
+import android.graphics.drawable.Drawable;
+
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.mapinterfaces.CacheOverlayItemImpl;
+
+public class mfCacheOverlayItem extends OverlayItem implements CacheOverlayItemImpl {
+ private String cacheType = null;
+ private cgCoord coord;
+
+ public mfCacheOverlayItem(cgCoord coordinate, String type) {
+ super(new GeoPoint((int)(coordinate.latitude * 1e6), (int)(coordinate.longitude * 1e6)), coordinate.name, "");
+
+ this.cacheType = type;
+ this.coord = coordinate;
+ }
+
+ public cgCoord getCoord() {
+ return coord;
+ }
+
+ public String getType() {
+ return cacheType;
+ }
+
+ @Override
+ public Drawable getMarker(int index) {
+ return getMarker();
+ }
+
+}
diff --git a/src/cgeo/geocaching/mapsforge/mfGeoPoint.java b/src/cgeo/geocaching/mapsforge/mfGeoPoint.java
new file mode 100644
index 0000000..1261887
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfGeoPoint.java
@@ -0,0 +1,12 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.GeoPoint;
+
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+
+public class mfGeoPoint extends GeoPoint implements GeoPointImpl {
+
+ public mfGeoPoint(int latitudeE6, int longitudeE6) {
+ super(latitudeE6, longitudeE6);
+ }
+}
diff --git a/src/cgeo/geocaching/mapsforge/mfMapActivity.java b/src/cgeo/geocaching/mapsforge/mfMapActivity.java
new file mode 100644
index 0000000..b878def
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfMapActivity.java
@@ -0,0 +1,96 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.MapActivity;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import cgeo.geocaching.mapcommon.MapBase;
+import cgeo.geocaching.mapcommon.cgeomap;
+import cgeo.geocaching.mapinterfaces.ActivityImpl;
+
+
+public class mfMapActivity extends MapActivity implements ActivityImpl {
+
+ private MapBase mapBase;
+
+ public mfMapActivity() {
+ mapBase = new cgeomap(this);
+ }
+
+ @Override
+ public Activity getActivity() {
+ return this;
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ mapBase.onCreate(icicle);
+ }
+
+ @Override
+ protected void onDestroy() {
+ mapBase.onDestroy();
+ }
+
+ @Override
+ protected void onPause() {
+ mapBase.onPause();
+ }
+
+ @Override
+ protected void onResume() {
+ mapBase.onResume();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ return mapBase.onCreateOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ return mapBase.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ return mapBase.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ protected void onStop() {
+ mapBase.onStop();
+ }
+
+ @Override
+ public void superOnCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public boolean superOnCreateOptionsMenu(Menu menu) {
+ return superOnCreateOptionsMenu(menu);
+ }
+
+ @Override
+ public void superOnDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ public boolean superOnOptionsItemSelected(MenuItem item) {
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void superOnResume() {
+ super.onResume();
+ }
+
+ @Override
+ public boolean superOnPrepareOptionsMenu(Menu menu) {
+ return super.onPrepareOptionsMenu(menu);
+ }
+}
diff --git a/src/cgeo/geocaching/mapsforge/mfMapController.java b/src/cgeo/geocaching/mapsforge/mfMapController.java
new file mode 100644
index 0000000..30f1c29
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfMapController.java
@@ -0,0 +1,43 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.GeoPoint;
+import org.mapsforge.android.maps.MapController;
+
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapControllerImpl;
+
+public class mfMapController implements MapControllerImpl {
+
+ private MapController mapController;
+
+ public mfMapController(MapController mapControllerIn) {
+ mapController = mapControllerIn;
+ }
+
+ @Override
+ public void animateTo(GeoPointImpl geoPoint) {
+ mapController.setCenter((GeoPoint)geoPoint);
+ }
+
+ @Override
+ public void setCenter(GeoPointImpl geoPoint) {
+ mapController.setCenter((GeoPoint)geoPoint);
+ }
+
+ @Override
+ public void setZoom(int mapzoom) {
+ mapController.setZoom(mapzoom);
+ }
+
+ @Override
+ public void zoomToSpan(int latSpanE6, int lonSpanE6) {
+
+ if (latSpanE6 != 0 && lonSpanE6 != 0) {
+ // calculate zoomlevel
+ int distDegree = Math.max(latSpanE6, lonSpanE6);
+ int zoomLevel = (int) Math.floor(Math.log(360.0*1e6/distDegree)/Math.log(2));
+ mapController.setZoom(zoomLevel);
+ }
+ }
+}
+
diff --git a/src/cgeo/geocaching/mapsforge/mfMapFactory.java b/src/cgeo/geocaching/mapsforge/mfMapFactory.java
new file mode 100644
index 0000000..2031187
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfMapFactory.java
@@ -0,0 +1,54 @@
+package cgeo.geocaching.mapsforge;
+
+import android.content.Context;
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.mapinterfaces.CacheOverlayItemImpl;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapFactory;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.OverlayImpl;
+import cgeo.geocaching.mapinterfaces.UserOverlayItemImpl;
+
+public class mfMapFactory implements MapFactory{
+
+ @Override
+ public Class getMapClass() {
+ return mfMapActivity.class;
+ }
+
+ @Override
+ public int getMapViewId() {
+ return R.id.mfmap;
+ }
+
+ @Override
+ public int getMapLayoutId() {
+ return R.layout.mfmap;
+ }
+
+ @Override
+ public GeoPointImpl getGeoPointBase(int latE6, int lonE6) {
+ return new mfGeoPoint(latE6, lonE6);
+ }
+
+ @Override
+ public OverlayImpl getOverlayBaseWrapper(OverlayBase ovlIn) {
+ mfOverlay baseOvl = new mfOverlay(ovlIn);
+ return baseOvl;
+ }
+
+ @Override
+ public CacheOverlayItemImpl getCacheOverlayItem(cgCoord coordinate, String type) {
+ mfCacheOverlayItem baseItem = new mfCacheOverlayItem(coordinate, type);
+ return baseItem;
+ }
+
+ @Override
+ public UserOverlayItemImpl getUserOverlayItemBase(Context context, cgUser userOne) {
+ mfUsersOverlayItem baseItem = new mfUsersOverlayItem(context, userOne);
+ return baseItem;
+ }
+
+}
diff --git a/src/cgeo/geocaching/mapsforge/mfMapProjection.java b/src/cgeo/geocaching/mapsforge/mfMapProjection.java
new file mode 100644
index 0000000..7252b17
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfMapProjection.java
@@ -0,0 +1,28 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.GeoPoint;
+import org.mapsforge.android.maps.Projection;
+
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import android.graphics.Point;
+
+public class mfMapProjection implements MapProjectionImpl {
+
+ private Projection projection;
+
+ public mfMapProjection(Projection projectionIn) {
+ projection = projectionIn;
+ }
+
+ @Override
+ public void toPixels(GeoPointImpl leftGeo, Point left) {
+ projection.toPixels((GeoPoint) leftGeo, left);
+ }
+
+ @Override
+ public Object getImpl() {
+ return projection;
+ }
+
+}
diff --git a/src/cgeo/geocaching/mapsforge/mfMapView.java b/src/cgeo/geocaching/mapsforge/mfMapView.java
new file mode 100644
index 0000000..a68e7c0
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfMapView.java
@@ -0,0 +1,159 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.GeoPoint;
+import org.mapsforge.android.maps.MapView;
+import org.mapsforge.android.maps.MapViewMode;
+import org.mapsforge.android.maps.Overlay;
+import org.mapsforge.android.maps.Projection;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.mapcommon.cgMapOverlay;
+import cgeo.geocaching.mapcommon.cgUsersOverlay;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapControllerImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+import cgeo.geocaching.mapinterfaces.OverlayImpl;
+
+public class mfMapView extends MapView implements MapViewImpl {
+
+ public mfMapView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ try {
+ if (getMapZoomLevel() >= 22) { // to avoid too close zoom level (mostly on Samsung Galaxy S series)
+ getController().setZoom(22);
+ }
+
+ super.draw(canvas);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapView.draw: " + e.toString());
+ }
+ }
+
+ @Override
+ public void displayZoomControls(boolean takeFocus) {
+ // nothing to do here
+ }
+
+ @Override
+ public MapControllerImpl getMapController() {
+ return new mfMapController(getController());
+ }
+
+ @Override
+ public GeoPointImpl getMapViewCenter() {
+ GeoPoint point = getMapCenter();
+ return new mfGeoPoint(point.getLatitudeE6(), point.getLongitudeE6());
+ }
+
+ @Override
+ public void addOverlay(OverlayImpl ovl) {
+ getOverlays().add((Overlay)ovl);
+ }
+
+ @Override
+ public void clearOverlays() {
+ getOverlays().clear();
+ }
+
+ @Override
+ public MapProjectionImpl getMapProjection() {
+ return new mfMapProjection(getProjection());
+ }
+
+ @Override
+ public cgMapOverlay createAddMapOverlay(cgSettings settings,
+ Context context, Drawable drawable, boolean fromDetailIntent) {
+
+ mfCacheOverlay ovl = new mfCacheOverlay(settings, context, drawable, fromDetailIntent);
+ getOverlays().add(ovl);
+ return ovl.getBase();
+ }
+
+ @Override
+ public cgUsersOverlay createAddUsersOverlay(Context context, Drawable markerIn) {
+ mfUsersOverlay ovl = new mfUsersOverlay(context, markerIn);
+ getOverlays().add(ovl);
+ return ovl.getBase();
+ }
+
+ @Override
+ public int getLatitudeSpan() {
+
+ Projection projection = getProjection();
+
+ GeoPoint low = projection.fromPixels(0, 0);
+ GeoPoint high = projection.fromPixels(0, getHeight());
+
+ return Math.abs(high.getLatitudeE6() - low.getLatitudeE6());
+ }
+
+ @Override
+ public int getLongitudeSpan() {
+ Projection projection = getProjection();
+
+ GeoPoint low = projection.fromPixels(0, 0);
+ GeoPoint high = projection.fromPixels(getWidth(), 0);
+
+ return Math.abs(high.getLongitudeE6() - low.getLongitudeE6());
+ }
+
+ @Override
+ public boolean isSatellite() {
+ return false;
+ }
+
+ @Override
+ public void preLoad() {
+ // Nothing to do here
+ }
+
+ @Override
+ public void setSatellite(boolean b) {
+ // Nothing to do here
+ }
+
+ @Override
+ public int getMapZoomLevel() {
+ return getZoomLevel();
+ }
+
+ @Override
+ public boolean needsScaleOverlay() {
+ return false;
+ }
+
+ @Override
+ public void setBuiltinScale(boolean b) {
+ setScaleBar(b);
+ }
+
+ @Override
+ public void setMapSource(cgSettings settings) {
+
+ setMapViewMode(MapViewMode.MAPNIK_TILE_DOWNLOAD);
+
+ switch(settings.mapProvider) {
+ case mapsforgeMapnik:
+ // is default
+ break;
+ case mapsforgeOsmarender:
+ setMapViewMode(MapViewMode.OSMARENDER_TILE_DOWNLOAD);
+ break;
+ case mapsforgeOffline:
+ if (isValidMapFile(settings.getMapFile())) {
+ setMapViewMode(MapViewMode.CANVAS_RENDERER);
+ super.setMapFile(settings.getMapFile());
+ }
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/mapsforge/mfOverlay.java b/src/cgeo/geocaching/mapsforge/mfOverlay.java
new file mode 100644
index 0000000..e015307
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfOverlay.java
@@ -0,0 +1,26 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.Overlay;
+import org.mapsforge.android.maps.Projection;
+
+import android.graphics.Canvas;
+import android.graphics.Point;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.OverlayImpl;
+
+public class mfOverlay extends Overlay implements OverlayImpl {
+
+ private OverlayBase overlayBase;
+
+ public mfOverlay(OverlayBase overlayBaseIn) {
+ overlayBase = overlayBaseIn;
+ }
+
+ @Override
+ protected void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ Projection projection, byte drawZoomLevel) {
+
+ overlayBase.drawOverlayBitmap(canvas, drawPosition, new mfMapProjection(projection), drawZoomLevel);
+ }
+
+}
diff --git a/src/cgeo/geocaching/mapsforge/mfUsersOverlay.java b/src/cgeo/geocaching/mapsforge/mfUsersOverlay.java
new file mode 100644
index 0000000..64ccc37
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfUsersOverlay.java
@@ -0,0 +1,98 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.ItemizedOverlay;
+import org.mapsforge.android.maps.MapView;
+import org.mapsforge.android.maps.Projection;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+import cgeo.geocaching.mapcommon.cgUsersOverlay;
+import cgeo.geocaching.mapinterfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+
+public class mfUsersOverlay extends ItemizedOverlay<mfUsersOverlayItem> implements ItemizedOverlayImpl {
+
+ private cgUsersOverlay base;
+
+ public mfUsersOverlay(Context contextIn, Drawable markerIn) {
+ super(boundCenter(markerIn));
+ base = new cgUsersOverlay(this, contextIn);
+ }
+
+ @Override
+ public cgUsersOverlay getBase() {
+ return base;
+ }
+
+ @Override
+ protected mfUsersOverlayItem createItem(int i) {
+ if (base == null)
+ return null;
+
+ return (mfUsersOverlayItem) base.createItem(i);
+ }
+
+ @Override
+ public int size() {
+ if (base == null)
+ return 0;
+
+ return base.size();
+ }
+
+ @Override
+ protected boolean onTap(int arg0) {
+ if (base == null)
+ return false;
+
+ return base.onTap(arg0);
+ }
+
+ @Override
+ protected void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ Projection projection, byte drawZoomLevel) {
+
+ base.drawOverlayBitmap(canvas, drawPosition, new mfMapProjection(projection), drawZoomLevel);
+ }
+
+ @Override
+ public void superPopulate() {
+ populate();
+ }
+
+ @Override
+ public Drawable superBoundCenter(Drawable markerIn) {
+ return super.boundCenter(markerIn);
+ }
+
+ @Override
+ public Drawable superBoundCenterBottom(Drawable marker) {
+ return super.boundCenterBottom(marker);
+ }
+
+ @Override
+ public void superSetLastFocusedItemIndex(int i) {
+ // Nothing to do here
+ }
+
+ @Override
+ public boolean superOnTap(int index) {
+ return super.onTap(index);
+ }
+
+ @Override
+ public void superDraw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ // Nothing to do here
+ }
+
+ @Override
+ public void superDrawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+
+ super.drawOverlayBitmap(canvas, drawPosition, (Projection) projection.getImpl(), drawZoomLevel);
+ }
+
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/mapsforge/mfUsersOverlayItem.java b/src/cgeo/geocaching/mapsforge/mfUsersOverlayItem.java
new file mode 100644
index 0000000..a38a0a6
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfUsersOverlayItem.java
@@ -0,0 +1,43 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.GeoPoint;
+import org.mapsforge.android.maps.OverlayItem;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.mapinterfaces.UserOverlayItemImpl;
+
+public class mfUsersOverlayItem extends OverlayItem implements UserOverlayItemImpl {
+ private Context context = null;
+ private cgUser user = null;
+
+ public mfUsersOverlayItem(Context contextIn, cgUser userIn) {
+ super(new GeoPoint((int)(userIn.latitude * 1e6), (int)(userIn.longitude * 1e6)), userIn.username, "");
+
+ context = contextIn;
+ user = userIn;
+ }
+
+ @Override
+ public Drawable getMarker(int state) {
+ Drawable marker = null;
+
+ if (user != null && user.located != null && user.located.getTime() >= (System.currentTimeMillis() - (20 * 60 * 1000))) {
+ marker = context.getResources().getDrawable(R.drawable.user_location_active);
+ } else {
+ marker = context.getResources().getDrawable(R.drawable.user_location);
+ }
+
+ marker.setBounds(0, 0, marker.getIntrinsicWidth(), marker.getIntrinsicHeight());
+ marker.setAlpha(190);
+ setMarker(marker);
+
+ return marker;
+ }
+
+ public cgUser getUser() {
+ return user;
+ }
+}