aboutsummaryrefslogtreecommitdiffstats
path: root/main/src
diff options
context:
space:
mode:
Diffstat (limited to 'main/src')
-rw-r--r--main/src/cgeo/geocaching/CacheDetailActivity.java91
-rw-r--r--main/src/cgeo/geocaching/LogEntry.java4
-rw-r--r--main/src/cgeo/geocaching/Settings.java5
-rw-r--r--main/src/cgeo/geocaching/cgCache.java14
-rw-r--r--main/src/cgeo/geocaching/cgData.java25
-rw-r--r--main/src/cgeo/geocaching/cgeocaches.java144
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCConstants.java2
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCParser.java61
-rw-r--r--main/src/cgeo/geocaching/connector/gc/Login.java6
-rw-r--r--main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java5
-rw-r--r--main/src/cgeo/geocaching/enumerations/LogType.java6
-rw-r--r--main/src/cgeo/geocaching/files/GPXParser.java12
-rw-r--r--main/src/cgeo/geocaching/files/LocParser.java16
-rw-r--r--main/src/cgeo/geocaching/gcvote/GCVote.java14
-rw-r--r--main/src/cgeo/geocaching/geopoint/DistanceParser.java5
-rw-r--r--main/src/cgeo/geocaching/geopoint/GeopointParser.java5
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java2
-rw-r--r--main/src/cgeo/geocaching/network/HtmlImage.java3
-rw-r--r--main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java10
-rw-r--r--main/src/cgeo/geocaching/ui/Formatter.java5
-rw-r--r--main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java13
-rw-r--r--main/src/cgeo/geocaching/utils/MatcherWrapper.java91
22 files changed, 337 insertions, 202 deletions
diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java
index 4307886..73675de 100644
--- a/main/src/cgeo/geocaching/CacheDetailActivity.java
+++ b/main/src/cgeo/geocaching/CacheDetailActivity.java
@@ -34,6 +34,7 @@ import cgeo.geocaching.utils.GeoDirHandler;
import cgeo.geocaching.utils.HtmlUtils;
import cgeo.geocaching.utils.ImageHelper;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.MatcherWrapper;
import cgeo.geocaching.utils.TranslationUtils;
import cgeo.geocaching.utils.UnknownTagsHandler;
@@ -102,7 +103,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
@@ -1139,8 +1139,10 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
details.addTerrain(cache);
details.addRating(cache);
- // favourite count
- details.add(R.string.cache_favourite, cache.getFavoritePoints() + "×");
+ // favorite count
+ if (cache.getFavoritePoints() > 0) {
+ details.add(R.string.cache_favourite, cache.getFavoritePoints() + "×");
+ }
// own rating
if (cache.getMyVote() > 0) {
@@ -1216,21 +1218,8 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
// favorite points
Button buttonFavPointAdd = (Button) view.findViewById(R.id.add_to_favpoint);
Button buttonFavPointRemove = (Button) view.findViewById(R.id.remove_from_favpoint);
- buttonFavPointAdd.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- GCConnector.addToFavorites(cache);
- updateFavPointBox();
- }
- });
- buttonFavPointRemove.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- GCConnector.removeFromFavorites(cache);
- updateFavPointBox();
- }
- });
-
+ buttonFavPointAdd.setOnClickListener(new FavoriteAddClickListener());
+ buttonFavPointRemove.setOnClickListener(new FavoriteRemoveClickListener());
updateFavPointBox();
// data license
@@ -1465,6 +1454,70 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
}
+ /** Thread to add this cache to the favourite list of the user */
+ private class FavoriteAddThread extends Thread {
+ private final Handler handler;
+
+ public FavoriteAddThread(Handler handler) {
+ this.handler = handler;
+ }
+
+ @Override
+ public void run() {
+ handler.sendEmptyMessage(GCConnector.addToFavorites(cache) ? 1 : -1);
+ }
+ }
+
+ /** Thread to remove this cache to the favourite list of the user */
+ private class FavoriteRemoveThread extends Thread {
+ private final Handler handler;
+
+ public FavoriteRemoveThread(Handler handler) {
+ this.handler = handler;
+ }
+
+ @Override
+ public void run() {
+ handler.sendEmptyMessage(GCConnector.removeFromFavorites(cache) ? 1 : -1);
+ }
+ }
+
+ private class FavoriteUpdateHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ progress.dismiss();
+ if (msg.what == -1) {
+ showToast(res.getString(R.string.err_favorite_failed));
+ } else {
+ updateFavPointBox();
+ }
+ }
+ }
+
+ /**
+ * Listener for "add to favourites" button
+ */
+ private class FavoriteAddClickListener extends AbstractWatchlistClickListener {
+ @Override
+ public void onClick(View arg0) {
+ doExecute(R.string.cache_dialog_favourite_add_title,
+ R.string.cache_dialog_favourite_add_message,
+ new FavoriteAddThread(new FavoriteUpdateHandler()));
+ }
+ }
+
+ /**
+ * Listener for "remove from favourites" button
+ */
+ private class FavoriteRemoveClickListener extends AbstractWatchlistClickListener {
+ @Override
+ public void onClick(View arg0) {
+ doExecute(R.string.cache_dialog_favourite_remove_title,
+ R.string.cache_dialog_favourite_remove_message,
+ new FavoriteRemoveThread(new FavoriteUpdateHandler()));
+ }
+ }
+
/**
* shows/hides buttons, sets text in watchlist box
*/
@@ -1873,7 +1926,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
backcolor = color.darker_gray;
}
else {
- Matcher matcher = DARK_COLOR_PATTERN.matcher(text);
+ MatcherWrapper matcher = new MatcherWrapper(DARK_COLOR_PATTERN, text);
if (matcher.find()) {
backcolor = color.darker_gray;
}
diff --git a/main/src/cgeo/geocaching/LogEntry.java b/main/src/cgeo/geocaching/LogEntry.java
index b625bb5..1cb3de3 100644
--- a/main/src/cgeo/geocaching/LogEntry.java
+++ b/main/src/cgeo/geocaching/LogEntry.java
@@ -2,6 +2,7 @@ package cgeo.geocaching;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.utils.DateUtils;
+import cgeo.geocaching.utils.MatcherWrapper;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@@ -10,7 +11,6 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class LogEntry {
@@ -107,7 +107,7 @@ public final class LogEntry {
*/
public String getDisplayText() {
if (Settings.getPlainLogs()) {
- Matcher matcher = PATTERN_REMOVE_COLORS.matcher(log);
+ MatcherWrapper matcher = new MatcherWrapper(PATTERN_REMOVE_COLORS, log);
return matcher.replaceAll("");
}
return log;
diff --git a/main/src/cgeo/geocaching/Settings.java b/main/src/cgeo/geocaching/Settings.java
index 5898bf7..96aab88 100644
--- a/main/src/cgeo/geocaching/Settings.java
+++ b/main/src/cgeo/geocaching/Settings.java
@@ -1382,8 +1382,9 @@ public final class Settings {
}
public static String getPreferencesName() {
- // there is currently no Android API to get the file name of the shared preferences
- return cgeoapplication.getInstance().getPackageName() + "_preferences";
+ // There is currently no Android API to get the file name of the shared preferences. Let's hardcode
+ // it without needing a cgeoapplication instance.
+ return "cgeo.geocaching_preferences";
}
public static boolean getPlainLogs() {
diff --git a/main/src/cgeo/geocaching/cgCache.java b/main/src/cgeo/geocaching/cgCache.java
index b486142..8f867b5 100644
--- a/main/src/cgeo/geocaching/cgCache.java
+++ b/main/src/cgeo/geocaching/cgCache.java
@@ -28,6 +28,7 @@ import cgeo.geocaching.utils.LazyInitializedList;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.LogTemplateProvider;
import cgeo.geocaching.utils.LogTemplateProvider.LogContext;
+import cgeo.geocaching.utils.MatcherWrapper;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@@ -48,7 +49,6 @@ import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
@@ -274,6 +274,8 @@ public class cgCache implements ICache, IWaypoint {
if (StringUtils.isBlank(description)) {
description = other.description;
}
+ // FIXME: this makes no sense to favor this over the other. 0 should not be a special case here as it is
+ // in the range of acceptable values. This is probably the case at other places (rating, votes, etc.) too.
if (favoritePoints == 0) {
favoritePoints = other.favoritePoints;
}
@@ -760,7 +762,7 @@ public class cgCache implements ICache, IWaypoint {
@Override
public String getNameForSorting() {
if (null == nameForSorting) {
- final Matcher matcher = NUMBER_PATTERN.matcher(name);
+ final MatcherWrapper matcher = new MatcherWrapper(NUMBER_PATTERN, name);
if (matcher.find()) {
nameForSorting = name.replace(matcher.group(), StringUtils.leftPad(matcher.group(), 6, '0'));
}
@@ -1318,7 +1320,7 @@ public class cgCache implements ICache, IWaypoint {
final Pattern coordPattern = Pattern.compile("\\b[nNsS]{1}\\s*\\d"); // begin of coordinates
int count = 1;
String note = getPersonalNote();
- Matcher matcher = coordPattern.matcher(note);
+ MatcherWrapper matcher = new MatcherWrapper(coordPattern, note);
while (matcher.find()) {
try {
final Geopoint point = new Geopoint(note.substring(matcher.start()));
@@ -1335,7 +1337,7 @@ public class cgCache implements ICache, IWaypoint {
}
note = note.substring(matcher.start() + 1);
- matcher = coordPattern.matcher(note);
+ matcher = new MatcherWrapper(coordPattern, note);
}
} catch (Exception e) {
Log.e("cgCache.parseWaypointsFromNote: " + e.toString());
@@ -1577,7 +1579,7 @@ public class cgCache implements ICache, IWaypoint {
}
// 12:34
final Pattern time = Pattern.compile("\\b(\\d{1,2})\\:(\\d\\d)\\b");
- final Matcher matcher = time.matcher(getDescription());
+ final MatcherWrapper matcher = new MatcherWrapper(time, getDescription());
while (matcher.find()) {
try {
final int hours = Integer.valueOf(matcher.group(1));
@@ -1593,7 +1595,7 @@ public class cgCache implements ICache, IWaypoint {
final String hourLocalized = cgeoapplication.getInstance().getString(R.string.cache_time_full_hours);
if (StringUtils.isNotBlank(hourLocalized)) {
final Pattern fullHours = Pattern.compile("\\b(\\d{1,2})\\s+" + Pattern.quote(hourLocalized), Pattern.CASE_INSENSITIVE);
- final Matcher matcherHours = fullHours.matcher(getDescription());
+ final MatcherWrapper matcherHours = new MatcherWrapper(fullHours, getDescription());
if (matcherHours.find()) {
try {
final int hours = Integer.valueOf(matcherHours.group(1));
diff --git a/main/src/cgeo/geocaching/cgData.java b/main/src/cgeo/geocaching/cgData.java
index 78611b8..e8865c7 100644
--- a/main/src/cgeo/geocaching/cgData.java
+++ b/main/src/cgeo/geocaching/cgData.java
@@ -372,6 +372,8 @@ public class cgData {
private static class DbHelper extends SQLiteOpenHelper {
+ private static boolean firstRun = true;
+
DbHelper(Context context) {
super(context, databasePath().getPath(), null, dbVersion);
}
@@ -665,6 +667,29 @@ public class cgData {
Log.i("Upgrade database from ver. " + oldVersion + " to ver. " + newVersion + ": completed");
}
+ @Override
+ public void onOpen(final SQLiteDatabase db) {
+ if (firstRun) {
+ sanityChecks(db);
+ firstRun = false;
+ }
+ }
+
+ /**
+ * Execute sanity checks that should be performed once per application after the database has been
+ * opened.
+ *
+ * @param db the database to perform sanity checks against
+ */
+ private static void sanityChecks(final SQLiteDatabase db) {
+ // Check that the history of searches is well formed as some dates seem to be missing according
+ // to NPE traces.
+ final int staleHistorySearches = db.delete(dbTableSearchDestionationHistory, "date is null", null);
+ if (staleHistorySearches > 0) {
+ Log.w(String.format("cgData.dbHelper.onOpen: removed %d bad search history entries", staleHistorySearches));
+ }
+ }
+
/**
* Method to remove static map files with double underscore due to issue#1670
* introduced with release on 2012-05-24.
diff --git a/main/src/cgeo/geocaching/cgeocaches.java b/main/src/cgeo/geocaching/cgeocaches.java
index 1210dd4..e4fcc2b 100644
--- a/main/src/cgeo/geocaching/cgeocaches.java
+++ b/main/src/cgeo/geocaching/cgeocaches.java
@@ -131,11 +131,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
@Override
public void updateGeoData(final IGeoData geo) {
- if (adapter == null) {
- return;
- }
-
- if (geo.getCoords() != null) {
+ if (geo.getCoords() != null) {
adapter.setActualCoordinates(geo.getCoords());
}
if (!Settings.isUseCompass() || geo.getSpeed() > 5) { // use GPS when speed is higher than 18 km/h
@@ -145,7 +141,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
@Override
public void updateDirection(final float direction) {
- if (adapter == null || !Settings.isLiveList()) {
+ if (!Settings.isLiveList()) {
return;
}
@@ -226,9 +222,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
Log.e("cgeocaches.loadCachesHandler.2: " + e2.toString());
}
- if (adapter != null) {
- adapter.setSelectMode(false);
- }
+ adapter.setSelectMode(false);
}
private Handler loadCachesHandler = new LoadCachesHandler(this);
@@ -254,12 +248,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
@Override
public void handleMessage(Message msg) {
try {
- if (search != null) {
- replaceCacheListFromSearch();
- if (adapter != null) {
- adapter.reFilter();
- }
- }
+ replaceCacheListFromSearch();
setAdapter();
updateTitle();
@@ -286,22 +275,30 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
hideLoading();
showProgress(false);
- if (adapter != null) {
- adapter.setSelectMode(false);
- }
+ adapter.setSelectMode(false);
}
};
- private Set<cgCache> cachesFromSearchResult;
/**
- * Loads the caches and fills the cachelist
+ * Loads the caches and fills the cachelist according to {@link #search} content.
+ *
+ * If {@link #search} is <code>null</code>, this does nothing.
*/
private void replaceCacheListFromSearch() {
- if (search!=null) {
- cachesFromSearchResult = search.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB);
+ if (search != null) {
+ final Set<cgCache> cachesFromSearchResult = search.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB);
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ cacheList.clear();
+ cacheList.addAll((Set<cgCache>) cachesFromSearchResult);
+ adapter.reFilter();
+ updateTitle();
+ showFooterMoreCaches();
+ }
+ });
}
- refreshCacheListHandler.sendEmptyMessage(0);
}
protected void updateTitle() {
@@ -329,9 +326,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
if (msg.what > -1) {
cacheList.get(msg.what).setStatusChecked(false);
- if (adapter != null) {
- adapter.notifyDataSetChanged();
- }
+ adapter.notifyDataSetChanged();
int secondsElapsed = (int) ((System.currentTimeMillis() - detailProgressTime) / 1000);
int minutesRemaining = ((detailTotal - detailProgress) * secondsElapsed / ((detailProgress > 0) ? detailProgress : 1) / 60);
@@ -375,9 +370,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
public void handleMessage(Message msg) {
setAdapter();
- if (adapter != null) {
- adapter.notifyDataSetChanged();
- }
+ adapter.notifyDataSetChanged();
if (msg.what == 0) { //no caches
progress.setMessage(res.getString(R.string.web_import_waiting));
@@ -399,9 +392,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
threadWeb.kill();
}
} else {
- if (adapter != null) {
- adapter.setSelectMode(false);
- }
+ adapter.setSelectMode(false);
replaceCacheListFromSearch();
@@ -414,9 +405,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
@Override
public void handleMessage(Message msg) {
if (msg.what != MSG_CANCEL) {
- if (adapter != null) {
- adapter.setSelectMode(false);
- }
+ adapter.setSelectMode(false);
refreshCurrentList();
@@ -435,9 +424,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
if (msg.what > -1) {
progress.setProgress(detailProgress);
} else {
- if (adapter != null) {
- adapter.setSelectMode(false);
- }
+ adapter.setSelectMode(false);
// reload history list
(new LoadByHistoryThread()).start();
@@ -652,10 +639,8 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
startGeoAndDir();
- if (adapter != null) {
- adapter.setSelectMode(false);
- setAdapterCurrentCoordinates(true);
- }
+ adapter.setSelectMode(false);
+ setAdapterCurrentCoordinates(true);
if (loadCachesHandler != null && search != null) {
replaceCacheListFromSearch();
@@ -683,9 +668,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
@Override
public void onDestroy() {
- if (adapter != null) {
- adapter = null;
- }
+ adapter = null;
super.onDestroy();
}
@@ -756,7 +739,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
super.onPrepareOptionsMenu(menu);
try {
- if (adapter != null && adapter.isSelectMode()) {
+ if (adapter.isSelectMode()) {
menu.findItem(MENU_SWITCH_SELECT_MODE).setTitle(res.getString(R.string.caches_select_mode_exit))
.setIcon(R.drawable.ic_menu_clear_playlist);
menu.findItem(MENU_INVERT_SELECTION).setVisible(true);
@@ -854,9 +837,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
int itemId = item.getItemId();
switch (itemId) {
case MENU_SWITCH_SELECT_MODE:
- if (adapter != null) {
- adapter.switchSelectMode();
- }
+ adapter.switchSelectMode();
invalidateOptionsMenuCompatible();
return true;
case MENU_REFRESH_STORED:
@@ -887,9 +868,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
renameList();
return false;
case MENU_INVERT_SELECTION:
- if (adapter != null) {
- adapter.invertSelection();
- }
+ adapter.invertSelection();
invalidateOptionsMenuCompatible();
return false;
case MENU_SWITCH_LIST:
@@ -957,28 +936,20 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
else {
// clear filter
- if (adapter != null) {
- setFilter(null);
- }
+ setFilter(null);
}
}
});
}
private void setComparator(final CacheComparator comparator) {
- if (adapter != null) {
- adapter.setComparator(comparator);
- }
+ adapter.setComparator(comparator);
}
@Override
public void onCreateContextMenu(final ContextMenu menu, final View view, final ContextMenu.ContextMenuInfo info) {
super.onCreateContextMenu(menu, view, info);
- if (adapter == null) {
- return;
- }
-
AdapterContextMenuInfo adapterInfo = null;
try {
adapterInfo = (AdapterContextMenuInfo) info;
@@ -1121,24 +1092,19 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
private boolean setFilter(IFilter filter) {
- if (adapter != null) {
- adapter.setFilter(filter);
- prepareFilterBar();
- updateTitle();
- invalidateOptionsMenuCompatible();
- return true;
- }
- return false;
+ adapter.setFilter(filter);
+ prepareFilterBar();
+ updateTitle();
+ invalidateOptionsMenuCompatible();
+ return true;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
- if (adapter != null) {
- if (adapter.isSelectMode()) {
- adapter.setSelectMode(false);
- return true;
- }
+ if (adapter.isSelectMode()) {
+ adapter.setSelectMode(false);
+ return true;
}
}
return super.onKeyDown(keyCode, event);
@@ -1298,7 +1264,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
dialog.setCancelable(true);
dialog.setTitle(res.getString(R.string.caches_drop_stored));
- if (adapter != null && adapter.getCheckedCount() > 0) {
+ if (adapter.getCheckedCount() > 0) {
dialog.setMessage(res.getString(R.string.caches_drop_selected_ask));
} else {
dialog.setMessage(res.getString(R.string.caches_drop_all_ask));
@@ -1767,22 +1733,6 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
}
- /**
- * Handler to refresh the current list of caches. This list is shared with the Adapter and therefore must be updated
- * in the UI-Thread
- */
-
- private Handler refreshCacheListHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- cacheList.clear();
- if (cachesFromSearchResult != null) {
- cacheList.addAll(cachesFromSearchResult);
- }
- }
- };
-
-
private void renameList() {
new StoredList.UserInterface(this).promptForListRename(listId, new Runnable() {
@@ -1850,13 +1800,11 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
SearchResult searchToUse = search;
// apply filter settings (if there's a filter)
- if (adapter != null) {
- Set<String> geocodes = new HashSet<String>();
- for (cgCache cache : adapter.getFilteredList()) {
- geocodes.add(cache.getGeocode());
- }
- searchToUse = new SearchResult(geocodes);
+ Set<String> geocodes = new HashSet<String>();
+ for (cgCache cache : adapter.getFilteredList()) {
+ geocodes.add(cache.getGeocode());
}
+ searchToUse = new SearchResult(geocodes);
int count = searchToUse.getCount();
String mapTitle = title;
diff --git a/main/src/cgeo/geocaching/connector/gc/GCConstants.java b/main/src/cgeo/geocaching/connector/gc/GCConstants.java
index a474e70..282c88c 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCConstants.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCConstants.java
@@ -57,7 +57,7 @@ public final class GCConstants {
public final static Pattern PATTERN_ATTRIBUTES = Pattern.compile("<h3 class=\"WidgetHeader\">.+?Attributes</h3>[^<]*<div class=\"WidgetBody\">((?:[^<]*<img src=\"[^\"]+\" alt=\"[^\"]+\"[^>]*>)+?)[^<]*<p");
/** Two groups ! */
public final static Pattern PATTERN_ATTRIBUTESINSIDE = Pattern.compile("[^<]*<img src=\"([^\"]+)\" alt=\"([^\"]+?)\"");
- public final static Pattern PATTERN_SPOILER_IMAGE = Pattern.compile("<a href=\"(http://img\\.geocaching\\.com/cache/[^.]+\\.jpe?g)\"[^>]+><img[^>]+><span>([^<]+)</span></a>(?:<br />([^<]+)<br /><br />)?");
+ public final static Pattern PATTERN_SPOILER_IMAGE = Pattern.compile("<a href=\"(http://img\\.geocaching\\.com/cache/[^.]+\\.(jpg|jpeg|png|gif))\"[^>]+><img[^>]+><span>([^<]+)</span></a>(?:<br />([^<]+)<br /><br />)?");
public final static Pattern PATTERN_INVENTORY = Pattern.compile("<span id=\"ctl00_ContentBody_uxTravelBugList_uxInventoryLabel\">\\W*Inventory[^<]*</span>[^<]*</h3>[^<]*<div class=\"WidgetBody\">([^<]*<ul>(([^<]*<li>[^<]*<a href=\"[^\"]+\"[^>]*>[^<]*<img src=\"[^\"]+\"[^>]*>[^<]*<span>[^<]+<\\/span>[^<]*<\\/a>[^<]*<\\/li>)+)[^<]*<\\/ul>)?");
public final static Pattern PATTERN_INVENTORYINSIDE = Pattern.compile("[^<]*<li>[^<]*<a href=\"[a-z0-9\\-\\_\\.\\?\\/\\:\\@]*\\/track\\/details\\.aspx\\?guid=([0-9a-z\\-]+)[^\"]*\"[^>]*>[^<]*<img src=\"[^\"]+\"[^>]*>[^<]*<span>([^<]+)<\\/span>[^<]*<\\/a>[^<]*<\\/li>");
public final static Pattern PATTERN_WATCHLIST = Pattern.compile(Pattern.quote("watchlist.aspx") + ".{1,50}" + Pattern.quote("action=rem"));
diff --git a/main/src/cgeo/geocaching/connector/gc/GCParser.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java
index fd4e3fa..91b0ddd 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCParser.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java
@@ -31,6 +31,7 @@ import cgeo.geocaching.utils.BaseUtils;
import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.LazyInitializedList;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.MatcherWrapper;
import ch.boye.httpclientandroidlib.HttpResponse;
@@ -54,7 +55,6 @@ import java.util.EnumSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
-import java.util.regex.Matcher;
public abstract class GCParser {
private final static SimpleDateFormat dateTbIn1 = new SimpleDateFormat("EEEEE, dd MMMMM yyyy", Locale.ENGLISH); // Saturday, 28 March 2009
@@ -128,7 +128,7 @@ public abstract class GCParser {
}
try {
- final Matcher matcherGuidAndDisabled = GCConstants.PATTERN_SEARCH_GUIDANDDISABLED.matcher(row);
+ final MatcherWrapper matcherGuidAndDisabled = new MatcherWrapper(GCConstants.PATTERN_SEARCH_GUIDANDDISABLED, row);
while (matcherGuidAndDisabled.find()) {
if (matcherGuidAndDisabled.groupCount() > 0) {
@@ -169,7 +169,7 @@ public abstract class GCParser {
}
// cache inventory
- final Matcher matcherTbs = GCConstants.PATTERN_SEARCH_TRACKABLES.matcher(row);
+ final MatcherWrapper matcherTbs = new MatcherWrapper(GCConstants.PATTERN_SEARCH_TRACKABLES, row);
String inventoryPre = null;
while (matcherTbs.find()) {
if (matcherTbs.groupCount() > 0) {
@@ -183,7 +183,7 @@ public abstract class GCParser {
}
if (StringUtils.isNotBlank(inventoryPre)) {
- final Matcher matcherTbsInside = GCConstants.PATTERN_SEARCH_TRACKABLESINSIDE.matcher(inventoryPre);
+ final MatcherWrapper matcherTbsInside = new MatcherWrapper(GCConstants.PATTERN_SEARCH_TRACKABLESINSIDE, inventoryPre);
while (matcherTbsInside.find()) {
if (matcherTbsInside.groupCount() == 2 &&
matcherTbsInside.group(2) != null &&
@@ -500,7 +500,7 @@ public abstract class GCParser {
try {
final String attributesPre = BaseUtils.getMatch(page, GCConstants.PATTERN_ATTRIBUTES, true, null);
if (null != attributesPre) {
- final Matcher matcherAttributesInside = GCConstants.PATTERN_ATTRIBUTESINSIDE.matcher(attributesPre);
+ final MatcherWrapper matcherAttributesInside = new MatcherWrapper(GCConstants.PATTERN_ATTRIBUTESINSIDE, attributesPre);
final ArrayList<String> attributes = new ArrayList<String>();
while (matcherAttributesInside.find()) {
@@ -534,7 +534,7 @@ public abstract class GCParser {
}
CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_spoilers);
- final Matcher matcherSpoilersInside = GCConstants.PATTERN_SPOILER_IMAGE.matcher(page);
+ final MatcherWrapper matcherSpoilersInside = new MatcherWrapper(GCConstants.PATTERN_SPOILER_IMAGE, page);
while (matcherSpoilersInside.find()) {
// the original spoiler URL (include .../display/... contains a low-resolution image
@@ -542,12 +542,12 @@ public abstract class GCParser {
String url = matcherSpoilersInside.group(1).replace("/display", "");
String title = null;
- if (matcherSpoilersInside.group(2) != null) {
- title = matcherSpoilersInside.group(2);
+ if (matcherSpoilersInside.group(3) != null) {
+ title = matcherSpoilersInside.group(3);
}
String description = null;
- if (matcherSpoilersInside.group(3) != null) {
- description = matcherSpoilersInside.group(3);
+ if (matcherSpoilersInside.group(4) != null) {
+ description = matcherSpoilersInside.group(4);
}
cache.addSpoiler(new cgImage(url, title, description));
}
@@ -560,7 +560,7 @@ public abstract class GCParser {
try {
cache.setInventoryItems(0);
- final Matcher matcherInventory = GCConstants.PATTERN_INVENTORY.matcher(page);
+ final MatcherWrapper matcherInventory = new MatcherWrapper(GCConstants.PATTERN_INVENTORY, page);
if (matcherInventory.find()) {
if (cache.getInventory() == null) {
cache.setInventory(new ArrayList<cgTrackable>());
@@ -570,7 +570,7 @@ public abstract class GCParser {
final String inventoryPre = matcherInventory.group(2);
if (StringUtils.isNotBlank(inventoryPre)) {
- final Matcher matcherInventoryInside = GCConstants.PATTERN_INVENTORYINSIDE.matcher(inventoryPre);
+ final MatcherWrapper matcherInventoryInside = new MatcherWrapper(GCConstants.PATTERN_INVENTORYINSIDE, inventoryPre);
while (matcherInventoryInside.find()) {
if (matcherInventoryInside.groupCount() > 0) {
@@ -591,14 +591,12 @@ public abstract class GCParser {
}
// cache logs counts
- try
- {
+ try {
final String countlogs = BaseUtils.getMatch(page, GCConstants.PATTERN_COUNTLOGS, true, null);
if (null != countlogs) {
- final Matcher matcherLog = GCConstants.PATTERN_COUNTLOG.matcher(countlogs);
+ final MatcherWrapper matcherLog = new MatcherWrapper(GCConstants.PATTERN_COUNTLOG, countlogs);
- while (matcherLog.find())
- {
+ while (matcherLog.find()) {
String typeStr = matcherLog.group(1);
String countStr = matcherLog.group(2).replaceAll("[.,]", "");
@@ -609,8 +607,7 @@ public abstract class GCParser {
}
}
}
- } catch (Exception e)
- {
+ } catch (Exception e) {
// failed to parse logs
Log.w("GCParser.parseCache: Failed to parse cache log count");
}
@@ -997,7 +994,7 @@ public abstract class GCParser {
// maintenance, archived needs to be confirmed
- final Matcher matcher = GCConstants.PATTERN_MAINTENANCE.matcher(page);
+ final MatcherWrapper matcher = new MatcherWrapper(GCConstants.PATTERN_MAINTENANCE, page);
try {
if (matcher.find() && matcher.groupCount() > 0) {
@@ -1046,7 +1043,7 @@ public abstract class GCParser {
try {
- final Matcher matcherOk = GCConstants.PATTERN_OK1.matcher(page);
+ final MatcherWrapper matcherOk = new MatcherWrapper(GCConstants.PATTERN_OK1, page);
if (matcherOk.find()) {
Log.i("Log successfully posted to cache #" + cacheid);
@@ -1115,7 +1112,7 @@ public abstract class GCParser {
try {
- final Matcher matcherOk = GCConstants.PATTERN_OK2.matcher(page);
+ final MatcherWrapper matcherOk = new MatcherWrapper(GCConstants.PATTERN_OK2, page);
if (matcherOk.find()) {
Log.i("Log successfully posted to trackable #" + trackingCode);
return StatusCode.NO_ERROR;
@@ -1286,7 +1283,7 @@ public abstract class GCParser {
// trackable owner name
try {
- final Matcher matcherOwner = GCConstants.PATTERN_TRACKABLE_OWNER.matcher(page);
+ final MatcherWrapper matcherOwner = new MatcherWrapper(GCConstants.PATTERN_TRACKABLE_OWNER, page);
if (matcherOwner.find() && matcherOwner.groupCount() > 0) {
trackable.setOwnerGuid(matcherOwner.group(1));
trackable.setOwner(matcherOwner.group(2).trim());
@@ -1301,14 +1298,14 @@ public abstract class GCParser {
// trackable spotted
try {
- final Matcher matcherSpottedCache = GCConstants.PATTERN_TRACKABLE_SPOTTEDCACHE.matcher(page);
+ final MatcherWrapper matcherSpottedCache = new MatcherWrapper(GCConstants.PATTERN_TRACKABLE_SPOTTEDCACHE, page);
if (matcherSpottedCache.find() && matcherSpottedCache.groupCount() > 0) {
trackable.setSpottedGuid(matcherSpottedCache.group(1));
trackable.setSpottedName(matcherSpottedCache.group(2).trim());
trackable.setSpottedType(cgTrackable.SPOTTED_CACHE);
}
- final Matcher matcherSpottedUser = GCConstants.PATTERN_TRACKABLE_SPOTTEDUSER.matcher(page);
+ final MatcherWrapper matcherSpottedUser = new MatcherWrapper(GCConstants.PATTERN_TRACKABLE_SPOTTEDUSER, page);
if (matcherSpottedUser.find() && matcherSpottedUser.groupCount() > 0) {
trackable.setSpottedGuid(matcherSpottedUser.group(1));
trackable.setSpottedName(matcherSpottedUser.group(2).trim());
@@ -1351,7 +1348,7 @@ public abstract class GCParser {
// trackable details & image
try {
- final Matcher matcherDetailsImage = GCConstants.PATTERN_TRACKABLE_DETAILSIMAGE.matcher(page);
+ final MatcherWrapper matcherDetailsImage = new MatcherWrapper(GCConstants.PATTERN_TRACKABLE_DETAILSIMAGE, page);
if (matcherDetailsImage.find() && matcherDetailsImage.groupCount() > 0) {
final String image = StringUtils.trim(matcherDetailsImage.group(3));
final String details = StringUtils.trim(matcherDetailsImage.group(4));
@@ -1370,7 +1367,7 @@ public abstract class GCParser {
// trackable logs
try {
- final Matcher matcherLogs = GCConstants.PATTERN_TRACKABLE_LOG.matcher(page);
+ final MatcherWrapper matcherLogs = new MatcherWrapper(GCConstants.PATTERN_TRACKABLE_LOG, page);
/*
* 1. Type (image)
* 2. Date
@@ -1400,7 +1397,7 @@ public abstract class GCParser {
// Apply the pattern for images in a trackable log entry against each full log (group(0))
final String logEntry = matcherLogs.group(0);
- final Matcher matcherLogImages = GCConstants.PATTERN_TRACKABLE_LOG_IMAGES.matcher(logEntry);
+ final MatcherWrapper matcherLogImages = new MatcherWrapper(GCConstants.PATTERN_TRACKABLE_LOG_IMAGES, logEntry);
/*
* 1. Image URL
* 2. Image title
@@ -1450,7 +1447,7 @@ public abstract class GCParser {
String rawResponse;
if (!getDataFromPage) {
- final Matcher userTokenMatcher = GCConstants.PATTERN_USERTOKEN.matcher(page);
+ final MatcherWrapper userTokenMatcher = new MatcherWrapper(GCConstants.PATTERN_USERTOKEN, page);
if (!userTokenMatcher.find()) {
Log.e("GCParser.loadLogsFromDetails: unable to extract userToken");
return null;
@@ -1549,7 +1546,7 @@ public abstract class GCParser {
final List<LogType> types = new ArrayList<LogType>();
- final Matcher typeBoxMatcher = GCConstants.PATTERN_TYPEBOX.matcher(page);
+ final MatcherWrapper typeBoxMatcher = new MatcherWrapper(GCConstants.PATTERN_TYPEBOX, page);
String typesText = null;
if (typeBoxMatcher.find()) {
if (typeBoxMatcher.groupCount() > 0) {
@@ -1559,7 +1556,7 @@ public abstract class GCParser {
if (typesText != null) {
- final Matcher typeMatcher = GCConstants.PATTERN_TYPE2.matcher(typesText);
+ final MatcherWrapper typeMatcher = new MatcherWrapper(GCConstants.PATTERN_TYPE2, typesText);
while (typeMatcher.find()) {
if (typeMatcher.groupCount() > 1) {
try {
@@ -1597,7 +1594,7 @@ public abstract class GCParser {
final List<TrackableLog> trackableLogs = new ArrayList<TrackableLog>();
- final Matcher trackableMatcher = GCConstants.PATTERN_TRACKABLE.matcher(page);
+ final MatcherWrapper trackableMatcher = new MatcherWrapper(GCConstants.PATTERN_TRACKABLE, page);
while (trackableMatcher.find()) {
if (trackableMatcher.groupCount() > 0) {
diff --git a/main/src/cgeo/geocaching/connector/gc/Login.java b/main/src/cgeo/geocaching/connector/gc/Login.java
index 494bcee..9a60f65 100644
--- a/main/src/cgeo/geocaching/connector/gc/Login.java
+++ b/main/src/cgeo/geocaching/connector/gc/Login.java
@@ -10,6 +10,7 @@ import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.utils.BaseUtils;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.MatcherWrapper;
import ch.boye.httpclientandroidlib.HttpResponse;
@@ -26,7 +27,6 @@ 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 {
@@ -349,7 +349,7 @@ public abstract class Login {
}
int count = 1;
- final Matcher matcherViewstateCount = GCConstants.PATTERN_VIEWSTATEFIELDCOUNT.matcher(page);
+ final MatcherWrapper matcherViewstateCount = new MatcherWrapper(GCConstants.PATTERN_VIEWSTATEFIELDCOUNT, page);
if (matcherViewstateCount.find()) {
try {
count = Integer.parseInt(matcherViewstateCount.group(1));
@@ -361,7 +361,7 @@ public abstract class Login {
String[] viewstates = new String[count];
// Get the viewstates
- final Matcher matcherViewstates = GCConstants.PATTERN_VIEWSTATES.matcher(page);
+ final MatcherWrapper matcherViewstates = new MatcherWrapper(GCConstants.PATTERN_VIEWSTATES, page);
while (matcherViewstates.find()) {
String sno = matcherViewstates.group(1); // number of viewstate
int no;
diff --git a/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java b/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java
index e34d277..5965fff 100644
--- a/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java
+++ b/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java
@@ -1,6 +1,7 @@
package cgeo.geocaching.connector.gc;
-import java.util.regex.Matcher;
+import cgeo.geocaching.utils.MatcherWrapper;
+
import java.util.regex.Pattern;
@@ -35,7 +36,7 @@ public final class UTFGridPosition {
* @return
*/
static UTFGridPosition fromString(String key) {
- final Matcher matcher = UTFGridPosition.PATTERN_JSON_KEY.matcher(key);
+ final MatcherWrapper matcher = new MatcherWrapper(UTFGridPosition.PATTERN_JSON_KEY, key);
try {
if (matcher.matches()) {
final int x = Integer.parseInt(matcher.group(1));
diff --git a/main/src/cgeo/geocaching/enumerations/LogType.java b/main/src/cgeo/geocaching/enumerations/LogType.java
index 5918fe1..71a5146 100644
--- a/main/src/cgeo/geocaching/enumerations/LogType.java
+++ b/main/src/cgeo/geocaching/enumerations/LogType.java
@@ -26,9 +26,9 @@ public enum LogType {
NEEDS_ARCHIVE(7, "7", "needs archived", R.string.log_needs_archived, R.drawable.mark_red),
WILL_ATTEND(9, "9", "will attend", R.string.log_attend),
ATTENDED(10, "10", "attended", R.string.log_attended, R.drawable.mark_green),
- RETRIEVED_IT(13, "13", "retrieved it", R.string.log_retrieved, R.drawable.mark_green),
- PLACED_IT(14, "14", "placed it", R.string.log_placed),
- GRABBED_IT(19, "19", "grabbed it", R.string.log_grabbed, R.drawable.mark_green),
+ RETRIEVED_IT(13, "13", "retrieved it", R.string.log_retrieved, R.drawable.mark_green_more),
+ PLACED_IT(14, "14", "placed it", R.string.log_placed, R.drawable.mark_green_more),
+ GRABBED_IT(19, "19", "grabbed it", R.string.log_grabbed, R.drawable.mark_green_more),
NEEDS_MAINTENANCE(45, "45", "needs maintenance", R.string.log_maintenance_needed, R.drawable.mark_red),
OWNER_MAINTENANCE(46, "46", "owner maintenance", R.string.log_maintained, R.drawable.mark_green_more),
UPDATE_COORDINATES(47, "47", "update coordinates", R.string.log_update),
diff --git a/main/src/cgeo/geocaching/files/GPXParser.java b/main/src/cgeo/geocaching/files/GPXParser.java
index 2ac19bb..e2d7205 100644
--- a/main/src/cgeo/geocaching/files/GPXParser.java
+++ b/main/src/cgeo/geocaching/files/GPXParser.java
@@ -19,6 +19,7 @@ import cgeo.geocaching.enumerations.WaypointType;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.MatcherWrapper;
import org.apache.commons.lang3.StringUtils;
import org.xml.sax.Attributes;
@@ -42,7 +43,6 @@ import java.util.EnumSet;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
public abstract class GPXParser extends FileParser {
@@ -209,7 +209,7 @@ public abstract class GPXParser extends FileParser {
return null;
}
// cut out baseName
- final Matcher m = BASENAME_PATTERN.matcher(stringName);
+ final MatcherWrapper m = new MatcherWrapper(BASENAME_PATTERN, stringName);
if (!m.matches()) {
return null;
}
@@ -235,7 +235,7 @@ public abstract class GPXParser extends FileParser {
static Date parseDate(String inputUntrimmed) throws ParseException {
String input = inputUntrimmed.trim();
// remove milliseconds to reduce number of needed patterns
- final Matcher matcher = PATTERN_MILLISECONDS.matcher(input);
+ final MatcherWrapper matcher = new MatcherWrapper(PATTERN_MILLISECONDS, input);
input = matcher.replaceFirst("");
if (input.contains("Z")) {
return formatSimpleZ.parse(input);
@@ -432,14 +432,14 @@ public abstract class GPXParser extends FileParser {
@Override
public void end(String url) {
- final Matcher matcher = patternGuid.matcher(url);
+ final MatcherWrapper matcher = new MatcherWrapper(patternGuid, url);
if (matcher.matches()) {
final String guid = matcher.group(1);
if (StringUtils.isNotBlank(guid)) {
cache.setGuid(guid);
}
}
- final Matcher matcherCode = patternUrlGeocode.matcher(url);
+ final MatcherWrapper matcherCode = new MatcherWrapper(patternUrlGeocode, url);
if (matcherCode.matches()) {
String geocode = matcherCode.group(1);
cache.setGeocode(geocode);
@@ -836,7 +836,7 @@ public abstract class GPXParser extends FileParser {
return;
}
final String trimmed = input.trim();
- final Matcher matcherGeocode = patternGeocode.matcher(trimmed);
+ final MatcherWrapper matcherGeocode = new MatcherWrapper(patternGeocode, trimmed);
if (matcherGeocode.find()) {
final String geocode = matcherGeocode.group(1);
// a geocode should not be part of a word
diff --git a/main/src/cgeo/geocaching/files/LocParser.java b/main/src/cgeo/geocaching/files/LocParser.java
index 9c24d39..730e224 100644
--- a/main/src/cgeo/geocaching/files/LocParser.java
+++ b/main/src/cgeo/geocaching/files/LocParser.java
@@ -9,6 +9,7 @@ import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.MatcherWrapper;
import org.apache.commons.lang3.StringUtils;
@@ -22,7 +23,6 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class LocParser extends FileParser {
@@ -148,12 +148,12 @@ public final class LocParser extends FileParser {
public static cgCache parseCache(final String pointString) {
final cgCache cache = new cgCache();
- final Matcher matcherGeocode = patternGeocode.matcher(pointString);
+ final MatcherWrapper matcherGeocode = new MatcherWrapper(patternGeocode, pointString);
if (matcherGeocode.find()) {
cache.setGeocode(matcherGeocode.group(1).trim());
}
- final Matcher matcherName = patternName.matcher(pointString);
+ final MatcherWrapper matcherName = new MatcherWrapper(patternName, pointString);
if (matcherName.find()) {
final String name = matcherName.group(1).trim();
cache.setName(StringUtils.substringBeforeLast(name, " by ").trim());
@@ -161,24 +161,24 @@ public final class LocParser extends FileParser {
cache.setName(cache.getGeocode());
}
- final Matcher matcherLat = patternLat.matcher(pointString);
- final Matcher matcherLon = patternLon.matcher(pointString);
+ final MatcherWrapper matcherLat = new MatcherWrapper(patternLat, pointString);
+ final MatcherWrapper matcherLon = new MatcherWrapper(patternLon, pointString);
if (matcherLat.find() && matcherLon.find()) {
cache.setCoords(parsePoint(matcherLat.group(1).trim(), matcherLon.group(1).trim()));
}
- final Matcher matcherDifficulty = patternDifficulty.matcher(pointString);
+ final MatcherWrapper matcherDifficulty = new MatcherWrapper(patternDifficulty, pointString);
try {
if (matcherDifficulty.find()) {
cache.setDifficulty(Float.parseFloat(matcherDifficulty.group(1).trim()));
}
- final Matcher matcherTerrain = patternTerrain.matcher(pointString);
+ final MatcherWrapper matcherTerrain = new MatcherWrapper(patternTerrain, pointString);
if (matcherTerrain.find()) {
cache.setTerrain(Float.parseFloat(matcherTerrain.group(1).trim()));
}
- final Matcher matcherContainer = patternContainer.matcher(pointString);
+ final MatcherWrapper matcherContainer = new MatcherWrapper(patternContainer, pointString);
if (matcherContainer.find()) {
final int size = Integer.parseInt(matcherContainer.group(1).trim());
if (size >= 1 && size <= 8) {
diff --git a/main/src/cgeo/geocaching/gcvote/GCVote.java b/main/src/cgeo/geocaching/gcvote/GCVote.java
index 3d87724..e98ba56 100644
--- a/main/src/cgeo/geocaching/gcvote/GCVote.java
+++ b/main/src/cgeo/geocaching/gcvote/GCVote.java
@@ -6,6 +6,7 @@ import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.utils.LeastRecentlyUsedMap;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.MatcherWrapper;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
@@ -15,7 +16,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class GCVote {
@@ -98,7 +98,7 @@ public final class GCVote {
return null;
}
- final Matcher matcherVoteElement = patternVoteElement.matcher(page);
+ final MatcherWrapper matcherVoteElement = new MatcherWrapper(patternVoteElement, page);
while (matcherVoteElement.find()) {
String voteData = matcherVoteElement.group(1);
if (voteData == null) {
@@ -107,7 +107,7 @@ public final class GCVote {
String guid = null;
try {
- final Matcher matcherGuid = patternGuid.matcher(voteData);
+ final MatcherWrapper matcherGuid = new MatcherWrapper(patternGuid, voteData);
if (matcherGuid.find()) {
if (matcherGuid.groupCount() > 0) {
guid = matcherGuid.group(1);
@@ -122,7 +122,7 @@ public final class GCVote {
boolean loggedIn = false;
try {
- final Matcher matcherLoggedIn = patternLogIn.matcher(page);
+ final MatcherWrapper matcherLoggedIn = new MatcherWrapper(patternLogIn, page);
if (matcherLoggedIn.find()) {
if (matcherLoggedIn.groupCount() > 0) {
if (matcherLoggedIn.group(1).equalsIgnoreCase("true")) {
@@ -136,7 +136,7 @@ public final class GCVote {
float rating = 0;
try {
- final Matcher matcherRating = patternRating.matcher(voteData);
+ final MatcherWrapper matcherRating = new MatcherWrapper(patternRating, voteData);
if (matcherRating.find()) {
rating = Float.parseFloat(matcherRating.group(1));
}
@@ -149,7 +149,7 @@ public final class GCVote {
int votes = -1;
try {
- final Matcher matcherVotes = patternVotes.matcher(voteData);
+ final MatcherWrapper matcherVotes = new MatcherWrapper(patternVotes, voteData);
if (matcherVotes.find()) {
votes = Integer.parseInt(matcherVotes.group(1));
}
@@ -163,7 +163,7 @@ public final class GCVote {
float myVote = 0;
if (loggedIn) {
try {
- final Matcher matcherVote = patternVote.matcher(voteData);
+ final MatcherWrapper matcherVote = new MatcherWrapper(patternVote, voteData);
if (matcherVote.find()) {
myVote = Float.parseFloat(matcherVote.group(1));
}
diff --git a/main/src/cgeo/geocaching/geopoint/DistanceParser.java b/main/src/cgeo/geocaching/geopoint/DistanceParser.java
index d8db8e4..e1692f4 100644
--- a/main/src/cgeo/geocaching/geopoint/DistanceParser.java
+++ b/main/src/cgeo/geocaching/geopoint/DistanceParser.java
@@ -1,9 +1,10 @@
package cgeo.geocaching.geopoint;
+import cgeo.geocaching.utils.MatcherWrapper;
+
import org.apache.commons.lang3.StringUtils;
import java.util.Locale;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class DistanceParser {
@@ -22,7 +23,7 @@ public final class DistanceParser {
* if the given number is invalid
*/
public static float parseDistance(String distanceText, final boolean metricUnit) {
- final Matcher matcher = pattern.matcher(distanceText);
+ final MatcherWrapper matcher = new MatcherWrapper(pattern, distanceText);
if (!matcher.find()) {
throw new NumberFormatException(distanceText);
diff --git a/main/src/cgeo/geocaching/geopoint/GeopointParser.java b/main/src/cgeo/geocaching/geopoint/GeopointParser.java
index 7604b9d..97a9ec8 100644
--- a/main/src/cgeo/geocaching/geopoint/GeopointParser.java
+++ b/main/src/cgeo/geocaching/geopoint/GeopointParser.java
@@ -1,9 +1,10 @@
package cgeo.geocaching.geopoint;
+import cgeo.geocaching.utils.MatcherWrapper;
+
import org.apache.commons.lang3.StringUtils;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
@@ -105,7 +106,7 @@ class GeopointParser {
{
final Pattern pattern = LatLon.LAT == latlon ? patternLat : patternLon;
- final Matcher matcher = pattern.matcher(text);
+ final MatcherWrapper matcher = new MatcherWrapper(pattern, text);
if (matcher.find()) {
final double sign = matcher.group(1).equalsIgnoreCase("S") || matcher.group(1).equalsIgnoreCase("W") ? -1.0 : 1.0;
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java
index 294eb79..dc0dbf8 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java
@@ -93,7 +93,7 @@ public final class MapsforgeMapProvider extends AbstractMapProvider {
}
private static boolean isMapfile024(String mapFileIn) {
- return org.mapsforge.android.mapsold.MapDatabase.isValidMapFile(mapFileIn);
+ return mapFileIn != null && org.mapsforge.android.mapsold.MapDatabase.isValidMapFile(mapFileIn);
}
@Override
diff --git a/main/src/cgeo/geocaching/network/HtmlImage.java b/main/src/cgeo/geocaching/network/HtmlImage.java
index e25eec5..cab92b6 100644
--- a/main/src/cgeo/geocaching/network/HtmlImage.java
+++ b/main/src/cgeo/geocaching/network/HtmlImage.java
@@ -41,7 +41,8 @@ public class HtmlImage implements Html.ImageGetter {
"besucherzaehler-homepage.de",
"hitwebcounter.com",
"kostenloser-counter.eu",
- "trendcounter.com"
+ "trendcounter.com",
+ "hit-counter-download.com"
};
final private String geocode;
diff --git a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java
index 96edebf..61478b5 100644
--- a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java
+++ b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java
@@ -7,6 +7,7 @@ import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.OAuth;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.MatcherWrapper;
import ch.boye.httpclientandroidlib.client.entity.UrlEncodedFormEntity;
import ch.boye.httpclientandroidlib.util.EntityUtils;
@@ -24,7 +25,6 @@ import android.view.View;
import android.widget.Button;
import android.widget.EditText;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TwitterAuthorizationActivity extends AbstractActivity {
@@ -142,11 +142,11 @@ public class TwitterAuthorizationActivity extends AbstractActivity {
if (StringUtils.isNotBlank(line)) {
- final Matcher paramsMatcher1 = paramsPattern1.matcher(line);
+ final MatcherWrapper paramsMatcher1 = new MatcherWrapper(paramsPattern1, line);
if (paramsMatcher1.find()) {
OAtoken = paramsMatcher1.group(1);
}
- final Matcher paramsMatcher2 = paramsPattern2.matcher(line);
+ final MatcherWrapper paramsMatcher2 = new MatcherWrapper(paramsPattern2, line);
if (paramsMatcher2.find()) {
OAtokenSecret = paramsMatcher2.group(1);
}
@@ -189,11 +189,11 @@ public class TwitterAuthorizationActivity extends AbstractActivity {
OAtoken = "";
OAtokenSecret = "";
- final Matcher paramsMatcher1 = paramsPattern1.matcher(line);
+ final MatcherWrapper paramsMatcher1 = new MatcherWrapper(paramsPattern1, line);
if (paramsMatcher1.find()) {
OAtoken = paramsMatcher1.group(1);
}
- final Matcher paramsMatcher2 = paramsPattern2.matcher(line);
+ final MatcherWrapper paramsMatcher2 = new MatcherWrapper(paramsPattern2, line);
if (paramsMatcher2.find() && paramsMatcher2.groupCount() > 0) {
OAtokenSecret = paramsMatcher2.group(1);
}
diff --git a/main/src/cgeo/geocaching/ui/Formatter.java b/main/src/cgeo/geocaching/ui/Formatter.java
index ea2ecb5..60fb3e6 100644
--- a/main/src/cgeo/geocaching/ui/Formatter.java
+++ b/main/src/cgeo/geocaching/ui/Formatter.java
@@ -13,6 +13,7 @@ import org.apache.commons.lang3.StringUtils;
import android.content.Context;
import android.text.format.DateUtils;
+import java.text.DateFormat;
import java.util.ArrayList;
import java.util.List;
@@ -70,8 +71,8 @@ public abstract class Formatter {
* @return the formatted string
*/
public static String formatShortDate(long date) {
- return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE
- | DateUtils.FORMAT_NUMERIC_DATE);
+ DateFormat dateFormat = android.text.format.DateFormat.getDateFormat(context);
+ return dateFormat.format(date);
}
/**
diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
index 0df3289..aafce4f 100644
--- a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
+++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
@@ -2,6 +2,7 @@ package cgeo.geocaching.utils;
import java.util.AbstractSet;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -102,6 +103,18 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E>
}
/**
+ * Synchronized removal of all elements contained in another collection.
+ */
+ @Override
+ public synchronized boolean removeAll(final Collection<?> c) {
+ boolean changed = false;
+ for (final Object o: c) {
+ changed |= remove(o);
+ }
+ return changed;
+ }
+
+ /**
* Synchronized clearing of the set
* Copy of the HashSet code if clear()
*
diff --git a/main/src/cgeo/geocaching/utils/MatcherWrapper.java b/main/src/cgeo/geocaching/utils/MatcherWrapper.java
new file mode 100644
index 0000000..c3c1663
--- /dev/null
+++ b/main/src/cgeo/geocaching/utils/MatcherWrapper.java
@@ -0,0 +1,91 @@
+package cgeo.geocaching.utils;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Wrapper around the regex {@link Matcher} class. This implementation optimizes the memory usage of the matched
+ * Strings.
+ *
+ */
+public class MatcherWrapper {
+ private final Matcher matcher;
+
+ public MatcherWrapper(Pattern pattern, String input) {
+ this.matcher = pattern.matcher(input);
+ }
+
+ /**
+ * see {@link Matcher#find()}
+ */
+ public boolean find() {
+ return matcher.find();
+ }
+
+ /**
+ * see {@link Matcher#group(int)}
+ */
+ public String group(int index) {
+ return newString(matcher.group(index));
+ }
+
+ /**
+ * This method explicitly creates a new String instance from an already existing String. This is necessary to avoid
+ * huge memory leaks in our parser. If we do regular expression matching on large Strings, the returned matches are
+ * otherwise memory mapped substrings of the huge original String, therefore blocking the garbage collector from
+ * removing the huge input String.
+ * <p>
+ * Do not change this method, even if Findbugs and other tools will report a violation for that line!
+ *
+ * @param input
+ * @return
+ */
+ private static String newString(String input) {
+ if (input == null) {
+ return null;
+ }
+ return new String(input); // DON'T REMOVE THE "new String" HERE!
+ }
+
+ /**
+ * see {@link Matcher#groupCount()}
+ */
+ public int groupCount() {
+ return matcher.groupCount();
+ }
+
+ /**
+ * see {@link Matcher#group()}
+ */
+ public String group() {
+ return newString(matcher.group());
+ }
+
+ /**
+ * see {@link Matcher#start()}
+ */
+ public int start() {
+ return matcher.start();
+ }
+
+ /**
+ * see {@link Matcher#replaceAll(String)}
+ */
+ public String replaceAll(String replacement) {
+ return newString(matcher.replaceAll(replacement));
+ }
+
+ /**
+ * see {@link Matcher#matches()}
+ */
+ public boolean matches() {
+ return matcher.matches();
+ }
+
+ /**
+ * see {@link Matcher#replaceFirst(String)}
+ */
+ public String replaceFirst(String replacement) {
+ return newString(matcher.replaceFirst(replacement));
+ }
+}