aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cgeo-calendar/src/cgeo/calendar/CalendarActivity.java209
-rw-r--r--cgeo-calendar/src/cgeo/calendar/Compatibility.java7
-rw-r--r--main/res/layout/cacheview_details.xml31
-rw-r--r--main/res/values-de/strings.xml9
-rw-r--r--main/res/values-it/strings.xml10
-rw-r--r--[-rwxr-xr-x]main/res/values-sv/strings.xml7
-rw-r--r--main/res/values/strings.xml199
-rw-r--r--main/src/cgeo/geocaching/CacheDetailActivity.java47
-rw-r--r--main/src/cgeo/geocaching/Settings.java19
-rw-r--r--main/src/cgeo/geocaching/StaticMapsProvider.java9
-rw-r--r--main/src/cgeo/geocaching/VisitCacheActivity.java11
-rw-r--r--main/src/cgeo/geocaching/activity/AbstractActivity.java55
-rw-r--r--main/src/cgeo/geocaching/cgBase.java956
-rw-r--r--main/src/cgeo/geocaching/cgCache.java66
-rw-r--r--main/src/cgeo/geocaching/cgData.java4
-rw-r--r--main/src/cgeo/geocaching/cgeo.java15
-rw-r--r--main/src/cgeo/geocaching/cgeocaches.java18
-rw-r--r--main/src/cgeo/geocaching/cgeoinit.java17
-rw-r--r--main/src/cgeo/geocaching/cgeopopup.java2
-rw-r--r--main/src/cgeo/geocaching/cgeotouch.java9
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCBase.java193
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCConnector.java14
-rw-r--r--main/src/cgeo/geocaching/connector/gc/IconDecoder.java164
-rw-r--r--main/src/cgeo/geocaching/connector/gc/Tile.java35
-rw-r--r--main/src/cgeo/geocaching/connector/gc/UTFGrid.java17
-rw-r--r--main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java22
-rw-r--r--main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java4
-rw-r--r--main/src/cgeo/geocaching/files/LocalStorage.java52
-rw-r--r--main/src/cgeo/geocaching/gcvote/GCVote.java6
-rw-r--r--main/src/cgeo/geocaching/geopoint/Geopoint.java39
-rw-r--r--main/src/cgeo/geocaching/geopoint/Viewport.java45
-rw-r--r--main/src/cgeo/geocaching/go4cache/Go4Cache.java5
-rw-r--r--main/src/cgeo/geocaching/maps/CGeoMap.java101
-rw-r--r--main/src/cgeo/geocaching/maps/google/GoogleMapView.java4
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java4
-rw-r--r--main/src/cgeo/geocaching/network/HtmlImage.java11
-rw-r--r--main/src/cgeo/geocaching/network/Login.java389
-rw-r--r--main/src/cgeo/geocaching/network/Network.java364
-rw-r--r--main/src/cgeo/geocaching/network/OAuth.java5
-rw-r--r--main/src/cgeo/geocaching/twitter/Twitter.java45
-rw-r--r--main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java6
-rw-r--r--main/src/cgeo/geocaching/ui/DirectionImage.java6
-rw-r--r--main/src/cgeo/geocaching/utils/LRUList.java46
-rw-r--r--main/src/cgeo/geocaching/utils/LogTemplateProvider.java6
-rw-r--r--tests/res/raw/tile12.pngbin0 -> 10414 bytes
-rw-r--r--tests/src/cgeo/geocaching/cgBaseTest.java2
-rw-r--r--tests/src/cgeo/geocaching/cgeoApplicationTest.java47
-rw-r--r--tests/src/cgeo/geocaching/connector/gc/GCBaseTest.java16
-rw-r--r--tests/src/cgeo/geocaching/connector/gc/GCConnectorTest.java93
-rw-r--r--tests/src/cgeo/geocaching/connector/gc/IconDecoderTest.java82
-rw-r--r--tests/src/cgeo/geocaching/test/mock/GC1ZXX2.java4
-rw-r--r--tests/src/cgeo/geocaching/test/mock/GC2CJPF.java4
-rw-r--r--tests/src/cgeo/geocaching/test/mock/GC2JVEH.java4
53 files changed, 1911 insertions, 1624 deletions
diff --git a/cgeo-calendar/src/cgeo/calendar/CalendarActivity.java b/cgeo-calendar/src/cgeo/calendar/CalendarActivity.java
index 6ff9450..b339954 100644
--- a/cgeo-calendar/src/cgeo/calendar/CalendarActivity.java
+++ b/cgeo-calendar/src/cgeo/calendar/CalendarActivity.java
@@ -4,6 +4,7 @@ import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.DialogInterface;
+import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
@@ -49,8 +50,14 @@ public final class CalendarActivity extends Activity {
name = getParameter(ICalendar.PARAM_NAME);
location = getParameter(ICalendar.PARAM_LOCATION);
coords = getParameter(ICalendar.PARAM_COORDS);
+
if (name.length() > 0 && hiddenDate.length() > 0) {
- selectCalendarForAdding();
+ if (Compatibility.isLevel14()) {
+ addToCalendarLevel14();
+ finish();
+ } else {
+ selectCalendarForAdding();
+ }
}
} catch (Exception e) {
Log.e(LOG_TAG, e.getMessage(), e);
@@ -81,33 +88,32 @@ public final class CalendarActivity extends Activity {
// TODO: Handle missing provider
final Cursor cursor = managedQuery(calendarProvider, projection, "selected=1", null, null);
+ if (cursor == null || cursor.getCount() <= 0) {
+ showToast(getResources().getString(R.string.event_fail));
+ return;
+ }
+
final Map<Integer, String> calendars = new HashMap<Integer, String>();
- if (cursor != null) {
- if (cursor.getCount() > 0) {
- cursor.moveToFirst();
-
- final int indexId = cursor.getColumnIndex("_id");
- final int indexName = cursor.getColumnIndex("displayName");
-
- do {
- final String idString = cursor.getString(indexId);
- if (idString != null) {
- try {
- int id = Integer.parseInt(idString);
- final String calName = cursor.getString(indexName);
-
- if (id > 0 && calName != null) {
- calendars.put(id, calName);
- }
- } catch (NumberFormatException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
+ cursor.moveToFirst();
+
+ final int indexId = cursor.getColumnIndex("_id");
+ final int indexName = cursor.getColumnIndex("displayName");
+
+ do {
+ final String idString = cursor.getString(indexId);
+ if (idString != null) {
+ try {
+ int id = Integer.parseInt(idString);
+ final String calName = cursor.getString(indexName);
+
+ if (id > 0 && calName != null) {
+ calendars.put(id, calName);
}
- } while (cursor.moveToNext());
+ } catch (NumberFormatException e) {
+ Log.e(LOG_TAG, "CalendarActivity.selectCalendarForAdding", e);
+ }
}
- cursor.close();
- }
+ } while (cursor.moveToNext());
if (calendars.isEmpty()) {
return;
@@ -135,59 +141,79 @@ public final class CalendarActivity extends Activity {
}
/**
- * @param calendars
- *
- * @param index
- * The selected calendar
+ * @return <code>Date</code> based on hidden date. Time is set to 00:00:00.
*/
- private void addToCalendar(Integer calendarId) {
- try {
- final Uri calendarProvider = Compatibility.getCalenderEventsProviderURI();
-
- // date
- final Date eventDate = new Date(Long.parseLong(hiddenDate));
- eventDate.setHours(0);
- eventDate.setMinutes(0);
- eventDate.setSeconds(0);
-
- // description
- final StringBuilder description = new StringBuilder();
- description.append(url);
- if (shortDesc.length() > 0) {
- // remove images in short description
- final Spanned spanned = Html.fromHtml(shortDesc, null, null);
- String text = spanned.toString();
- final ImageSpan[] spans = spanned.getSpans(0, spanned.length(), ImageSpan.class);
- for (int i = spans.length - 1; i >= 0; i--) {
- text = text.substring(0, spanned.getSpanStart(spans[i])) + text.substring(spanned.getSpanEnd(spans[i]));
- }
- if (text.length() > 0) {
- description.append("\n\n");
- description.append(text);
- }
- }
+ private Date parseDate() {
+ final Date eventDate = new Date(Long.parseLong(hiddenDate));
+ eventDate.setHours(0);
+ eventDate.setMinutes(0);
+ eventDate.setSeconds(0);
- if (personalNote.length() > 0) {
- description.append("\n\n").append(Html.fromHtml(personalNote).toString());
+ return eventDate;
+ }
+
+ /**
+ * @return description string with images removed and personal note included
+ */
+ private String parseDescription() {
+ final StringBuilder description = new StringBuilder();
+ description.append(url);
+ if (shortDesc.length() > 0) {
+ // remove images in short description
+ final Spanned spanned = Html.fromHtml(shortDesc, null, null);
+ String text = spanned.toString();
+ final ImageSpan[] spans = spanned.getSpans(0, spanned.length(), ImageSpan.class);
+ for (int i = spans.length - 1; i >= 0; i--) {
+ text = text.substring(0, spanned.getSpanStart(spans[i])) + text.substring(spanned.getSpanEnd(spans[i]));
}
+ if (text.length() > 0) {
+ description.append("\n\n");
+ description.append(text);
+ }
+ }
+
+ if (personalNote.length() > 0) {
+ description.append("\n\n").append(Html.fromHtml(personalNote).toString());
+ }
- // location
- final StringBuilder locBuffer = new StringBuilder();
- if (coords.length() > 0) {
- locBuffer.append(coords);
+ return description.toString();
+ }
+
+ /**
+ * @return location string with coordinates and location
+ */
+ private String parseLocation() {
+ final StringBuilder locBuffer = new StringBuilder();
+ if (coords.length() > 0) {
+ locBuffer.append(coords);
+ }
+ if (location.length() > 0) {
+ boolean addParentheses = false;
+ if (locBuffer.length() > 0) {
+ addParentheses = true;
+ locBuffer.append(" (");
}
- if (location.length() > 0) {
- boolean addParentheses = false;
- if (locBuffer.length() > 0) {
- addParentheses = true;
- locBuffer.append(" (");
- }
- locBuffer.append(Html.fromHtml(location).toString());
- if (addParentheses) {
- locBuffer.append(')');
- }
+ locBuffer.append(Html.fromHtml(location).toString());
+ if (addParentheses) {
+ locBuffer.append(')');
}
+ }
+
+ return locBuffer.toString();
+ }
+
+ /**
+ * @param calendarId
+ * The selected calendar
+ */
+ private void addToCalendar(Integer calendarId) {
+ try {
+ final Uri calendarProvider = Compatibility.getCalendarEventsProviderURI();
+
+ final Date eventDate = parseDate();
+ final String description = parseDescription();
+ final String location = parseLocation();
// values
final ContentValues event = new ContentValues();
@@ -196,10 +222,10 @@ public final class CalendarActivity extends Activity {
event.put("dtend", eventDate.getTime() + 43200000 + 3600000); // + one hour
event.put("eventTimezone", "UTC");
event.put("title", Html.fromHtml(name).toString());
- event.put("description", description.toString());
+ event.put("description", description);
- if (locBuffer.length() > 0) {
- event.put("eventLocation", locBuffer.toString());
+ if (location.length() > 0) {
+ event.put("eventLocation", location);
}
event.put("allDay", 1);
event.put("hasAlarm", 0);
@@ -210,7 +236,40 @@ public final class CalendarActivity extends Activity {
} catch (Exception e) {
showToast(getResources().getString(R.string.event_fail));
- Log.e(LOG_TAG, "CalendarActivity.addToCalendarFn: " + e.toString());
+ Log.e(LOG_TAG, "CalendarActivity.addToCalendarFn", e);
+ }
+ }
+
+ /**
+ * Add cache to calendar in Android versions 4.0 and greater using <code>Intent</code>. This does not require
+ * calendar permissions.
+ * TODO Does this work with apps other than default calendar app?
+ */
+ private void addToCalendarLevel14() {
+ try {
+ final Date eventDate = parseDate();
+ final String description = parseDescription();
+ final String location = parseLocation();
+
+ /*
+ * TODO These strings are available as constants starting with API 14 and can be used when
+ * targetSdkVersion changes to 14. For example CalendarContract.EXTRA_EVENT_BEGIN_TIME and
+ * Events.TITLE
+ */
+ final Intent intent = new Intent(Intent.ACTION_INSERT)
+ .setData(Compatibility.getCalendarEventsProviderURI())
+ .putExtra("beginTime", eventDate.getTime() + 43200000)
+ .putExtra("allDay", true)
+ .putExtra("title", Html.fromHtml(name).toString())
+ .putExtra("description", description)
+ .putExtra("hasAlarm", false)
+ .putExtra("eventTimezone", "UTC")
+ .putExtra("eventLocation", location);
+ startActivity(intent);
+ } catch (Exception e) {
+ showToast(getResources().getString(R.string.event_fail));
+
+ Log.e(LOG_TAG, "CalendarActivity.addToCalendarLevel14: " + e.toString());
}
}
diff --git a/cgeo-calendar/src/cgeo/calendar/Compatibility.java b/cgeo-calendar/src/cgeo/calendar/Compatibility.java
index 7d770ea..905d6df 100644
--- a/cgeo-calendar/src/cgeo/calendar/Compatibility.java
+++ b/cgeo-calendar/src/cgeo/calendar/Compatibility.java
@@ -7,12 +7,17 @@ public final class Compatibility {
private final static int sdkVersion = Integer.parseInt(Build.VERSION.SDK);
private final static boolean isLevel8 = sdkVersion >= 8;
+ private final static boolean isLevel14 = sdkVersion >= 14;
public static Uri getCalendarProviderURI() {
return Uri.parse(isLevel8 ? "content://com.android.calendar/calendars" : "content://calendar/calendars");
}
- public static Uri getCalenderEventsProviderURI() {
+ public static Uri getCalendarEventsProviderURI() {
return Uri.parse(isLevel8 ? "content://com.android.calendar/events" : "content://calendar/events");
}
+
+ public static boolean isLevel14() {
+ return isLevel14;
+ }
}
diff --git a/main/res/layout/cacheview_details.xml b/main/res/layout/cacheview_details.xml
index 3da0789..4baf5c2 100644
--- a/main/res/layout/cacheview_details.xml
+++ b/main/res/layout/cacheview_details.xml
@@ -136,37 +136,6 @@
</RelativeLayout>
</LinearLayout>
- <!-- Debug info Box -->
-
- <LinearLayout
- android:id="@+id/debug_box"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical" >
-
- <View
- style="@style/separator_horizontal"
- android:layout_marginBottom="9dp"
- android:layout_marginTop="9dp" />
-
- <RelativeLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content" >
-
- <TextView
- android:id="@+id/debug_text"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_gravity="left"
- android:layout_marginLeft="6dip"
- android:layout_marginRight="130dip"
- android:paddingRight="3dip"
- android:textColor="?text_color"
- android:textSize="14dip" />
- </RelativeLayout>
- </LinearLayout>
-
<!-- License Box -->
<LinearLayout
diff --git a/main/res/values-de/strings.xml b/main/res/values-de/strings.xml
index b88d066..1bb2dc6 100644
--- a/main/res/values-de/strings.xml
+++ b/main/res/values-de/strings.xml
@@ -165,7 +165,6 @@
<string name="err_store_failed">Speichern des Caches fehlgeschlagen.</string>
<string name="err_refresh_failed">Aktualisierung fehlgeschlagen.</string>
<string name="err_dwld_details_failed">Download der Cache-Details fehlgeschlagen.</string>
- <string name="err_dwld_details_failed_reason">Download der Cache-Details fehlgeschlagen, wegen</string>
<string name="err_load_descr_failed">Laden der Cachebeschreibung fehlgeschlagen.</string>
<string name="err_location_unknown">c:geo erkennt die Position des Caches nicht.</string>
<string name="err_missing_device_name">Bitte lege einen Namen für dein Handy fest, bevor du dich registrierst.</string>
@@ -423,7 +422,7 @@
<string name="init_maptrail">Zeige Spur auf Karte</string>
<string name="init_trackautovisit">Trackables automatisch auf \"besuchen\" setzen</string>
<string name="init_sigautoinsert">Signatur automatisch einfügen</string>
- <string name="init_loaddirectionimg">Richtungs-Grafik laden wenn nötig</string>
+ <string name="init_loaddirectionimg">Richtungs-Grafik laden wenn nötig (nur Basic Member)</string>
<string name="init_default_navigation_tool">Standardnavigation</string>
<string name="init_default_navigation_tool_description">Hier kannst du dein bevorzugtes Navigationswerkzeug festlegen.</string>
<string name="init_default_navigation_tool_select">Wähle Werkzeug</string>
@@ -658,6 +657,12 @@
<string name="map_static_loading">Lade statische Karte…</string>
<string name="map_token_err">c:geo konnte nur Teildaten herunterladen, die Koordinaten der Caches könnten ungenau sein.</string>
<string name="map_as_list">Als Liste anzeigen</string>
+ <string name="map_strategy">Strategie</string>
+ <string name="map_strategy_title">Strategie für Live-Karte</string>
+ <string name="map_strategy_fastest">Schnellste</string>
+ <string name="map_strategy_fast">Schnell</string>
+ <string name="map_strategy_auto">Geschwindigkeitsabhängig</string>
+ <string name="map_strategy_detailed">Detailliert</string>
<!-- search -->
<string name="search_bar_hint">Suche nach Caches</string>
diff --git a/main/res/values-it/strings.xml b/main/res/values-it/strings.xml
index a3ab64b..8790469 100644
--- a/main/res/values-it/strings.xml
+++ b/main/res/values-it/strings.xml
@@ -117,6 +117,14 @@
<string name="log_new_log">Log</string>
<string name="log_new_log_text">Testo Log</string>
<string name="log_announcement">Annuncio</string>
+
+ <!-- copy -->
+ <string name="options_context_menu_title">Opzioni</string>
+ <string name="copy_coords">Copia Coordinate</string>
+ <string name="copy_desc">Copia Descrizione</string>
+ <string name="copy_personalnote">Copia Note personali</string>
+ <string name="copy_hint">Copia Aiuti</string>
+ <string name="copy_log">Copia Log</string>
<!-- translation -->
<string name="translate_to_sys_lang">Traduci in %s</string>
@@ -429,7 +437,7 @@
<string name="init_default_navigation_tool">Navigatore preferito</string>
<string name="init_default_navigation_tool_description">Qui puoi scegliere il tuo strumento di navigazione preferito.</string>
<string name="init_default_navigation_tool_select">Scegli navigatore</string>
- <string name="init_default_navigation_tool_2_description">Qui puoi scegliere il tuo secondo navigatore preferito. Sarà attivato tenendo cliccato l\'icona di navigazione nella action bar.</string>
+ <string name="init_default_navigation_tool_2_description">Qui puoi scegliere il tuo secondo navigatore preferito. Sarà attivato tenendo premuto l\'icona di navigazione vicino al titolo della cache.</string>
<string name="init_sendToCgeo">Send to c:geo</string>
<string name="init_sendToCgeo_name">Nome dispositivo:</string>
diff --git a/main/res/values-sv/strings.xml b/main/res/values-sv/strings.xml
index f607727..fe3c759 100755..100644
--- a/main/res/values-sv/strings.xml
+++ b/main/res/values-sv/strings.xml
@@ -589,6 +589,7 @@
<!-- gpx -->
<string name="gpx_import_loading_caches">Läser in cacher från .gpx filen</string>
<string name="gpx_import_loading_waypoints">Läser in punkter från .gpx file</string>
+ <string name="gpx_import_store_static_maps">Sparar kartor</string>
<string name="gpx_import_storing">Skriver cacher till databasen</string>
<string name="gpx_import_caches_imported">cacher importerade</string>
<string name="gpx_import_title">Importera GPX</string>
@@ -664,6 +665,12 @@
<string name="map_static_loading">Laddar sparade kartor…</string>
<string name="map_token_err">Eftersom c:geo bara kunde hämta en del av informationen så kan positionen för cacher vara felaktig.</string>
<string name="map_as_list">Visa som lista</string>
+ <string name="map_strategy">Strategi</string>
+ <string name="map_strategy_title">Strategi för Live karta</string>
+ <string name="map_strategy_fastest">Snabbaste</string>
+ <string name="map_strategy_fast">Snabbt</string>
+ <string name="map_strategy_auto">Hastighetsberoende (gps)</string>
+ <string name="map_strategy_detailed">Exakta positioner</string>
<!-- search -->
<string name="search_bar_hint">Sök cache/TB</string>
diff --git a/main/res/values/strings.xml b/main/res/values/strings.xml
index a5d9228..c60aa99 100644
--- a/main/res/values/strings.xml
+++ b/main/res/values/strings.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
<resources>
<string name="app_name">c:geo</string>
<string name="app_name_compass">c:geo compass</string>
@@ -423,7 +423,7 @@
<string name="init_maptrail">Show trail on Map</string>
<string name="init_trackautovisit">Set trackables to \"Visited\" as a default</string>
<string name="init_sigautoinsert">Insert signature automatically</string>
- <string name="init_loaddirectionimg">Load direction-image if necessary</string>
+ <string name="init_loaddirectionimg">Load direction-image if necessary (only Basic Member)</string>
<string name="init_default_navigation_tool">Default Navigation</string>
<string name="init_default_navigation_tool_description">Here you can select your preferred navigation tool.</string>
<string name="init_default_navigation_tool_select">Select tool</string>
@@ -692,6 +692,7 @@
<string name="map_token_err">Since c:geo is able to download only partial data, coordinates of caches could be inaccurate.</string>
<string name="map_as_list">Show as list</string>
<string name="map_strategy">Strategy</string>
+ <string name="map_strategy_title">Live Map strategy</string>
<string name="map_strategy_fastest">Fastest</string>
<string name="map_strategy_fast">Fast</string>
<string name="map_strategy_auto">Speed dependent</string>
@@ -1005,157 +1006,49 @@
<!-- changelog -->
<string name="changelog">\n
- <b>next release</b>\n
- · New: Moved calendar operations to separate calendar add-on (available on Android Market).\n
+ <b>Next Release</b>\n\n
+ <b>New Features/Functions:</b>\n
+ · Live Map re-implementation with selectable strategy:\n
+ Fastest: Load approximated cache coords only\n
+ Fast: Same as fastest but try to identify the cache type\n
+ Detailed: Same as fast but load details for 20 caches around your position\n
+ Speed dependent: Automatic switch from detailed to fastest at 30kmh\n
+ · New markers in map and partly in lists:\n
+ Personal Note available(Pen icon)\n
+ Modified coordinates available (Flagpost icon)\n
+ Caches is saved on device (Disk icon)\n
+ Offline log is stored (Red smiley)\n
+ Cache coords are approximated (Encircled in Orange)\n
+ · Calendar operations moved to calendar add-on (Android Market)\n
c:geo doesn\'t require calendar permissions anymore\n
- · New: Login status and find count shown on start screen\n
- · New: Improved markers in the map with additional information for stored caches:\n
- Personal Note available, Modified coordinates, Saved on device, Offline log available, Non-reliable coordinates (orange circle)\n
- · New: Copy, translate and forward available with long press for cache- and log-text\n
- · New: User can select two preffered navigation tools for easier accessibility\n
- · New: Type of waypoint can be selected for custom waypoints\n
- · New: Day of week is now shown for event-caches\n
- · New: Static maps can now also be stored for waypoints of a cache\n
- · Fix: Live Map\n
- · Fix: Deletion of outdated caches did not work\n
- · Fix: Changed internal caching causing a better overall performance\n
- · Fix: Caches with modified coordinates are displayed at the modified coords and not at the original coords\n
- · Fix: Improved consistency for offline-logging operations\n
- · Fix: Removed OSM:Osmarender map as it is no longer available\n
- · Fix: Find-count not working in signature\n
- · Fix: Keep screen on while viewing cache-lists\n
-\n
- <a href="https://github.com/cgeo/c-geo-opensource/issues?milestone=3&amp;state=closed">Detailed list of all Changes</a>\n
- \n\n
- <b>04.01.2012</b>\n
- · new: additional page in the details view for logs from friends\n
- · new: horizontal scrollable pages for cache details\n
- · new: click on cache coordinates to change format\n
- · new: show own rating in cache details\n
- · new: import zipped pocket queries\n
- · new: import pocket queries from e-mail\n
- · new: show original coordinates as waypoint if user has modified listing-coordinates on gc.com\n
- · new: delete caches and list together\n
- · new: have link from hint section to spoiler images\n
- · new: edit and more options for any-location-history\n
- · new: allow offline log without any login data stored\n
- · new: ask for restore after reinstallation\n
- · new: context menu to open spoiler/log images online\n
- · new: create waypoints from personal cache note\n
- · fix: several calendar bugs\n
- · fix: some enhancement due to gc.com update\n
- · fix: new translation IT, several translation-updates\n
- · fix: lot of design enhancements (icons, font-size, autoresizing text-fields, auto-suggestion, seperators, inventory-actions, stars color and value, keyboard, colors, many more)\n
- · fix: Refresh not stored caches\n
- · fix: batch-actions for trackables not working\n
- · fix: missing cache-name as title in cache details\n
- · fix: some map-issues for gc.com-premium-members\n
- · fix: edited waypoints are overwritten by cache update\n
- · fix: spoiler images are too small\n
- · fix: incorrect storage time in cache details\n
- · fix: incorrect handling of GeoKrety trackables\n
- · 100+ bugfixes and enhancements\n
- \n\n
- <b>08.11.2011</b>\n
- · fix: adaption to GC.com changes\n
- \n\n
- <b>31.10.2011</b>\n
- · fix: Store for offline from Live map\n
- \n\n
- <b>30.10.2011</b>\n
- · new: cleanup the cgeo private cache directory when caches are removed from database\n
- · new: display user avatar when checking login/password from geocaching.com\n
- · new: support Geocaching Australia caches (GAxxxx, TPxxxx)\n
- · new: import GPX from mail\n
- · new: support geopeitus.ee caches\n
- · new: verbose cache-loading\n
- · fix: Twitter authorization\n
- · fix: login problems\n
- · fix: Google &amp; OSM maps consistency\n
- · fix: readable cache description (black on black, white on white)\n
- · fix: many other bugs\n
- \n\n
- <b>09.10.2011</b>\n
- · fix: small bugs due to GC.com change\n
- \n\n
- <b>06.10.2011</b>\n
- · new: import waypoint files from pocket query\n
- · new: automatically filter out counter images from cache description\n
- · new: show all the images belonging to a log entry at once\n
- · new: make it possible to display intermediate waypoints on live map\n
- · new: better progress information when importing GPX files\n
- · new: better progress information during backup/restore of database\n
- · new: better French, German, Hungarian, and Slovak translations\n
- · new: better icon for caches needing maintenance\n
- · fix: work again on all devices, it was broken on some Android 1.6 models\n
- · fix: correctly display target on map when using any coordinates mode\n
- · fix: forwarding of OC caches used wrong URL\n
- · fix: better performance when parsing cache description\n
- · fix: performance improvements when importing waypoints\n
- · fix: reclaim bitmap memory earlier to prevent memory exhaustion\n
- · fix: cleaner location names (no more HTML) in cache descriptions\n
- · fix: load descriptions from database only when needed (lower memory consumption)\n
- · fix: one of the coordinates entry mode was using the wrong coordinate when reediting\n
- · fix: latitude and longitude are now localized\n
- · fix: remove redundant fields in the database to reduce used space\n
- · fix: various bug fixes and internal enhancements\n
- \n\n
- <b>24.09.2011</b>\n
- · new: import of LOC files\n
- · new: search for geo code supports OpenCaching.ORG.UK/.PL/.US\n
- · new: restore settings after reinstallation (Android 2.3+)\n
- · new: save the log locally when leaving the log activity\n
- · new: insert signature after the cursor when logging\n
- · fix: various bug fixes\n
- \n\n
- <b>18.09.2011</b>\n
- · fix: Android 3+ compatibility\n
- \n\n
- <b>17.09.2011</b>\n
- · fix: more small fixes\n
- \n\n
- <b>16.09.2011</b>\n
- · fix: many small fixed due to GC.com changes\n
- \n\n
- <b>15.09.2011</b>\n
- · new: sort by state, sort by find count\n
- · new: experimental support for .gpx from opencaching.com\n
- · new: scan QR code to open cache description (Barcode Scanner from Market)\n
- · new: context menu on stored caches button (main screen)\n
- · new: compass immediately shows the right direction\n
- · new: active filters are shown in list mode\n
- · fix: performance of GPX import\n
- · fix: performance of deleting caches from list\n
- · fix: performance of web traffic\n
- · fix: return to list after GPX import\n
- · fix: fill signature when logging offline\n
- · fix: show strikethrough in caches\n
- · fix: no more empty map previews\n
- · fix: send2c:geo authorization\n
- \n\n
- <b>26.08.2011</b>\n
- · new: street view\n
- · new: attribute icons\n
- · new: experimental support for .gpx from opencaching.de\n
- · fix: log-dates\n
- · fix: coordinates input\n
- · fix: nearby list performance update\n
- \n\n
- <b>22.08.2011</b>\n
- · fix: due to GC.com changes c:geo hangs in displaying cache detail\n
- \n\n
- <b>20.08.2011</b>\n
- · fix: Additional adaption to GC.com changes\n
- \n\n
- <b>19.08.2011</b>\n
- · new: Numeric entry for coordinates\n
- · fix: adaption to GC.com changes\n
- \n\n
- <b>15.08.2011</b>\n
- · new: OpenStreetMap support\n
- · new: Send to c:geo from web\n
- · new: Export field notes\n
- · new: Clear history\n
- · fix: A lot of bugs\n
+ · Login status and find count shown on main screen\n
+ · Copy, translate, forward with long press for cache- and log-text\n
+ · Two preferred navigation tools selectable\n
+ · Type of waypoint can be selected on creation\n
+ · Day of week shown for event-caches\n
+ · Static maps can be saved for waypoints\n
+ · Static maps saved while importing GPX-files\n\n
+ <b>Bugfixing:</b>\n
+ · Deletion of outdated caches improved\n
+ · Changed internal caching for better performance\n
+ · Caches with modified coords are displayed at the modified coords\n
+ · Improved consistency for offline logging\n
+ · Removed OSM:Osmarender as it is no longer available\n
+ · Find-count not working in signature\n
+ · Keep screen on while viewing cache-lists\n
+ · TB-icons now shown in correct size\n
+ · Cache count on live map corrected\n
+ \n
+ <a href="https://github.com/cgeo/c-geo-opensource/issues?milestone=3&amp;state=closed">Detailed list of all changes</a>\n
+ \n
+ <b>Known Limitations/Bugs:</b>\n
+ · Live map:\n
+ Approximated coords due to limitations on the GC-website\n
+ In fast mode the cache type might be wrong in rare cases\n
+ Fast mode only detectes Tradi, Multi, Mystery, Event caches\n
+ · Other:\n
+ Log images with huge size will cause a long loading time\n\n\n
+ <b>Old releases</b>\n
+ · Please refer to the release notes on the <a href="http://www.cgeo.org">c:geo-website</a>.\n
\n</string>
</resources>
diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java
index f3776ea..4649477 100644
--- a/main/src/cgeo/geocaching/CacheDetailActivity.java
+++ b/main/src/cgeo/geocaching/CacheDetailActivity.java
@@ -1,7 +1,6 @@
package cgeo.geocaching;
import cgeo.calendar.ICalendar;
-import cgeo.geocaching.cgData.StorageLocation;
import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.activity.Progress;
import cgeo.geocaching.apps.cache.GeneralAppsFactory;
@@ -17,6 +16,7 @@ import cgeo.geocaching.geopoint.GeopointFormatter;
import cgeo.geocaching.geopoint.HumanDistance;
import cgeo.geocaching.geopoint.IConversion;
import cgeo.geocaching.network.HtmlImage;
+import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.ui.DecryptTextClickListener;
import cgeo.geocaching.ui.Formatter;
@@ -635,11 +635,6 @@ public class CacheDetailActivity extends AbstractActivity {
// Data loaded, we're ready to show it!
notifyDataSetChanged();
- // cache isn't available until after notifyDataSetChanged is called
- if (cache != null) {
- cache.setChangeNotificationHandler(cacheChangeNotificationHandler);
- }
-
}
}
@@ -670,6 +665,9 @@ public class CacheDetailActivity extends AbstractActivity {
return;
}
+ // allow cache to notify CacheDetailActivity when it changes so it can be reloaded
+ cache.setChangeNotificationHandler(cacheChangeNotificationHandler);
+
// notify all creators that the data has changed
for (PageViewCreator creator : viewCreators.values()) {
creator.notifyDataSetChanged();
@@ -1521,8 +1519,6 @@ public class CacheDetailActivity extends AbstractActivity {
buttonWatchlistRemove.setOnClickListener(new RemoveFromWatchlistClickListener());
updateWatchlistBox();
- updateDebugInfos();
-
// data license
IConnector connector = ConnectorFactory.getConnector(cache);
if (connector != null) {
@@ -1562,7 +1558,7 @@ public class CacheDetailActivity extends AbstractActivity {
viewName.setText(res.getString(nameId));
viewValue.setText(String.format("%.1f", value) + ' ' + res.getString(R.string.cache_rating_of) + " 5");
- layoutStars.addView(cgBase.createStarRating(value, 5, CacheDetailActivity.this), 1);
+ layoutStars.addView(createStarRating(value, 5, CacheDetailActivity.this), 1);
detailsList.addView(layout);
return layout;
@@ -1877,26 +1873,6 @@ public class CacheDetailActivity extends AbstractActivity {
offlineRefresh.setClickable(true);
}
- private void updateDebugInfos() {
-
- if (Settings.isDebugInfos()) {
- ((LinearLayout) view.findViewById(R.id.debug_box)).setVisibility(View.VISIBLE);
- final TextView internalsText = (TextView) view.findViewById(R.id.debug_text);
-
- String sl = "Storage location: ";
- if (cache.getStorageLocation().contains(StorageLocation.CACHE)) {
- sl += "Cache ";
- }
- if (cache.getStorageLocation().contains(StorageLocation.DATABASE)) {
- sl += "Database (" + cache.getListId() + ")";
- }
-
- internalsText.setText(sl);
- } else {
- ((LinearLayout) view.findViewById(R.id.debug_box)).setVisibility(View.GONE);
- }
- }
-
private class PreviewMapTask extends AsyncTask<Void, Void, BitmapDrawable> {
@Override
protected BitmapDrawable doInBackground(Void... params) {
@@ -1912,7 +1888,7 @@ public class CacheDetailActivity extends AbstractActivity {
final int height = (int) (110 * metrics.density);
// TODO move this code to StaticMapProvider and use its constant values
- final String markerUrl = cgBase.urlencode_rfc3986("http://cgeo.carnero.cc/_markers/my_location_mdpi.png");
+ final String markerUrl = Network.urlencode_rfc3986("http://cgeo.carnero.cc/_markers/my_location_mdpi.png");
final HtmlImage mapGetter = new HtmlImage(CacheDetailActivity.this, cache.getGeocode(), false, 0, false);
image = mapGetter.getDrawable("http://maps.google.com/maps/api/staticmap?zoom=15&size=" + width + "x" + height + "&maptype=roadmap&markers=icon%3A" + markerUrl + "%7Cshadow:false%7C" + latlonMap + "&sensor=false");
@@ -2013,7 +1989,7 @@ public class CacheDetailActivity extends AbstractActivity {
if (StringUtils.isNotBlank(cache.getHint())) {
TextView hintView = ((TextView) view.findViewById(R.id.hint));
if (BaseUtils.containsHtml(cache.getHint())) {
- hintView.setText(Html.fromHtml(cache.getHint(), new HtmlImage(CacheDetailActivity.this, null, false, cache.getListId(), false), null), TextView.BufferType.SPANNABLE);
+ hintView.setText(Html.fromHtml(cache.getHint(), new HtmlImage(CacheDetailActivity.this, cache.getGeocode(), false, cache.getListId(), false), null), TextView.BufferType.SPANNABLE);
hintView.setText(CryptUtils.rot13((Spannable) hintView.getText()));
}
else {
@@ -2245,6 +2221,9 @@ public class CacheDetailActivity extends AbstractActivity {
}
view.setAdapter(new ArrayAdapter<cgLog>(CacheDetailActivity.this, R.layout.cacheview_logs_item, cache.getLogs(allLogs)) {
+ final UserActionsClickListener userActionsClickListener = new UserActionsClickListener();
+ final DecryptTextClickListener decryptTextClickListener = new DecryptTextClickListener();
+
@Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
View rowView = convertView;
@@ -2283,7 +2262,7 @@ public class CacheDetailActivity extends AbstractActivity {
// logtext, avoid parsing HTML if not necessary
if (BaseUtils.containsHtml(log.log)) {
- holder.text.setText(Html.fromHtml(log.log, new HtmlImage(CacheDetailActivity.this, null, false, cache.getListId(), false), null), TextView.BufferType.SPANNABLE);
+ holder.text.setText(Html.fromHtml(log.log, new HtmlImage(CacheDetailActivity.this, cache.getGeocode(), false, cache.getListId(), false), null), TextView.BufferType.SPANNABLE);
}
else {
holder.text.setText(log.log);
@@ -2337,9 +2316,9 @@ public class CacheDetailActivity extends AbstractActivity {
if (null == convertView) {
// if convertView != null then this listeners are already set
- holder.author.setOnClickListener(new UserActionsClickListener());
+ holder.author.setOnClickListener(userActionsClickListener);
holder.text.setMovementMethod(LinkMovementMethod.getInstance());
- holder.text.setOnClickListener(new DecryptTextClickListener());
+ holder.text.setOnClickListener(decryptTextClickListener);
registerForContextMenu(holder.text);
}
diff --git a/main/src/cgeo/geocaching/Settings.java b/main/src/cgeo/geocaching/Settings.java
index 40ad96d..4949b62 100644
--- a/main/src/cgeo/geocaching/Settings.java
+++ b/main/src/cgeo/geocaching/Settings.java
@@ -76,7 +76,6 @@ public final class Settings {
private static final String KEY_COOKIE_STORE = "cookiestore";
private static final String KEY_OPEN_LAST_DETAILS_PAGE = "opendetailslastpage";
private static final String KEY_LAST_DETAILS_PAGE = "lastdetailspage";
- private static final String KEY_DEBUG_INFORMATIONS = "debuginfos";
private static final String KEY_DEFAULT_NAVIGATION_TOOL = "defaultNavigationTool";
private static final String KEY_DEFAULT_NAVIGATION_TOOL_2 = "defaultNavigationTool2";
private static final String KEY_LIVE_MAP_STRATEGY = "livemapstrategy";
@@ -416,10 +415,10 @@ public final class Settings {
}
public static boolean getLoadDirImg() {
- return sharedPrefs.getBoolean(KEY_LOAD_DIRECTION_IMG, true);
+ return isPremiumMember() ? false : sharedPrefs.getBoolean(KEY_LOAD_DIRECTION_IMG, true);
}
- static void setGcCustomDate(final String format) {
+ public static void setGcCustomDate(final String format) {
editSharedSettings(new PrefRunnable() {
@Override
@@ -974,20 +973,6 @@ public final class Settings {
});
}
- public static boolean isDebugInfos() {
- return sharedPrefs.getBoolean(KEY_DEBUG_INFORMATIONS, false);
- }
-
- public static void setDebugInfos(final boolean showDebugInfos) {
- editSharedSettings(new PrefRunnable() {
-
- @Override
- public void edit(Editor edit) {
- edit.putBoolean(KEY_DEBUG_INFORMATIONS, showDebugInfos);
- }
- });
- }
-
public static int getDefaultNavigationTool() {
return sharedPrefs.getInt(KEY_DEFAULT_NAVIGATION_TOOL, 0);
}
diff --git a/main/src/cgeo/geocaching/StaticMapsProvider.java b/main/src/cgeo/geocaching/StaticMapsProvider.java
index 1461e59..fcb8ed9 100644
--- a/main/src/cgeo/geocaching/StaticMapsProvider.java
+++ b/main/src/cgeo/geocaching/StaticMapsProvider.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.concurrent.BlockingThreadPool;
import cgeo.geocaching.concurrent.Task;
import cgeo.geocaching.files.LocalStorage;
import cgeo.geocaching.geopoint.GeopointFormatter.Format;
+import cgeo.geocaching.network.Network;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@@ -41,10 +42,10 @@ public class StaticMapsProvider {
final String mapUrl = "http://maps.google.com/maps/api/staticmap?center=" + latlonMap;
final String url = mapUrl + "&zoom=" + zoom + "&size=" + edge + "x" + edge + "&maptype=" + mapType + "&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints + "&sensor=false";
final File file = getMapFile(cache.getGeocode(), prefix, level, true);
- final HttpResponse httpResponse = cgBase.request(url, null, false);
+ final HttpResponse httpResponse = Network.request(url, null, false);
if (httpResponse != null) {
- if (LocalStorage.saveEntityToFile(httpResponse.getEntity(), file)) {
+ if (LocalStorage.saveEntityToFile(httpResponse, file)) {
// Delete image if it has no contents
final long fileSize = file.length();
if (fileSize < MIN_MAP_IMAGE_BYTES) {
@@ -167,12 +168,12 @@ public class StaticMapsProvider {
type += "_disabled";
}
- return cgBase.urlencode_rfc3986(MARKERS_URL + "marker_cache_" + type + ".png");
+ return Network.urlencode_rfc3986(MARKERS_URL + "marker_cache_" + type + ".png");
}
private static String getWpMarkerUrl(final cgWaypoint waypoint) {
String type = waypoint.getWaypointType() != null ? waypoint.getWaypointType().id : null;
- return cgBase.urlencode_rfc3986(MARKERS_URL + "marker_waypoint_" + type + ".png");
+ return Network.urlencode_rfc3986(MARKERS_URL + "marker_waypoint_" + type + ".png");
}
public static void removeWpStaticMaps(int wp_id, String geocode) {
diff --git a/main/src/cgeo/geocaching/VisitCacheActivity.java b/main/src/cgeo/geocaching/VisitCacheActivity.java
index 6d0097a..f0acd97 100644
--- a/main/src/cgeo/geocaching/VisitCacheActivity.java
+++ b/main/src/cgeo/geocaching/VisitCacheActivity.java
@@ -8,7 +8,10 @@ import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.enumerations.LogTypeTrackable;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.gcvote.GCVote;
+import cgeo.geocaching.network.Login;
+import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
+import cgeo.geocaching.twitter.Twitter;
import cgeo.geocaching.ui.DateDialog;
import cgeo.geocaching.utils.LogTemplateProvider;
import cgeo.geocaching.utils.LogTemplateProvider.LogTemplate;
@@ -352,7 +355,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D
private void insertIntoLog(String newText, final boolean moveCursor) {
final EditText log = (EditText) findViewById(R.id.log);
- cgBase.insertAtPosition(log, newText, moveCursor);
+ insertAtPosition(log, newText, moveCursor);
}
private static String ratingTextValue(final double rating) {
@@ -653,9 +656,9 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D
return;
}
- final String page = cgBase.getResponseData(cgBase.request("http://www.geocaching.com/seek/log.aspx", params, false, false, false));
+ final String page = Network.getResponseData(Network.request("http://www.geocaching.com/seek/log.aspx", params, false, false, false));
- viewstates = cgBase.getViewstates(page);
+ viewstates = Login.getViewstates(page);
trackables = cgBase.parseTrackableLog(page);
final List<LogType> typesPre = cgBase.parseTypes(page);
@@ -729,7 +732,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D
if (status == StatusCode.NO_ERROR && typeSelected == LogType.LOG_FOUND_IT && Settings.isUseTwitter()
&& Settings.isTwitterLoginValid()
&& tweetCheck.isChecked() && tweetBox.getVisibility() == View.VISIBLE) {
- cgBase.postTweetCache(geocode);
+ Twitter.postTweetCache(geocode);
}
if (status == StatusCode.NO_ERROR && typeSelected == LogType.LOG_FOUND_IT && Settings.isGCvoteLogin()) {
diff --git a/main/src/cgeo/geocaching/activity/AbstractActivity.java b/main/src/cgeo/geocaching/activity/AbstractActivity.java
index 941cd08..8e8ad9d 100644
--- a/main/src/cgeo/geocaching/activity/AbstractActivity.java
+++ b/main/src/cgeo/geocaching/activity/AbstractActivity.java
@@ -1,18 +1,24 @@
package cgeo.geocaching.activity;
+import cgeo.geocaching.R;
import cgeo.geocaching.Settings;
import cgeo.geocaching.cgBase;
import cgeo.geocaching.cgCache;
import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.compatibility.Compatibility;
+import cgeo.geocaching.network.Network;
import android.app.Activity;
+import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
public abstract class AbstractActivity extends Activity implements IAbstractActivity {
@@ -82,7 +88,7 @@ public abstract class AbstractActivity extends Activity implements IAbstractActi
cgBase.initialize(app);
// Restore cookie store if needed
- cgBase.restoreCookieStore(Settings.getCookieStore());
+ Network.restoreCookieStore(Settings.getCookieStore());
ActivityMixin.keepScreenOn(this, keepScreenOn);
}
@@ -103,4 +109,51 @@ public abstract class AbstractActivity extends Activity implements IAbstractActi
ActivityMixin.invalidateOptionsMenu(this);
}
+ public static LinearLayout createStarRating(final float value, final int count, final Context context) {
+ LayoutInflater inflater = LayoutInflater.from(context);
+ LinearLayout starsContainer = new LinearLayout(context);
+ starsContainer.setOrientation(LinearLayout.HORIZONTAL);
+
+ for (int i = 0; i < count; i++) {
+ ImageView star = (ImageView) inflater.inflate(R.layout.star, null);
+ if (value - i >= 0.75) {
+ star.setImageResource(R.drawable.star_on);
+ } else if (value - i >= 0.25) {
+ star.setImageResource(R.drawable.star_half);
+ } else {
+ star.setImageResource(R.drawable.star_off);
+ }
+ starsContainer.addView(star);
+ }
+
+ return starsContainer;
+ }
+
+ /**
+ * insert text into the EditText at the current cursor position
+ *
+ * @param editText
+ * @param insertText
+ * @param moveCursor
+ * place the cursor after the inserted text
+ */
+ public static void insertAtPosition(final EditText editText, final String insertText, final boolean moveCursor) {
+ int selectionStart = editText.getSelectionStart();
+ int selectionEnd = editText.getSelectionEnd();
+ int start = Math.min(selectionStart, selectionEnd);
+ int end = Math.max(selectionStart, selectionEnd);
+
+ final String content = editText.getText().toString();
+ String completeText;
+ if (start > 0 && !Character.isWhitespace(content.charAt(start - 1))) {
+ completeText = " " + insertText;
+ } else {
+ completeText = insertText;
+ }
+
+ editText.getText().replace(start, end, completeText);
+ int newCursor = moveCursor ? start + completeText.length() : start;
+ editText.setSelection(newCursor, newCursor);
+ }
+
}
diff --git a/main/src/cgeo/geocaching/cgBase.java b/main/src/cgeo/geocaching/cgBase.java
index 3c24cdb..0023499 100644
--- a/main/src/cgeo/geocaching/cgBase.java
+++ b/main/src/cgeo/geocaching/cgBase.java
@@ -19,10 +19,10 @@ import cgeo.geocaching.gcvote.GCVote;
import cgeo.geocaching.gcvote.GCVoteRating;
import cgeo.geocaching.geopoint.DistanceParser;
import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.GeopointFormatter.Format;
import cgeo.geocaching.network.HtmlImage;
+import cgeo.geocaching.network.Login;
+import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
-import cgeo.geocaching.twitter.Twitter;
import cgeo.geocaching.ui.DirectionImage;
import cgeo.geocaching.utils.BaseUtils;
import cgeo.geocaching.utils.CancellableHandler;
@@ -30,25 +30,7 @@ import cgeo.geocaching.utils.CancellableHandler;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.http.HttpResponse;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.CookieStore;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.entity.UrlEncodedFormEntity;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.methods.HttpRequestBase;
-import org.apache.http.cookie.Cookie;
-import org.apache.http.impl.client.BasicCookieStore;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.cookie.BasicClientCookie;
-import org.apache.http.params.BasicHttpParams;
-import org.apache.http.params.CoreConnectionPNames;
-import org.apache.http.params.CoreProtocolPNames;
-import org.apache.http.params.HttpParams;
-import org.apache.http.protocol.HTTP;
-import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -60,9 +42,6 @@ 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.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
@@ -72,81 +51,29 @@ import android.text.Spanned;
import android.text.format.DateUtils;
import android.text.style.StrikethroughSpan;
import android.util.Log;
-import android.view.LayoutInflater;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
+
import java.net.URLDecoder;
-import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
-import java.util.Collections;
-import java.util.Date;
import java.util.EnumSet;
-import java.util.Enumeration;
-import java.util.HashMap;
import java.util.List;
import java.util.Locale;
-import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.SSLSession;
-
public class cgBase {
- private static final String passMatch = "(?<=[\\?&])[Pp]ass(w(or)?d)?=[^&#$]+";
-
- private final static Map<String, SimpleDateFormat> gcCustomDateFormats;
- static {
- final String[] formats = new String[] {
- "MM/dd/yyyy",
- "yyyy-MM-dd",
- "yyyy/MM/dd",
- "dd/MMM/yyyy",
- "MMM/dd/yyyy",
- "dd MMM yy",
- "dd/MM/yyyy"
- };
-
- Map<String, SimpleDateFormat> map = new HashMap<String, SimpleDateFormat>();
-
- for (String format : formats) {
- map.put(format, new SimpleDateFormat(format, Locale.ENGLISH));
- }
-
- gcCustomDateFormats = Collections.unmodifiableMap(map);
- }
private final static SimpleDateFormat dateTbIn1 = new SimpleDateFormat("EEEEE, dd MMMMM yyyy", Locale.ENGLISH); // Saturday, 28 March 2009
private final static SimpleDateFormat dateTbIn2 = new SimpleDateFormat("EEEEE, MMMMM dd, yyyy", Locale.ENGLISH); // Saturday, March 28, 2009
public static String version = null;
private static Context context;
- private static Resources res;
-
- private static final int NB_DOWNLOAD_RETRIES = 4;
+ public static Resources res;
public static final int UPDATE_LOAD_PROGRESS_DETAIL = 42186;
- // false = not logged in
- private static boolean actualLoginStatus = false;
- private static String actualUserName = "";
- private static String actualMemberStatus = "";
- private static int actualCachesFound = -1;
- private static String actualStatus = "";
-
- /** User agent id */
- public final static String USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:9.0.1) Gecko/20100101 Firefox/9.0.1";
-
private cgBase() {
//initialize(app);
throw new UnsupportedOperationException(); // static class, not to be instantiated
@@ -171,10 +98,6 @@ public class cgBase {
}
}
- public static String hidePassword(final String message) {
- return message.replaceAll(passMatch, "password=***");
- }
-
public static void sendLoadProgressDetail(final Handler handler, final int str) {
if (null != handler) {
handler.obtainMessage(UPDATE_LOAD_PROGRESS_DETAIL, cgeoapplication.getInstance().getString(str)).sendToTarget();
@@ -182,72 +105,6 @@ public class cgBase {
}
/**
- * read all viewstates from page
- *
- * @return String[] with all view states
- */
- public static String[] getViewstates(String page) {
- // Get the number of viewstates.
- // If there is only one viewstate, __VIEWSTATEFIELDCOUNT is not present
-
- if (page == null) { // no network access
- return null;
- }
-
- int count = 1;
- final Matcher matcherViewstateCount = GCConstants.PATTERN_VIEWSTATEFIELDCOUNT.matcher(page);
- if (matcherViewstateCount.find()) {
- count = Integer.parseInt(matcherViewstateCount.group(1));
- }
-
- String[] viewstates = new String[count];
-
- // Get the viewstates
- int no;
- final Matcher matcherViewstates = GCConstants.PATTERN_VIEWSTATES.matcher(page);
- while (matcherViewstates.find()) {
- String sno = matcherViewstates.group(1); // number of viewstate
- if (sno.length() == 0) {
- no = 0;
- }
- else {
- no = Integer.parseInt(sno);
- }
- viewstates[no] = matcherViewstates.group(2);
- }
-
- if (viewstates.length != 1 || viewstates[0] != null) {
- return viewstates;
- }
- // no viewstates were present
- return null;
- }
-
- /**
- * put viewstates into request parameters
- */
- private static void putViewstates(final Parameters params, final String[] viewstates) {
- if (ArrayUtils.isEmpty(viewstates)) {
- return;
- }
- params.put("__VIEWSTATE", viewstates[0]);
- if (viewstates.length > 1) {
- for (int i = 1; i < viewstates.length; i++) {
- params.put("__VIEWSTATE" + i, viewstates[i]);
- }
- params.put("__VIEWSTATEFIELDCOUNT", String.valueOf(viewstates.length));
- }
- }
-
- /**
- * transfers the viewstates variables from a page (response) to parameters
- * (next request)
- */
- public static void transferViewstates(final String page, final Parameters params) {
- putViewstates(params, getViewstates(page));
- }
-
- /**
* checks if an Array of Strings is empty or not. Empty means:
* - Array is null
* - or all elements are null or empty strings
@@ -265,157 +122,6 @@ public class cgBase {
return true;
}
- public static StatusCode login() {
- final ImmutablePair<String, String> login = Settings.getLogin();
-
- if (login == null || StringUtils.isEmpty(login.left) || StringUtils.isEmpty(login.right)) {
- cgBase.setActualStatus(res.getString(R.string.err_login));
- Log.e(Settings.tag, "cgeoBase.login: No login information stored");
- return StatusCode.NO_LOGIN_INFO_STORED;
- }
-
- // res is null during the unit tests
- if (res != null) {
- cgBase.setActualStatus(res.getString(R.string.init_login_popup_working));
- }
- HttpResponse loginResponse = request("https://www.geocaching.com/login/default.aspx", null, false, false, false);
- String loginData = getResponseData(loginResponse);
- if (loginResponse != null && loginResponse.getStatusLine().getStatusCode() == 503 && BaseUtils.matches(loginData, GCConstants.PATTERN_MAINTENANCE)) {
- return StatusCode.MAINTENANCE;
- }
-
- if (StringUtils.isBlank(loginData)) {
- Log.e(Settings.tag, "cgeoBase.login: Failed to retrieve login page (1st)");
- return StatusCode.CONNECTION_FAILED; // no loginpage
- }
-
- if (getLoginStatus(loginData)) {
- Log.i(Settings.tag, "Already logged in Geocaching.com as " + login.left);
- switchToEnglish(loginData);
- return StatusCode.NO_ERROR; // logged in
- }
-
- clearCookies();
- Settings.setCookieStore(null);
-
- final Parameters params = new Parameters(
- "__EVENTTARGET", "",
- "__EVENTARGUMENT", "",
- "ctl00$ContentBody$tbUsername", login.left,
- "ctl00$ContentBody$tbPassword", login.right,
- "ctl00$ContentBody$cbRememberMe", "on",
- "ctl00$ContentBody$btnSignIn", "Login");
- final String[] viewstates = getViewstates(loginData);
- if (isEmpty(viewstates)) {
- Log.e(Settings.tag, "cgeoBase.login: Failed to find viewstates");
- return StatusCode.LOGIN_PARSE_ERROR; // no viewstates
- }
- putViewstates(params, viewstates);
-
- loginResponse = postRequest("https://www.geocaching.com/login/default.aspx", params);
- loginData = getResponseData(loginResponse);
-
- if (StringUtils.isNotBlank(loginData)) {
- if (getLoginStatus(loginData)) {
- Log.i(Settings.tag, "Successfully logged in Geocaching.com as " + login.left);
-
- switchToEnglish(loginData);
- Settings.setCookieStore(dumpCookieStore());
-
- return StatusCode.NO_ERROR; // logged in
- } else {
- if (loginData.contains("Your username/password combination does not match.")) {
- Log.i(Settings.tag, "Failed to log in Geocaching.com as " + login.left + " because of wrong username/password");
- return StatusCode.WRONG_LOGIN_DATA; // wrong login
- } else {
- Log.i(Settings.tag, "Failed to log in Geocaching.com as " + login.left + " for some unknown reason");
- return StatusCode.UNKNOWN_ERROR; // can't login
- }
- }
- } else {
- Log.e(Settings.tag, "cgeoBase.login: Failed to retrieve login page (2nd)");
- // FIXME: should it be CONNECTION_FAILED to match the first attempt?
- return StatusCode.COMMUNICATION_ERROR; // no login page
- }
- }
-
- public static StatusCode logout() {
- HttpResponse logoutResponse = request("https://www.geocaching.com/login/default.aspx?RESET=Y&redir=http%3a%2f%2fwww.geocaching.com%2fdefault.aspx%3f", null, false, false, false);
- String logoutData = getResponseData(logoutResponse);
- if (logoutResponse != null && logoutResponse.getStatusLine().getStatusCode() == 503 && BaseUtils.matches(logoutData, GCConstants.PATTERN_MAINTENANCE)) {
- return StatusCode.MAINTENANCE;
- }
-
- clearCookies();
- Settings.setCookieStore(null);
- return StatusCode.NO_ERROR;
- }
-
- /**
- * Check if the user has been logged in when he retrieved the data.
- *
- * @param page
- * @return <code>true</code> if user is logged in, <code>false</code> otherwise
- */
- private static boolean getLoginStatus(final String page) {
- if (StringUtils.isBlank(page)) {
- Log.e(Settings.tag, "cgeoBase.checkLogin: No page given");
- return false;
- }
-
- // res is null during the unit tests
- if (res != null) {
- setActualStatus(res.getString(R.string.init_login_popup_ok));
- }
-
- // on every page except login page
- setActualLoginStatus(BaseUtils.matches(page, GCConstants.PATTERN_LOGIN_NAME));
- if (isActualLoginStatus()) {
- setActualUserName(BaseUtils.getMatch(page, GCConstants.PATTERN_LOGIN_NAME, true, "???"));
- setActualMemberStatus(BaseUtils.getMatch(page, GCConstants.PATTERN_MEMBER_STATUS, true, "???"));
- setActualCachesFound(Integer.parseInt(BaseUtils.getMatch(page, GCConstants.PATTERN_CACHES_FOUND, true, "0").replaceAll("[,.]", "")));
- return true;
- }
-
- // login page
- setActualLoginStatus(BaseUtils.matches(page, GCConstants.PATTERN_LOGIN_NAME_LOGIN_PAGE));
- if (isActualLoginStatus()) {
- setActualUserName(Settings.getUsername());
- setActualMemberStatus(Settings.getMemberStatus());
- // number of caches found is not part of this page
- return true;
- }
-
- // res is null during the unit tests
- if (res != null) {
- setActualStatus(res.getString(R.string.init_login_popup_failed));
- }
- return false;
- }
-
- public static void switchToEnglish(String previousPage) {
- final String ENGLISH = "English&#9660;";
- if (previousPage != null && previousPage.indexOf(ENGLISH) >= 0) {
- Log.i(Settings.tag, "Geocaching.com language already set to English");
- // get find count
- getLoginStatus(getResponseData(request("http://www.geocaching.com/email/", null, false)));
- } else {
- final String page = getResponseData(request("http://www.geocaching.com/default.aspx", null, false));
- getLoginStatus(page);
- if (page == null) {
- Log.e(Settings.tag, "Failed to read viewstates to set geocaching.com language");
- }
- final Parameters params = new Parameters(
- "__EVENTTARGET", "ctl00$uxLocaleList$uxLocaleList$ctl00$uxLocaleItem", // switch to english
- "__EVENTARGUMENT", "");
- transferViewstates(page, params);
- final HttpResponse response = postRequest("http://www.geocaching.com/default.aspx", params);
- if (!isSuccess(response)) {
- Log.e(Settings.tag, "Failed to set geocaching.com language to English");
- }
- }
- }
-
private static SearchResult parseSearch(final cgSearchThread thread, final String url, final String pageContent, final boolean showCaptcha) {
if (StringUtils.isBlank(pageContent)) {
Log.e(Settings.tag, "cgeoBase.parseSearch: No page given");
@@ -430,7 +136,7 @@ public class cgBase {
final SearchResult searchResult = new SearchResult();
searchResult.setUrl(url);
- searchResult.viewstates = getViewstates(page);
+ searchResult.viewstates = Login.getViewstates(page);
// recaptcha
if (showCaptcha) {
@@ -438,7 +144,7 @@ public class cgBase {
if (recaptchaJsParam != null) {
final Parameters params = new Parameters("k", recaptchaJsParam.trim());
- final String recaptchaJs = cgBase.getResponseData(request("http://www.google.com/recaptcha/api/challenge", params, true));
+ final String recaptchaJs = Network.getResponseData(Network.request("http://www.google.com/recaptcha/api/challenge", params, true));
if (StringUtils.isNotBlank(recaptchaJs)) {
recaptchaChallenge = BaseUtils.getMatch(recaptchaJs, GCConstants.PATTERN_SEARCH_RECAPTCHACHALLENGE, true, 1, null, true);
@@ -587,9 +293,6 @@ public class cgBase {
}
}
- // location is reliable because the search return correct coordinates independent of the login status
- cache.setReliableLatLon(true);
-
searchResult.addCache(cache);
}
@@ -638,7 +341,7 @@ public class cgBase {
}
params.put("ctl00$ContentBody$uxDownloadLoc", "Download Waypoints");
- final String coordinates = getResponseData(postRequest("http://www.geocaching.com/seek/nearest.aspx", params), false);
+ final String coordinates = Network.getResponseData(Network.postRequest("http://www.geocaching.com/seek/nearest.aspx", params), false);
if (StringUtils.isNotBlank(coordinates)) {
if (coordinates.contains("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")) {
@@ -651,6 +354,11 @@ public class cgBase {
}
LocParser.parseLoc(searchResult, coordinates);
+
+ // now we have the coords...
+ for (cgCache cache : searchResult.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB)) {
+ cache.setReliableLatLon(true);
+ }
} catch (Exception e) {
Log.e(Settings.tag, "cgBase.parseSearch.CIDs: " + e.toString());
}
@@ -658,7 +366,7 @@ public class cgBase {
// get direction images
if (Settings.getLoadDirImg()) {
- final Set<cgCache> caches = cgeoapplication.getInstance().loadCaches(searchResult.getGeocodes(), LoadFlags.LOAD_CACHE_OR_DB);
+ final Set<cgCache> caches = searchResult.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB);
for (cgCache cache : caches) {
if (cache.getCoords() == null && StringUtils.isNotEmpty(cache.getDirectionImg())) {
DirectionImage.getDrawable(cache.getGeocode(), cache.getDirectionImg());
@@ -711,6 +419,12 @@ public class cgBase {
return searchResult;
}
+ final String cacheName = Html.fromHtml(BaseUtils.getMatch(page, GCConstants.PATTERN_NAME, true, "")).toString();
+ if ("An Error Has Occurred".equalsIgnoreCase(cacheName)) {
+ searchResult.error = StatusCode.UNKNOWN_ERROR;
+ return searchResult;
+ }
+
final cgCache cache = new cgCache();
cache.setDisabled(page.contains("<li>This cache is temporarily unavailable."));
@@ -730,7 +444,7 @@ public class cgBase {
cache.setGuid(BaseUtils.getMatch(page, GCConstants.PATTERN_GUID, true, cache.getGuid()));
// name
- cache.setName(Html.fromHtml(BaseUtils.getMatch(page, GCConstants.PATTERN_NAME, true, cache.getName())).toString());
+ cache.setName(cacheName);
// owner real name
cache.setOwnerReal(URLDecoder.decode(BaseUtils.getMatch(page, GCConstants.PATTERN_OWNERREAL, true, cache.getOwnerReal())));
@@ -778,13 +492,13 @@ public class cgBase {
try {
String hiddenString = BaseUtils.getMatch(tableInside, GCConstants.PATTERN_HIDDEN, true, null);
if (StringUtils.isNotBlank(hiddenString)) {
- cache.setHidden(parseGcCustomDate(hiddenString));
+ cache.setHidden(Login.parseGcCustomDate(hiddenString));
}
if (cache.getHiddenDate() == null) {
// event date
hiddenString = BaseUtils.getMatch(tableInside, GCConstants.PATTERN_HIDDENEVENT, true, null);
if (StringUtils.isNotBlank(hiddenString)) {
- cache.setHidden(parseGcCustomDate(hiddenString));
+ cache.setHidden(Login.parseGcCustomDate(hiddenString));
}
}
} catch (ParseException e) {
@@ -1088,7 +802,7 @@ public class cgBase {
}
sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_elevation);
if (cache.getCoords() != null) {
- cache.setElevation(getElevation(cache.getCoords()));
+ cache.setElevation(cache.getCoords().getElevation());
}
}
@@ -1135,7 +849,7 @@ public class cgBase {
// "sp", Boolean.toString(personal), // personal logs
"sf", Boolean.toString(friends));
- final HttpResponse response = request("http://www.geocaching.com/seek/geocache.logbook", params, false, false, false);
+ final HttpResponse response = Network.request("http://www.geocaching.com/seek/geocache.logbook", params, false, false, false);
if (response == null) {
Log.e(Settings.tag, "cgBase.loadLogsFromDetails: cannot log logs, response is null");
return null;
@@ -1145,7 +859,7 @@ public class cgBase {
Log.e(Settings.tag, "cgBase.loadLogsFromDetails: error " + statusCode + " when requesting log information");
return null;
}
- rawResponse = cgBase.getResponseData(response);
+ rawResponse = Network.getResponseData(response);
if (rawResponse == null) {
Log.e(Settings.tag, "cgBase.loadLogsFromDetails: unable to read whole response");
return null;
@@ -1177,7 +891,7 @@ public class cgBase {
logDone.type = LogType.getByIconName(logIconName);
try {
- logDone.date = parseGcCustomDate(entry.getString("Visited")).getTime();
+ logDone.date = Login.parseGcCustomDate(entry.getString("Visited")).getTime();
} catch (ParseException e) {
Log.e(Settings.tag, "cgBase.loadLogsFromDetails: failed to parse log date.");
}
@@ -1250,73 +964,6 @@ public class cgBase {
}
}
- public static Date parseGcCustomDate(final String input, final String format) throws ParseException {
- if (StringUtils.isBlank(input)) {
- throw new ParseException("Input is null", 0);
- }
-
- final String trimmed = input.trim();
-
- if (gcCustomDateFormats.containsKey(format)) {
- try {
- return gcCustomDateFormats.get(format).parse(trimmed);
- } catch (ParseException e) {
- }
- }
-
- for (SimpleDateFormat sdf : gcCustomDateFormats.values()) {
- try {
- return sdf.parse(trimmed);
- } catch (ParseException e) {
- }
- }
-
- throw new ParseException("No matching pattern", 0);
- }
-
- public static Date parseGcCustomDate(final String input) throws ParseException {
- return parseGcCustomDate(input, Settings.getGcCustomDate());
- }
-
- /**
- * Detect user date settings on geocaching.com
- */
- public static void detectGcCustomDate() {
-
- final String result = getResponseData(request("http://www.geocaching.com/account/ManagePreferences.aspx", null, false, false, false));
-
- if (null == result) {
- Log.w(Settings.tag, "cgeoBase.detectGcCustomDate: result is null");
- return;
- }
-
- String customDate = BaseUtils.getMatch(result, GCConstants.PATTERN_CUSTOMDATE, true, null);
- if (null != customDate) {
- Settings.setGcCustomDate(customDate);
- }
- }
-
- public static BitmapDrawable downloadAvatarAndGetMemberStatus(final Context context) {
- try {
- final String profile = BaseUtils.replaceWhitespace(getResponseData(request("http://www.geocaching.com/my/", null, false)));
-
- Settings.setMemberStatus(BaseUtils.getMatch(profile, GCConstants.PATTERN_MEMBER_STATUS, true, null));
-
- setActualCachesFound(Integer.parseInt(BaseUtils.getMatch(profile, GCConstants.PATTERN_CACHES_FOUND, true, "-1").replaceAll("[,.]", "")));
-
- final String avatarURL = BaseUtils.getMatch(profile, GCConstants.PATTERN_AVATAR_IMAGE_PROFILE_PAGE, false, null);
- if (null != avatarURL) {
- final HtmlImage imgGetter = new HtmlImage(context, "", false, 0, false);
- return imgGetter.getDrawable(avatarURL);
- }
- // No match? There may be no avatar set by user.
- Log.d(Settings.tag, "No avatar set for user");
- } catch (Exception e) {
- Log.w(Settings.tag, "Error when retrieving user avatar", e);
- }
- return null;
- }
-
/**
* Parse a trackable HTML description into a cgTrackable object
*
@@ -1462,7 +1109,7 @@ public class cgBase {
try
{
- logDone.date = parseGcCustomDate(matcherLogs.group(2)).getTime();
+ logDone.date = Login.parseGcCustomDate(matcherLogs.group(2)).getTime();
} catch (ParseException e) {
}
@@ -1631,13 +1278,13 @@ public class cgBase {
final Parameters params = new Parameters(
"__EVENTTARGET", "ctl00$ContentBody$pgrBottom$ctl08",
"__EVENTARGUMENT", "");
- putViewstates(params, viewstates);
+ Login.putViewstates(params, viewstates);
- String page = getResponseData(postRequest(uri, params));
- if (!getLoginStatus(page)) {
- final StatusCode loginState = login();
+ String page = Network.getResponseData(Network.postRequest(uri, params));
+ if (!Login.getLoginStatus(page)) {
+ final StatusCode loginState = Login.login();
if (loginState == StatusCode.NO_ERROR) {
- page = getResponseData(postRequest(uri, params));
+ page = Network.getResponseData(Network.postRequest(uri, params));
} else if (loginState == StatusCode.NO_LOGIN_INFO_STORED) {
Log.i(Settings.tag, "Working as guest.");
} else {
@@ -1708,7 +1355,7 @@ public class cgBase {
final String uri = "http://www.geocaching.com/seek/nearest.aspx";
final String fullUri = uri + "?" + addFToParams(params, false, true);
- String page = requestLogged(uri, params, false, my, true);
+ String page = Network.requestLogged(uri, params, false, my, true);
if (StringUtils.isBlank(page)) {
Log.e(Settings.tag, "cgeoBase.searchByAny: No data from server");
@@ -1723,7 +1370,7 @@ public class cgBase {
final SearchResult search = searchResult.filterSearchResults(Settings.isExcludeDisabledCaches(), false, cacheType);
- getLoginStatus(page);
+ Login.getLoginStatus(page);
return search;
}
@@ -1770,32 +1417,6 @@ public class cgBase {
return searchByAny(thread, cacheType, false, showCaptcha, params);
}
- /** Request .png image for a tile. */
- public static Bitmap requestMapTile(final String url, final String referer) {
- final HttpGet request = new HttpGet(url);
- request.addHeader("Accept", "image/png,image/*;q=0.8,*/*;q=0.5");
- //request.addHeader("Accept-Encoding", "gzip, deflate");
- request.addHeader("Referer", referer);
- request.addHeader("X-Requested-With", "XMLHttpRequest");
- final HttpResponse response = request(request);
- try {
- return response != null ? BitmapFactory.decodeStream(response.getEntity().getContent()) : null;
- } catch (IOException e) {
- Log.e(Settings.tag, "cgBase.requestMapTile() " + e.getMessage());
- }
- return null;
- }
-
- /** Request JSON informations for a tile */
- public static String requestMapInfo(final String url, final String referer) {
- final HttpGet request = new HttpGet(url);
- request.addHeader("Accept", "application/json, text/javascript, */*; q=0.01");
- // NO request.addHeader("Accept-Encoding", "gzip deflate");
- request.addHeader("Referer", referer);
- request.addHeader("X-Requested-With", "XMLHttpRequest");
- return getResponseData(request(request), false);
- }
-
public static cgTrackable searchTrackable(final String geocode, final String guid, final String id) {
if (StringUtils.isBlank(geocode) && StringUtils.isBlank(guid) && StringUtils.isBlank(id)) {
Log.w(Settings.tag, "cgeoBase.searchTrackable: No geocode nor guid nor id given");
@@ -1814,7 +1435,7 @@ public class cgBase {
params.put("id", id);
}
- String page = requestLogged("http://www.geocaching.com/track/details.aspx", params, false, false, false);
+ String page = Network.requestLogged("http://www.geocaching.com/track/details.aspx", params, false, false, false);
if (StringUtils.isBlank(page)) {
Log.e(Settings.tag, "cgeoBase.searchTrackable: No data from server");
@@ -1879,7 +1500,7 @@ public class cgBase {
"ctl00$ContentBody$LogBookPanel1$uxLogInfo", logInfo,
"ctl00$ContentBody$LogBookPanel1$LogButton", "Submit Log Entry",
"ctl00$ContentBody$uxVistOtherListingGC", "");
- putViewstates(params, viewstates);
+ Login.putViewstates(params, viewstates);
if (trackables != null && !trackables.isEmpty()) { // we have some trackables to proceed
final StringBuilder hdnSelected = new StringBuilder();
@@ -1896,11 +1517,11 @@ public class cgBase {
}
final String uri = new Uri.Builder().scheme("http").authority("www.geocaching.com").path("/seek/log.aspx").encodedQuery("ID=" + cacheid).build().toString();
- String page = getResponseData(postRequest(uri, params));
- if (!getLoginStatus(page)) {
- final StatusCode loginState = login();
+ String page = Network.getResponseData(Network.postRequest(uri, params));
+ if (!Login.getLoginStatus(page)) {
+ final StatusCode loginState = Login.login();
if (loginState == StatusCode.NO_ERROR) {
- page = getResponseData(postRequest(uri, params));
+ page = Network.getResponseData(Network.postRequest(uri, params));
} else {
Log.e(Settings.tag, "cgeoBase.postLog: Can not log in geocaching (error: " + loginState + ")");
return loginState;
@@ -1918,7 +1539,7 @@ public class cgBase {
try {
if (matcher.find() && matcher.groupCount() > 0) {
- final String[] viewstatesConfirm = getViewstates(page);
+ final String[] viewstatesConfirm = Login.getViewstates(page);
if (isEmpty(viewstatesConfirm)) {
Log.e(Settings.tag, "cgeoBase.postLog: No viewstate for confirm log");
@@ -1926,7 +1547,7 @@ public class cgBase {
}
params.clear();
- putViewstates(params, viewstatesConfirm);
+ Login.putViewstates(params, viewstatesConfirm);
params.put("__EVENTTARGET", "");
params.put("__EVENTARGUMENT", "");
params.put("__LASTFOCUS", "");
@@ -1957,7 +1578,7 @@ public class cgBase {
params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$hdnCurrentFilter", "");
}
- page = getResponseData(postRequest(uri, params));
+ page = Network.getResponseData(Network.postRequest(uri, params));
}
} catch (Exception e) {
Log.e(Settings.tag, "cgeoBase.postLog.confim: " + e.toString());
@@ -1973,10 +1594,10 @@ public class cgBase {
cgeoapplication.getInstance().saveVisitDate(geocode);
}
- getLoginStatus(page);
+ Login.getLoginStatus(page);
// the log-successful-page contains still the old value
- if (getActualCachesFound() >= 0) {
- setActualCachesFound(getActualCachesFound() + 1);
+ if (Login.getActualCachesFound() >= 0) {
+ Login.setActualCachesFound(Login.getActualCachesFound() + 1);
}
return StatusCode.NO_ERROR;
}
@@ -2011,7 +1632,7 @@ public class cgBase {
"__LASTFOCUS", "",
"ctl00$ContentBody$LogBookPanel1$ddLogType", Integer.toString(logType.id),
"ctl00$ContentBody$LogBookPanel1$tbCode", trackingCode);
- putViewstates(params, viewstates);
+ Login.putViewstates(params, viewstates);
if (currentDate.get(Calendar.YEAR) == year && (currentDate.get(Calendar.MONTH) + 1) == month && currentDate.get(Calendar.DATE) == day) {
params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged", "");
} else {
@@ -2026,11 +1647,11 @@ public class cgBase {
"ctl00$ContentBody$uxVistOtherListingGC", "");
final String uri = new Uri.Builder().scheme("http").authority("www.geocaching.com").path("/track/log.aspx").encodedQuery("wid=" + tbid).build().toString();
- String page = getResponseData(postRequest(uri, params));
- if (!getLoginStatus(page)) {
- final StatusCode loginState = login();
+ String page = Network.getResponseData(Network.postRequest(uri, params));
+ if (!Login.getLoginStatus(page)) {
+ final StatusCode loginState = Login.login();
if (loginState == StatusCode.NO_ERROR) {
- page = getResponseData(postRequest(uri, params));
+ page = Network.getResponseData(Network.postRequest(uri, params));
} else {
Log.e(Settings.tag, "cgeoBase.postLogTrackable: Can not log in geocaching (error: " + loginState + ")");
return loginState;
@@ -2066,7 +1687,7 @@ public class cgBase {
*/
public static int addToWatchlist(final cgCache cache) {
final String uri = "http://www.geocaching.com/my/watchlist.aspx?w=" + cache.getCacheId();
- String page = postRequestLogged(uri);
+ String page = Network.postRequestLogged(uri);
if (StringUtils.isBlank(page)) {
Log.e(Settings.tag, "cgBase.addToWatchlist: No data from server");
@@ -2092,7 +1713,7 @@ public class cgBase {
*/
public static int removeFromWatchlist(final cgCache cache) {
final String uri = "http://www.geocaching.com/my/watchlist.aspx?ds=1&action=rem&id=" + cache.getCacheId();
- String page = postRequestLogged(uri);
+ String page = Network.postRequestLogged(uri);
if (StringUtils.isBlank(page)) {
Log.e(Settings.tag, "cgBase.removeFromWatchlist: No data from server");
@@ -2104,9 +1725,9 @@ public class cgBase {
"__EVENTTARGET", "",
"__EVENTARGUMENT", "",
"ctl00$ContentBody$btnYes", "Yes");
- transferViewstates(page, params);
+ Login.transferViewstates(page, params);
- page = getResponseData(postRequest(uri, params));
+ page = Network.getResponseData(Network.postRequest(uri, params));
boolean guidOnPage = cache.isGuidContainedInPage(page);
if (!guidOnPage) {
Log.i(Settings.tag, "cgBase.removeFromWatchlist: cache removed from watchlist");
@@ -2117,75 +1738,6 @@ public class cgBase {
return guidOnPage ? -1 : 0; // on watchlist (=error) / not on watchlist
}
- final public static HostnameVerifier doNotVerify = new HostnameVerifier() {
-
- public boolean verify(String hostname, SSLSession session) {
- return true;
- }
- };
-
- public static void postTweetCache(String geocode) {
- final cgCache cache = cgeoapplication.getInstance().loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB);
- String status;
- final String url = cache.getUrl();
- if (url.length() >= 100) {
- status = "I found " + url;
- }
- else {
- String name = cache.getName();
- status = "I found " + name + " (" + url + ")";
- if (status.length() > Twitter.MAX_TWEET_SIZE) {
- name = name.substring(0, name.length() - (status.length() - Twitter.MAX_TWEET_SIZE) - 3) + "...";
- }
- status = "I found " + name + " (" + url + ")";
- status = Twitter.appendHashTag(status, "cgeo");
- status = Twitter.appendHashTag(status, "geocaching");
- }
-
- Twitter.postTweet(cgeoapplication.getInstance(), status, null);
- }
-
- public static void postTweetTrackable(String geocode) {
- final cgTrackable trackable = cgeoapplication.getInstance().getTrackableByGeocode(geocode);
- String name = trackable.getName();
- if (name.length() > 82) {
- name = name.substring(0, 79) + "...";
- }
- StringBuilder builder = new StringBuilder("I touched ");
- builder.append(name);
- if (trackable.getUrl() != null) {
- builder.append(" (").append(trackable.getUrl()).append(')');
- }
- builder.append('!');
- String status = Twitter.appendHashTag(builder.toString(), "cgeo");
- status = Twitter.appendHashTag(status, "geocaching");
- Twitter.postTweet(cgeoapplication.getInstance(), status, null);
- }
-
- public static 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();
- }
- }
- }
- } catch (SocketException e) {
- // nothing
- }
-
- return null;
- }
-
- public static String urlencode_rfc3986(String text) {
- final String encoded = StringUtils.replace(URLEncoder.encode(text).replace("+", "%20"), "%7E", "~");
-
- return encoded;
- }
-
/**
* Possibly hide caches found or hidden by user. This mutates its params argument when possible.
*
@@ -2207,269 +1759,6 @@ public class cgBase {
return params;
}
- static private String prepareParameters(final String baseUri, final Parameters params) {
- return CollectionUtils.isNotEmpty(params) ? baseUri + "?" + params.toString() : baseUri;
- }
-
- static public String[] requestViewstates(final String uri, final Parameters params, boolean xContentType, boolean my) {
- final HttpResponse response = request(uri, params, xContentType, my, false);
-
- return getViewstates(getResponseData(response));
- }
-
- static private String getResponseDataNoError(final HttpResponse response, boolean replaceWhitespace) {
- try {
- String data = EntityUtils.toString(response.getEntity(), HTTP.UTF_8);
- return replaceWhitespace ? BaseUtils.replaceWhitespace(data) : data;
- } catch (Exception e) {
- Log.e(Settings.tag, "getResponseData", e);
- return null;
- }
- }
-
- static public String getResponseData(final HttpResponse response) {
- return getResponseData(response, true);
- }
-
- static public String getResponseData(final HttpResponse response, boolean replaceWhitespace) {
- if (!isSuccess(response)) {
- return null;
- }
- return getResponseDataNoError(response, replaceWhitespace);
- }
-
- /**
- * POST HTTP request. Do the request a second time if the user is not logged in
- *
- * @param uri
- * @return
- */
- public static String postRequestLogged(final String uri) {
- HttpResponse response = postRequest(uri, null);
- String data = getResponseData(response);
-
- if (!getLoginStatus(data)) {
- if (login() == StatusCode.NO_ERROR) {
- response = postRequest(uri, null);
- data = getResponseData(response);
- } else {
- Log.i(Settings.tag, "Working as guest.");
- }
- }
- return data;
- }
-
- /**
- * GET HTTP request. Do the request a second time if the user is not logged in
- *
- * @param uri
- * @param params
- * @param xContentType
- * @param my
- * @param addF
- * @return
- */
- public static String requestLogged(final String uri, final Parameters params, boolean xContentType, boolean my, boolean addF) {
- HttpResponse response = request(uri, params, xContentType, my, addF);
- String data = getResponseData(response);
-
- if (!getLoginStatus(data)) {
- if (login() == StatusCode.NO_ERROR) {
- response = request(uri, params, xContentType, my, addF);
- data = getResponseData(response);
- } else {
- Log.i(Settings.tag, "Working as guest.");
- }
- }
- return data;
- }
-
- /**
- * GET HTTP request
- *
- * @param uri
- * @param params
- * @param xContentType
- * @param my
- * @param addF
- * @return
- */
- public static HttpResponse request(final String uri, final Parameters params, boolean xContentType, boolean my, boolean addF) {
- return request(uri, addFToParams(params, my, addF), xContentType);
- }
-
- final private static CookieStore cookieStore = new BasicCookieStore();
- private static boolean cookieStoreRestored = false;
- final private static HttpParams clientParams = new BasicHttpParams();
-
- static {
- clientParams.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, HTTP.UTF_8);
- clientParams.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 30000);
- clientParams.setParameter(CoreConnectionPNames.SO_TIMEOUT, 30000);
- }
-
- public static HttpClient getHttpClient() {
- final DefaultHttpClient client = new DefaultHttpClient();
- client.setCookieStore(cookieStore);
- client.setParams(clientParams);
- return client;
- }
-
- public static void restoreCookieStore(final String oldCookies) {
- if (!cookieStoreRestored) {
- clearCookies();
- if (oldCookies != null) {
- for (final String cookie : StringUtils.split(oldCookies, ';')) {
- final String[] split = StringUtils.split(cookie, "=", 3);
- if (split.length == 3) {
- final BasicClientCookie newCookie = new BasicClientCookie(split[0], split[1]);
- newCookie.setDomain(split[2]);
- cookieStore.addCookie(newCookie);
- }
- }
- }
- cookieStoreRestored = true;
- }
- }
-
- public static String dumpCookieStore() {
- StringBuilder cookies = new StringBuilder();
- for (final Cookie cookie : cookieStore.getCookies()) {
- cookies.append(cookie.getName());
- cookies.append('=');
- cookies.append(cookie.getValue());
- cookies.append('=');
- cookies.append(cookie.getDomain());
- cookies.append(';');
- }
- return cookies.toString();
- }
-
- public static void clearCookies() {
- cookieStore.clear();
- }
-
- /**
- * POST HTTP request
- *
- * @param uri
- * @param params
- * @return
- */
- public static HttpResponse postRequest(final String uri, final List<? extends NameValuePair> params) {
- try {
- HttpPost request = new HttpPost(uri);
- if (params != null) {
- request.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
- }
- request.setHeader("X-Requested-With", "XMLHttpRequest");
- return request(request);
- } catch (Exception e) {
- // Can be UnsupportedEncodingException, ClientProtocolException or IOException
- Log.e(Settings.tag, "postRequest", e);
- return null;
- }
- }
-
- /**
- * GET HTTP request
- *
- * @param uri
- * @param params
- * @param xContentType
- * @return
- */
- public static HttpResponse request(final String uri, final Parameters params, final boolean xContentType) {
- final String fullUri = params == null ? uri : Uri.parse(uri).buildUpon().encodedQuery(params.toString()).build().toString();
- final HttpRequestBase request = new HttpGet(fullUri);
-
- request.setHeader("X-Requested-With", "XMLHttpRequest");
-
- if (xContentType) {
- request.setHeader("Content-Type", "application/x-www-form-urlencoded");
- }
-
- return request(request);
- }
-
- private static HttpResponse request(final HttpRequestBase request) {
- request.setHeader("Accept-Charset", "utf-8,iso-8859-1;q=0.8,utf-16;q=0.8,*;q=0.7");
- request.setHeader("Accept-Language", "en-US,*;q=0.9");
- request.getParams().setParameter(CoreProtocolPNames.USER_AGENT, cgBase.USER_AGENT);
- return doRequest(request);
- }
-
- static private String formatTimeSpan(final long before) {
- // don't use String.format in a pure logging routine, it has very bad performance
- return " (" + (System.currentTimeMillis() - before) + " ms) ";
- }
-
- static public boolean isSuccess(final HttpResponse response) {
- return response != null && response.getStatusLine().getStatusCode() == 200;
- }
-
- static public HttpResponse doRequest(final HttpRequestBase request) {
- final String reqLogStr = request.getMethod() + " " + hidePassword(request.getURI().toString());
- Log.d(Settings.tag, reqLogStr);
-
- final HttpClient client = getHttpClient();
- for (int i = 0; i <= NB_DOWNLOAD_RETRIES; i++) {
- final long before = System.currentTimeMillis();
- try {
- final HttpResponse response = client.execute(request);
- int status = response.getStatusLine().getStatusCode();
- if (status == 200) {
- Log.d(Settings.tag, status + formatTimeSpan(before) + reqLogStr);
- } else {
- Log.w(Settings.tag, status + " [" + response.getStatusLine().getReasonPhrase() + "]" + formatTimeSpan(before) + reqLogStr);
- }
- return response;
- } catch (IOException e) {
- final String timeSpan = formatTimeSpan(before);
- final String tries = (i + 1) + "/" + (NB_DOWNLOAD_RETRIES + 1);
- if (i == NB_DOWNLOAD_RETRIES) {
- Log.e(Settings.tag, "Failure " + tries + timeSpan + reqLogStr, e);
- } else {
- Log.e(Settings.tag, "Failure " + tries + " (" + e.toString() + ")" + timeSpan + "- retrying " + reqLogStr);
- }
- }
- }
-
- return null;
- }
-
- public static JSONObject requestJSON(final String uri, final Parameters params) {
- final HttpGet request = new HttpGet(prepareParameters(uri, params));
- request.setHeader("Accept", "application/json, text/javascript, */*; q=0.01");
- request.setHeader("Content-Type", "application/json; charset=UTF-8");
- request.setHeader("X-Requested-With", "XMLHttpRequest");
-
- final HttpResponse response = doRequest(request);
- if (response != null && response.getStatusLine().getStatusCode() == 200) {
- try {
- return new JSONObject(getResponseData(response));
- } catch (JSONException e) {
- Log.e(Settings.tag, "cgeoBase.requestJSON", e);
- }
- }
-
- return null;
- }
-
- public static boolean deleteDirectory(File path) {
- if (path.exists()) {
- for (final File file : path.listFiles()) {
- if (file.isDirectory()) {
- deleteDirectory(file);
- } else {
- file.delete();
- }
- }
- }
-
- return path.delete();
- }
-
public static void storeCache(Activity activity, cgCache origCache, String geocode, int listId, CancellableHandler handler) {
try {
cgCache cache;
@@ -2615,34 +1904,6 @@ public class cgBase {
return false;
}
- public static Double getElevation(final Geopoint coords) {
- try {
- final String uri = "http://maps.googleapis.com/maps/api/elevation/json";
- final Parameters params = new Parameters(
- "sensor", "false",
- "locations", coords.format(Format.LAT_LON_DECDEGREE_COMMA));
- final JSONObject response = requestJSON(uri, params);
-
- if (response == null) {
- return null;
- }
-
- if (!StringUtils.equalsIgnoreCase(response.getString("status"), "OK")) {
- return null;
- }
-
- if (response.has("results")) {
- JSONArray results = response.getJSONArray("results");
- JSONObject result = results.getJSONObject(0);
- return result.getDouble("elevation");
- }
- } catch (Exception e) {
- Log.w(Settings.tag, "cgBase.getElevation: " + e.toString());
- }
-
- return null;
- }
-
/**
* Generate a time string according to system-wide settings (locale, 12/24 hour)
* such as "13:24".
@@ -2709,113 +1970,6 @@ public class cgBase {
}
/**
- * insert text into the EditText at the current cursor position
- *
- * @param editText
- * @param insertText
- * @param moveCursor
- * place the cursor after the inserted text
- */
- public static void insertAtPosition(final EditText editText, final String insertText, final boolean moveCursor) {
- int selectionStart = editText.getSelectionStart();
- int selectionEnd = editText.getSelectionEnd();
- int start = Math.min(selectionStart, selectionEnd);
- int end = Math.max(selectionStart, selectionEnd);
-
- final String content = editText.getText().toString();
- String completeText;
- if (start > 0 && !Character.isWhitespace(content.charAt(start - 1))) {
- completeText = " " + insertText;
- } else {
- completeText = insertText;
- }
-
- editText.getText().replace(start, end, completeText);
- int newCursor = moveCursor ? start + completeText.length() : start;
- editText.setSelection(newCursor, newCursor);
- }
-
- public static LinearLayout createStarRating(final float value, final int count, final Context context) {
- LayoutInflater inflater = LayoutInflater.from(context);
- LinearLayout starsContainer = new LinearLayout(context);
- starsContainer.setOrientation(LinearLayout.HORIZONTAL);
-
- for (int i = 0; i < count; i++) {
- ImageView star = (ImageView) inflater.inflate(R.layout.star, null);
- if (value - i >= 0.75) {
- star.setImageResource(R.drawable.star_on);
- } else if (value - i >= 0.25) {
- star.setImageResource(R.drawable.star_half);
- } else {
- star.setImageResource(R.drawable.star_off);
- }
- starsContainer.addView(star);
- }
-
- return starsContainer;
- }
-
- public static boolean isActualLoginStatus() {
- return actualLoginStatus;
- }
-
- private static void setActualLoginStatus(boolean actualLoginStatus) {
- cgBase.actualLoginStatus = actualLoginStatus;
- }
-
- public static String getActualUserName() {
- return actualUserName;
- }
-
- private static void setActualUserName(String actualUserName) {
- cgBase.actualUserName = actualUserName;
- }
-
- public static String getActualMemberStatus() {
- return actualMemberStatus;
- }
-
- private static void setActualMemberStatus(final String actualMemberStatus) {
- cgBase.actualMemberStatus = actualMemberStatus;
- }
-
- public static int getActualCachesFound() {
- return actualCachesFound;
- }
-
- private static void setActualCachesFound(final int actualCachesFound) {
- cgBase.actualCachesFound = actualCachesFound;
- }
-
- public static String getActualStatus() {
- return actualStatus;
- }
-
- private static void setActualStatus(final String actualStatus) {
- cgBase.actualStatus = actualStatus;
- }
-
- /**
- * Indicates whether the specified action can be used as an intent. This
- * method queries the package manager for installed packages that can
- * respond to an intent with the specified action. If no suitable package is
- * found, this method returns false.
- *
- * From: http://android-developers.blogspot.com/2009/01/can-i-use-this-intent.html
- *
- * @param context
- * The application's environment.
- * @param action
- * The Intent action to check for availability.
- *
- * @return True if an Intent with the specified action can be sent and
- * responded to, false otherwise.
- */
- public static boolean isIntentAvailable(Context context, String action) {
- return isIntentAvailable(context, action, null);
- }
-
- /**
* Indicates whether the specified action can be used as an intent. This
* method queries the package manager for installed packages that can
* respond to an intent with the specified action. If no suitable package is
diff --git a/main/src/cgeo/geocaching/cgCache.java b/main/src/cgeo/geocaching/cgCache.java
index 821b9de..79a4209 100644
--- a/main/src/cgeo/geocaching/cgCache.java
+++ b/main/src/cgeo/geocaching/cgCache.java
@@ -6,6 +6,7 @@ import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.IConnector;
import cgeo.geocaching.connector.gc.GCBase;
import cgeo.geocaching.connector.gc.GCConnector;
+import cgeo.geocaching.connector.gc.Tile;
import cgeo.geocaching.enumerations.CacheSize;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LoadFlags.RemoveFlag;
@@ -99,7 +100,7 @@ public class cgCache implements ICache {
private String nameForSorting;
private final EnumSet<StorageLocation> storageLocation = EnumSet.of(StorageLocation.HEAP);
private boolean finalDefined = false;
- private int zoomlevel = -1;
+ private int zoomlevel = Tile.ZOOMLEVEL_MAX;
private static final Pattern NUMBER_PATTERN = Pattern.compile("\\d+");
@@ -135,9 +136,13 @@ public class cgCache implements ICache {
detailed = true;
detailedUpdate = other.detailedUpdate;
coords = other.coords;
+ // boolean values must be enumerated here. Other types are assigned outside this if-statement
premiumMembersOnly = other.premiumMembersOnly;
reliableLatLon = other.reliableLatLon;
archived = other.archived;
+ found = other.found;
+ own = other.own;
+ disabled = other.disabled;
favorite = other.favorite;
onWatchlist = other.onWatchlist;
logOffline = other.logOffline;
@@ -145,7 +150,7 @@ public class cgCache implements ICache {
}
/*
- * No gathering for boolean members
+ * No gathering for boolean members if a cache is not-detailed
* - found
* - own
* - disabled
@@ -1163,17 +1168,13 @@ public class cgCache implements ICache {
finalDefined = true;
}
} else { // this is a waypoint being edited
- deleteWaypoint(waypoint);
-
- waypoints.add(waypoint);
- // when waypoint was edited, finalDefined may have changed. check all waypoints and set again
- finalDefined = false;
- for (cgWaypoint wp : waypoints) {
- if (wp.isFinalWithCoords()) {
- finalDefined = true;
- break;
- }
+ final int index = getWaypointIndex(waypoint);
+ if (index >= 0) {
+ waypoints.remove(index);
}
+ waypoints.add(waypoint);
+ // when waypoint was edited, finalDefined may have changed
+ resetFinalDefined();
}
if (saveToDatabase) {
@@ -1196,6 +1197,19 @@ public class cgCache implements ICache {
this.finalDefined = finalDefined;
}
+ /**
+ * Reset <code>finalDefined</code> based on current list of stored waypoints
+ */
+ private void resetFinalDefined() {
+ finalDefined = false;
+ for (cgWaypoint wp : waypoints) {
+ if (wp.isFinalWithCoords()) {
+ finalDefined = true;
+ break;
+ }
+ }
+ }
+
public boolean hasUserModifiedCoords() {
return userModifiedCoords;
}
@@ -1247,13 +1261,7 @@ public class cgCache implements ICache {
cgeoapplication.getInstance().removeCache(geocode, EnumSet.of(RemoveFlag.REMOVE_CACHE));
// Check status if Final is defined
if (waypoint.isFinalWithCoords()) {
- finalDefined = false;
- for (cgWaypoint wp : waypoints) {
- if (wp.isFinalWithCoords()) {
- finalDefined = true;
- break;
- }
- }
+ resetFinalDefined();
}
return true;
}
@@ -1272,16 +1280,32 @@ public class cgCache implements ICache {
return false;
}
+ final int index = getWaypointIndex(waypoint);
+ if (index >= 0) {
+ return deleteWaypoint(index);
+ }
+
+ return false;
+ }
+
+ /**
+ * Find index of given <code>waypoint</code> in cache's <code>waypoints</code> list
+ *
+ * @param waypoint
+ * to find index for
+ * @return index in <code>waypoints</code> if found, else -1
+ */
+ private int getWaypointIndex(cgWaypoint waypoint) {
int index = 0;
for (cgWaypoint wp : waypoints) {
if (wp.getId() == waypoint.getId()) {
- return deleteWaypoint(index);
+ return index;
}
index++;
}
- return false;
+ return -1;
}
/**
diff --git a/main/src/cgeo/geocaching/cgData.java b/main/src/cgeo/geocaching/cgData.java
index ac0be8f..f6d17c7 100644
--- a/main/src/cgeo/geocaching/cgData.java
+++ b/main/src/cgeo/geocaching/cgData.java
@@ -969,7 +969,7 @@ public class cgData {
public void run() {
for (final File dir : toRemove) {
Log.i(Settings.tag, "Removing obsolete cache directory for " + dir.getName());
- cgBase.deleteDirectory(dir);
+ LocalStorage.deleteDirectory(dir);
}
}
}).start();
@@ -3047,7 +3047,7 @@ public class cgData {
// Delete cache directories
for (final String geocode : geocodes) {
- cgBase.deleteDirectory(LocalStorage.getStorageDir(geocode));
+ LocalStorage.deleteDirectory(LocalStorage.getStorageDir(geocode));
}
}
}
diff --git a/main/src/cgeo/geocaching/cgeo.java b/main/src/cgeo/geocaching/cgeo.java
index 03184b3..7367d82 100644
--- a/main/src/cgeo/geocaching/cgeo.java
+++ b/main/src/cgeo/geocaching/cgeo.java
@@ -12,6 +12,7 @@ import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.HumanDistance;
import cgeo.geocaching.geopoint.IConversion;
import cgeo.geocaching.maps.CGeoMap;
+import cgeo.geocaching.network.Login;
import cgeo.geocaching.ui.Formatter;
import org.apache.commons.collections.CollectionUtils;
@@ -77,14 +78,14 @@ public class cgeo extends AbstractActivity {
TextView userInfoView = (TextView) findViewById(R.id.user_info);
StringBuilder userInfo = new StringBuilder("geocaching.com").append(Formatter.SEPARATOR);
- if (cgBase.isActualLoginStatus()) {
- userInfo.append(cgBase.getActualUserName());
- if (cgBase.getActualCachesFound() >= 0) {
- userInfo.append(" (").append(String.valueOf(cgBase.getActualCachesFound())).append(')');
+ if (Login.isActualLoginStatus()) {
+ userInfo.append(Login.getActualUserName());
+ if (Login.getActualCachesFound() >= 0) {
+ userInfo.append(" (").append(String.valueOf(Login.getActualCachesFound())).append(')');
}
userInfo.append(Formatter.SEPARATOR);
}
- userInfo.append(cgBase.getActualStatus());
+ userInfo.append(Login.getActualStatus());
userInfoView.setText(userInfo.toString());
}
@@ -790,11 +791,11 @@ public class cgeo extends AbstractActivity {
}
// login
- final StatusCode status = cgBase.login();
+ final StatusCode status = Login.login();
if (status == StatusCode.NO_ERROR) {
app.firstRun = false;
- cgBase.detectGcCustomDate();
+ Login.detectGcCustomDate();
updateUserInfoHandler.sendEmptyMessage(-1);
}
diff --git a/main/src/cgeo/geocaching/cgeocaches.java b/main/src/cgeo/geocaching/cgeocaches.java
index b38c466..fa5ca02 100644
--- a/main/src/cgeo/geocaching/cgeocaches.java
+++ b/main/src/cgeo/geocaching/cgeocaches.java
@@ -21,6 +21,7 @@ import cgeo.geocaching.filter.TrackablesFilter;
import cgeo.geocaching.filter.TypeFilter;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.maps.CGeoMap;
+import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.sorting.CacheComparator;
import cgeo.geocaching.sorting.DateComparator;
@@ -205,14 +206,14 @@ public class cgeocaches extends AbstractListActivity {
dialog.setNegativeButton(res.getString(R.string.license_dismiss), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
- cgBase.clearCookies();
+ Network.clearCookies();
dialog.cancel();
}
});
dialog.setPositiveButton(res.getString(R.string.license_show), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
- cgBase.clearCookies();
+ Network.clearCookies();
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/software/agreement.aspx?ID=0")));
}
});
@@ -1903,10 +1904,10 @@ public class cgeocaches extends AbstractListActivity {
deviceCode = "";
}
final Parameters params = new Parameters("code", deviceCode);
- HttpResponse responseFromWeb = cgBase.request("http://send2.cgeo.org/read.html", params, true);
+ HttpResponse responseFromWeb = Network.request("http://send2.cgeo.org/read.html", params, true);
if (responseFromWeb != null && responseFromWeb.getStatusLine().getStatusCode() == 200) {
- final String response = cgBase.getResponseData(responseFromWeb);
+ final String response = Network.getResponseData(responseFromWeb);
if (response.length() > 2) {
String GCcode = response;
@@ -2246,11 +2247,12 @@ public class cgeocaches extends AbstractListActivity {
}
public void switchListById(int id) {
- StoredList list = null;
+ if (id < 0) {
+ return;
+ }
- if (id >= 0) {
- list = app.getList(id);
- } else {
+ StoredList list = app.getList(id);
+ if (list == null) {
return;
}
diff --git a/main/src/cgeo/geocaching/cgeoinit.java b/main/src/cgeo/geocaching/cgeoinit.java
index 1a694bd..a8e660a 100644
--- a/main/src/cgeo/geocaching/cgeoinit.java
+++ b/main/src/cgeo/geocaching/cgeoinit.java
@@ -7,6 +7,8 @@ import cgeo.geocaching.compatibility.Compatibility;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.maps.MapProviderFactory;
+import cgeo.geocaching.network.Login;
+import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.twitter.TwitterAuthorizationActivity;
import cgeo.geocaching.utils.LogTemplateProvider;
@@ -213,7 +215,7 @@ public class cgeoinit extends AbstractActivity {
private boolean insertSignatureTemplate(final LogTemplate template) {
EditText sig = (EditText) findViewById(R.id.signature);
String insertText = "[" + template.getTemplateString() + "]";
- cgBase.insertAtPosition(sig, insertText, true);
+ insertAtPosition(sig, insertText, true);
return true;
}
@@ -404,6 +406,7 @@ public class cgeoinit extends AbstractActivity {
});
final CheckBox dirImgButton = (CheckBox) findViewById(R.id.loaddirectionimg);
+ dirImgButton.setEnabled(!Settings.isPremiumMember());
dirImgButton.setChecked(Settings.getLoadDirImg());
dirImgButton.setOnClickListener(new View.OnClickListener() {
@@ -807,17 +810,17 @@ public class cgeoinit extends AbstractActivity {
loginDialog.setCancelable(false);
Settings.setLogin(username, password);
- cgBase.clearCookies();
+ Network.clearCookies();
(new Thread() {
@Override
public void run() {
- final StatusCode loginResult = cgBase.login();
+ final StatusCode loginResult = Login.login();
Object payload = loginResult;
if (loginResult == StatusCode.NO_ERROR) {
- cgBase.detectGcCustomDate();
- payload = cgBase.downloadAvatarAndGetMemberStatus(cgeoinit.this);
+ Login.detectGcCustomDate();
+ payload = Login.downloadAvatarAndGetMemberStatus(cgeoinit.this);
}
logInHandler.obtainMessage(0, payload).sendToTarget();
}
@@ -849,12 +852,12 @@ public class cgeoinit extends AbstractActivity {
final String cod = StringUtils.defaultString(deviceCode);
final Parameters params = new Parameters("name", nam, "code", cod);
- HttpResponse response = cgBase.request("http://send2.cgeo.org/auth.html", params, true);
+ HttpResponse response = Network.request("http://send2.cgeo.org/auth.html", params, true);
if (response != null && response.getStatusLine().getStatusCode() == 200)
{
//response was OK
- String[] strings = cgBase.getResponseData(response).split(",");
+ String[] strings = Network.getResponseData(response).split(",");
try {
pin = Integer.parseInt(strings[1].trim());
} catch (Exception e) {
diff --git a/main/src/cgeo/geocaching/cgeopopup.java b/main/src/cgeo/geocaching/cgeopopup.java
index ac74519..91546b8 100644
--- a/main/src/cgeo/geocaching/cgeopopup.java
+++ b/main/src/cgeo/geocaching/cgeopopup.java
@@ -605,7 +605,7 @@ public class cgeopopup extends AbstractActivity {
itemName.setText(res.getString(R.string.cache_rating));
itemValue.setText(String.format("%.1f", rating) + ' ' + res.getString(R.string.cache_rating_of) + " 5");
- itemStars.addView(cgBase.createStarRating(rating, 5, this), 1);
+ itemStars.addView(createStarRating(rating, 5, this), 1);
if (votes > 0) {
final TextView itemAddition = (TextView) itemLayout.findViewById(R.id.addition);
diff --git a/main/src/cgeo/geocaching/cgeotouch.java b/main/src/cgeo/geocaching/cgeotouch.java
index 6271ec1..e5af4d3 100644
--- a/main/src/cgeo/geocaching/cgeotouch.java
+++ b/main/src/cgeo/geocaching/cgeotouch.java
@@ -3,7 +3,10 @@ package cgeo.geocaching;
import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.enumerations.StatusCode;
+import cgeo.geocaching.network.Login;
+import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
+import cgeo.geocaching.twitter.Twitter;
import cgeo.geocaching.ui.DateDialog;
import org.apache.commons.lang3.StringUtils;
@@ -389,9 +392,9 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog
return;
}
- final String page = cgBase.getResponseData(cgBase.request("http://www.geocaching.com/track/log.aspx", params, false, false, false));
+ final String page = Network.getResponseData(Network.request("http://www.geocaching.com/track/log.aspx", params, false, false, false));
- viewstates = cgBase.getViewstates(page);
+ viewstates = Login.getViewstates(page);
final List<LogType> typesPre = cgBase.parseTypes(page);
if (typesPre.size() > 0) {
@@ -444,7 +447,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog
if (status == StatusCode.NO_ERROR && Settings.isUseTwitter() &&
Settings.isTwitterLoginValid() &&
tweetCheck.isChecked() && tweetBox.getVisibility() == View.VISIBLE) {
- cgBase.postTweetTrackable(geocode);
+ Twitter.postTweetTrackable(geocode);
}
return status;
diff --git a/main/src/cgeo/geocaching/connector/gc/GCBase.java b/main/src/cgeo/geocaching/connector/gc/GCBase.java
index e7008aa..993e062 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCBase.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCBase.java
@@ -9,7 +9,10 @@ import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy;
import cgeo.geocaching.enumerations.LiveMapStrategy.StrategyFlag;
import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.geopoint.IConversion;
import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.network.Network;
+import cgeo.geocaching.ui.Formatter;
import cgeo.geocaching.utils.BaseUtils;
import cgeo.geocaching.utils.LeastRecentlyUsedCache;
@@ -29,8 +32,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
/**
* GC.com/Groundspeak (GS) specific stuff
@@ -46,25 +47,6 @@ public class GCBase {
protected final static long GC_BASE31 = 31;
protected final static long GC_BASE16 = 16;
- // Pixel colors in tile
- private final static int BORDER_GRAY = 0x5F5F5F;
- private final static int DARK_GREEN = 0x316013; // Tradi 14
- private final static int LIGHT_GREEN = 0x80AF64; // Tradi 13
- private final static int DARK_BLUE = 0x243C97; // Mystery
- private final static int YELLOW = 0xFFDE19; // Multi 14,13
- private final static int FOUND = 0xFBEA5D; // Found
-
- // Offset inside cache icon
- private final static int POSX_TRADI = 7;
- private final static int POSY_TRADI = -12;
- private final static int POSX_MULTI = 5; // for orange 8
- private final static int POSY_MULTI = -9; // for orange 10
- private final static int POSX_MYSTERY = 5;
- private final static int POSY_MYSTERY = -13;
- private final static int POSX_FOUND = 10;
- private final static int POSY_FOUND = -8;
-
- private final static Pattern PATTERN_JSON_KEY = Pattern.compile("[^\\d]*" + "(\\d+),\\s*(\\d+)" + "[^\\d]*"); // (12, 34)
/**
* Searches the view port on the live map with Strategy.AUTO
*
@@ -78,9 +60,23 @@ public class GCBase {
Strategy strategy = Settings.getLiveMapStrategy();
if (strategy == Strategy.AUTO) {
float speedNow = cgeoapplication.getInstance().getSpeedFromGeo();
- strategy = speedNow >= 8 ? Strategy.FASTEST : Strategy.DETAILED; // 8 m/s = 30 km/h
+ strategy = speedNow >= 8 ? Strategy.FAST : Strategy.DETAILED; // 8 m/s = 30 km/h
+ }
+ // return searchByViewport(viewport, tokens, strategy);
+
+ // testing purpose
+ {
+ SearchResult result = searchByViewport(viewport, tokens, strategy);
+ String text = Formatter.SEPARATOR + strategy.getL10n() + Formatter.SEPARATOR;
+ int speed = (int) cgeoapplication.getInstance().getSpeedFromGeo();
+ if (Settings.isUseMetricUnits()) {
+ text += speed + " km/h";
+ } else {
+ text += speed / IConversion.MILES_TO_KILOMETER + " mph";
+ }
+ result.setUrl(result.getUrl() + text);
+ return result;
}
- return searchByViewport(viewport, tokens, strategy);
}
/**
@@ -108,6 +104,12 @@ public class GCBase {
final Set<Tile> tiles = getTilesForViewport(viewport);
for (Tile tile : tiles) {
+
+ // testing purpose
+ {
+ searchResult.setUrl("Zoom=" + tile.getZoomlevel());
+ }
+
StringBuilder url = new StringBuilder();
url.append("?x=").append(tile.getX()) // x tile
.append("&y=").append(tile.getY()) // y tile
@@ -136,12 +138,12 @@ public class GCBase {
final String urlString = url.toString();
// The PNG must be request before ! Else the following request would return with 204 - No Content
- Bitmap bitmap = cgBase.requestMapTile(GCConstants.URL_MAP_TILE + urlString, referer);
+ Bitmap bitmap = Tile.requestMapTile(GCConstants.URL_MAP_TILE + urlString, referer);
assert bitmap.getWidth() == Tile.TILE_SIZE : "Bitmap has wrong width";
assert bitmap.getHeight() == Tile.TILE_SIZE : "Bitmap has wrong height";
- String data = cgBase.requestMapInfo(GCConstants.URL_MAP_INFO + urlString, referer);
+ String data = Tile.requestMapInfo(GCConstants.URL_MAP_INFO + urlString, referer);
if (StringUtils.isEmpty(data)) {
Log.e(Settings.tag, "GCBase.searchByViewport: No data from server for tile (" + tile.getX() + "/" + tile.getY() + ")");
} else {
@@ -234,7 +236,7 @@ public class GCBase {
for (int i = 1; i < keys.length(); i++) { // index 0 is empty
String key = keys.getString(i);
if (StringUtils.isNotBlank(key)) {
- int[] xy = splitJSONKey(key);
+ UTFGridPosition pos = UTFGridPosition.fromString(key);
JSONArray dataForKey = dataObject.getJSONArray(key);
for (int j = 0; j < dataForKey.length(); j++) {
JSONObject cacheInfo = dataForKey.getJSONObject(j);
@@ -244,21 +246,17 @@ public class GCBase {
List<UTFGridPosition> listOfPositions = positions.get(id);
if (listOfPositions == null) {
listOfPositions = new ArrayList<UTFGridPosition>();
+ positions.put(id, listOfPositions);
}
- /*
- * Optimization
- * UTFGridPosition pos = keyPositions.get(key);
- */
- UTFGridPosition pos = new UTFGridPosition(xy[0], xy[1]);
+
listOfPositions.add(pos);
- positions.put(id, listOfPositions);
}
}
}
for (String id : positions.keySet()) {
List<UTFGridPosition> pos = positions.get(id);
- UTFGridPosition xy = getPositionInGrid(pos);
+ UTFGridPosition xy = UTFGrid.getPositionInGrid(pos);
cgCache cache = new cgCache();
cache.setDetailed(false);
cache.setReliableLatLon(false);
@@ -266,12 +264,9 @@ public class GCBase {
cache.setName(nameCache.get(id));
cache.setZoomlevel(tile.getZoomlevel());
cache.setCoords(tile.getCoord(xy));
- if (strategy.flags.contains(StrategyFlag.PARSE_TILES)) {
- if (tile.getZoomlevel() >= 14) {
- parseMapPNG14(cache, bitmap, xy);
- } else {
- parseMapPNG13(cache, bitmap, xy);
- }
+ if (strategy.flags.contains(StrategyFlag.PARSE_TILES) && positions.size() < 64) {
+ // don't parse if there are too many caches. The decoding would return too much wrong results
+ IconDecoder.parseMapPNG(cache, bitmap, xy, tile.getZoomlevel());
} else {
cache.setType(CacheType.UNKNOWN);
}
@@ -286,89 +281,6 @@ public class GCBase {
return searchResult;
}
- // Try to get the cache type from the PNG image for a tile */
- public static void parseMapPNG14(cgCache cache, Bitmap bitmap, UTFGridPosition xy) {
- int x = xy.getX() * 4 + 2;
- int y = xy.getY() * 4 + 2;
- int countX = 0;
- int countY = 0;
-
- // search for left border
- while ((bitmap.getPixel(x, y) & 0x00FFFFFF) != BORDER_GRAY) {
- if (--x < 0 || ++countX > 20) {
- return;
- }
- }
- // search for bottom border
- while ((bitmap.getPixel(x, y) & 0x00FFFFFF) != 0x000000) {
- if (++y >= Tile.TILE_SIZE || ++countY > 20) {
- return;
- }
- }
-
- try {
- if ((bitmap.getPixel(x + POSX_TRADI, y + POSY_TRADI) & 0x00FFFFFF) == DARK_GREEN) {
- cache.setType(CacheType.TRADITIONAL);
- return;
- }
- if ((bitmap.getPixel(x + POSX_MYSTERY, y + POSY_MYSTERY) & 0x00FFFFFF) == DARK_BLUE) {
- cache.setType(CacheType.MYSTERY);
- return;
- }
- if ((bitmap.getPixel(x + POSX_MULTI, y + POSY_MULTI) & 0x00FFFFFF) == YELLOW) {
- cache.setType(CacheType.MULTI);
- return;
- }
- if ((bitmap.getPixel(x + POSX_FOUND, y + POSY_FOUND) & 0x00FFFFFF) == FOUND) {
- cache.setFound(true);
- return;
- }
- } catch (IllegalArgumentException e) {
- // intentionally left blank
- }
-
- return;
- }
-
- // Try to get the cache type from the PNG image for a tile */
- public static void parseMapPNG13(cgCache cache, Bitmap bitmap, UTFGridPosition xy) {
-
- int x = xy.getX() * 4 + 2;
- int y = xy.getY() * 4 + 2;
- int countY = 0;
-
- // search for top border
- while ((bitmap.getPixel(x, y) & 0x00FFFFFF) != BORDER_GRAY) {
- if (--y < 0 || ++countY > 12) {
- return;
- }
- }
-
- try {
- int color = bitmap.getPixel(x, y + 2) & 0x00FFFFFF;
-
- switch (color) {
- case LIGHT_GREEN:
- cache.setType(CacheType.TRADITIONAL);
- return;
- case YELLOW:
- cache.setType(CacheType.MULTI);
- return;
- }
- if ((color | 0x00FFFF) == 0x00FFFF) { // BLUE
- cache.setType(CacheType.MYSTERY);
- return;
- }
- // Found consists out of too many different colors
- }
- catch (IllegalArgumentException e) {
- // intentionally left blank
- }
-
- return;
- }
-
-
/**
* Calculate needed tiles for the given viewport
@@ -387,21 +299,6 @@ public class GCBase {
return tiles;
}
- /** Calculate from a list of positions (x/y) the coords */
- protected static UTFGridPosition getPositionInGrid(List<UTFGridPosition> positions) {
- int minX = UTFGrid.GRID_MAXX;
- int maxX = 0;
- int minY = UTFGrid.GRID_MAXY;
- int maxY = 0;
- for (UTFGridPosition pos : positions) {
- minX = Math.min(minX, pos.x);
- maxX = Math.max(maxX, pos.x);
- minY = Math.min(minY, pos.y);
- maxY = Math.max(maxY, pos.y);
- }
- return new UTFGridPosition((minX + maxX) / 2, (minY + maxY) / 2);
- }
-
/**
* Convert GCCode (geocode) to (old) GCIds
*
@@ -485,29 +382,11 @@ public class GCBase {
/** Get user session & session token from the Live Map. Needed for following requests */
public static String[] getTokens() {
- final HttpResponse response = cgBase.request(GCConstants.URL_LIVE_MAP, null, false);
- final String data = cgBase.getResponseData(response);
+ final HttpResponse response = Network.request(GCConstants.URL_LIVE_MAP, null, false);
+ final String data = Network.getResponseData(response);
String userSession = BaseUtils.getMatch(data, GCConstants.PATTERN_USERSESSION, "");
String sessionToken = BaseUtils.getMatch(data, GCConstants.PATTERN_SESSIONTOKEN, "");
return new String[] { userSession, sessionToken };
}
- /**
- * @param key
- * Key in the format (xx, xx)
- * @return
- */
- static int[] splitJSONKey(String key) {
- final Matcher matcher = PATTERN_JSON_KEY.matcher(key);
- try {
- if (matcher.matches()) {
- final int x = Integer.parseInt(matcher.group(1));
- final int y = Integer.parseInt(matcher.group(2));
- return new int[] { x, y };
- }
- } catch (NumberFormatException e) {
- }
- return new int[] { 0, 0 };
- }
-
}
diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
index 95e4921..4f319f3 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
@@ -8,8 +8,8 @@ import cgeo.geocaching.cgCache;
import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.connector.AbstractConnector;
import cgeo.geocaching.enumerations.StatusCode;
-import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.utils.CancellableHandler;
@@ -104,10 +104,10 @@ public class GCConnector extends AbstractConnector {
cgBase.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_loadpage);
- final String page = cgBase.requestLogged("http://www.geocaching.com/seek/cache_details.aspx", params, false, false, false);
+ final String page = Network.requestLogged("http://www.geocaching.com/seek/cache_details.aspx", params, false, false, false);
if (StringUtils.isEmpty(page)) {
- SearchResult search = new SearchResult();
+ final SearchResult search = new SearchResult();
if (app.isThere(geocode, guid, true, false)) {
if (StringUtils.isBlank(geocode) && StringUtils.isNotBlank(guid)) {
Log.i(Settings.tag, "Loading old cache from cache.");
@@ -132,18 +132,12 @@ public class GCConnector extends AbstractConnector {
return searchResult;
}
- SearchResult search = searchResult.filterSearchResults(false, false, Settings.getCacheType());
+ final SearchResult search = searchResult.filterSearchResults(false, false, Settings.getCacheType());
return search;
}
@Override
- public SearchResult searchByCoordinate(Geopoint center) {
- // TODO Auto-generated method stub
- return super.searchByCoordinate(center);
- }
-
- @Override
public SearchResult searchByViewport(Viewport viewport, String[] tokens) {
return GCBase.searchByViewport(viewport, tokens);
}
diff --git a/main/src/cgeo/geocaching/connector/gc/IconDecoder.java b/main/src/cgeo/geocaching/connector/gc/IconDecoder.java
new file mode 100644
index 0000000..43ca2ce
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/gc/IconDecoder.java
@@ -0,0 +1,164 @@
+package cgeo.geocaching.connector.gc;
+
+import cgeo.geocaching.cgCache;
+import cgeo.geocaching.enumerations.CacheType;
+
+import android.graphics.Bitmap;
+
+/**
+ * icon decoder for cache icons
+ *
+ */
+public abstract class IconDecoder {
+
+ public static void parseMapPNG(final cgCache cache, Bitmap bitmap, UTFGridPosition xy, int zoomlevel) {
+ if (zoomlevel >= 14) {
+ parseMapPNG14(cache, bitmap, xy);
+ } else {
+ parseMapPNG13(cache, bitmap, xy);
+ }
+ }
+
+ private static final int[] OFFSET_X = new int[] { 0, -1, -1, 0, 1, 1, 1, 0, -1, -2, -2, -2, -2, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2 };
+ private static final int[] OFFSET_Y = new int[] { 0, 0, 1, 1, 1, 0, -1, -1, -1, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2, -2, -2, -2 };
+
+ /**
+ * The icon decoder walks a spiral around the center pixel position of the cache
+ * and searches for characteristic colors.
+ *
+ * @param cache
+ * @param bitmap
+ * @param xy
+ */
+ private static void parseMapPNG13(final cgCache cache, Bitmap bitmap, UTFGridPosition xy) {
+ final int xCenter = xy.getX() * 4 + 2;
+ final int yCenter = xy.getY() * 4 + 2;
+ final int bitmapWidth = bitmap.getWidth();
+ final int bitmapHeight = bitmap.getHeight();
+
+ int countMulti = 0;
+ int countFound = 0;
+
+ for (int i = 0; i < OFFSET_X.length; i++) {
+
+ // assert that we are still in the tile
+ final int x = xCenter + OFFSET_X[i];
+ if (x < 0 || x >= bitmapWidth) {
+ continue;
+ }
+
+ final int y = yCenter + OFFSET_Y[i];
+ if (y < 0 || y >= bitmapHeight) {
+ continue;
+ }
+
+ int color = bitmap.getPixel(x, y) & 0x00FFFFFF;
+
+ // transparent pixels are not interesting
+ if (color == 0) {
+ continue;
+ }
+
+ int red = (color & 0xFF0000) >> 16;
+ int green = (color & 0xFF00) >> 8;
+ int blue = color & 0xFF;
+
+ // these are quite sure, so one pixel is enough for matching
+ if (green > 0x80 && green > red && green > blue) {
+ cache.setType(CacheType.TRADITIONAL);
+ return;
+ }
+ if (blue > 0x80 && blue > red && blue > green) {
+ cache.setType(CacheType.MYSTERY);
+ return;
+ }
+ if (red > 0x90 && blue < 0x10 && green < 0x10) {
+ cache.setType(CacheType.EVENT);
+ return;
+ }
+
+ // next two are hard to distinguish, therefore we sample all pixels of the spiral
+ if (red > 0xFA && green > 0xD0) {
+ countMulti++;
+ }
+ if (red < 0xF3 && red > 0xa0 && green > 0x20 && blue < 0x80) {
+ countFound++;
+ }
+ }
+
+ // now check whether we are sure about found/multi
+ if (countFound > countMulti && countFound >= 2) {
+ cache.setFound(true);
+ }
+ if (countMulti > countFound && countMulti >= 5) {
+ cache.setType(CacheType.MULTI);
+ }
+ }
+
+ // Pixel colors in tile
+ private final static int COLOR_BORDER_GRAY = 0x5F5F5F;
+ private final static int COLOR_TRADITIONAL = 0x316013;
+ private final static int COLOR_MYSTERY = 0x243C97;
+ private final static int COLOR_MULTI = 0xFFDE19;
+ private final static int COLOR_FOUND = 0xFBEA5D;
+
+ // Offset inside cache icon
+ private final static int POSX_TRADI = 7;
+ private final static int POSY_TRADI = -12;
+ private final static int POSX_MULTI = 5; // for orange 8
+ private final static int POSY_MULTI = -9; // for orange 10
+ private final static int POSX_MYSTERY = 5;
+ private final static int POSY_MYSTERY = -13;
+ private final static int POSX_FOUND = 10;
+ private final static int POSY_FOUND = -8;
+
+ /**
+ * For level 14 find the borders of the icons and then use a single pixel and color to match.
+ *
+ * @param cache
+ * @param bitmap
+ * @param xy
+ */
+ private static void parseMapPNG14(cgCache cache, Bitmap bitmap, UTFGridPosition xy) {
+ int x = xy.getX() * 4 + 2;
+ int y = xy.getY() * 4 + 2;
+
+ // search for left border
+ int countX = 0;
+ while ((bitmap.getPixel(x, y) & 0x00FFFFFF) != COLOR_BORDER_GRAY) {
+ if (--x < 0 || ++countX > 20) {
+ return;
+ }
+ }
+ // search for bottom border
+ int countY = 0;
+ while ((bitmap.getPixel(x, y) & 0x00FFFFFF) != 0x000000) {
+ if (++y >= Tile.TILE_SIZE || ++countY > 20) {
+ return;
+ }
+ }
+
+ try {
+ if ((bitmap.getPixel(x + POSX_TRADI, y + POSY_TRADI) & 0x00FFFFFF) == COLOR_TRADITIONAL) {
+ cache.setType(CacheType.TRADITIONAL);
+ return;
+ }
+ if ((bitmap.getPixel(x + POSX_MYSTERY, y + POSY_MYSTERY) & 0x00FFFFFF) == COLOR_MYSTERY) {
+ cache.setType(CacheType.MYSTERY);
+ return;
+ }
+ if ((bitmap.getPixel(x + POSX_MULTI, y + POSY_MULTI) & 0x00FFFFFF) == COLOR_MULTI) {
+ cache.setType(CacheType.MULTI);
+ return;
+ }
+ if ((bitmap.getPixel(x + POSX_FOUND, y + POSY_FOUND) & 0x00FFFFFF) == COLOR_FOUND) {
+ cache.setFound(true);
+ return;
+ }
+ } catch (IllegalArgumentException e) {
+ // intentionally left blank
+ }
+
+ return;
+ }
+}
diff --git a/main/src/cgeo/geocaching/connector/gc/Tile.java b/main/src/cgeo/geocaching/connector/gc/Tile.java
index 9d38a64..eec83b0 100644
--- a/main/src/cgeo/geocaching/connector/gc/Tile.java
+++ b/main/src/cgeo/geocaching/connector/gc/Tile.java
@@ -1,6 +1,17 @@
package cgeo.geocaching.connector.gc;
+import cgeo.geocaching.Settings;
import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.network.Network;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.util.Log;
+
+import java.io.IOException;
/**
* All about tiles.
@@ -200,4 +211,28 @@ public class Tile {
public int hashCode() {
return toString().hashCode();
}
+
+ /** Request JSON informations for a tile */
+ public static String requestMapInfo(final String url, final String referer) {
+ final HttpGet request = new HttpGet(url);
+ request.addHeader("Accept", "application/json, text/javascript, */*; q=0.01");
+ request.addHeader("Referer", referer);
+ request.addHeader("X-Requested-With", "XMLHttpRequest");
+ return Network.getResponseData(Network.request(request), false);
+ }
+
+ /** Request .png image for a tile. */
+ public static Bitmap requestMapTile(final String url, final String referer) {
+ final HttpGet request = new HttpGet(url);
+ request.addHeader("Accept", "image/png,image/*;q=0.8,*/*;q=0.5");
+ request.addHeader("Referer", referer);
+ request.addHeader("X-Requested-With", "XMLHttpRequest");
+ final HttpResponse response = Network.request(request);
+ try {
+ return response != null ? BitmapFactory.decodeStream(response.getEntity().getContent()) : null;
+ } catch (IOException e) {
+ Log.e(Settings.tag, "cgBase.requestMapTile() " + e.getMessage());
+ }
+ return null;
+ }
}
diff --git a/main/src/cgeo/geocaching/connector/gc/UTFGrid.java b/main/src/cgeo/geocaching/connector/gc/UTFGrid.java
index cf490ec..a663a71 100644
--- a/main/src/cgeo/geocaching/connector/gc/UTFGrid.java
+++ b/main/src/cgeo/geocaching/connector/gc/UTFGrid.java
@@ -1,5 +1,7 @@
package cgeo.geocaching.connector.gc;
+import java.util.List;
+
/**
*
* @author blafoo
@@ -28,4 +30,19 @@ public final class UTFGrid {
return (short) (result - 32);
}
+ /** Calculate from a list of positions (x/y) the coords */
+ protected static UTFGridPosition getPositionInGrid(List<UTFGridPosition> positions) {
+ int minX = GRID_MAXX;
+ int maxX = 0;
+ int minY = GRID_MAXY;
+ int maxY = 0;
+ for (UTFGridPosition pos : positions) {
+ minX = Math.min(minX, pos.x);
+ maxX = Math.max(maxX, pos.x);
+ minY = Math.min(minY, pos.y);
+ maxY = Math.max(maxY, pos.y);
+ }
+ return new UTFGridPosition((minX + maxX) / 2, (minY + maxY) / 2);
+ }
+
}
diff --git a/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java b/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java
index e88a425..1aae560 100644
--- a/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java
+++ b/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java
@@ -1,5 +1,8 @@
package cgeo.geocaching.connector.gc;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
/**
* Representation of a position inside an UTFGrid
@@ -11,6 +14,7 @@ public final class UTFGridPosition {
public final int x;
public final int y;
+ private final static Pattern PATTERN_JSON_KEY = Pattern.compile("[^\\d]*" + "(\\d+),\\s*(\\d+)" + "[^\\d]*"); // (12, 34)
public UTFGridPosition(final int x, final int y) {
assert x >= 0 && x <= UTFGrid.GRID_MAXX : "x outside bounds";
@@ -28,4 +32,22 @@ public final class UTFGridPosition {
return y;
}
+ /**
+ * @param key
+ * Key in the format (xx, xx)
+ * @return
+ */
+ static UTFGridPosition fromString(String key) {
+ final Matcher matcher = UTFGridPosition.PATTERN_JSON_KEY.matcher(key);
+ try {
+ if (matcher.matches()) {
+ final int x = Integer.parseInt(matcher.group(1));
+ final int y = Integer.parseInt(matcher.group(2));
+ return new UTFGridPosition(x, y);
+ }
+ } catch (NumberFormatException e) {
+ }
+ return new UTFGridPosition(0, 0);
+ }
+
}
diff --git a/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java b/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java
index a69d5c9..9c3ab4a 100644
--- a/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java
+++ b/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java
@@ -1,7 +1,6 @@
package cgeo.geocaching.connector.opencaching;
import cgeo.geocaching.Settings;
-import cgeo.geocaching.cgBase;
import cgeo.geocaching.cgCache;
import cgeo.geocaching.cgImage;
import cgeo.geocaching.cgLog;
@@ -13,6 +12,7 @@ import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.GeopointFormatter;
import cgeo.geocaching.geopoint.GeopointParser;
+import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import org.apache.commons.lang3.StringUtils;
@@ -304,6 +304,6 @@ final public class OkapiClient {
final String uri = "http://" + host + service;
((ApiOpenCachingConnector) connector).addAuthentication(params);
- return cgBase.requestJSON(uri, params);
+ return Network.requestJSON(uri, params);
}
}
diff --git a/main/src/cgeo/geocaching/files/LocalStorage.java b/main/src/cgeo/geocaching/files/LocalStorage.java
index c127e89..b5fa5f6 100644
--- a/main/src/cgeo/geocaching/files/LocalStorage.java
+++ b/main/src/cgeo/geocaching/files/LocalStorage.java
@@ -4,7 +4,7 @@ import cgeo.geocaching.Settings;
import cgeo.geocaching.utils.CryptUtils;
import org.apache.commons.lang3.StringUtils;
-import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
import android.os.Environment;
import android.util.Log;
@@ -143,27 +143,49 @@ public class LocalStorage {
* the entity whose content will be saved
* @param targetFile
* the target file, which will be created if necessary
- * @return true if the operation was sucessful, false otherwise
+ * @return true if the operation was successful, false otherwise
*/
- public static boolean saveEntityToFile(final HttpEntity entity, final File targetFile) {
- if (entity == null) {
+ public static boolean saveEntityToFile(final HttpResponse response, final File targetFile) {
+ if (response == null) {
+ return false;
+ }
+
+ try {
+ return saveToFile(response.getEntity().getContent(), targetFile);
+ } catch (IOException e) {
+ Log.e(Settings.tag, "LocalStorage.saveEntityToFile", e);
+ }
+
+ return false;
+ }
+
+ /**
+ * Save an HTTP response to a file.
+ *
+ * @param entity
+ * the entity whose content will be saved
+ * @param targetFile
+ * the target file, which will be created if necessary
+ * @return true if the operation was successful, false otherwise
+ */
+ public static boolean saveToFile(final InputStream inputStream, final File targetFile) {
+ if (inputStream == null) {
return false;
}
try {
- final InputStream is = entity.getContent();
try {
final FileOutputStream fos = new FileOutputStream(targetFile);
try {
- return copy(is, fos);
+ return copy(inputStream, fos);
} finally {
fos.close();
}
} finally {
- is.close();
+ inputStream.close();
}
} catch (IOException e) {
- Log.e(Settings.tag, "LocalStorage.saveEntityToFile", e);
+ Log.e(Settings.tag, "LocalStorage.saveToFile", e);
}
return false;
}
@@ -235,4 +257,18 @@ public class LocalStorage {
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
}
+ public static boolean deleteDirectory(File path) {
+ if (path.exists()) {
+ for (final File file : path.listFiles()) {
+ if (file.isDirectory()) {
+ deleteDirectory(file);
+ } else {
+ file.delete();
+ }
+ }
+ }
+
+ return path.delete();
+ }
+
}
diff --git a/main/src/cgeo/geocaching/gcvote/GCVote.java b/main/src/cgeo/geocaching/gcvote/GCVote.java
index c98d4d9..fa2af0d 100644
--- a/main/src/cgeo/geocaching/gcvote/GCVote.java
+++ b/main/src/cgeo/geocaching/gcvote/GCVote.java
@@ -1,8 +1,8 @@
package cgeo.geocaching.gcvote;
import cgeo.geocaching.Settings;
-import cgeo.geocaching.cgBase;
import cgeo.geocaching.cgCache;
+import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.utils.LeastRecentlyUsedCache;
@@ -96,7 +96,7 @@ public final class GCVote {
params.put("waypoints", StringUtils.join(geocodes.toArray(), ','));
}
params.put("version", "cgeo");
- final String page = cgBase.getResponseData(cgBase.request("http://gcvote.com/getVotes.php", params, false, false, false));
+ final String page = Network.getResponseData(Network.request("http://gcvote.com/getVotes.php", params, false, false, false));
if (page == null) {
return null;
}
@@ -220,7 +220,7 @@ public final class GCVote {
"voteUser", String.format("%.1f", vote).replace(',', '.'),
"version", "cgeo");
- final String result = cgBase.getResponseData(cgBase.request("http://gcvote.com/setVote.php", params, false, false, false));
+ final String result = Network.getResponseData(Network.request("http://gcvote.com/setVote.php", params, false, false, false));
return result.trim().equalsIgnoreCase("ok");
}
diff --git a/main/src/cgeo/geocaching/geopoint/Geopoint.java b/main/src/cgeo/geocaching/geopoint/Geopoint.java
index ca67014..fdcc663 100644
--- a/main/src/cgeo/geocaching/geopoint/Geopoint.java
+++ b/main/src/cgeo/geocaching/geopoint/Geopoint.java
@@ -1,8 +1,16 @@
package cgeo.geocaching.geopoint;
+import cgeo.geocaching.Settings;
+import cgeo.geocaching.geopoint.GeopointFormatter.Format;
+import cgeo.geocaching.network.Network;
+import cgeo.geocaching.network.Parameters;
+
import org.apache.commons.lang3.StringUtils;
+import org.json.JSONArray;
+import org.json.JSONObject;
import android.location.Location;
+import android.util.Log;
import java.math.BigDecimal;
import java.math.RoundingMode;
@@ -234,7 +242,7 @@ public final class Geopoint
/**
* Returns formatted coordinates with default format.
* Default format is decimalminutes, e.g. N 52° 36.123 E 010° 03.456
- *
+ *
* @return formatted coordinates
*/
@Override
@@ -475,4 +483,33 @@ public final class Geopoint
super(msg);
}
}
+
+ public Double getElevation() {
+ try {
+ final String uri = "http://maps.googleapis.com/maps/api/elevation/json";
+ final Parameters params = new Parameters(
+ "sensor", "false",
+ "locations", format(Format.LAT_LON_DECDEGREE_COMMA));
+ final JSONObject response = Network.requestJSON(uri, params);
+
+ if (response == null) {
+ return null;
+ }
+
+ if (!StringUtils.equalsIgnoreCase(response.getString("status"), "OK")) {
+ return null;
+ }
+
+ if (response.has("results")) {
+ JSONArray results = response.getJSONArray("results");
+ JSONObject result = results.getJSONObject(0);
+ return result.getDouble("elevation");
+ }
+ } catch (Exception e) {
+ Log.w(Settings.tag, "cgBase.getElevation: " + e.toString());
+ }
+
+ return null;
+ }
+
}
diff --git a/main/src/cgeo/geocaching/geopoint/Viewport.java b/main/src/cgeo/geocaching/geopoint/Viewport.java
index 3e92b78..4d46970 100644
--- a/main/src/cgeo/geocaching/geopoint/Viewport.java
+++ b/main/src/cgeo/geocaching/geopoint/Viewport.java
@@ -50,10 +50,9 @@ public class Viewport {
return "(" + bottomLeft.toString() + "," + topRight.toString() + ")";
}
- // viewport is defined by center, span and some (10%) reserve on every side
/**
* Check if coordinates are located in a viewport (defined by its center and span
- * in each direction). The viewport also includes a 10% extension on each side.
+ * in each direction).
*
* @param centerLat
* the viewport center latitude
@@ -68,39 +67,55 @@ public class Viewport {
* @return true if the coordinates are in the viewport
*/
public static boolean isCacheInViewPort(int centerLat, int centerLon, int spanLat, int spanLon, final Geopoint coords) {
- return Math.abs(coords.getLatitudeE6() - centerLat) <= Math.abs(spanLat) * 0.6 &&
- Math.abs(coords.getLongitudeE6() - centerLon) <= Math.abs(spanLon) * 0.6;
+ return 2 * Math.abs(coords.getLatitudeE6() - centerLat) <= Math.abs(spanLat) &&
+ 2 * Math.abs(coords.getLongitudeE6() - centerLon) <= Math.abs(spanLon);
}
+ /**
+ * Check if an area is located in a viewport (defined by its center and span
+ * in each direction).
+ *
+ * expects coordinates in E6 format
+ *
+ * @param centerLat1
+ * @param centerLon1
+ * @param centerLat2
+ * @param centerLon2
+ * @param spanLat1
+ * @param spanLon1
+ * @param spanLat2
+ * @param spanLon2
+ * @return
+ */
public static 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;
}
+
+ final int right1 = centerLat1 + (spanLat1 / 2);
+ final int right2 = centerLat2 + (spanLat2 / 2);
if (right2 >= right1) {
return false;
}
+
+ final int top1 = centerLon1 + (spanLon1 / 2);
+ final int top2 = centerLon2 + (spanLon2 / 2);
if (top2 >= top1) {
return false;
}
+
+ final int bottom1 = centerLon1 - (spanLon1 / 2);
+ final int bottom2 = centerLon2 - (spanLon2 / 2);
if (bottom2 <= bottom1) {
return false;
}
-
+
return true;
} catch (Exception e) {
- Log.e(Settings.tag, "cgBase.isInViewPort: " + e.toString());
+ Log.e(Settings.tag, "Viewport.isInViewPort: " + e.toString());
return false;
}
}
diff --git a/main/src/cgeo/geocaching/go4cache/Go4Cache.java b/main/src/cgeo/geocaching/go4cache/Go4Cache.java
index 7243383..fb53c27 100644
--- a/main/src/cgeo/geocaching/go4cache/Go4Cache.java
+++ b/main/src/cgeo/geocaching/go4cache/Go4Cache.java
@@ -6,6 +6,7 @@ import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.GeopointFormatter.Format;
import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.utils.CryptUtils;
@@ -99,7 +100,7 @@ public final class Go4Cache extends Thread {
params.put("v", cgBase.version);
}
- cgBase.postRequest("http://api.go4cache.com/", params);
+ Network.postRequest("http://api.go4cache.com/", params);
// Update our coordinates even if the request was not successful, as not to hammer the server
// with invalid requests for every new GPS position.
@@ -134,7 +135,7 @@ public final class Go4Cache extends Thread {
"lnm", viewport.bottomLeft.format(Format.LON_DECDEGREE_RAW),
"lnx", viewport.topRight.format(Format.LON_DECDEGREE_RAW));
- final String data = cgBase.getResponseData(cgBase.postRequest("http://api.go4cache.com/get.php", params));
+ final String data = Network.getResponseData(Network.postRequest("http://api.go4cache.com/get.php", params));
if (StringUtils.isBlank(data)) {
Log.e(Settings.tag, "cgeoBase.getGeocachersInViewport: No data from server");
diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java
index 2ce4c42..8e451b6 100644
--- a/main/src/cgeo/geocaching/maps/CGeoMap.java
+++ b/main/src/cgeo/geocaching/maps/CGeoMap.java
@@ -34,7 +34,9 @@ import cgeo.geocaching.maps.interfaces.MapProvider;
import cgeo.geocaching.maps.interfaces.MapViewImpl;
import cgeo.geocaching.maps.interfaces.OnMapDragListener;
import cgeo.geocaching.maps.interfaces.OtherCachersOverlayItemImpl;
+import cgeo.geocaching.network.Login;
import cgeo.geocaching.utils.CancellableHandler;
+import cgeo.geocaching.utils.LRUList;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@@ -75,6 +77,9 @@ import java.util.Set;
*/
public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFactory {
+ /** max. number of caches displayed in the Live Map */
+ public static final int MAX_CACHES = 500;
+
/** Handler Messages */
private static final int HIDE_PROGRESS = 0;
private static final int SHOW_PROGRESS = 1;
@@ -134,6 +139,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
private Integer centerLongitudeUsers = null;
private Integer spanLatitudeUsers = null;
private Integer spanLongitudeUsers = null;
+ private int zoom = -100;
// threads
private LoadTimer loadTimer = null;
private UsersTimer usersTimer = null;
@@ -164,7 +170,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
private static Map<Integer, LayerDrawable> overlaysCache = new HashMap<Integer, LayerDrawable>();
private int cachesCnt = 0;
/** List of caches in the viewport */
- private Set<cgCache> caches = new HashSet<cgCache>();
+ private final LRUList<cgCache> caches = new LRUList<cgCache>(MAX_CACHES);
/** List of users in the viewport */
private List<Go4CacheUser> users = new ArrayList<Go4CacheUser>();
private List<cgCoord> coordinates = new ArrayList<cgCoord>();
@@ -200,11 +206,20 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
title.append(mapTitle);
}
+ countVisibleCaches();
if (caches != null && caches.size() > 0 && !mapTitle.contains("[")) {
- title.append(" [");
- title.append(caches.size());
+ title.append(" [").append(cachesCnt);
+ if (cachesCnt != caches.size()) {
+ title.append('/').append(caches.size());
+ }
title.append(']');
}
+ // testing purpose
+ {
+ if (search != null && StringUtils.isNotBlank(search.getUrl())) {
+ title.append("[" + search.getUrl() + "]");
+ }
+ }
ActivityMixin.setTitle(activity, title.toString());
break;
@@ -305,6 +320,28 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
super(activity);
}
+ protected void countVisibleCaches() {
+ final ArrayList<cgCache> protectedCaches = new ArrayList<cgCache>(caches);
+
+ int count = 0;
+ if (protectedCaches.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 cache : protectedCaches) {
+ if (cache != null && cache.getCoords() != null) {
+ if (Viewport.isCacheInViewPort(mapCenterLat, mapCenterLon, mapSpanLat, mapSpanLon, cache.getCoords())) {
+ count++;
+ }
+ }
+ }
+ }
+ cachesCnt = count;
+ }
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -456,7 +493,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
}
dirtyCaches.clear();
// force an update of the display. Includes a call to DownloadThread :-(
- liveChanged = true;
+ // liveChanged = true;
}
startTimer();
@@ -558,7 +595,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
Strategy strategy = Settings.getLiveMapStrategy();
SubMenu subMenuStrategy = menu.addSubMenu(0, SUBMENU_STRATEGY, 0, res.getString(R.string.map_strategy));
- subMenuStrategy.setHeaderTitle("Live Map strategy");
+ subMenuStrategy.setHeaderTitle(res.getString(R.string.map_strategy_title));
subMenuStrategy.add(2, MENU_STRATEGY_FASTEST, 0, Strategy.FASTEST.getL10n()).setCheckable(true).setChecked(strategy == Strategy.FASTEST);
subMenuStrategy.add(2, MENU_STRATEGY_FAST, 0, Strategy.FAST.getL10n()).setCheckable(true).setChecked(strategy == Strategy.FAST);
subMenuStrategy.add(2, MENU_STRATEGY_AUTO, 0, Strategy.AUTO.getL10n()).setCheckable(true).setChecked(strategy == Strategy.AUTO);
@@ -648,10 +685,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
final int mapSpanLat = mapView.getLatitudeSpan();
final int mapSpanLon = mapView.getLongitudeSpan();
- for (cgCache oneCache : cachesProtected) {
- if (oneCache != null && oneCache.getCoords() != null) {
- if (Viewport.isCacheInViewPort(mapCenterLat, mapCenterLon, mapSpanLat, mapSpanLon, oneCache.getCoords()) && !app.isOffline(oneCache.getGeocode(), null)) {
- geocodes.add(oneCache.getGeocode());
+ for (cgCache cache : cachesProtected) {
+ if (cache != null && cache.getCoords() != null) {
+ if (Viewport.isCacheInViewPort(mapCenterLat, mapCenterLon, mapSpanLat, mapSpanLon, cache.getCoords()) && !app.isOffline(cache.getGeocode(), null)) {
+ geocodes.add(cache.getGeocode());
}
}
}
@@ -945,6 +982,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
int centerLongitudeNow;
int spanLatitudeNow;
int spanLongitudeNow;
+ int zoomNow;
boolean moved = false;
boolean force = false;
long currentTime = 0;
@@ -986,7 +1024,13 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
force = true;
}
- //LeeB
+ // update title on any change
+ zoomNow = mapView.getMapZoomLevel();
+ if (moved || zoomNow != zoom || spanLatitudeNow != spanLatitude || spanLongitudeNow != spanLongitude || centerLatitudeNow != centerLatitude || centerLongitudeNow != centerLongitude) {
+ displayHandler.sendEmptyMessage(UPDATE_TITLE);
+ }
+ zoom = zoomNow;
+
// save new values
if (moved) {
liveChanged = false;
@@ -1018,7 +1062,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
spanLatitude = spanLatitudeNow;
spanLongitude = spanLongitudeNow;
- showProgressHandler.sendEmptyMessage(SHOW_PROGRESS); // show progress
+ showProgressHandler.sendEmptyMessage(SHOW_PROGRESS);
loadThread = new LoadThread(centerLatitude, centerLongitude, spanLatitude, spanLongitude);
loadThread.start(); //loadThread will kick off downloadThread once it's done
@@ -1027,7 +1071,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
}
if (!isLoading()) {
- showProgressHandler.sendEmptyMessage(HIDE_PROGRESS); // hide progress
+ showProgressHandler.sendEmptyMessage(HIDE_PROGRESS);
}
yield();
@@ -1330,12 +1374,11 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
}
final Viewport viewport = new Viewport(new Geopoint(latMin, lonMin), new Geopoint(latMax, lonMax));
- // search = cgBase.searchByViewport(token, viewport);
search = ConnectorFactory.searchByViewport(viewport, tokens);
if (search != null) {
downloaded = true;
if (search.error == StatusCode.NOT_LOGGED_IN) {
- cgBase.login();
+ Login.login();
tokens = null;
} else {
break;
@@ -1395,50 +1438,50 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
}
// display caches
- final List<cgCache> cachesProtected = new ArrayList<cgCache>(caches);
- final List<CachesOverlayItemImpl> items = new ArrayList<CachesOverlayItemImpl>();
+ final List<cgCache> cachesToDisplay = new ArrayList<cgCache>(caches);
+ final List<CachesOverlayItemImpl> itemsToDisplay = new ArrayList<CachesOverlayItemImpl>();
- if (!cachesProtected.isEmpty()) {
- for (cgCache cacheOne : cachesProtected) {
+ if (!cachesToDisplay.isEmpty()) {
+ for (cgCache cache : cachesToDisplay) {
if (stop) {
throw new ThreadDeath();
}
- if (cacheOne.getCoords() == null) {
+ if (cache.getCoords() == null) {
continue;
}
// display cache waypoints
- if (cacheOne.hasWaypoints()
+ if (cache.hasWaypoints()
// Only show waypoints for single view or setting
// when less than showWaypointsthreshold Caches shown
- && (cachesProtected.size() == 1 || (cachesProtected.size() < Settings.getWayPointsThreshold()))) {
- for (cgWaypoint oneWaypoint : cacheOne.getWaypoints()) {
- if (oneWaypoint.getCoords() == null) {
+ && (cachesToDisplay.size() == 1 || (cachesToDisplay.size() < Settings.getWayPointsThreshold()))) {
+ for (cgWaypoint waypoint : cache.getWaypoints()) {
+ if (waypoint.getCoords() == null) {
continue;
}
- items.add(getItem(new cgCoord(oneWaypoint), null, oneWaypoint));
+ itemsToDisplay.add(getItem(new cgCoord(waypoint), null, waypoint));
}
}
- items.add(getItem(new cgCoord(cacheOne), cacheOne, null));
+ itemsToDisplay.add(getItem(new cgCoord(cache), cache, null));
}
- overlayCaches.updateItems(items);
+ overlayCaches.updateItems(itemsToDisplay);
displayHandler.sendEmptyMessage(INVALIDATE_MAP);
- cachesCnt = cachesProtected.size();
+ cachesCnt = cachesToDisplay.size();
if (stop) {
throw new ThreadDeath();
}
} else {
- overlayCaches.updateItems(items);
+ overlayCaches.updateItems(itemsToDisplay);
displayHandler.sendEmptyMessage(INVALIDATE_MAP);
}
- cachesProtected.clear();
+ cachesToDisplay.clear();
displayHandler.sendEmptyMessage(UPDATE_TITLE);
} catch (ThreadDeath e) {
diff --git a/main/src/cgeo/geocaching/maps/google/GoogleMapView.java b/main/src/cgeo/geocaching/maps/google/GoogleMapView.java
index 766c941..8afba89 100644
--- a/main/src/cgeo/geocaching/maps/google/GoogleMapView.java
+++ b/main/src/cgeo/geocaching/maps/google/GoogleMapView.java
@@ -60,7 +60,7 @@ public class GoogleMapView extends MapView implements MapViewImpl {
super.draw(canvas);
} catch (Exception e) {
- Log.e(Settings.tag, "cgMapView.draw: " + e.toString());
+ Log.e(Settings.tag, "GoogleMapView.draw: " + e.toString());
}
}
@@ -74,7 +74,7 @@ public class GoogleMapView extends MapView implements MapViewImpl {
super.displayZoomControls(takeFocus);
} catch (Exception e) {
- Log.e(Settings.tag, "cgMapView.displayZoomControls: " + e.toString());
+ Log.e(Settings.tag, "GoogleMapView.displayZoomControls: " + e.toString());
}
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java
index 9f010fb..d14ea8c 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java
@@ -49,7 +49,7 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
super.draw(canvas);
} catch (Exception e) {
- Log.e(Settings.tag, "cgMapView.draw: " + e.toString());
+ Log.e(Settings.tag, "MapsforgeMapView.draw: " + e.toString());
}
}
@@ -196,7 +196,7 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
}
} catch (Exception e) {
- Log.e(Settings.tag, "mfMapView.repaintRequired: " + e.toString());
+ Log.e(Settings.tag, "MapsforgeMapView.repaintRequired: " + e.toString());
}
}
}
diff --git a/main/src/cgeo/geocaching/network/HtmlImage.java b/main/src/cgeo/geocaching/network/HtmlImage.java
index a643383..1811110 100644
--- a/main/src/cgeo/geocaching/network/HtmlImage.java
+++ b/main/src/cgeo/geocaching/network/HtmlImage.java
@@ -3,13 +3,11 @@ package cgeo.geocaching.network;
import cgeo.geocaching.R;
import cgeo.geocaching.Settings;
import cgeo.geocaching.StoredList;
-import cgeo.geocaching.cgBase;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.files.LocalStorage;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
-import org.apache.http.entity.BufferedHttpEntity;
import android.content.Context;
import android.graphics.Bitmap;
@@ -84,21 +82,18 @@ public class HtmlImage implements Html.ImageGetter {
// Download image and save it to the cache
if (imagePre == null || onlySave) {
final String absoluteURL = makeAbsoluteURL(url);
- BufferedHttpEntity bufferedEntity = null;
if (absoluteURL != null) {
try {
- final HttpResponse httpResponse = cgBase.request(absoluteURL, null, false);
+ final HttpResponse httpResponse = Network.request(absoluteURL, null, false);
if (httpResponse != null) {
- bufferedEntity = new BufferedHttpEntity(httpResponse.getEntity());
+ final File file = LocalStorage.getStorageFile(geocode, url, true, true);
+ LocalStorage.saveEntityToFile(httpResponse, file);
}
} catch (Exception e) {
Log.e(Settings.tag, "HtmlImage.getDrawable (downloading from web)", e);
}
}
-
- final File file = LocalStorage.getStorageFile(geocode, url, true, true);
- LocalStorage.saveEntityToFile(bufferedEntity, file);
}
if (onlySave) {
diff --git a/main/src/cgeo/geocaching/network/Login.java b/main/src/cgeo/geocaching/network/Login.java
new file mode 100644
index 0000000..8db370d
--- /dev/null
+++ b/main/src/cgeo/geocaching/network/Login.java
@@ -0,0 +1,389 @@
+package cgeo.geocaching.network;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.Settings;
+import cgeo.geocaching.cgBase;
+import cgeo.geocaching.connector.gc.GCConstants;
+import cgeo.geocaching.enumerations.StatusCode;
+import cgeo.geocaching.utils.BaseUtils;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.http.HttpResponse;
+
+import android.content.Context;
+import android.graphics.drawable.BitmapDrawable;
+import android.util.Log;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Matcher;
+
+public abstract class Login {
+
+ private final static String ENGLISH = "English&#9660;";
+
+ // false = not logged in
+ private static boolean actualLoginStatus = false;
+ private static String actualUserName = "";
+ private static String actualMemberStatus = "";
+ private static int actualCachesFound = -1;
+ private static String actualStatus = "";
+
+ private final static Map<String, SimpleDateFormat> gcCustomDateFormats;
+ static {
+ final String[] formats = new String[] {
+ "MM/dd/yyyy",
+ "yyyy-MM-dd",
+ "yyyy/MM/dd",
+ "dd/MMM/yyyy",
+ "MMM/dd/yyyy",
+ "dd MMM yy",
+ "dd/MM/yyyy"
+ };
+
+ Map<String, SimpleDateFormat> map = new HashMap<String, SimpleDateFormat>();
+
+ for (String format : formats) {
+ map.put(format, new SimpleDateFormat(format, Locale.ENGLISH));
+ }
+
+ gcCustomDateFormats = Collections.unmodifiableMap(map);
+ }
+
+ public static StatusCode login() {
+ final ImmutablePair<String, String> login = Settings.getLogin();
+
+ if (login == null || StringUtils.isEmpty(login.left) || StringUtils.isEmpty(login.right)) {
+ Login.setActualStatus(cgBase.res.getString(R.string.err_login));
+ Log.e(Settings.tag, "cgeoBase.login: No login information stored");
+ return StatusCode.NO_LOGIN_INFO_STORED;
+ }
+
+ // res is null during the unit tests
+ if (cgBase.res != null) {
+ Login.setActualStatus(cgBase.res.getString(R.string.init_login_popup_working));
+ }
+ HttpResponse loginResponse = Network.request("https://www.geocaching.com/login/default.aspx", null, false, false, false);
+ String loginData = Network.getResponseData(loginResponse);
+ if (loginResponse != null && loginResponse.getStatusLine().getStatusCode() == 503 && BaseUtils.matches(loginData, GCConstants.PATTERN_MAINTENANCE)) {
+ return StatusCode.MAINTENANCE;
+ }
+
+ if (StringUtils.isBlank(loginData)) {
+ Log.e(Settings.tag, "cgeoBase.login: Failed to retrieve login page (1st)");
+ return StatusCode.CONNECTION_FAILED; // no loginpage
+ }
+
+ if (Login.getLoginStatus(loginData)) {
+ Log.i(Settings.tag, "Already logged in Geocaching.com as " + login.left);
+ Login.switchToEnglish(loginData);
+ return StatusCode.NO_ERROR; // logged in
+ }
+
+ Network.clearCookies();
+ Settings.setCookieStore(null);
+
+ final Parameters params = new Parameters(
+ "__EVENTTARGET", "",
+ "__EVENTARGUMENT", "",
+ "ctl00$ContentBody$tbUsername", login.left,
+ "ctl00$ContentBody$tbPassword", login.right,
+ "ctl00$ContentBody$cbRememberMe", "on",
+ "ctl00$ContentBody$btnSignIn", "Login");
+ final String[] viewstates = Login.getViewstates(loginData);
+ if (cgBase.isEmpty(viewstates)) {
+ Log.e(Settings.tag, "cgeoBase.login: Failed to find viewstates");
+ return StatusCode.LOGIN_PARSE_ERROR; // no viewstates
+ }
+ Login.putViewstates(params, viewstates);
+
+ loginResponse = Network.postRequest("https://www.geocaching.com/login/default.aspx", params);
+ loginData = Network.getResponseData(loginResponse);
+
+ if (StringUtils.isNotBlank(loginData)) {
+ if (Login.getLoginStatus(loginData)) {
+ Log.i(Settings.tag, "Successfully logged in Geocaching.com as " + login.left);
+
+ Login.switchToEnglish(loginData);
+ Settings.setCookieStore(Network.dumpCookieStore());
+
+ return StatusCode.NO_ERROR; // logged in
+ } else {
+ if (loginData.contains("Your username/password combination does not match.")) {
+ Log.i(Settings.tag, "Failed to log in Geocaching.com as " + login.left + " because of wrong username/password");
+ return StatusCode.WRONG_LOGIN_DATA; // wrong login
+ } else {
+ Log.i(Settings.tag, "Failed to log in Geocaching.com as " + login.left + " for some unknown reason");
+ return StatusCode.UNKNOWN_ERROR; // can't login
+ }
+ }
+ } else {
+ Log.e(Settings.tag, "cgeoBase.login: Failed to retrieve login page (2nd)");
+ // FIXME: should it be CONNECTION_FAILED to match the first attempt?
+ return StatusCode.COMMUNICATION_ERROR; // no login page
+ }
+ }
+
+ public static StatusCode logout() {
+ HttpResponse logoutResponse = Network.request("https://www.geocaching.com/login/default.aspx?RESET=Y&redir=http%3a%2f%2fwww.geocaching.com%2fdefault.aspx%3f", null, false, false, false);
+ String logoutData = Network.getResponseData(logoutResponse);
+ if (logoutResponse != null && logoutResponse.getStatusLine().getStatusCode() == 503 && BaseUtils.matches(logoutData, GCConstants.PATTERN_MAINTENANCE)) {
+ return StatusCode.MAINTENANCE;
+ }
+
+ Network.clearCookies();
+ Settings.setCookieStore(null);
+ return StatusCode.NO_ERROR;
+ }
+
+ public static void setActualCachesFound(final int found) {
+ actualCachesFound = found;
+ }
+
+ public static String getActualStatus() {
+ return actualStatus;
+ }
+
+ public static void setActualStatus(final String status) {
+ actualStatus = status;
+ }
+
+ public static boolean isActualLoginStatus() {
+ return actualLoginStatus;
+ }
+
+ public static void setActualLoginStatus(boolean loginStatus) {
+ actualLoginStatus = loginStatus;
+ }
+
+ public static String getActualUserName() {
+ return actualUserName;
+ }
+
+ public static void setActualUserName(String userName) {
+ actualUserName = userName;
+ }
+
+ public static String getActualMemberStatus() {
+ return actualMemberStatus;
+ }
+
+ public static void setActualMemberStatus(final String memberStatus) {
+ actualMemberStatus = memberStatus;
+ }
+
+ public static int getActualCachesFound() {
+ return actualCachesFound;
+ }
+
+ /**
+ * Check if the user has been logged in when he retrieved the data.
+ *
+ * @param page
+ * @return <code>true</code> if user is logged in, <code>false</code> otherwise
+ */
+ public static boolean getLoginStatus(final String page) {
+ if (StringUtils.isBlank(page)) {
+ Log.e(Settings.tag, "cgeoBase.checkLogin: No page given");
+ return false;
+ }
+
+ // res is null during the unit tests
+ if (cgBase.res != null) {
+ setActualStatus(cgBase.res.getString(R.string.init_login_popup_ok));
+ }
+
+ // on every page except login page
+ setActualLoginStatus(BaseUtils.matches(page, GCConstants.PATTERN_LOGIN_NAME));
+ if (isActualLoginStatus()) {
+ setActualUserName(BaseUtils.getMatch(page, GCConstants.PATTERN_LOGIN_NAME, true, "???"));
+ setActualMemberStatus(BaseUtils.getMatch(page, GCConstants.PATTERN_MEMBER_STATUS, true, "???"));
+ setActualCachesFound(Integer.parseInt(BaseUtils.getMatch(page, GCConstants.PATTERN_CACHES_FOUND, true, "0").replaceAll("[,.]", "")));
+ return true;
+ }
+
+ // login page
+ setActualLoginStatus(BaseUtils.matches(page, GCConstants.PATTERN_LOGIN_NAME_LOGIN_PAGE));
+ if (isActualLoginStatus()) {
+ setActualUserName(Settings.getUsername());
+ setActualMemberStatus(Settings.getMemberStatus());
+ // number of caches found is not part of this page
+ return true;
+ }
+
+ // res is null during the unit tests
+ if (cgBase.res != null) {
+ setActualStatus(cgBase.res.getString(R.string.init_login_popup_failed));
+ }
+ return false;
+ }
+
+ private static void switchToEnglish(String previousPage) {
+ if (previousPage != null && previousPage.indexOf(ENGLISH) >= 0) {
+ Log.i(Settings.tag, "Geocaching.com language already set to English");
+ // get find count
+ getLoginStatus(Network.getResponseData(Network.request("http://www.geocaching.com/email/", null, false)));
+ } else {
+ final String page = Network.getResponseData(Network.request("http://www.geocaching.com/default.aspx", null, false));
+ getLoginStatus(page);
+ if (page == null) {
+ Log.e(Settings.tag, "Failed to read viewstates to set geocaching.com language");
+ }
+ final Parameters params = new Parameters(
+ "__EVENTTARGET", "ctl00$uxLocaleList$uxLocaleList$ctl00$uxLocaleItem", // switch to english
+ "__EVENTARGUMENT", "");
+ Login.transferViewstates(page, params);
+ final HttpResponse response = Network.postRequest("http://www.geocaching.com/default.aspx", params);
+ if (!Network.isSuccess(response)) {
+ Log.e(Settings.tag, "Failed to set geocaching.com language to English");
+ }
+ }
+ }
+
+ public static BitmapDrawable downloadAvatarAndGetMemberStatus(final Context context) {
+ try {
+ final String profile = BaseUtils.replaceWhitespace(Network.getResponseData(Network.request("http://www.geocaching.com/my/", null, false)));
+
+ Settings.setMemberStatus(BaseUtils.getMatch(profile, GCConstants.PATTERN_MEMBER_STATUS, true, null));
+
+ setActualCachesFound(Integer.parseInt(BaseUtils.getMatch(profile, GCConstants.PATTERN_CACHES_FOUND, true, "-1").replaceAll("[,.]", "")));
+
+ final String avatarURL = BaseUtils.getMatch(profile, GCConstants.PATTERN_AVATAR_IMAGE_PROFILE_PAGE, false, null);
+ if (null != avatarURL) {
+ final HtmlImage imgGetter = new HtmlImage(context, "", false, 0, false);
+ return imgGetter.getDrawable(avatarURL);
+ }
+ // No match? There may be no avatar set by user.
+ Log.d(Settings.tag, "No avatar set for user");
+ } catch (Exception e) {
+ Log.w(Settings.tag, "Error when retrieving user avatar", e);
+ }
+ return null;
+ }
+
+ /**
+ * Detect user date settings on geocaching.com
+ */
+ public static void detectGcCustomDate() {
+
+ final String result = Network.getResponseData(Network.request("http://www.geocaching.com/account/ManagePreferences.aspx", null, false, false, false));
+
+ if (null == result) {
+ Log.w(Settings.tag, "cgeoBase.detectGcCustomDate: result is null");
+ return;
+ }
+
+ String customDate = BaseUtils.getMatch(result, GCConstants.PATTERN_CUSTOMDATE, true, null);
+ if (null != customDate) {
+ Settings.setGcCustomDate(customDate);
+ }
+ }
+
+ public static Date parseGcCustomDate(final String input, final String format) throws ParseException {
+ if (StringUtils.isBlank(input)) {
+ throw new ParseException("Input is null", 0);
+ }
+
+ final String trimmed = input.trim();
+
+ if (gcCustomDateFormats.containsKey(format)) {
+ try {
+ return gcCustomDateFormats.get(format).parse(trimmed);
+ } catch (ParseException e) {
+ }
+ }
+
+ for (SimpleDateFormat sdf : gcCustomDateFormats.values()) {
+ try {
+ return sdf.parse(trimmed);
+ } catch (ParseException e) {
+ }
+ }
+
+ throw new ParseException("No matching pattern", 0);
+ }
+
+ public static Date parseGcCustomDate(final String input) throws ParseException {
+ return parseGcCustomDate(input, Settings.getGcCustomDate());
+ }
+
+ /**
+ * read all viewstates from page
+ *
+ * @return String[] with all view states
+ */
+ public static String[] getViewstates(String page) {
+ // Get the number of viewstates.
+ // If there is only one viewstate, __VIEWSTATEFIELDCOUNT is not present
+
+ if (page == null) { // no network access
+ return null;
+ }
+
+ int count = 1;
+ final Matcher matcherViewstateCount = GCConstants.PATTERN_VIEWSTATEFIELDCOUNT.matcher(page);
+ if (matcherViewstateCount.find()) {
+ count = Integer.parseInt(matcherViewstateCount.group(1));
+ }
+
+ String[] viewstates = new String[count];
+
+ // Get the viewstates
+ int no;
+ final Matcher matcherViewstates = GCConstants.PATTERN_VIEWSTATES.matcher(page);
+ while (matcherViewstates.find()) {
+ String sno = matcherViewstates.group(1); // number of viewstate
+ if (sno.length() == 0) {
+ no = 0;
+ }
+ else {
+ no = Integer.parseInt(sno);
+ }
+ viewstates[no] = matcherViewstates.group(2);
+ }
+
+ if (viewstates.length != 1 || viewstates[0] != null) {
+ return viewstates;
+ }
+ // no viewstates were present
+ return null;
+ }
+
+ /**
+ * put viewstates into request parameters
+ */
+ public static void putViewstates(final Parameters params, final String[] viewstates) {
+ if (ArrayUtils.isEmpty(viewstates)) {
+ return;
+ }
+ params.put("__VIEWSTATE", viewstates[0]);
+ if (viewstates.length > 1) {
+ for (int i = 1; i < viewstates.length; i++) {
+ params.put("__VIEWSTATE" + i, viewstates[i]);
+ }
+ params.put("__VIEWSTATEFIELDCOUNT", String.valueOf(viewstates.length));
+ }
+ }
+
+ /**
+ * transfers the viewstates variables from a page (response) to parameters
+ * (next request)
+ */
+ public static void transferViewstates(final String page, final Parameters params) {
+ putViewstates(params, getViewstates(page));
+ }
+
+ static public String[] requestViewstates(final String uri, final Parameters params, boolean xContentType, boolean my) {
+ final HttpResponse response = Network.request(uri, params, xContentType, my, false);
+
+ return getViewstates(Network.getResponseData(response));
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/network/Network.java b/main/src/cgeo/geocaching/network/Network.java
new file mode 100644
index 0000000..0afe095
--- /dev/null
+++ b/main/src/cgeo/geocaching/network/Network.java
@@ -0,0 +1,364 @@
+package cgeo.geocaching.network;
+
+import cgeo.geocaching.Settings;
+import cgeo.geocaching.cgBase;
+import cgeo.geocaching.enumerations.StatusCode;
+import cgeo.geocaching.utils.BaseUtils;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpResponseInterceptor;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.entity.HttpEntityWrapper;
+import org.apache.http.impl.client.BasicCookieStore;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.cookie.BasicClientCookie;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.CoreConnectionPNames;
+import org.apache.http.params.CoreProtocolPNames;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.util.EntityUtils;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.net.Uri;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLEncoder;
+import java.util.List;
+import java.util.zip.GZIPInputStream;
+
+
+public abstract class Network {
+
+ static class GzipDecompressingEntity extends HttpEntityWrapper {
+ public GzipDecompressingEntity(final HttpEntity entity) {
+ super(entity);
+ }
+
+ @Override
+ public InputStream getContent() throws IOException, IllegalStateException {
+ // the wrapped entity's getContent() decides about repeatability
+ InputStream wrappedin = wrappedEntity.getContent();
+ return new GZIPInputStream(wrappedin);
+ }
+
+ @Override
+ public long getContentLength() {
+ // length of ungzipped content is not known
+ return -1;
+ }
+ }
+
+ private static final int NB_DOWNLOAD_RETRIES = 4;
+ /** User agent id */
+ private final static String USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:9.0.1) Gecko/20100101 Firefox/9.0.1";
+ private static final String PATTERN_PASSWORD = "(?<=[\\?&])[Pp]ass(w(or)?d)?=[^&#$]+";
+
+ private final static HttpParams clientParams = new BasicHttpParams();
+ private static boolean cookieStoreRestored = false;
+ private final static CookieStore cookieStore = new BasicCookieStore();
+
+ static {
+ Network.clientParams.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, HTTP.UTF_8);
+ Network.clientParams.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 30000);
+ Network.clientParams.setParameter(CoreConnectionPNames.SO_TIMEOUT, 30000);
+ }
+
+ private static String hidePassword(final String message) {
+ return message.replaceAll(Network.PATTERN_PASSWORD, "password=***");
+ }
+
+ private static HttpClient getHttpClient() {
+ final DefaultHttpClient client = new DefaultHttpClient();
+ client.setCookieStore(cookieStore);
+ client.setParams(clientParams);
+
+ client.addRequestInterceptor(new HttpRequestInterceptor() {
+
+ @Override
+ public void process(
+ final HttpRequest request,
+ final HttpContext context) throws HttpException, IOException {
+ if (!request.containsHeader("Accept-Encoding")) {
+ request.addHeader("Accept-Encoding", "gzip");
+ }
+ }
+ });
+ client.addResponseInterceptor(new HttpResponseInterceptor() {
+
+ public void process(
+ final HttpResponse response,
+ final HttpContext context) throws HttpException, IOException {
+ HttpEntity entity = response.getEntity();
+ if (null != entity) {
+ Header ceheader = entity.getContentEncoding();
+ if (ceheader != null) {
+ HeaderElement[] codecs = ceheader.getElements();
+ for (int i = 0; i < codecs.length; i++) {
+ if (codecs[i].getName().equalsIgnoreCase("gzip")) {
+ Log.d(Settings.tag, "Decompressing response");
+ response.setEntity(
+ new Network.GzipDecompressingEntity(response.getEntity()));
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ });
+
+ return client;
+ }
+
+ public static void restoreCookieStore(final String oldCookies) {
+ if (!cookieStoreRestored) {
+ Network.clearCookies();
+ if (oldCookies != null) {
+ for (final String cookie : StringUtils.split(oldCookies, ';')) {
+ final String[] split = StringUtils.split(cookie, "=", 3);
+ if (split.length == 3) {
+ final BasicClientCookie newCookie = new BasicClientCookie(split[0], split[1]);
+ newCookie.setDomain(split[2]);
+ cookieStore.addCookie(newCookie);
+ }
+ }
+ }
+ cookieStoreRestored = true;
+ }
+ }
+
+ public static String dumpCookieStore() {
+ StringBuilder cookies = new StringBuilder();
+ for (final Cookie cookie : cookieStore.getCookies()) {
+ cookies.append(cookie.getName());
+ cookies.append('=');
+ cookies.append(cookie.getValue());
+ cookies.append('=');
+ cookies.append(cookie.getDomain());
+ cookies.append(';');
+ }
+ return cookies.toString();
+ }
+
+ public static void clearCookies() {
+ cookieStore.clear();
+ }
+
+ /**
+ * POST HTTP request
+ *
+ * @param uri
+ * @param params
+ * @return
+ */
+ public static HttpResponse postRequest(final String uri, final List<? extends NameValuePair> params) {
+ try {
+ HttpPost request = new HttpPost(uri);
+ if (params != null) {
+ request.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
+ }
+ request.setHeader("X-Requested-With", "XMLHttpRequest");
+ return Network.request(request);
+ } catch (Exception e) {
+ // Can be UnsupportedEncodingException, ClientProtocolException or IOException
+ Log.e(Settings.tag, "postRequest", e);
+ return null;
+ }
+ }
+
+ /**
+ * GET HTTP request
+ *
+ * @param uri
+ * @param params
+ * @param xContentType
+ * @param my
+ * @param addF
+ * @return
+ */
+ public static HttpResponse request(final String uri, final Parameters params, boolean xContentType, boolean my, boolean addF) {
+ return Network.request(uri, cgBase.addFToParams(params, my, addF), xContentType);
+ }
+
+ /**
+ * GET HTTP request
+ *
+ * @param uri
+ * @param params
+ * @param xContentType
+ * @return
+ */
+ public static HttpResponse request(final String uri, final Parameters params, final boolean xContentType) {
+ final String fullUri = params == null ? uri : Uri.parse(uri).buildUpon().encodedQuery(params.toString()).build().toString();
+ final HttpRequestBase request = new HttpGet(fullUri);
+
+ request.setHeader("X-Requested-With", "XMLHttpRequest");
+
+ if (xContentType) {
+ request.setHeader("Content-Type", "application/x-www-form-urlencoded");
+ }
+
+ return Network.request(request);
+ }
+
+ public static HttpResponse request(final HttpRequestBase request) {
+ request.setHeader("Accept-Charset", "utf-8,iso-8859-1;q=0.8,utf-16;q=0.8,*;q=0.7");
+ request.setHeader("Accept-Language", "en-US,*;q=0.9");
+ request.getParams().setParameter(CoreProtocolPNames.USER_AGENT, USER_AGENT);
+ return Network.doRequest(request);
+ }
+
+ private static HttpResponse doRequest(final HttpRequestBase request) {
+ final String reqLogStr = request.getMethod() + " " + hidePassword(request.getURI().toString());
+ Log.d(Settings.tag, reqLogStr);
+
+ final HttpClient client = getHttpClient();
+ for (int i = 0; i <= NB_DOWNLOAD_RETRIES; i++) {
+ final long before = System.currentTimeMillis();
+ try {
+ final HttpResponse response = client.execute(request);
+ int status = response.getStatusLine().getStatusCode();
+ if (status == 200) {
+ Log.d(Settings.tag, status + Network.formatTimeSpan(before) + reqLogStr);
+ } else {
+ Log.w(Settings.tag, status + " [" + response.getStatusLine().getReasonPhrase() + "]" + Network.formatTimeSpan(before) + reqLogStr);
+ }
+ return response;
+ } catch (IOException e) {
+ final String timeSpan = Network.formatTimeSpan(before);
+ final String tries = (i + 1) + "/" + (NB_DOWNLOAD_RETRIES + 1);
+ if (i == NB_DOWNLOAD_RETRIES) {
+ Log.e(Settings.tag, "Failure " + tries + timeSpan + reqLogStr, e);
+ } else {
+ Log.e(Settings.tag, "Failure " + tries + " (" + e.toString() + ")" + timeSpan + "- retrying " + reqLogStr);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static String formatTimeSpan(final long before) {
+ // don't use String.format in a pure logging routine, it has very bad performance
+ return " (" + (System.currentTimeMillis() - before) + " ms) ";
+ }
+
+ static public boolean isSuccess(final HttpResponse response) {
+ return response != null && response.getStatusLine().getStatusCode() == 200;
+ }
+
+ public static JSONObject requestJSON(final String uri, final Parameters params) {
+ final HttpGet request = new HttpGet(Network.prepareParameters(uri, params));
+ request.setHeader("Accept", "application/json, text/javascript, */*; q=0.01");
+ request.setHeader("Content-Type", "application/json; charset=UTF-8");
+ request.setHeader("X-Requested-With", "XMLHttpRequest");
+
+ final HttpResponse response = doRequest(request);
+ if (response != null && response.getStatusLine().getStatusCode() == 200) {
+ try {
+ return new JSONObject(Network.getResponseData(response));
+ } catch (JSONException e) {
+ Log.e(Settings.tag, "Network.requestJSON", e);
+ }
+ }
+
+ return null;
+ }
+
+ private static String prepareParameters(final String baseUri, final Parameters params) {
+ return CollectionUtils.isNotEmpty(params) ? baseUri + "?" + params.toString() : baseUri;
+ }
+
+ private static String getResponseDataNoError(final HttpResponse response, boolean replaceWhitespace) {
+ try {
+ String data = EntityUtils.toString(response.getEntity(), HTTP.UTF_8);
+ return replaceWhitespace ? BaseUtils.replaceWhitespace(data) : data;
+ } catch (Exception e) {
+ Log.e(Settings.tag, "getResponseData", e);
+ return null;
+ }
+ }
+
+ public static String getResponseData(final HttpResponse response) {
+ return Network.getResponseData(response, true);
+ }
+
+ static public String getResponseData(final HttpResponse response, boolean replaceWhitespace) {
+ if (!isSuccess(response)) {
+ return null;
+ }
+ return getResponseDataNoError(response, replaceWhitespace);
+ }
+
+ /**
+ * POST HTTP request. Do the request a second time if the user is not logged in
+ *
+ * @param uri
+ * @return
+ */
+ public static String postRequestLogged(final String uri) {
+ HttpResponse response = postRequest(uri, null);
+ String data = getResponseData(response);
+
+ if (!Login.getLoginStatus(data)) {
+ if (Login.login() == StatusCode.NO_ERROR) {
+ response = postRequest(uri, null);
+ data = getResponseData(response);
+ } else {
+ Log.i(Settings.tag, "Working as guest.");
+ }
+ }
+ return data;
+ }
+
+ /**
+ * GET HTTP request. Do the request a second time if the user is not logged in
+ *
+ * @param uri
+ * @param params
+ * @param xContentType
+ * @param my
+ * @param addF
+ * @return
+ */
+ public static String requestLogged(final String uri, final Parameters params, boolean xContentType, boolean my, boolean addF) {
+ HttpResponse response = request(uri, params, xContentType, my, addF);
+ String data = getResponseData(response);
+
+ if (!Login.getLoginStatus(data)) {
+ if (Login.login() == StatusCode.NO_ERROR) {
+ response = request(uri, params, xContentType, my, addF);
+ data = getResponseData(response);
+ } else {
+ Log.i(Settings.tag, "Working as guest.");
+ }
+ }
+ return data;
+ }
+
+ public static String urlencode_rfc3986(String text) {
+ final String encoded = StringUtils.replace(URLEncoder.encode(text).replace("+", "%20"), "%7E", "~");
+
+ return encoded;
+ }
+}
diff --git a/main/src/cgeo/geocaching/network/OAuth.java b/main/src/cgeo/geocaching/network/OAuth.java
index a5393f6..cefa90d 100644
--- a/main/src/cgeo/geocaching/network/OAuth.java
+++ b/main/src/cgeo/geocaching/network/OAuth.java
@@ -1,7 +1,6 @@
package cgeo.geocaching.network;
import cgeo.geocaching.Settings;
-import cgeo.geocaching.cgBase;
import cgeo.geocaching.utils.CryptUtils;
import org.apache.commons.lang3.StringUtils;
@@ -24,11 +23,11 @@ public class OAuth {
final List<String> paramsEncoded = new ArrayList<String>();
for (final NameValuePair nameValue : params) {
- paramsEncoded.add(nameValue.getName() + "=" + cgBase.urlencode_rfc3986(nameValue.getValue()));
+ paramsEncoded.add(nameValue.getName() + "=" + Network.urlencode_rfc3986(nameValue.getValue()));
}
final String keysPacked = Settings.getKeyConsumerSecret() + "&" + StringUtils.defaultString(tokenSecret); // both even if empty some of them!
- final String requestPacked = method + "&" + cgBase.urlencode_rfc3986((https ? "https" : "http") + "://" + host + path) + "&" + cgBase.urlencode_rfc3986(StringUtils.join(paramsEncoded.toArray(), '&'));
+ final String requestPacked = method + "&" + Network.urlencode_rfc3986((https ? "https" : "http") + "://" + host + path) + "&" + Network.urlencode_rfc3986(StringUtils.join(paramsEncoded.toArray(), '&'));
params.put("oauth_signature", CryptUtils.base64Encode(CryptUtils.hashHmac(requestPacked, keysPacked)));
}
}
diff --git a/main/src/cgeo/geocaching/twitter/Twitter.java b/main/src/cgeo/geocaching/twitter/Twitter.java
index a47409f..fa1a39d 100644
--- a/main/src/cgeo/geocaching/twitter/Twitter.java
+++ b/main/src/cgeo/geocaching/twitter/Twitter.java
@@ -1,10 +1,13 @@
package cgeo.geocaching.twitter;
import cgeo.geocaching.Settings;
-import cgeo.geocaching.cgBase;
+import cgeo.geocaching.cgCache;
+import cgeo.geocaching.cgTrackable;
import cgeo.geocaching.cgeoapplication;
+import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.GeopointFormatter.Format;
+import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.OAuth;
import cgeo.geocaching.network.Parameters;
@@ -33,7 +36,7 @@ public final class Twitter {
}
OAuth.signOAuth("api.twitter.com", "/1/statuses/update.json", "POST", false, parameters, Settings.getTokenPublic(), Settings.getTokenSecret());
- final HttpResponse httpResponse = cgBase.postRequest("http://api.twitter.com/1/statuses/update.json", parameters);
+ final HttpResponse httpResponse = Network.postRequest("http://api.twitter.com/1/statuses/update.json", parameters);
if (httpResponse != null && httpResponse.getStatusLine().getStatusCode() == 200) {
Log.i(Settings.tag, "Tweet posted");
} else {
@@ -51,4 +54,42 @@ public final class Twitter {
}
return result;
}
+
+ public static void postTweetCache(String geocode) {
+ final cgCache cache = cgeoapplication.getInstance().loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB);
+ String status;
+ final String url = cache.getUrl();
+ if (url.length() >= 100) {
+ status = "I found " + url;
+ }
+ else {
+ String name = cache.getName();
+ status = "I found " + name + " (" + url + ")";
+ if (status.length() > MAX_TWEET_SIZE) {
+ name = name.substring(0, name.length() - (status.length() - MAX_TWEET_SIZE) - 3) + "...";
+ }
+ status = "I found " + name + " (" + url + ")";
+ status = appendHashTag(status, "cgeo");
+ status = appendHashTag(status, "geocaching");
+ }
+
+ postTweet(cgeoapplication.getInstance(), status, null);
+ }
+
+ public static void postTweetTrackable(String geocode) {
+ final cgTrackable trackable = cgeoapplication.getInstance().getTrackableByGeocode(geocode);
+ String name = trackable.getName();
+ if (name.length() > 82) {
+ name = name.substring(0, 79) + "...";
+ }
+ StringBuilder builder = new StringBuilder("I touched ");
+ builder.append(name);
+ if (trackable.getUrl() != null) {
+ builder.append(" (").append(trackable.getUrl()).append(')');
+ }
+ builder.append('!');
+ String status = appendHashTag(builder.toString(), "cgeo");
+ status = appendHashTag(status, "geocaching");
+ postTweet(cgeoapplication.getInstance(), status, null);
+ }
}
diff --git a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java
index 83b1569..fffe12e 100644
--- a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java
+++ b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java
@@ -2,8 +2,8 @@ package cgeo.geocaching.twitter;
import cgeo.geocaching.R;
import cgeo.geocaching.Settings;
-import cgeo.geocaching.cgBase;
import cgeo.geocaching.activity.AbstractActivity;
+import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.OAuth;
import cgeo.geocaching.network.Parameters;
@@ -141,7 +141,7 @@ public class TwitterAuthorizationActivity extends AbstractActivity {
try {
final Parameters params = new Parameters();
OAuth.signOAuth(host, pathRequest, method, true, params, null, null);
- final String line = cgBase.getResponseData(cgBase.request("https://" + host + pathRequest, params, false));
+ final String line = Network.getResponseData(Network.request("https://" + host + pathRequest, params, false));
if (StringUtils.isNotBlank(line)) {
@@ -186,7 +186,7 @@ public class TwitterAuthorizationActivity extends AbstractActivity {
final Parameters params = new Parameters("oauth_verifier", pinEntry.getText().toString());
OAuth.signOAuth(host, path, method, true, params, OAtoken, OAtokenSecret);
- final String line = StringUtils.defaultString(cgBase.getResponseData(cgBase.postRequest("https://" + host + path, params)));
+ final String line = StringUtils.defaultString(Network.getResponseData(Network.postRequest("https://" + host + path, params)));
OAtoken = "";
OAtokenSecret = "";
diff --git a/main/src/cgeo/geocaching/ui/DirectionImage.java b/main/src/cgeo/geocaching/ui/DirectionImage.java
index c559531..aa01b97 100644
--- a/main/src/cgeo/geocaching/ui/DirectionImage.java
+++ b/main/src/cgeo/geocaching/ui/DirectionImage.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.ui;
-import cgeo.geocaching.cgBase;
import cgeo.geocaching.files.LocalStorage;
+import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import org.apache.commons.lang3.StringUtils;
@@ -17,9 +17,9 @@ public class DirectionImage {
}
final HttpResponse httpResponse =
- cgBase.request("http://www.geocaching.com/ImgGen/seek/CacheDir.ashx", new Parameters("k", code), false);
+ Network.request("http://www.geocaching.com/ImgGen/seek/CacheDir.ashx", new Parameters("k", code), false);
if (httpResponse != null) {
- LocalStorage.saveEntityToFile(httpResponse.getEntity(), getDirectionFile(geocode, true));
+ LocalStorage.saveEntityToFile(httpResponse, getDirectionFile(geocode, true));
}
}
diff --git a/main/src/cgeo/geocaching/utils/LRUList.java b/main/src/cgeo/geocaching/utils/LRUList.java
new file mode 100644
index 0000000..13596b1
--- /dev/null
+++ b/main/src/cgeo/geocaching/utils/LRUList.java
@@ -0,0 +1,46 @@
+package cgeo.geocaching.utils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Base class for a limited list.
+ *
+ * @author blafoo
+ */
+public class LRUList<T> extends ArrayList<T> {
+
+ private static final long serialVersionUID = -5077882607489806620L;
+ private final int maxEntries;
+
+ public LRUList(int maxEntries) {
+ this.maxEntries = maxEntries;
+ }
+
+ private void removeElements(int count) {
+ for (int i = 0; i < count; i++) {
+ this.remove(0);
+ }
+ }
+
+ @Override
+ public boolean add(T item) {
+ removeElements(this.size() + 1 - maxEntries);
+ return super.add(item);
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends T> collection) {
+ if (collection.size() > this.size()) {
+ this.clear();
+ for (T item : collection) {
+ this.add(item);
+ }
+ return false;
+ } else {
+ removeElements(this.size() + collection.size() - maxEntries);
+ return super.addAll(collection);
+ }
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java
index 522bbf4..da7fb86 100644
--- a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java
+++ b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java
@@ -4,6 +4,8 @@ import cgeo.geocaching.R;
import cgeo.geocaching.Settings;
import cgeo.geocaching.cgBase;
import cgeo.geocaching.connector.gc.GCConstants;
+import cgeo.geocaching.network.Login;
+import cgeo.geocaching.network.Network;
import org.apache.commons.lang3.StringUtils;
@@ -81,12 +83,12 @@ public class LogTemplateProvider {
@Override
public String getValue(final boolean offline) {
- int current = cgBase.getActualCachesFound();
+ int current = Login.getActualCachesFound();
if (current == 0) {
if (offline) {
return "";
}
- final String page = cgBase.getResponseData(cgBase.request("http://www.geocaching.com/email/", null, false, false, false));
+ final String page = Network.getResponseData(Network.request("http://www.geocaching.com/email/", null, false, false, false));
current = parseFindCount(page);
}
diff --git a/tests/res/raw/tile12.png b/tests/res/raw/tile12.png
new file mode 100644
index 0000000..f8d9cb3
--- /dev/null
+++ b/tests/res/raw/tile12.png
Binary files differ
diff --git a/tests/src/cgeo/geocaching/cgBaseTest.java b/tests/src/cgeo/geocaching/cgBaseTest.java
index e6aa862..c89e41c 100644
--- a/tests/src/cgeo/geocaching/cgBaseTest.java
+++ b/tests/src/cgeo/geocaching/cgBaseTest.java
@@ -31,7 +31,7 @@ public class cgBaseTest extends AndroidTestCase {
}
public static void testElevation() {
- assertEquals(125.663703918457, cgBase.getElevation(new Geopoint(48.0, 2.0)), 0.1);
+ assertEquals(125.663703918457, (new Geopoint(48.0, 2.0)).getElevation(), 0.1);
}
public static void testCompareCaches(ICache expected, cgCache actual) {
diff --git a/tests/src/cgeo/geocaching/cgeoApplicationTest.java b/tests/src/cgeo/geocaching/cgeoApplicationTest.java
index e28cb80..0bdd3f2 100644
--- a/tests/src/cgeo/geocaching/cgeoApplicationTest.java
+++ b/tests/src/cgeo/geocaching/cgeoApplicationTest.java
@@ -8,6 +8,7 @@ import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.network.Login;
import cgeo.geocaching.test.RegExPerformanceTest;
import cgeo.geocaching.test.mock.GC1ZXX2;
import cgeo.geocaching.test.mock.GC2CJPF;
@@ -55,7 +56,7 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> {
@SuppressWarnings("static-method")
@SmallTest
public void testPreconditions() {
- assertEquals(StatusCode.NO_ERROR, cgBase.login());
+ assertEquals(StatusCode.NO_ERROR, Login.login());
}
/**
@@ -130,7 +131,7 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> {
try {
// non premium cache
- MockedCache cache = new GC1ZXX2();
+ MockedCache cache = new GC2CJPF();
deleteCacheFromDBAndLogout(cache.getGeocode());
@@ -155,7 +156,33 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> {
// restore user and password
Settings.setLogin(login.left, login.right);
Settings.setMemberStatus(memberStatus);
- cgBase.login();
+ Login.login();
+ }
+ }
+
+ /**
+ * Test {@link cgBase#searchByGeocode(String, String, int, boolean, CancellableHandler)}
+ */
+ @MediumTest
+ public static void testSearchErrorOccured() {
+ ImmutablePair<String, String> login = Settings.getLogin();
+ String memberStatus = Settings.getMemberStatus();
+
+ try {
+ // non premium cache
+ MockedCache cache = new GC1ZXX2();
+
+ deleteCacheFromDBAndLogout(cache.getGeocode());
+
+ SearchResult search = cgBase.searchByGeocode(cache.getGeocode(), null, StoredList.TEMPORARY_LIST_ID, true, null);
+ assertNotNull(search);
+ assertEquals(0, search.getGeocodes().size());
+
+ } finally {
+ // restore user and password
+ Settings.setLogin(login.left, login.right);
+ Settings.setMemberStatus(memberStatus);
+ Login.login();
}
}
@@ -237,7 +264,8 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> {
ImmutablePair<String, String> login = Settings.getLogin();
String memberStatus = Settings.getMemberStatus();
Strategy strategy = Settings.getLiveMapStrategy();
- Settings.setLiveMapStrategy(Strategy.DETAILED);
+ Strategy testStrategy = Strategy.FAST; // FASTEST, FAST or DETAILED for tests
+ Settings.setLiveMapStrategy(testStrategy);
try {
@@ -257,7 +285,8 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> {
Log.d(Settings.tag, "cgeoApplicationTest.testSearchByViewportNotLoggedIn: Coords expected = " + cache.getCoords());
Log.d(Settings.tag, "cgeoApplicationTest.testSearchByViewportNotLoggedIn: Coords actual = " + cacheFromViewport.getCoords());
assertFalse(cache.getCoords().isEqualTo(cacheFromViewport.getCoords(), 1e-3));
- // issue #1242 assertFalse(cacheFromViewport.isReliableLatLon());
+ // depending on the chosen strategy the coords can be reliable or not
+ assertEquals(testStrategy == Strategy.DETAILED, cacheFromViewport.isReliableLatLon());
// premium cache
cache = new GC2JVEH();
@@ -267,14 +296,14 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> {
search = ConnectorFactory.searchByViewport(viewport, tokens);
assertNotNull(search);
- // It's a premium member cache only and thus not visible to guests (old Live Map !). Visible in new Live Map
- assertTrue(search.getGeocodes().contains(cache.getGeocode()));
+ // depending on the chosen strategy the cache is part of the search or not
+ assertEquals(testStrategy == Strategy.DETAILED, search.getGeocodes().contains(cache.getGeocode()));
} finally {
// restore user and password
Settings.setLogin(login.left, login.right);
Settings.setMemberStatus(memberStatus);
- cgBase.login();
+ Login.login();
Settings.setLiveMapStrategy(strategy);
}
}
@@ -307,7 +336,7 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> {
private static void deleteCacheFromDBAndLogout(String geocode) {
cgeoapplication.getInstance().removeCache(geocode, LoadFlags.REMOVE_ALL);
- cgBase.logout();
+ Login.logout();
// Modify login data to avoid an automatic login again
Settings.setLogin("c:geo", "c:geo");
Settings.setMemberStatus("Basic member");
diff --git a/tests/src/cgeo/geocaching/connector/gc/GCBaseTest.java b/tests/src/cgeo/geocaching/connector/gc/GCBaseTest.java
index 5f07f60..32ab1f2 100644
--- a/tests/src/cgeo/geocaching/connector/gc/GCBaseTest.java
+++ b/tests/src/cgeo/geocaching/connector/gc/GCBaseTest.java
@@ -1,14 +1,18 @@
package cgeo.geocaching.connector.gc;
-import java.util.Arrays;
-
import junit.framework.TestCase;
public class GCBaseTest extends TestCase {
public static void testSplitJSONKey() {
- assertTrue(Arrays.equals(new int[] { 1, 2 }, GCBase.splitJSONKey("(1, 2)")));
- assertTrue(Arrays.equals(new int[] { 12, 34 }, GCBase.splitJSONKey("(12, 34)")));
- assertTrue(Arrays.equals(new int[] { 1234, 56 }, GCBase.splitJSONKey("(1234,56)")));
- assertTrue(Arrays.equals(new int[] { 1234, 567 }, GCBase.splitJSONKey("(1234, 567)")));
+ assertKey("(1, 2)", 1, 2);
+ assertKey("(12, 34)", 12, 34);
+ assertKey("(1234,56)", 1234, 56);
+ assertKey("(1234, 567)", 1234, 567);
+ }
+
+ private static void assertKey(String key, int x, int y) {
+ UTFGridPosition pos = UTFGridPosition.fromString(key);
+ assertEquals(x, pos.getX());
+ assertEquals(y, pos.getY());
}
}
diff --git a/tests/src/cgeo/geocaching/connector/gc/GCConnectorTest.java b/tests/src/cgeo/geocaching/connector/gc/GCConnectorTest.java
index 7f63ef3..dfa9a8b 100644
--- a/tests/src/cgeo/geocaching/connector/gc/GCConnectorTest.java
+++ b/tests/src/cgeo/geocaching/connector/gc/GCConnectorTest.java
@@ -1,24 +1,16 @@
package cgeo.geocaching.connector.gc;
import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.Settings;
-import cgeo.geocaching.cgBase;
-import cgeo.geocaching.cgCache;
import cgeo.geocaching.connector.ConnectorFactory;
-import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.network.Login;
import cgeo.geocaching.test.AbstractResourceInstrumentationTestCase;
-import cgeo.geocaching.test.R;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.util.Log;
public class GCConnectorTest extends AbstractResourceInstrumentationTestCase {
public static void testGetViewport() {
- cgBase.login();
+ Login.login();
String[] tokens = GCBase.getTokens();
@@ -50,78 +42,25 @@ public class GCConnectorTest extends AbstractResourceInstrumentationTestCase {
/** Tile computation with different zoom levels */
public static void testTile() {
- {
- // http://coord.info/GC2CT8K = N 52° 30.462 E 013° 27.906
- Tile tile = new Tile(new Geopoint(52.5077, 13.4651), 14);
- assertEquals(8804, tile.getX());
- assertEquals(5374, tile.getY());
- }
- {
- // (8633, 5381); N 52° 24,516 E 009° 42,592
- Tile tile = new Tile(new Geopoint("N 52° 24,516 E 009° 42,592"), 14);
- assertEquals(8633, tile.getX());
- assertEquals(5381, tile.getY());
- }
- {
- // Hannover, GC22VTB UKM Memorial Tour
- Tile tile = new Tile(new Geopoint("N 52° 22.177 E 009° 45.385"), 12);
- assertEquals(2159, tile.getX());
- assertEquals(1346, tile.getY());
- }
- {
- // Seatle, GCK25B Groundspeak Headquarters
- Tile tile = new Tile(new Geopoint("N 47° 38.000 W 122° 20.000"), 15);
- assertEquals(5248, tile.getX());
- assertEquals(11440, tile.getY());
- }
- {
- // Sydney, GCXT2R Victoria Cross
- Tile tile = new Tile(new Geopoint("S 33° 50.326 E 151° 12.426"), 13);
- assertEquals(7536, tile.getX());
- assertEquals(4915, tile.getY());
- }
- }
+ // http://coord.info/GC2CT8K = N 52° 30.462 E 013° 27.906
+ assertTileAt(8804, 5374, new Tile(new Geopoint(52.5077, 13.4651), 14));
- public void testparseMapPNG() {
- // createApplication();
- // cgBase.initialize(getApplication());
+ // (8633, 5381); N 52° 24,516 E 009° 42,592
+ assertTileAt(8633, 5381, new Tile(new Geopoint("N 52° 24,516 E 009° 42,592"), 14));
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inScaled = false;
- Bitmap bitmap = BitmapFactory.decodeStream(getInstrumentation().getContext().getResources().openRawResource(R.raw.tile14));
- assert bitmap.getWidth() == Tile.TILE_SIZE : "Wrong size";
+ // Hannover, GC22VTB UKM Memorial Tour
+ assertTileAt(2159, 1346, new Tile(new Geopoint("N 52° 22.177 E 009° 45.385"), 12));
- Log.d(Settings.tag, "Bitmap=" + bitmap.getWidth() + "x" + bitmap.getHeight());
+ // Seattle, GCK25B Groundspeak Headquarters
+ assertTileAt(5248, 11440, new Tile(new Geopoint("N 47° 38.000 W 122° 20.000"), 15));
- cgCache cache = new cgCache();
-
- // Tradi
- GCBase.parseMapPNG14(cache, bitmap, new UTFGridPosition(97 / 4, 136 / 4));
- assertEquals(CacheType.TRADITIONAL, cache.getType());
- // Mystery
- GCBase.parseMapPNG14(cache, bitmap, new UTFGridPosition(226 / 4, 104 / 4));
- assertEquals(CacheType.MYSTERY, cache.getType());
- // Multi
- GCBase.parseMapPNG14(cache, bitmap, new UTFGridPosition(54 / 4, 97 / 4));
- assertEquals(CacheType.MULTI, cache.getType());
- // Found
- GCBase.parseMapPNG14(cache, bitmap, new UTFGridPosition(119 / 4, 108 / 4));
- assertTrue(cache.isFound());
- cache.setFound(false); // reset
-
- bitmap = BitmapFactory.decodeStream(getInstrumentation().getContext().getResources().openRawResource(R.raw.tile13));
-
- // Tradi
- GCBase.parseMapPNG13(cache, bitmap, new UTFGridPosition(146 / 4, 225 / 4));
- assertEquals(CacheType.TRADITIONAL, cache.getType());
- // Mystery
- GCBase.parseMapPNG13(cache, bitmap, new UTFGridPosition(181 / 4, 116 / 4));
- assertEquals(CacheType.MYSTERY, cache.getType());
- // Multi
- GCBase.parseMapPNG13(cache, bitmap, new UTFGridPosition(118 / 4, 230 / 4));
- assertEquals(CacheType.MULTI, cache.getType());
- // Found - not available in parseMapPNG13
+ // Sydney, GCXT2R Victoria Cross
+ assertTileAt(7536, 4915, new Tile(new Geopoint("S 33° 50.326 E 151° 12.426"), 13));
}
+ private static void assertTileAt(int x, int y, final Tile tile) {
+ assertEquals(x, tile.getX());
+ assertEquals(y, tile.getY());
+ }
}
diff --git a/tests/src/cgeo/geocaching/connector/gc/IconDecoderTest.java b/tests/src/cgeo/geocaching/connector/gc/IconDecoderTest.java
new file mode 100644
index 0000000..74704b3
--- /dev/null
+++ b/tests/src/cgeo/geocaching/connector/gc/IconDecoderTest.java
@@ -0,0 +1,82 @@
+package cgeo.geocaching.connector.gc;
+
+import cgeo.geocaching.Settings;
+import cgeo.geocaching.cgCache;
+import cgeo.geocaching.enumerations.CacheType;
+import cgeo.geocaching.test.AbstractResourceInstrumentationTestCase;
+import cgeo.geocaching.test.R;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.util.Log;
+
+public class IconDecoderTest extends AbstractResourceInstrumentationTestCase {
+
+ public void testparseMapPNG14() {
+ final Bitmap bitmap = getBitmap(R.raw.tile14);
+ Log.d(Settings.tag, "Bitmap=" + bitmap.getWidth() + "x" + bitmap.getHeight());
+
+ assertEquals(CacheType.TRADITIONAL, parseMapPNG(bitmap, 97, 136, 14).getType());
+ assertEquals(CacheType.MYSTERY, parseMapPNG(bitmap, 226, 104, 14).getType());
+ assertEquals(CacheType.MULTI, parseMapPNG(bitmap, 54, 97, 14).getType());
+ assertTrue(parseMapPNG(bitmap, 119, 108, 14).isFound());
+ }
+
+ private Bitmap getBitmap(int resourceId) {
+ final BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inScaled = false;
+ final Bitmap bitmap = BitmapFactory.decodeStream(getInstrumentation().getContext().getResources().openRawResource(resourceId));
+ assert bitmap.getWidth() == Tile.TILE_SIZE : "Wrong size";
+ return bitmap;
+ }
+
+ private static cgCache parseMapPNG(Bitmap bitmap, int x, int y, int zoomlevel) {
+ final cgCache cache = new cgCache();
+ IconDecoder.parseMapPNG(cache, bitmap, new UTFGridPosition(x / 4, y / 4), zoomlevel);
+ return cache;
+ }
+
+ public void testParseMap13() {
+ final Bitmap bitmap = getBitmap(R.raw.tile13);
+
+ assertEquals(CacheType.TRADITIONAL, parseMapPNG(bitmap, 146, 225, 13).getType());
+ assertEquals(CacheType.MYSTERY, parseMapPNG(bitmap, 181, 116, 13).getType());
+ assertEquals(CacheType.MULTI, parseMapPNG(bitmap, 118, 230, 13).getType());
+ }
+
+ public void testParseMap12() {
+ final Bitmap bitmap = getBitmap(R.raw.tile12);
+
+ int multi = 0;
+ multi = parseMapPNG(bitmap, 130, 92, 12).getType() == CacheType.MULTI ? multi + 1 : multi;
+ multi = parseMapPNG(bitmap, 93, 222, 12).getType() == CacheType.MULTI ? multi + 1 : multi;
+ multi = parseMapPNG(bitmap, 129, 227, 12).getType() == CacheType.MULTI ? multi + 1 : multi;
+ multi = parseMapPNG(bitmap, 234, 170, 12).getType() == CacheType.MULTI ? multi + 1 : multi;
+ multi = parseMapPNG(bitmap, 195, 113, 12).getType() == CacheType.MULTI ? multi + 1 : multi;
+ multi = parseMapPNG(bitmap, 195, 124, 12).getType() == CacheType.MULTI ? multi + 1 : multi;
+ multi = parseMapPNG(bitmap, 111, 74, 12).getType() == CacheType.MULTI ? multi + 1 : multi;
+
+ int mystery = 0;
+ mystery = parseMapPNG(bitmap, 37, 25, 12).getType() == CacheType.MYSTERY ? mystery + 1 : mystery;
+ mystery = parseMapPNG(bitmap, 49, 183, 12).getType() == CacheType.MYSTERY ? mystery + 1 : mystery;
+ mystery = parseMapPNG(bitmap, 183, 181, 12).getType() == CacheType.MYSTERY ? mystery + 1 : mystery;
+ mystery = parseMapPNG(bitmap, 176, 94, 12).getType() == CacheType.MYSTERY ? mystery + 1 : mystery;
+ mystery = parseMapPNG(bitmap, 161, 124, 12).getType() == CacheType.MYSTERY ? mystery + 1 : mystery;
+ mystery = parseMapPNG(bitmap, 168, 118, 12).getType() == CacheType.MYSTERY ? mystery + 1 : mystery;
+ mystery = parseMapPNG(bitmap, 231, 114, 12).getType() == CacheType.MYSTERY ? mystery + 1 : mystery;
+
+ int tradi = 0;
+ tradi = parseMapPNG(bitmap, 179, 27, 12).getType() == CacheType.TRADITIONAL ? tradi + 1 : tradi;
+ tradi = parseMapPNG(bitmap, 106, 93, 12).getType() == CacheType.TRADITIONAL ? tradi + 1 : tradi;
+ tradi = parseMapPNG(bitmap, 145, 147, 12).getType() == CacheType.TRADITIONAL ? tradi + 1 : tradi;
+ tradi = parseMapPNG(bitmap, 204, 163, 12).getType() == CacheType.TRADITIONAL ? tradi + 1 : tradi;
+ tradi = parseMapPNG(bitmap, 9, 146, 12).getType() == CacheType.TRADITIONAL ? tradi + 1 : tradi;
+ tradi = parseMapPNG(bitmap, 117, 225, 12).getType() == CacheType.TRADITIONAL ? tradi + 1 : tradi;
+ tradi = parseMapPNG(bitmap, 90, 107, 12).getType() == CacheType.TRADITIONAL ? tradi + 1 : tradi;
+
+ assertEquals(7, multi);
+ assertEquals(7, mystery);
+ assertEquals(7, tradi);
+
+ }
+}
diff --git a/tests/src/cgeo/geocaching/test/mock/GC1ZXX2.java b/tests/src/cgeo/geocaching/test/mock/GC1ZXX2.java
index 0f6fe79..bf4d0cf 100644
--- a/tests/src/cgeo/geocaching/test/mock/GC1ZXX2.java
+++ b/tests/src/cgeo/geocaching/test/mock/GC1ZXX2.java
@@ -1,10 +1,10 @@
package cgeo.geocaching.test.mock;
-import cgeo.geocaching.cgBase;
import cgeo.geocaching.enumerations.CacheSize;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.network.Login;
import java.text.ParseException;
import java.util.Arrays;
@@ -96,7 +96,7 @@ public class GC1ZXX2 extends MockedCache {
@Override
public Date getHiddenDate() {
try {
- return cgBase.parseGcCustomDate("16/10/2009", getDateFormat());
+ return Login.parseGcCustomDate("16/10/2009", getDateFormat());
} catch (ParseException e) {
// intentionally left blank
}
diff --git a/tests/src/cgeo/geocaching/test/mock/GC2CJPF.java b/tests/src/cgeo/geocaching/test/mock/GC2CJPF.java
index f78527f..b97d2bc 100644
--- a/tests/src/cgeo/geocaching/test/mock/GC2CJPF.java
+++ b/tests/src/cgeo/geocaching/test/mock/GC2CJPF.java
@@ -1,11 +1,11 @@
package cgeo.geocaching.test.mock;
import cgeo.geocaching.Settings;
-import cgeo.geocaching.cgBase;
import cgeo.geocaching.enumerations.CacheSize;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.network.Login;
import java.text.ParseException;
import java.util.Arrays;
@@ -122,7 +122,7 @@ public class GC2CJPF extends MockedCache {
@Override
public Date getHiddenDate() {
try {
- return cgBase.parseGcCustomDate("31/07/2010", getDateFormat());
+ return Login.parseGcCustomDate("31/07/2010", getDateFormat());
} catch (ParseException e) {
// intentionally left blank
}
diff --git a/tests/src/cgeo/geocaching/test/mock/GC2JVEH.java b/tests/src/cgeo/geocaching/test/mock/GC2JVEH.java
index fe860a1..6fdd753 100644
--- a/tests/src/cgeo/geocaching/test/mock/GC2JVEH.java
+++ b/tests/src/cgeo/geocaching/test/mock/GC2JVEH.java
@@ -1,12 +1,12 @@
package cgeo.geocaching.test.mock;
-import cgeo.geocaching.cgBase;
import cgeo.geocaching.cgImage;
import cgeo.geocaching.cgTrackable;
import cgeo.geocaching.enumerations.CacheSize;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.network.Login;
import java.text.ParseException;
import java.util.ArrayList;
@@ -90,7 +90,7 @@ public class GC2JVEH extends MockedCache {
@Override
public Date getHiddenDate() {
try {
- return cgBase.parseGcCustomDate("28/11/2010", getDateFormat());
+ return Login.parseGcCustomDate("28/11/2010", getDateFormat());
} catch (ParseException e) {
// intentionally left blank
}