diff options
Diffstat (limited to 'main/src')
130 files changed, 4577 insertions, 3916 deletions
diff --git a/main/src/cgeo/geocaching/AdressListActivity.java b/main/src/cgeo/geocaching/AdressListActivity.java index 39b9f22..57d3cdd 100644 --- a/main/src/cgeo/geocaching/AdressListActivity.java +++ b/main/src/cgeo/geocaching/AdressListActivity.java @@ -49,7 +49,7 @@ public class AdressListActivity extends AbstractListActivity { try { return geocoder.getFromLocationName(keyword, 20); } catch (Exception e) { - Log.e(Settings.tag, "AdressListActivity.doInBackground", e); + Log.e("AdressListActivity.doInBackground", e); return null; } } @@ -68,7 +68,7 @@ public class AdressListActivity extends AbstractListActivity { } } } catch (Exception e) { - Log.e(Settings.tag, "AdressListActivity.onPostExecute", e); + Log.e("AdressListActivity.onPostExecute", e); } } diff --git a/main/src/cgeo/geocaching/CacheCache.java b/main/src/cgeo/geocaching/CacheCache.java index a2b5324..7f6f67e 100644 --- a/main/src/cgeo/geocaching/CacheCache.java +++ b/main/src/cgeo/geocaching/CacheCache.java @@ -1,10 +1,18 @@ package cgeo.geocaching; import cgeo.geocaching.cgData.StorageLocation; -import cgeo.geocaching.utils.LeastRecentlyUsedCache; +import cgeo.geocaching.connector.gc.GCBase; +import cgeo.geocaching.enumerations.CacheType; +import cgeo.geocaching.geopoint.Viewport; +import cgeo.geocaching.utils.LeastRecentlyUsedMap; +import cgeo.geocaching.utils.LeastRecentlyUsedMap.RemoveHandler; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; +import java.util.HashSet; +import java.util.Set; + /** * Cache for Caches. Every cache is stored in memory while c:geo is active to * speed up the app and to minimize network request - which are slow. @@ -14,12 +22,15 @@ import org.apache.commons.lang3.StringUtils; public class CacheCache { private static final int MAX_CACHED_CACHES = 1000; - final private LeastRecentlyUsedCache<String, cgCache> cachesCache; + final private LeastRecentlyUsedMap<String, cgCache> cachesCache; + final private RemoveHandler<cgCache> removeHandler; private static CacheCache instance = null; private CacheCache() { - cachesCache = new LeastRecentlyUsedCache<String, cgCache>(MAX_CACHED_CACHES); + cachesCache = new LeastRecentlyUsedMap.LruCache<String, cgCache>(MAX_CACHED_CACHES); + removeHandler = new CacheRemoveHandler(); + cachesCache.setRemoveHandler(removeHandler); } public static CacheCache getInstance() { @@ -74,9 +85,33 @@ public class CacheCache { return cachesCache.get(geocode); } + public Set<String> getInViewport(final Viewport viewport, final CacheType cacheType) { + final Set<String> geocodes = new HashSet<String>(); + for (final cgCache cache : cachesCache.values()) { + if (cache.getCoords() == null) { + // FIXME: this kludge must be removed, it is only present to help us debug the cases where + // caches contain null coordinates. + Log.e("CacheCache.getInViewport: got cache with null coordinates: " + cache.getGeocode()); + continue; + } + if ((CacheType.ALL == cacheType || cache.getType() == cacheType) && viewport.contains(cache)) { + geocodes.add(cache.getGeocode()); + } + } + return geocodes; + } + @Override public String toString() { return StringUtils.join(cachesCache.keySet(), ' '); } + private class CacheRemoveHandler implements RemoveHandler<cgCache> { + + @Override + public void onRemove(cgCache removed) { + GCBase.removeFromTileCache(removed.getCoords()); + } + } + } diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java index de754b9..847d04c 100644 --- a/main/src/cgeo/geocaching/CacheDetailActivity.java +++ b/main/src/cgeo/geocaching/CacheDetailActivity.java @@ -7,6 +7,7 @@ import cgeo.geocaching.apps.cache.GeneralAppsFactory; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.IConnector; +import cgeo.geocaching.connector.gc.GCParser; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.LogType; @@ -15,7 +16,6 @@ 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; @@ -39,6 +39,8 @@ import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.graphics.Bitmap; import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; @@ -219,9 +221,9 @@ public class CacheDetailActivity extends AbstractActivity { String uriQuery = uri.getQuery(); if (uriQuery != null) { - Log.i(Settings.tag, "Opening URI: " + uriHost + uriPath + "?" + uriQuery); + Log.i("Opening URI: " + uriHost + uriPath + "?" + uriQuery); } else { - Log.i(Settings.tag, "Opening URI: " + uriHost + uriPath); + Log.i("Opening URI: " + uriHost + uriPath); } if (uriHost.contains("geocaching.com")) { @@ -580,7 +582,7 @@ public class CacheDetailActivity extends AbstractActivity { cache.openInBrowser(this); return true; } else if (menuItem == MENU_CACHES_AROUND) { - cachesAround(); + cgeocaches.startActivityCachesAround(this, cache.getCoords()); return true; } else if (menuItem == MENU_CALENDAR) { addToCalendarWithIntent(); @@ -607,7 +609,7 @@ public class CacheDetailActivity extends AbstractActivity { private class LoadCacheHandler extends CancellableHandler { @Override public void handleRegularMessage(final Message msg) { - if (cgBase.UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) { + if (UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) { updateStatusMsg((String) msg.obj); } else { if (search == null) { @@ -743,7 +745,7 @@ public class CacheDetailActivity extends AbstractActivity { cacheDistanceView.setText(dist.toString()); cacheDistanceView.bringToFront(); } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); + Log.w("Failed to update location."); } } } @@ -773,25 +775,43 @@ public class CacheDetailActivity extends AbstractActivity { @Override public void run() { - search = cgBase.searchByGeocode(geocode, StringUtils.isBlank(geocode) ? guid : null, 0, false, handler); + search = cgCache.searchByGeocode(geocode, StringUtils.isBlank(geocode) ? guid : null, 0, false, handler); handler.sendMessage(Message.obtain()); } } /** - * Starts activity to search for caches near this cache. + * 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. * - * Also finishes this activity. + * @param context + * The application's environment. + * @param action + * The Intent action to check for availability. + * @param uri + * The Intent URI to check for availability. + * + * @return True if an Intent with the specified action can be sent and + * responded to, false otherwise. */ - private void cachesAround() { - cgeocaches.startActivityCachesAround(this, cache.getCoords()); - - finish(); + private static boolean isIntentAvailable(Context context, String action, Uri uri) { + final PackageManager packageManager = context.getPackageManager(); + final Intent intent; + if (uri == null) { + intent = new Intent(action); + } else { + intent = new Intent(action, uri); + } + List<ResolveInfo> list = packageManager.queryIntentActivities(intent, + PackageManager.MATCH_DEFAULT_ONLY); + return list.size() > 0; } private void addToCalendarWithIntent() { - final boolean calendarAddOnAvailable = cgBase.isIntentAvailable(this, ICalendar.INTENT, Uri.parse(ICalendar.URI_SCHEME + "://" + ICalendar.URI_HOST)); + final boolean calendarAddOnAvailable = isIntentAvailable(this, ICalendar.INTENT, Uri.parse(ICalendar.URI_SCHEME + "://" + ICalendar.URI_HOST)); if (calendarAddOnAvailable) { final Parameters params = new Parameters( @@ -832,25 +852,6 @@ public class CacheDetailActivity extends AbstractActivity { } /** - * Creates a {@link List} of all coordinates (cache and waypoints) for the current cache. - * - * @return A {@link List} of all coordinates - */ - public List<IWaypoint> getCoordinates() { - List<IWaypoint> coordinates = new ArrayList<IWaypoint>(); - - // cache - coordinates.add(cache); - - // waypoints - if (cache.hasWaypoints()) { - coordinates.addAll(cache.getWaypoints()); - } - - return coordinates; - } - - /** * Tries to navigate to the {@link cgCache} of this activity. */ private void startDefaultNavigation() { @@ -1038,7 +1039,7 @@ public class CacheDetailActivity extends AbstractActivity { ((ViewPager) container).addView(view, 0); } } catch (Exception e) { - Log.e(Settings.tag, "ViewPagerAdapter.instantiateItem ", e); + Log.e("ViewPagerAdapter.instantiateItem ", e); } return view; @@ -1157,7 +1158,7 @@ public class CacheDetailActivity extends AbstractActivity { } /** - * lazy-creates the layout holding the icons of the chaches attributes + * lazy-creates the layout holding the icons of the caches attributes * and makes it visible */ private void showAttributeIcons(LinearLayout attribBox, int parentWidth) { @@ -1175,7 +1176,7 @@ public class CacheDetailActivity extends AbstractActivity { } /** - * lazy-creates the layout holding the discriptions of the chaches attributes + * lazy-creates the layout holding the descriptions of the caches attributes * and makes it visible */ private void showAttributeDescriptions(LinearLayout attribBox) { @@ -1457,7 +1458,7 @@ public class CacheDetailActivity extends AbstractActivity { if (cache.getHiddenDate() != null) { long time = cache.getHiddenDate().getTime(); if (time > 0) { - String dateString = cgBase.formatFullDate(time); + String dateString = Formatter.formatFullDate(time); if (cache.isEventCache()) { dateString = DateUtils.formatDateTime(cgeoapplication.getInstance().getBaseContext(), time, DateUtils.FORMAT_SHOW_WEEKDAY) + ", " + dateString; } @@ -1556,7 +1557,7 @@ public class CacheDetailActivity extends AbstractActivity { private class StoreCacheHandler extends CancellableHandler { @Override public void handleRegularMessage(Message msg) { - if (cgBase.UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) { + if (UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) { updateStatusMsg((String) msg.obj); } else { storeThread = null; @@ -1574,7 +1575,7 @@ public class CacheDetailActivity extends AbstractActivity { private class RefreshCacheHandler extends CancellableHandler { @Override public void handleRegularMessage(Message msg) { - if (cgBase.UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) { + if (UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) { updateStatusMsg((String) msg.obj); } else { refreshThread = null; @@ -1658,7 +1659,7 @@ public class CacheDetailActivity extends AbstractActivity { @Override public void run() { - cgBase.refreshCache(CacheDetailActivity.this, cache.getGeocode(), cache.getListId(), handler); + cache.refresh(CacheDetailActivity.this, cache.getListId(), handler); handler.sendEmptyMessage(0); } @@ -1688,7 +1689,7 @@ public class CacheDetailActivity extends AbstractActivity { @Override public void run() { - cgBase.dropCache(cache, handler); + cache.drop(handler); } } @@ -1744,7 +1745,7 @@ public class CacheDetailActivity extends AbstractActivity { @Override public void run() { - handler.sendEmptyMessage(cgBase.addToWatchlist(cache)); + handler.sendEmptyMessage(GCParser.addToWatchlist(cache)); } } @@ -1758,7 +1759,7 @@ public class CacheDetailActivity extends AbstractActivity { @Override public void run() { - handler.sendEmptyMessage(cgBase.removeFromWatchlist(cache)); + handler.sendEmptyMessage(GCParser.removeFromWatchlist(cache)); } } @@ -1845,9 +1846,7 @@ public class CacheDetailActivity extends AbstractActivity { private class PreviewMapTask extends AsyncTask<Void, Void, BitmapDrawable> { @Override - protected BitmapDrawable doInBackground(Void... params) { - BitmapDrawable image = null; - + protected BitmapDrawable doInBackground(Void... parameters) { try { final String latlonMap = cache.getCoords().format(GeopointFormatter.Format.LAT_LON_DECDEGREE_COMMA); @@ -1858,15 +1857,15 @@ 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 = Network.urlencode_rfc3986("http://cgeo.carnero.cc/_markers/my_location_mdpi.png"); + final String markerUrl = "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"); + final Parameters params = new Parameters("zoom", "15", "size", width + "x" + height, "maptype", "roadmap", "markers", "icon:" + markerUrl + "|shadow:false|" + latlonMap, "sensor", "false"); + return mapGetter.getDrawable("http://maps.google.com/maps/api/staticmap?" + params); } catch (Exception e) { - Log.w(Settings.tag, "CacheDetailActivity.PreviewMapTask", e); + Log.w("CacheDetailActivity.PreviewMapTask", e); + return null; } - - return image; } @Override @@ -2190,7 +2189,7 @@ public class CacheDetailActivity extends AbstractActivity { } } - view.setAdapter(new ArrayAdapter<cgLog>(CacheDetailActivity.this, R.layout.cacheview_logs_item, cache.getLogs(allLogs)) { + view.setAdapter(new ArrayAdapter<LogEntry>(CacheDetailActivity.this, R.layout.cacheview_logs_item, cache.getLogs(allLogs)) { final UserActionsClickListener userActionsClickListener = new UserActionsClickListener(); final DecryptTextClickListener decryptTextClickListener = new DecryptTextClickListener(); @@ -2206,10 +2205,10 @@ public class CacheDetailActivity extends AbstractActivity { rowView.setTag(holder); } - final cgLog log = getItem(position); + final LogEntry log = getItem(position); if (log.date > 0) { - holder.date.setText(cgBase.formatShortDate(log.date)); + holder.date.setText(Formatter.formatShortDate(log.date)); holder.date.setVisibility(View.VISIBLE); } else { holder.date.setVisibility(View.GONE); @@ -2239,10 +2238,10 @@ public class CacheDetailActivity extends AbstractActivity { } // images - if (CollectionUtils.isNotEmpty(log.logImages)) { + if (log.hasLogImages()) { List<String> titles = new ArrayList<String>(5); - for (cgImage image : log.logImages) { + for (cgImage image : log.getLogImages()) { if (StringUtils.isNotBlank(image.getTitle())) { titles.add(image.getTitle()); } @@ -2256,7 +2255,7 @@ public class CacheDetailActivity extends AbstractActivity { holder.images.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - cgeoimages.startActivityLogImages(CacheDetailActivity.this, cache.getGeocode(), new ArrayList<cgImage>(log.logImages)); + cgeoimages.startActivityLogImages(CacheDetailActivity.this, cache.getGeocode(), new ArrayList<cgImage>(log.getLogImages())); } }); } else { @@ -2368,7 +2367,7 @@ public class CacheDetailActivity extends AbstractActivity { // info final List<String> infoTextList = new ArrayList<String>(3); - if (WaypointType.ALL_TYPES_EXCEPT_OWN.containsKey(wpt.getWaypointType())) { + if (WaypointType.ALL_TYPES_EXCEPT_OWN.contains(wpt.getWaypointType())) { infoTextList.add(wpt.getWaypointType().getL10n()); } if (cgWaypoint.PREFIX_OWN.equalsIgnoreCase(wpt.getPrefix())) { @@ -2506,4 +2505,18 @@ public class CacheDetailActivity extends AbstractActivity { return view; } } + + public static void startActivity(final Context context, final String geocode, final String cacheName) { + final Intent cachesIntent = new Intent(context, CacheDetailActivity.class); + cachesIntent.putExtra("geocode", geocode); + cachesIntent.putExtra("name", cacheName); + context.startActivity(cachesIntent); + } + + public static void startActivityGuid(final Context context, final String guid, final String cacheName) { + final Intent cacheIntent = new Intent(context, CacheDetailActivity.class); + cacheIntent.putExtra("guid", guid); + cacheIntent.putExtra("name", cacheName); + context.startActivity(cacheIntent); + } } diff --git a/main/src/cgeo/geocaching/Destination.java b/main/src/cgeo/geocaching/Destination.java new file mode 100644 index 0000000..441e959 --- /dev/null +++ b/main/src/cgeo/geocaching/Destination.java @@ -0,0 +1,44 @@ +package cgeo.geocaching; + +import cgeo.geocaching.geopoint.Geopoint; + +public final class Destination implements ICoordinates { + + final private long id; + final private long date; + final private Geopoint coords; + + public Destination(long id, long date, final Geopoint coords) { + this.id = id; + this.date = date; + this.coords = coords; + } + + public Destination(final Geopoint coords) { + this(0, System.currentTimeMillis(), coords); + } + + public long getDate() { + return date; + } + + @Override + public Geopoint getCoords() { + return coords; + } + + @Override + public int hashCode() { + return coords.hashCode(); + } + + @Override + public boolean equals(final Object obj) { + return obj != null && obj instanceof Destination && ((Destination) obj).coords.equals(coords); + } + + public long getId() { + return id; + } + +} diff --git a/main/src/cgeo/geocaching/IBasicCache.java b/main/src/cgeo/geocaching/IBasicCache.java index 5e67b2d..195572b 100644 --- a/main/src/cgeo/geocaching/IBasicCache.java +++ b/main/src/cgeo/geocaching/IBasicCache.java @@ -11,7 +11,7 @@ import cgeo.geocaching.enumerations.CacheType; * @author blafoo * */ -public interface IBasicCache extends ILogable { +public interface IBasicCache extends ILogable, ICoordinates { public abstract String getGuid(); diff --git a/main/src/cgeo/geocaching/ICache.java b/main/src/cgeo/geocaching/ICache.java index b6a809f..dccdb85 100644 --- a/main/src/cgeo/geocaching/ICache.java +++ b/main/src/cgeo/geocaching/ICache.java @@ -28,16 +28,6 @@ public interface ICache extends IBasicCache { public String getOwnerReal(); /** - * @return Latitude, e.g. N 52ยฐ 12.345 - */ - public String getLatitude(); - - /** - * @return Longitude, e.g. E 9ยฐ 34.567 - */ - public String getLongitude(); - - /** * @return true if the user is the owner of the cache, false else */ public boolean isOwn(); diff --git a/main/src/cgeo/geocaching/ICoordinates.java b/main/src/cgeo/geocaching/ICoordinates.java new file mode 100644 index 0000000..b70e4ac --- /dev/null +++ b/main/src/cgeo/geocaching/ICoordinates.java @@ -0,0 +1,9 @@ +package cgeo.geocaching; + +import cgeo.geocaching.geopoint.Geopoint; + +public interface ICoordinates { + + public abstract Geopoint getCoords(); + +} diff --git a/main/src/cgeo/geocaching/IWaypoint.java b/main/src/cgeo/geocaching/IWaypoint.java index 3e26052..ad12d48 100644 --- a/main/src/cgeo/geocaching/IWaypoint.java +++ b/main/src/cgeo/geocaching/IWaypoint.java @@ -4,18 +4,15 @@ package cgeo.geocaching; import cgeo.geocaching.enumerations.WaypointType; -import cgeo.geocaching.geopoint.Geopoint; /** * @author blafoo * */ -public interface IWaypoint extends ILogable { +public interface IWaypoint extends ILogable, ICoordinates { public abstract int getId(); - public abstract Geopoint getCoords(); - public abstract WaypointType getWaypointType(); public abstract String getCoordType(); diff --git a/main/src/cgeo/geocaching/LogEntry.java b/main/src/cgeo/geocaching/LogEntry.java new file mode 100644 index 0000000..3f6ed74 --- /dev/null +++ b/main/src/cgeo/geocaching/LogEntry.java @@ -0,0 +1,69 @@ +package cgeo.geocaching; + +import cgeo.geocaching.enumerations.LogType; + +import org.apache.commons.collections.CollectionUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public final class LogEntry { + /** + * avoid creating new empty lists all the time using this constant. We could also return Collections.EMPTY_LIST + * using a cast, but that might trigger static code analysis tools. + */ + private static final List<cgImage> EMPTY_LIST = Collections.emptyList(); + public int id = 0; + public LogType type = LogType.LOG_NOTE; // note + public String author = ""; + public String log = ""; + public long date = 0; + public int found = -1; + /** Friend's log entry */ + public boolean friend = false; + private List<cgImage> logImages = null; + public String cacheName = ""; // used for trackables + public String cacheGuid = ""; // used for trackables + + @Override + public int hashCode() { + return (int) date * type.hashCode() * author.hashCode() * log.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof LogEntry)) { + return false; + } + final LogEntry otherLog = (LogEntry) obj; + return date == otherLog.date && + type == otherLog.type && + author.compareTo(otherLog.author) == 0 && + log.compareTo(otherLog.log) == 0; + } + + public void addLogImage(final cgImage image) { + if (logImages == null) { + logImages = new ArrayList<cgImage>(); + } + logImages.add(image); + } + + /** + * @return the log images or an empty list, never <code>null</code> + */ + public List<cgImage> getLogImages() { + if (logImages == null) { + return EMPTY_LIST; + } + return logImages; + } + + public boolean hasLogImages() { + return CollectionUtils.isNotEmpty(logImages); + } +} diff --git a/main/src/cgeo/geocaching/SearchResult.java b/main/src/cgeo/geocaching/SearchResult.java index e7c9a88..2e56c7c 100644 --- a/main/src/cgeo/geocaching/SearchResult.java +++ b/main/src/cgeo/geocaching/SearchResult.java @@ -1,5 +1,6 @@ package cgeo.geocaching; +import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LoadFlags.LoadFlag; @@ -7,7 +8,6 @@ import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.gcvote.GCVote; -import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import android.os.Parcel; @@ -129,7 +129,7 @@ public class SearchResult implements Parcelable { } public void setViewstates(String[] viewstates) { - if (cgBase.isEmpty(viewstates)) { + if (Login.isEmpty(viewstates)) { return; } @@ -201,14 +201,8 @@ public class SearchResult implements Parcelable { return cgeoapplication.getInstance().saveCache(cache, EnumSet.of(SaveFlag.SAVE_CACHE)); } - /** Add the cache geocodes to the search and store them in the CacheCache */ - public void addCaches(final Set<cgCache> caches) { - if (CollectionUtils.isEmpty(caches)) { - return; - } - - for (final cgCache cache : caches) { - addCache(cache); - } + public boolean isEmpty() { + return geocodes.isEmpty(); } + } diff --git a/main/src/cgeo/geocaching/Settings.java b/main/src/cgeo/geocaching/Settings.java index 76d185e..03427c5 100644 --- a/main/src/cgeo/geocaching/Settings.java +++ b/main/src/cgeo/geocaching/Settings.java @@ -5,17 +5,19 @@ import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.maps.MapProviderFactory; import cgeo.geocaching.maps.interfaces.MapProvider; +import cgeo.geocaching.maps.mapsforge.MapsforgeMapProvider; import cgeo.geocaching.utils.CryptUtils; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; -import org.mapsforge.android.maps.MapDatabase; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.res.Configuration; import android.content.res.Resources; +import android.preference.PreferenceManager; import java.util.Locale; @@ -82,9 +84,9 @@ public final class Settings { private static final String KEY_DEBUG = "debug"; private static final String KEY_HIDE_LIVE_MAP_HINT = "hidelivemaphint"; private static final String KEY_LIVE_MAP_HINT_SHOW_COUNT = "livemaphintshowcount"; + private static final String KEY_SETTINGS_VERSION = "settingsversion"; private final static int unitsMetric = 1; - private final static int unitsImperial = 2; // twitter api keys private final static String keyConsumerPublic = CryptUtils.rot13("ESnsCvAv3kEupF1GCR3jGj"); @@ -110,18 +112,14 @@ public final class Settings { } } - // usable values - public static final String tag = "cgeo"; - - /** Name of the preferences file */ - public static final String preferences = "cgeo.pref"; - - private static final SharedPreferences sharedPrefs = cgeoapplication.getInstance().getSharedPreferences(Settings.preferences, Context.MODE_PRIVATE); private static String username = null; private static String password = null; - // Debug settings are accessed often enough to be cached - private static Boolean cachedDebug = sharedPrefs.getBoolean(KEY_DEBUG, false); + private static final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(cgeoapplication.getInstance().getBaseContext()); + static { + migrateSettings(); + Log.setDebugUnsaved(sharedPrefs.getBoolean(KEY_DEBUG, false)); + } // maps private static MapProvider mapProvider = null; @@ -130,6 +128,77 @@ public final class Settings { // this class is not to be instantiated; } + private static void migrateSettings() { + // migrate from non standard file location and integer based boolean types + if (sharedPrefs.getInt(KEY_SETTINGS_VERSION, 0) < 1) { + final String oldPreferencesName = "cgeo.pref"; + final SharedPreferences old = cgeoapplication.getInstance().getSharedPreferences(oldPreferencesName, Context.MODE_PRIVATE); + final Editor e = sharedPrefs.edit(); + + e.putString(KEY_TEMP_TOKEN_SECRET, old.getString(KEY_TEMP_TOKEN_SECRET, null)); + e.putString(KEY_TEMP_TOKEN_PUBLIC, old.getString(KEY_TEMP_TOKEN_PUBLIC, null)); + e.putBoolean(KEY_HELP_SHOWN, old.getInt(KEY_HELP_SHOWN, 0) != 0); + e.putFloat(KEY_ANYLONGITUDE, old.getFloat(KEY_ANYLONGITUDE, 0)); + e.putFloat(KEY_ANYLATITUDE, old.getFloat(KEY_ANYLATITUDE, 0)); + e.putBoolean(KEY_PUBLICLOC, 0 != old.getInt(KEY_PUBLICLOC, 0)); + e.putBoolean(KEY_USE_OFFLINEMAPS, 0 != old.getInt(KEY_USE_OFFLINEMAPS, 1)); + e.putBoolean(KEY_USE_OFFLINEWPMAPS, 0 != old.getInt(KEY_USE_OFFLINEWPMAPS, 0)); + e.putString(KEY_WEB_DEVICE_CODE, old.getString(KEY_WEB_DEVICE_CODE, null)); + e.putString(KEY_WEBDEVICE_NAME, old.getString(KEY_WEBDEVICE_NAME, null)); + e.putBoolean(KEY_MAP_LIVE, old.getInt(KEY_MAP_LIVE, 1) != 0); + e.putInt(KEY_MAP_SOURCE, old.getInt(KEY_MAP_SOURCE, 0)); + e.putBoolean(KEY_USE_TWITTER, 0 != old.getInt(KEY_USE_TWITTER, 0)); + e.putBoolean(KEY_SHOW_ADDRESS, 0 != old.getInt(KEY_SHOW_ADDRESS, 1)); + e.putBoolean(KEY_SHOW_CAPTCHA, old.getBoolean(KEY_SHOW_CAPTCHA, false)); + e.putBoolean(KEY_MAP_TRAIL, old.getInt(KEY_MAP_TRAIL, 1) != 0); + e.putInt(KEY_LAST_MAP_ZOOM, old.getInt(KEY_LAST_MAP_ZOOM, 14)); + e.putBoolean(KEY_LIVE_LIST, 0 != old.getInt(KEY_LIVE_LIST, 1)); + e.putBoolean(KEY_METRIC_UNITS, old.getInt(KEY_METRIC_UNITS, unitsMetric) == unitsMetric); + e.putBoolean(KEY_SKIN, old.getInt(KEY_SKIN, 0) != 0); + e.putInt(KEY_LAST_USED_LIST, old.getInt(KEY_LAST_USED_LIST, StoredList.STANDARD_LIST_ID)); + e.putString(KEY_CACHE_TYPE, old.getString(KEY_CACHE_TYPE, CacheType.ALL.id)); + e.putString(KEY_TWITTER_TOKEN_SECRET, old.getString(KEY_TWITTER_TOKEN_SECRET, null)); + e.putString(KEY_TWITTER_TOKEN_PUBLIC, old.getString(KEY_TWITTER_TOKEN_PUBLIC, null)); + e.putInt(KEY_VERSION, old.getInt(KEY_VERSION, 0)); + e.putBoolean(KEY_LOAD_DESCRIPTION, 0 != old.getInt(KEY_LOAD_DESCRIPTION, 0)); + e.putBoolean(KEY_RATING_WANTED, old.getBoolean(KEY_RATING_WANTED, true)); + e.putBoolean(KEY_ELEVATION_WANTED, old.getBoolean(KEY_ELEVATION_WANTED, true)); + e.putBoolean(KEY_FRIENDLOGS_WANTED, old.getBoolean(KEY_FRIENDLOGS_WANTED, true)); + e.putBoolean(KEY_USE_ENGLISH, old.getBoolean(KEY_USE_ENGLISH, false)); + e.putBoolean(KEY_USE_COMPASS, 0 != old.getInt(KEY_USE_COMPASS, 1)); + e.putBoolean(KEY_AUTO_VISIT_TRACKABLES, old.getBoolean(KEY_AUTO_VISIT_TRACKABLES, false)); + e.putBoolean(KEY_AUTO_INSERT_SIGNATURE, old.getBoolean(KEY_AUTO_INSERT_SIGNATURE, false)); + e.putInt(KEY_ALTITUDE_CORRECTION, old.getInt(KEY_ALTITUDE_CORRECTION, 0)); + e.putBoolean(KEY_USE_GOOGLE_NAVIGATION, 0 != old.getInt(KEY_USE_GOOGLE_NAVIGATION, 1)); + e.putBoolean(KEY_STORE_LOG_IMAGES, old.getBoolean(KEY_STORE_LOG_IMAGES, false)); + e.putBoolean(KEY_EXCLUDE_DISABLED, 0 != old.getInt(KEY_EXCLUDE_DISABLED, 0)); + e.putBoolean(KEY_EXCLUDE_OWN, 0 != old.getInt(KEY_EXCLUDE_OWN, 0)); + e.putString(KEY_MAPFILE, old.getString(KEY_MAPFILE, null)); + e.putString(KEY_SIGNATURE, old.getString(KEY_SIGNATURE, null)); + e.putString(KEY_GCVOTE_PASSWORD, old.getString(KEY_GCVOTE_PASSWORD, null)); + e.putString(KEY_PASSWORD, old.getString(KEY_PASSWORD, null)); + e.putString(KEY_USERNAME, old.getString(KEY_USERNAME, null)); + e.putString(KEY_MEMBER_STATUS, old.getString(KEY_MEMBER_STATUS, "")); + e.putInt(KEY_COORD_INPUT_FORMAT, old.getInt(KEY_COORD_INPUT_FORMAT, 0)); + e.putBoolean(KEY_LOG_OFFLINE, old.getBoolean(KEY_LOG_OFFLINE, false)); + e.putBoolean(KEY_LOAD_DIRECTION_IMG, old.getBoolean(KEY_LOAD_DIRECTION_IMG, true)); + e.putString(KEY_GC_CUSTOM_DATE, old.getString(KEY_GC_CUSTOM_DATE, null)); + e.putInt(KEY_SHOW_WAYPOINTS_THRESHOLD, old.getInt(KEY_SHOW_WAYPOINTS_THRESHOLD, 0)); + e.putString(KEY_COOKIE_STORE, old.getString(KEY_COOKIE_STORE, null)); + e.putBoolean(KEY_OPEN_LAST_DETAILS_PAGE, old.getBoolean(KEY_OPEN_LAST_DETAILS_PAGE, false)); + e.putInt(KEY_LAST_DETAILS_PAGE, old.getInt(KEY_LAST_DETAILS_PAGE, 1)); + e.putInt(KEY_DEFAULT_NAVIGATION_TOOL, old.getInt(KEY_DEFAULT_NAVIGATION_TOOL, 0)); + e.putInt(KEY_DEFAULT_NAVIGATION_TOOL_2, old.getInt(KEY_DEFAULT_NAVIGATION_TOOL_2, 0)); + e.putInt(KEY_LIVE_MAP_STRATEGY, old.getInt(KEY_LIVE_MAP_STRATEGY, Strategy.AUTO.id)); + e.putBoolean(KEY_DEBUG, old.getBoolean(KEY_DEBUG, false)); + e.putBoolean(KEY_HIDE_LIVE_MAP_HINT, old.getInt(KEY_HIDE_LIVE_MAP_HINT, 0) != 0); + e.putInt(KEY_LIVE_MAP_HINT_SHOW_COUNT, old.getInt(KEY_LIVE_MAP_HINT_SHOW_COUNT, 0)); + + e.putInt(KEY_SETTINGS_VERSION, 1) ; // mark migrated + e.commit(); + } + } + public static void setLanguage(boolean useEnglish) { final Configuration config = new Configuration(); config.locale = useEnglish ? new Locale("en") : Locale.getDefault(); @@ -315,7 +384,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_MAP_LIVE, live ? 1 : 0); + edit.putBoolean(KEY_MAP_LIVE, live); } }); } @@ -371,15 +440,8 @@ public final class Settings { return commitResult; } - public static boolean isValidMapFile() { - return checkMapfile(getMapFile()); - } - - private static boolean checkMapfile(final String mapFileIn) { - if (null == mapFileIn) { - return false; - } - return MapDatabase.isValidMapFile(mapFileIn); + public static boolean isValidMapFile(final String mapFileIn) { + return MapsforgeMapProvider.isValidMapFile(mapFileIn); } public static coordInputFormatEnum getCoordInputFormat() { @@ -443,7 +505,7 @@ public final class Settings { } public static boolean isExcludeMyCaches() { - return 0 != sharedPrefs.getInt(KEY_EXCLUDE_OWN, 0); + return sharedPrefs.getBoolean(KEY_EXCLUDE_OWN, false); } /** @@ -463,7 +525,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_EXCLUDE_OWN, exclude ? 1 : 0); + edit.putBoolean(KEY_EXCLUDE_OWN, exclude); } }); } @@ -483,7 +545,7 @@ public final class Settings { } public static boolean isShowAddress() { - return 0 != sharedPrefs.getInt(KEY_SHOW_ADDRESS, 1); + return sharedPrefs.getBoolean(KEY_SHOW_ADDRESS, true); } public static void setShowAddress(final boolean showAddress) { @@ -491,7 +553,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_SHOW_ADDRESS, showAddress ? 1 : 0); + edit.putBoolean(KEY_SHOW_ADDRESS, showAddress); } }); } @@ -511,7 +573,7 @@ public final class Settings { } public static boolean isExcludeDisabledCaches() { - return 0 != sharedPrefs.getInt(KEY_EXCLUDE_DISABLED, 0); + return sharedPrefs.getBoolean(KEY_EXCLUDE_DISABLED, false); } public static void setExcludeDisabledCaches(final boolean exclude) { @@ -519,13 +581,13 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_EXCLUDE_DISABLED, exclude ? 1 : 0); + edit.putBoolean(KEY_EXCLUDE_DISABLED, exclude); } }); } public static boolean isStoreOfflineMaps() { - return 0 != sharedPrefs.getInt(KEY_USE_OFFLINEMAPS, 1); + return sharedPrefs.getBoolean(KEY_USE_OFFLINEMAPS, true); } public static void setStoreOfflineMaps(final boolean offlineMaps) { @@ -533,13 +595,13 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_USE_OFFLINEMAPS, offlineMaps ? 1 : 0); + edit.putBoolean(KEY_USE_OFFLINEMAPS, offlineMaps); } }); } public static boolean isStoreOfflineWpMaps() { - return 0 != sharedPrefs.getInt(KEY_USE_OFFLINEWPMAPS, 1); + return sharedPrefs.getBoolean(KEY_USE_OFFLINEWPMAPS, false); } public static void setStoreOfflineWpMaps(final boolean offlineMaps) { @@ -547,7 +609,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_USE_OFFLINEWPMAPS, offlineMaps ? 1 : 0); + edit.putBoolean(KEY_USE_OFFLINEWPMAPS, offlineMaps); } }); } @@ -567,7 +629,7 @@ public final class Settings { } public static boolean isUseGoogleNavigation() { - return 0 != sharedPrefs.getInt(KEY_USE_GOOGLE_NAVIGATION, 1); + return sharedPrefs.getBoolean(KEY_USE_GOOGLE_NAVIGATION, true); } public static void setUseGoogleNavigation(final boolean useGoogleNavigation) { @@ -575,13 +637,13 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_USE_GOOGLE_NAVIGATION, useGoogleNavigation ? 1 : 0); + edit.putBoolean(KEY_USE_GOOGLE_NAVIGATION, useGoogleNavigation); } }); } public static boolean isAutoLoadDescription() { - return 0 != sharedPrefs.getInt(KEY_LOAD_DESCRIPTION, 0); + return sharedPrefs.getBoolean(KEY_LOAD_DESCRIPTION, false); } public static void setAutoLoadDesc(final boolean autoLoad) { @@ -589,7 +651,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_LOAD_DESCRIPTION, autoLoad ? 1 : 0); + edit.putBoolean(KEY_LOAD_DESCRIPTION, autoLoad); } }); } @@ -641,7 +703,7 @@ public final class Settings { } public static boolean isLiveList() { - return 0 != sharedPrefs.getInt(KEY_LIVE_LIST, 1); + return sharedPrefs.getBoolean(KEY_LIVE_LIST, true); } public static void setLiveList(final boolean liveList) { @@ -649,13 +711,13 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_LIVE_LIST, liveList ? 1 : 0); + edit.putBoolean(KEY_LIVE_LIST, liveList); } }); } public static boolean isPublicLoc() { - return 0 != sharedPrefs.getInt(KEY_PUBLICLOC, 0); + return sharedPrefs.getBoolean(KEY_PUBLICLOC, false); } public static void setPublicLoc(final boolean publicLocation) { @@ -663,7 +725,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_PUBLICLOC, publicLocation ? 1 : 0); + edit.putBoolean(KEY_PUBLICLOC, publicLocation); } }); } @@ -697,7 +759,7 @@ public final class Settings { } public static boolean isUseMetricUnits() { - return sharedPrefs.getInt(KEY_METRIC_UNITS, unitsMetric) == unitsMetric; + return sharedPrefs.getBoolean(KEY_METRIC_UNITS, true); } public static void setUseMetricUnits(final boolean metric) { @@ -705,17 +767,17 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_METRIC_UNITS, metric ? unitsMetric : unitsImperial); + edit.putBoolean(KEY_METRIC_UNITS, metric); } }); } public static boolean isLiveMap() { - return sharedPrefs.getInt(KEY_MAP_LIVE, 1) != 0; + return sharedPrefs.getBoolean(KEY_MAP_LIVE, true); } public static boolean isMapTrail() { - return sharedPrefs.getInt(KEY_MAP_TRAIL, 1) != 0; + return sharedPrefs.getBoolean(KEY_MAP_TRAIL, true); } public static void setMapTrail(final boolean showTrail) { @@ -723,7 +785,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_MAP_TRAIL, showTrail ? 1 : 0); + edit.putBoolean(KEY_MAP_TRAIL, showTrail); } }); } @@ -786,7 +848,7 @@ public final class Settings { } public static boolean isUseCompass() { - return 0 != sharedPrefs.getInt(KEY_USE_COMPASS, 1); + return sharedPrefs.getBoolean(KEY_USE_COMPASS, true); } public static void setUseCompass(final boolean useCompass) { @@ -794,13 +856,13 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_USE_COMPASS, useCompass ? 1 : 0); + edit.putBoolean(KEY_USE_COMPASS, useCompass); } }); } public static boolean isHelpShown() { - return sharedPrefs.getInt(KEY_HELP_SHOWN, 0) != 0; + return sharedPrefs.getBoolean(KEY_HELP_SHOWN, false); } public static void setHelpShown() { @@ -808,13 +870,13 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_HELP_SHOWN, 1); + edit.putBoolean(KEY_HELP_SHOWN, true); } }); } public static boolean isLightSkin() { - return sharedPrefs.getInt(KEY_SKIN, 0) != 0; + return sharedPrefs.getBoolean(KEY_SKIN, false); } public static void setLightSkin(final boolean lightSkin) { @@ -822,7 +884,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_SKIN, lightSkin ? 1 : 0); + edit.putBoolean(KEY_SKIN, lightSkin); } }); } @@ -864,6 +926,12 @@ public final class Settings { return CacheType.getById(sharedPrefs.getString(KEY_CACHE_TYPE, CacheType.ALL.id)); } + /** + * The Threshold for the showing of child waypoints + * + * @return + */ + public static int getWayPointsThreshold() { return sharedPrefs.getInt(KEY_SHOW_WAYPOINTS_THRESHOLD, 0); } @@ -879,7 +947,7 @@ public final class Settings { } public static boolean isUseTwitter() { - return 0 != sharedPrefs.getInt(KEY_USE_TWITTER, 0); + return sharedPrefs.getBoolean(KEY_USE_TWITTER, false); } public static void setUseTwitter(final boolean useTwitter) { @@ -887,7 +955,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_USE_TWITTER, useTwitter ? 1 : 0); + edit.putBoolean(KEY_USE_TWITTER, useTwitter); } }); } @@ -1023,7 +1091,7 @@ public final class Settings { public static boolean isDebug() { - return cachedDebug; + return Log.isDebug(); } public static void setDebug(final boolean debug) { @@ -1033,11 +1101,11 @@ public final class Settings { edit.putBoolean(KEY_DEBUG, debug); } }); - cachedDebug = debug; + Log.setDebugUnsaved(debug); } public static boolean getHideLiveMapHint() { - return sharedPrefs.getInt(KEY_HIDE_LIVE_MAP_HINT, 0) == 0 ? false : true; + return sharedPrefs.getBoolean(KEY_HIDE_LIVE_MAP_HINT, false); } public static void setHideLiveHint(final boolean hide) { @@ -1045,7 +1113,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_HIDE_LIVE_MAP_HINT, hide ? 1 : 0); + edit.putBoolean(KEY_HIDE_LIVE_MAP_HINT, hide); } }); } @@ -1063,4 +1131,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"; + } } diff --git a/main/src/cgeo/geocaching/StaticMapsActivity.java b/main/src/cgeo/geocaching/StaticMapsActivity.java index f9d023f..fdb6d67 100644 --- a/main/src/cgeo/geocaching/StaticMapsActivity.java +++ b/main/src/cgeo/geocaching/StaticMapsActivity.java @@ -78,7 +78,7 @@ public class StaticMapsActivity extends AbstractActivity { if (waitDialog != null) { waitDialog.dismiss(); } - Log.e(Settings.tag, "StaticMapsActivity.loadMapsHandler: " + e.toString()); + Log.e("StaticMapsActivity.loadMapsHandler: " + e.toString()); } } }; @@ -160,7 +160,7 @@ public class StaticMapsActivity extends AbstractActivity { } } } catch (Exception e) { - Log.e(Settings.tag, "StaticMapsActivity.LoadMapsThread.run.1: " + e.toString()); + Log.e("StaticMapsActivity.LoadMapsThread.run.1: " + e.toString()); } } @@ -179,14 +179,14 @@ public class StaticMapsActivity extends AbstractActivity { } } } catch (Exception e) { - Log.e(Settings.tag, "StaticMapsActivity.LoadMapsThread.run.2: " + e.toString()); + Log.e("StaticMapsActivity.LoadMapsThread.run.2: " + e.toString()); } } } loadMapsHandler.sendMessage(Message.obtain()); } catch (Exception e) { - Log.e(Settings.tag, "StaticMapsActivity.LoadMapsThread.run: " + e.toString()); + Log.e("StaticMapsActivity.LoadMapsThread.run: " + e.toString()); } } } diff --git a/main/src/cgeo/geocaching/StaticMapsProvider.java b/main/src/cgeo/geocaching/StaticMapsProvider.java index 9c17a34..fc55949 100644 --- a/main/src/cgeo/geocaching/StaticMapsProvider.java +++ b/main/src/cgeo/geocaching/StaticMapsProvider.java @@ -1,10 +1,10 @@ package cgeo.geocaching; 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 cgeo.geocaching.network.Parameters; import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; @@ -30,7 +30,7 @@ public class StaticMapsProvider { return LocalStorage.getStorageFile(geocode, "map_" + prefix + level, false, createDirs); } - private static void downloadDifferentZooms(final cgCache cache, String markerUrl, String prefix, String latlonMap, int edge, String waypoints) { + private static void downloadDifferentZooms(final cgCache cache, String markerUrl, String prefix, String latlonMap, int edge, final Parameters waypoints) { downloadMap(cache, 20, "satellite", markerUrl, prefix, 1, latlonMap, edge, waypoints); downloadMap(cache, 18, "satellite", markerUrl, prefix, 2, latlonMap, edge, waypoints); downloadMap(cache, 16, "roadmap", markerUrl, prefix, 3, latlonMap, edge, waypoints); @@ -38,13 +38,22 @@ public class StaticMapsProvider { downloadMap(cache, 11, "roadmap", markerUrl, prefix, 5, latlonMap, edge, waypoints); } - private static void downloadMap(cgCache cache, int zoom, String mapType, String markerUrl, String prefix, int level, String latlonMap, int edge, String waypoints) { - 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 = Network.request(url, null, false); + private static void downloadMap(cgCache cache, int zoom, String mapType, String markerUrl, String prefix, int level, String latlonMap, int edge, final Parameters waypoints) { + final String mapUrl = "http://maps.google.com/maps/api/staticmap"; + final Parameters params = new Parameters( + "center", latlonMap, + "zoom", String.valueOf(zoom), + "size", edge + "x" + edge, + "maptype", mapType, + "markers", "icon:" + markerUrl + '|' + latlonMap, + "sensor", "false"); + if (waypoints != null) { + params.addAll(waypoints); + } + final HttpResponse httpResponse = Network.getRequest(mapUrl, params); if (httpResponse != null) { + final File file = getMapFile(cache.getGeocode(), prefix, level, true); if (LocalStorage.saveEntityToFile(httpResponse, file)) { // Delete image if it has no contents final long fileSize = file.length(); @@ -96,7 +105,7 @@ public class StaticMapsProvider { String wpLatlonMap = waypoint.getCoords().format(Format.LAT_LON_DECDEGREE_COMMA); String wpMarkerUrl = getWpMarkerUrl(waypoint); // download map images in separate background thread for higher performance - downloadMaps(cache, wpMarkerUrl, "wp" + waypoint.getId() + "_", wpLatlonMap, edge, "", waitForResult); + downloadMaps(cache, wpMarkerUrl, "wp" + waypoint.getId() + "_", wpLatlonMap, edge, null, waitForResult); } public static void storeCacheStaticMap(cgCache cache, Activity activity, final boolean waitForResult) { @@ -106,22 +115,19 @@ public class StaticMapsProvider { private static void storeCacheStaticMap(cgCache cache, int edge, final boolean waitForResult) { final String latlonMap = cache.getCoords().format(Format.LAT_LON_DECDEGREE_COMMA); - final StringBuilder waypoints = new StringBuilder(); + final Parameters waypoints = new Parameters(); if (cache.hasWaypoints()) { for (cgWaypoint waypoint : cache.getWaypoints()) { if (waypoint.getCoords() == null) { continue; } - String wpMarkerUrl = getWpMarkerUrl(waypoint); - waypoints.append("&markers=icon%3A"); - waypoints.append(wpMarkerUrl); - waypoints.append("%7C"); - waypoints.append(waypoint.getCoords().format(Format.LAT_LON_DECDEGREE_COMMA)); + final String wpMarkerUrl = getWpMarkerUrl(waypoint); + waypoints.put("markers", "icon:" + wpMarkerUrl + "|" + waypoint.getCoords().format(Format.LAT_LON_DECDEGREE_COMMA)); } } // download map images in separate background thread for higher performance final String cacheMarkerUrl = getCacheMarkerUrl(cache); - downloadMaps(cache, cacheMarkerUrl, "", latlonMap, edge, waypoints.toString(), waitForResult); + downloadMaps(cache, cacheMarkerUrl, "", latlonMap, edge, waypoints, waitForResult); } private static int guessMinDisplaySide(Display display) { @@ -141,12 +147,12 @@ public class StaticMapsProvider { } private static void downloadMaps(final cgCache cache, final String markerUrl, final String prefix, final String latlonMap, final int edge, - final String waypoints, boolean waitForResult) { + final Parameters waypoints, boolean waitForResult) { if (waitForResult) { downloadDifferentZooms(cache, markerUrl, prefix, latlonMap, edge, waypoints); } else { - Task currentTask = new Task("getting static map") { + final Runnable currentTask = new Runnable() { @Override public void run() { downloadDifferentZooms(cache, markerUrl, prefix, latlonMap, edge, waypoints); @@ -155,7 +161,7 @@ public class StaticMapsProvider { try { pool.add(currentTask, 20, TimeUnit.SECONDS); } catch (InterruptedException e) { - Log.e(Settings.tag, "StaticMapsProvider.downloadMaps error adding task: " + e.toString()); + Log.e("StaticMapsProvider.downloadMaps error adding task: " + e.toString()); } } } @@ -168,12 +174,12 @@ public class StaticMapsProvider { type += "_disabled"; } - return Network.urlencode_rfc3986(MARKERS_URL + "marker_cache_" + type + ".png"); + return MARKERS_URL + "marker_cache_" + type + ".png"; } private static String getWpMarkerUrl(final cgWaypoint waypoint) { String type = waypoint.getWaypointType() != null ? waypoint.getWaypointType().id : null; - return Network.urlencode_rfc3986(MARKERS_URL + "marker_waypoint_" + type + ".png"); + return MARKERS_URL + "marker_waypoint_" + type + ".png"; } public static void removeWpStaticMaps(int wp_id, String geocode) { @@ -183,7 +189,7 @@ public class StaticMapsProvider { StaticMapsProvider.getMapFile(geocode, "wp" + wp_id + "_", level, false).delete(); } } catch (Exception e) { - Log.e(Settings.tag, "StaticMapsProvider.removeWpStaticMaps: " + e.toString()); + Log.e("StaticMapsProvider.removeWpStaticMaps: " + e.toString()); } } } diff --git a/main/src/cgeo/geocaching/StoredList.java b/main/src/cgeo/geocaching/StoredList.java index 3b5a47a..fc03b26 100644 --- a/main/src/cgeo/geocaching/StoredList.java +++ b/main/src/cgeo/geocaching/StoredList.java @@ -1,5 +1,19 @@ package cgeo.geocaching; +import cgeo.geocaching.activity.IAbstractActivity; +import cgeo.geocaching.utils.RunnableWithArgument; + +import org.apache.commons.lang3.StringUtils; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.res.Resources; +import android.view.View; +import android.widget.EditText; + +import java.util.ArrayList; +import java.util.List; public class StoredList { public static final int TEMPORARY_LIST_ID = 0; @@ -18,4 +32,108 @@ public class StoredList { public String getTitleAndCount() { return title + " [" + count + "]"; } + + public static class UserInterface { + private final IAbstractActivity activity; + private final cgeoapplication app; + private final Resources res; + + public UserInterface(final IAbstractActivity activity) { + this.activity = activity; + app = cgeoapplication.getInstance(); + res = app.getResources(); + } + + public void promptForListSelection(final int titleId, final RunnableWithArgument<Integer> runAfterwards) { + final List<StoredList> lists = app.getLists(); + + if (lists == null) { + return; + } + + final List<CharSequence> listsTitle = new ArrayList<CharSequence>(); + for (StoredList list : lists) { + listsTitle.add(list.getTitleAndCount()); + } + listsTitle.add("<" + res.getString(R.string.list_menu_create) + ">"); + + final CharSequence[] items = new CharSequence[listsTitle.size()]; + + AlertDialog.Builder builder = new AlertDialog.Builder((Activity) activity); + builder.setTitle(res.getString(titleId)); + builder.setItems(listsTitle.toArray(items), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialogInterface, int itemId) { + if (itemId >= lists.size()) { + // create new list on the fly + promptForListCreation(runAfterwards); + } + else { + if (runAfterwards != null) { + runAfterwards.run(lists.get(itemId).id); + } + } + } + }); + builder.create().show(); + } + + public void promptForListCreation(final RunnableWithArgument<Integer> runAfterwards) { + handleListNameInput("", R.string.list_dialog_create_title, R.string.list_dialog_create, new RunnableWithArgument<String>() { + + @Override + public void run(final String listName) { + final int newId = app.createList(listName); + + if (newId >= 10) { + activity.showToast(res.getString(R.string.list_dialog_create_ok)); + if (runAfterwards != null) { + runAfterwards.run(newId); + } + } else { + activity.showToast(res.getString(R.string.list_dialog_create_err)); + } + } + }); + } + + private void handleListNameInput(final String defaultValue, int dialogTitle, int buttonTitle, final RunnableWithArgument<String> runnable) { + final AlertDialog.Builder alert = new AlertDialog.Builder((Activity) activity); + final View view = ((Activity) activity).getLayoutInflater().inflate(R.layout.list_create_dialog, null); + final EditText input = (EditText) view.findViewById(R.id.text); + input.setText(defaultValue); + + alert.setTitle(dialogTitle); + alert.setView(view); + alert.setPositiveButton(buttonTitle, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + // remove whitespaces added by autocompletion of Android keyboard + String listName = StringUtils.trim(input.getText().toString()); + if (StringUtils.isNotBlank(listName)) { + runnable.run(listName); + } + } + }); + alert.setNegativeButton(res.getString(R.string.list_dialog_cancel), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + dialog.dismiss(); + } + }); + + alert.show(); + } + + public void promptForListRename(final int listId, final Runnable runAfterRename) { + final StoredList list = app.getList(listId); + handleListNameInput(list.title, R.string.list_dialog_rename_title, R.string.list_dialog_rename, new RunnableWithArgument<String>() { + + @Override + public void run(final String listName) { + app.renameList(listId, listName); + if (runAfterRename != null) { + runAfterRename.run(); + } + } + }); + } + } } diff --git a/main/src/cgeo/geocaching/TrackableLog.java b/main/src/cgeo/geocaching/TrackableLog.java new file mode 100644 index 0000000..8e2ad90 --- /dev/null +++ b/main/src/cgeo/geocaching/TrackableLog.java @@ -0,0 +1,18 @@ +package cgeo.geocaching; + +import cgeo.geocaching.enumerations.LogTypeTrackable; + +public final class TrackableLog { + public TrackableLog(String trackCode, String name, int id, int ctl) { + this.trackCode = trackCode; + this.name = name; + this.id = id; + this.ctl = ctl; + } + + public final int ctl; + public final int id; + public final String trackCode; + public final String name; + public LogTypeTrackable action = LogTypeTrackable.DO_NOTHING; // base.logTrackablesAction - no action +} diff --git a/main/src/cgeo/geocaching/VisitCacheActivity.java b/main/src/cgeo/geocaching/VisitCacheActivity.java index a471483..a2fde26 100644 --- a/main/src/cgeo/geocaching/VisitCacheActivity.java +++ b/main/src/cgeo/geocaching/VisitCacheActivity.java @@ -1,6 +1,8 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.connector.gc.GCParser; +import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LoadFlags.RemoveFlag; import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; @@ -8,11 +10,11 @@ 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.ui.Formatter; import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.LogTemplateProvider; import cgeo.geocaching.utils.LogTemplateProvider.LogTemplate; @@ -64,7 +66,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D private List<LogType> possibleLogTypes = new ArrayList<LogType>(); private String[] viewstates = null; private boolean gettingViewstate = true; - private List<cgTrackableLog> trackables = null; + private List<TrackableLog> trackables = null; private Calendar date = Calendar.getInstance(); private LogType typeSelected = LogType.LOG_UNKNOWN; private int attempts = 0; @@ -88,13 +90,13 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D showToast(res.getString(R.string.info_log_type_changed)); } - if (cgBase.isEmpty(viewstates) && attempts < 2) { + if (Login.isEmpty(viewstates) && attempts < 2) { final LoadDataThread thread; thread = new LoadDataThread(); thread.start(); return; - } else if (cgBase.isEmpty(viewstates) && attempts >= 2) { + } else if (Login.isEmpty(viewstates) && attempts >= 2) { showToast(res.getString(R.string.err_log_load_data)); showProgress(false); @@ -114,7 +116,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D final LinearLayout inventoryView = (LinearLayout) findViewById(R.id.inventory); inventoryView.removeAllViews(); - for (cgTrackableLog tb : trackables) { + for (TrackableLog tb : trackables) { LinearLayout inventoryItem = (LinearLayout) inflater.inflate(R.layout.visit_trackable, null); ((TextView) inventoryItem.findViewById(R.id.trackcode)).setText(tb.trackCode); @@ -370,7 +372,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D if (viewId == R.id.type) { for (final LogType typeOne : possibleLogTypes) { menu.add(viewId, typeOne.id, 0, typeOne.getL10n()); - Log.w(Settings.tag, "Adding " + typeOne + " " + typeOne.getL10n()); + Log.w("Adding " + typeOne + " " + typeOne.getL10n()); } } else if (viewId == R.id.changebutton) { final int textId = ((TextView) findViewById(viewId)).getId(); @@ -382,7 +384,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D } else { final int realViewId = ((LinearLayout) findViewById(viewId)).getId(); - for (final cgTrackableLog tb : trackables) { + for (final TrackableLog tb : trackables) { if (tb.id == realViewId) { menu.setHeaderTitle(tb.name); } @@ -419,14 +421,14 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D } tbText.setText(res.getString(logType.resourceId) + " โผ"); } - for (cgTrackableLog tb : trackables) { + for (TrackableLog tb : trackables) { tb.action = logType; } tbChanged = true; return true; } } catch (Exception e) { - Log.e(Settings.tag, "cgeovisit.onContextItemSelected: " + e.toString()); + Log.e("cgeovisit.onContextItemSelected: " + e.toString()); } } else { try { @@ -442,21 +444,21 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D return false; } - for (cgTrackableLog tb : trackables) { + for (TrackableLog tb : trackables) { if (tb.id == group) { tbChanged = true; tb.action = logType; tbText.setText(res.getString(logType.resourceId) + " โผ"); - Log.i(Settings.tag, "Trackable " + tb.trackCode + " (" + tb.name + ") has new action: #" + id); + Log.i("Trackable " + tb.trackCode + " (" + tb.name + ") has new action: #" + id); } } return true; } } catch (Exception e) { - Log.e(Settings.tag, "cgeovisit.onContextItemSelected: " + e.toString()); + Log.e("cgeovisit.onContextItemSelected: " + e.toString()); } } @@ -475,7 +477,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D possibleLogTypes = cache.getPossibleLogTypes(); - final cgLog log = app.loadLogOffline(geocode); + final LogEntry log = app.loadLogOffline(geocode); if (log != null) { typeSelected = log.type; date.setTime(new Date(log.date)); @@ -507,7 +509,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D }); final Button dateButton = (Button) findViewById(R.id.date); - dateButton.setText(cgBase.formatShortDate(date.getTime().getTime())); + dateButton.setText(Formatter.formatShortDate(date.getTime().getTime())); dateButton.setOnClickListener(new DateListener()); final EditText logView = (EditText) findViewById(R.id.log); @@ -522,7 +524,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D lastState.restore(this); } - if (cgBase.isEmpty(viewstates)) { + if (Login.isEmpty(viewstates)) { enablePostButton(false); new LoadDataThread().start(); } else { @@ -545,7 +547,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D date = dateIn; final Button dateButton = (Button) findViewById(R.id.date); - dateButton.setText(cgBase.formatShortDate(date.getTime().getTime())); + dateButton.setText(Formatter.formatShortDate(date.getTime().getTime())); } public void setType(LogType type) { @@ -609,7 +611,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D setType(typeSelected); final Button dateButton = (Button) findViewById(R.id.date); - dateButton.setText(cgBase.formatShortDate(date.getTime().getTime())); + dateButton.setText(Formatter.formatShortDate(date.getTime().getTime())); dateButton.setOnClickListener(new DateListener()); final EditText logView = (EditText) findViewById(R.id.log); @@ -656,19 +658,19 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D return; } - final String page = Network.getResponseData(Network.request("http://www.geocaching.com/seek/log.aspx", params, false, false, false)); + final String page = Network.getResponseData(Network.getRequest("http://www.geocaching.com/seek/log.aspx", params)); viewstates = Login.getViewstates(page); - trackables = cgBase.parseTrackableLog(page); + trackables = GCParser.parseTrackableLog(page); - final List<LogType> typesPre = cgBase.parseTypes(page); + final List<LogType> typesPre = GCParser.parseTypes(page); if (CollectionUtils.isNotEmpty(typesPre)) { possibleLogTypes.clear(); possibleLogTypes.addAll(typesPre); possibleLogTypes.remove(LogType.LOG_UPDATE_COORDINATES); } } catch (Exception e) { - Log.e(Settings.tag, "cgeovisit.loadData.run: " + e.toString()); + Log.e("cgeovisit.loadData.run: " + e.toString()); } loadDataHandler.sendEmptyMessage(0); @@ -695,12 +697,12 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D public StatusCode postLogFn(String log) { try { - final StatusCode status = cgBase.postLog(geocode, cacheid, viewstates, typeSelected, + final StatusCode status = GCParser.postLog(geocode, cacheid, viewstates, typeSelected, date.get(Calendar.YEAR), (date.get(Calendar.MONTH) + 1), date.get(Calendar.DATE), log, trackables); if (status == StatusCode.NO_ERROR) { - final cgLog logNow = new cgLog(); + final LogEntry logNow = new LogEntry(); logNow.author = Settings.getUsername(); logNow.date = date.getTimeInMillis(); logNow.type = typeSelected; @@ -741,7 +743,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D return status; } catch (Exception e) { - Log.e(Settings.tag, "cgeovisit.postLogFn: " + e.toString()); + Log.e("cgeovisit.postLogFn: " + e.toString()); } return StatusCode.LOG_POST_ERROR; @@ -765,7 +767,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D private class ActivityState { private final String[] viewstates; - private final List<cgTrackableLog> trackables; + private final List<TrackableLog> trackables; private final int attempts; private final List<LogType> possibleLogTypes; private final LogType typeSelected; diff --git a/main/src/cgeo/geocaching/activity/AbstractActivity.java b/main/src/cgeo/geocaching/activity/AbstractActivity.java index 8e8ad9d..8ddd21a 100644 --- a/main/src/cgeo/geocaching/activity/AbstractActivity.java +++ b/main/src/cgeo/geocaching/activity/AbstractActivity.java @@ -2,11 +2,10 @@ 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 cgeo.geocaching.network.Cookies; import android.app.Activity; import android.content.Context; @@ -85,10 +84,8 @@ public abstract class AbstractActivity extends Activity implements IAbstractActi res = this.getResources(); app = (cgeoapplication) this.getApplication(); - cgBase.initialize(app); - // Restore cookie store if needed - Network.restoreCookieStore(Settings.getCookieStore()); + Cookies.restoreCookieStore(Settings.getCookieStore()); ActivityMixin.keepScreenOn(this, keepScreenOn); } @@ -131,7 +128,7 @@ public abstract class AbstractActivity extends Activity implements IAbstractActi /** * insert text into the EditText at the current cursor position - * + * * @param editText * @param insertText * @param moveCursor diff --git a/main/src/cgeo/geocaching/activity/AbstractListActivity.java b/main/src/cgeo/geocaching/activity/AbstractListActivity.java index b3bbb3f..7af75b8 100644 --- a/main/src/cgeo/geocaching/activity/AbstractListActivity.java +++ b/main/src/cgeo/geocaching/activity/AbstractListActivity.java @@ -1,6 +1,5 @@ package cgeo.geocaching.activity; -import cgeo.geocaching.cgBase; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.compatibility.Compatibility; @@ -73,7 +72,6 @@ public abstract class AbstractListActivity extends ListActivity implements // init res = this.getResources(); app = (cgeoapplication) this.getApplication(); - cgBase.initialize(app); ActivityMixin.keepScreenOn(this, keepScreenOn); } diff --git a/main/src/cgeo/geocaching/activity/IAbstractActivity.java b/main/src/cgeo/geocaching/activity/IAbstractActivity.java index dd22cff..2503b99 100644 --- a/main/src/cgeo/geocaching/activity/IAbstractActivity.java +++ b/main/src/cgeo/geocaching/activity/IAbstractActivity.java @@ -1,8 +1,5 @@ package cgeo.geocaching.activity; -import cgeo.geocaching.cgCache; - -import android.view.Menu; import android.view.View; public interface IAbstractActivity { @@ -13,19 +10,11 @@ public interface IAbstractActivity { public void goManual(View view); - public void showProgress(final boolean show); - - public void setTheme(); - public void showToast(String text); public void showShortToast(String text); public void helpDialog(String title, String message); - public void setTitle(final String title); - - void addVisitMenu(Menu menu, cgCache cache); - public void invalidateOptionsMenuCompatible(); } diff --git a/main/src/cgeo/geocaching/apps/AbstractLocusApp.java b/main/src/cgeo/geocaching/apps/AbstractLocusApp.java index 1ccf8dc..80e2dac 100644 --- a/main/src/cgeo/geocaching/apps/AbstractLocusApp.java +++ b/main/src/cgeo/geocaching/apps/AbstractLocusApp.java @@ -1,7 +1,6 @@ package cgeo.geocaching.apps; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.enumerations.CacheSize; @@ -112,7 +111,7 @@ public abstract class AbstractLocusApp extends AbstractApp { } // create one simple point with location - final Location loc = new Location(Settings.tag); + final Location loc = new Location("cgeo"); loc.setLatitude(cache.getCoords().getLatitude()); loc.setLongitude(cache.getCoords().getLongitude()); @@ -191,7 +190,7 @@ public abstract class AbstractLocusApp extends AbstractApp { } // create one simple point with location - final Location loc = new Location(Settings.tag); + final Location loc = new Location("cgeo"); loc.setLatitude(waypoint.getCoords().getLatitude()); loc.setLongitude(waypoint.getCoords().getLongitude()); diff --git a/main/src/cgeo/geocaching/apps/cache/GeneralAppsFactory.java b/main/src/cgeo/geocaching/apps/cache/GeneralAppsFactory.java index df5e991..49db025 100644 --- a/main/src/cgeo/geocaching/apps/cache/GeneralAppsFactory.java +++ b/main/src/cgeo/geocaching/apps/cache/GeneralAppsFactory.java @@ -1,6 +1,5 @@ package cgeo.geocaching.apps.cache; -import cgeo.geocaching.Settings; import cgeo.geocaching.cgCache; import cgeo.geocaching.apps.AbstractAppFactory; import cgeo.geocaching.utils.Log; @@ -37,7 +36,7 @@ public final class GeneralAppsFactory extends AbstractAppFactory { try { return app.invoke(activity, cache); } catch (Exception e) { - Log.e(Settings.tag, "GeneralAppsFactory.onMenuItemSelected: " + e.toString()); + Log.e("GeneralAppsFactory.onMenuItemSelected: " + e.toString()); } } return false; diff --git a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java index 878bbb8..24aa693 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java @@ -1,7 +1,6 @@ package cgeo.geocaching.apps.cache.navi; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.utils.Log; @@ -32,7 +31,7 @@ class GoogleMapsApp extends AbstractPointNavigationApp { } catch (Exception e) { // nothing } - Log.i(Settings.tag, "cgBase.runExternalMap: No maps application available."); + Log.i("cgBase.runExternalMap: No maps application available."); ActivityMixin.showToast(activity, getString(R.string.err_application_no)); } diff --git a/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java index a3d335c..74141c3 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java @@ -84,8 +84,7 @@ class GoogleNavigationApp extends AbstractNavigationApp { // nothing } - Log.i(Settings.tag, - "cgBase.runNavigation: No navigation application available."); + Log.i("cgBase.runNavigation: No navigation application available."); return false; } diff --git a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java index 8bb54b7..052189a 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java @@ -19,10 +19,7 @@ import android.app.AlertDialog; import android.content.DialogInterface; import android.view.Menu; import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; import android.widget.ArrayAdapter; -import android.widget.TextView; import java.util.ArrayList; import java.util.List; @@ -66,6 +63,16 @@ public final class NavigationAppFactory extends AbstractAppFactory { * The id - used in c:geo settings */ public final int id; + + /* + * display app name in array adapter + * + * @see java.lang.Enum#toString() + */ + @Override + public String toString() { + return app.getName(); + } } /** @@ -127,24 +134,9 @@ public final class NavigationAppFactory extends AbstractAppFactory { } /* * Using an ArrayAdapter with list of NavigationAppsEnum items avoids - * handling between mapping list positions allows us to do dynamic filtering of the list based on usecase. + * handling between mapping list positions allows us to do dynamic filtering of the list based on use case. */ - final ArrayAdapter<NavigationAppsEnum> adapter = new ArrayAdapter<NavigationAppsEnum>(activity, android.R.layout.select_dialog_item, items) { - @Override - public View getView(int position, View convertView, ViewGroup parent) { - TextView textView = (TextView) super.getView(position, convertView, parent); - textView.setText(getItem(position).app.getName()); - return textView; - } - - @Override - public View getDropDownView(int position, View convertView, ViewGroup parent) { - TextView textView = (TextView) super.getDropDownView(position, convertView, parent); - textView.setText(getItem(position).app.getName()); - return textView; - } - }; - adapter.setDropDownViewResource(android.R.layout.select_dialog_item); + final ArrayAdapter<NavigationAppsEnum> adapter = new ArrayAdapter<NavigationAppsEnum>(activity, android.R.layout.select_dialog_item, items); builder.setAdapter(adapter, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { @@ -257,7 +249,7 @@ public final class NavigationAppFactory extends AbstractAppFactory { try { return app.invoke(geo, activity, cache, waypoint, destination); } catch (Exception e) { - Log.e(Settings.tag, "NavigationAppFactory.onMenuItemSelected: " + e.toString()); + Log.e("NavigationAppFactory.onMenuItemSelected: " + e.toString()); } } return false; @@ -291,14 +283,14 @@ public final class NavigationAppFactory extends AbstractAppFactory { try { app.invoke(geo, activity, cache, waypoint, destination); } catch (Exception e) { - Log.e(Settings.tag, "NavigationAppFactory.startDefaultNavigationApplication: " + e.toString()); + Log.e("NavigationAppFactory.startDefaultNavigationApplication: " + e.toString()); } } } /** * Starts the second default navigation tool if correctly set and installed or the compass app as default fallback. - * + * * @param geo * @param activity * @param cache @@ -314,14 +306,14 @@ public final class NavigationAppFactory extends AbstractAppFactory { try { app.invoke(geo, activity, cache, waypoint, destination); } catch (Exception e) { - Log.e(Settings.tag, "NavigationAppFactory.startDefaultNavigationApplication2: " + e.toString()); + Log.e("NavigationAppFactory.startDefaultNavigationApplication2: " + e.toString()); } } } /** * Returns the default navigation tool if correctly set and installed or the compass app as default fallback - * + * * @param activity * @return never <code>null</code> */ @@ -341,7 +333,7 @@ public final class NavigationAppFactory extends AbstractAppFactory { /** * Returns the second default navigation tool if correctly set and installed or the compass app as default fallback - * + * * @param activity * @return never <code>null</code> */ diff --git a/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java b/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java index a73ac4d..c8f201d 100644 --- a/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java +++ b/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java @@ -2,7 +2,6 @@ package cgeo.geocaching.apps.cachelist; import cgeo.geocaching.R; import cgeo.geocaching.SearchResult; -import cgeo.geocaching.Settings; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgGeo; import cgeo.geocaching.activity.IAbstractActivity; @@ -73,7 +72,7 @@ public final class CacheListAppFactory extends AbstractAppFactory { activity.invalidateOptionsMenuCompatible(); return result; } catch (Exception e) { - Log.e(Settings.tag, "CacheListAppFactory.onMenuItemSelected: " + e.toString()); + Log.e("CacheListAppFactory.onMenuItemSelected: " + e.toString()); } } return false; diff --git a/main/src/cgeo/geocaching/backup/CentralBackupAgent.java b/main/src/cgeo/geocaching/backup/CentralBackupAgent.java index 28b9e4b..aef2b7b 100644 --- a/main/src/cgeo/geocaching/backup/CentralBackupAgent.java +++ b/main/src/cgeo/geocaching/backup/CentralBackupAgent.java @@ -7,11 +7,11 @@ import android.app.backup.SharedPreferencesBackupHelper; public class CentralBackupAgent extends BackupAgentHelper { - static final String PREFS_BACKUP_KEY = "prefs"; + private static final String PREFS_BACKUP_KEY = "prefs"; @Override public void onCreate() { - SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, Settings.preferences); + final SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, Settings.getPreferencesName()); addHelper(PREFS_BACKUP_KEY, helper); } diff --git a/main/src/cgeo/geocaching/cgCache.java b/main/src/cgeo/geocaching/cgCache.java index beffa85..f95fb2c 100644 --- a/main/src/cgeo/geocaching/cgCache.java +++ b/main/src/cgeo/geocaching/cgCache.java @@ -9,12 +9,14 @@ 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; import cgeo.geocaching.enumerations.LoadFlags.RemoveFlag; +import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.WaypointType; import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.geopoint.GeopointFormatter; import cgeo.geocaching.geopoint.GeopointParser; +import cgeo.geocaching.network.HtmlImage; import cgeo.geocaching.utils.CancellableHandler; import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.LogTemplateProvider; @@ -27,6 +29,8 @@ import android.content.Intent; import android.content.res.Resources; import android.net.Uri; import android.os.Handler; +import android.os.Message; +import android.text.Html; import android.text.Spannable; import java.util.ArrayList; @@ -88,7 +92,7 @@ public class cgCache implements ICache, IWaypoint { private List<String> attributes = null; private List<cgWaypoint> waypoints = null; private ArrayList<cgImage> spoilers = null; - private List<cgLog> logs = null; + private List<LogEntry> logs = null; private List<cgTrackable> inventory = null; private Map<LogType, Integer> logCounts = new HashMap<LogType, Integer>(); private boolean logOffline = false; @@ -100,7 +104,7 @@ public class cgCache implements ICache, IWaypoint { private String nameForSorting; private final EnumSet<StorageLocation> storageLocation = EnumSet.of(StorageLocation.HEAP); private boolean finalDefined = false; - private int zoomlevel = Tile.ZOOMLEVEL_MAX; + private int zoomlevel = Tile.ZOOMLEVEL_MAX + 1; private static final Pattern NUMBER_PATTERN = Pattern.compile("\\d+"); @@ -298,18 +302,10 @@ public class cgCache implements ICache, IWaypoint { * @param other * @return true if both caches have the same content */ - public boolean isEqualTo(cgCache other) { - if (other == null) { - return false; - } - - if ( - // updated - // detailedUpdate - // visitedDate - detailed == other.detailed && - geocode.equalsIgnoreCase(other.geocode) && - name.equalsIgnoreCase(other.name) && + private boolean isEqualTo(final cgCache other) { + return detailed == other.detailed && + StringUtils.equalsIgnoreCase(geocode, other.geocode) && + StringUtils.equalsIgnoreCase(name, other.name) && cacheType == other.cacheType && size == other.size && found == other.found && @@ -317,25 +313,25 @@ public class cgCache implements ICache, IWaypoint { premiumMembersOnly == other.premiumMembersOnly && difficulty == other.difficulty && terrain == other.terrain && - (coords != null ? coords.isEqualTo(other.coords) : coords == other.coords) && + (coords != null ? coords.equals(other.coords) : null == other.coords) && reliableLatLon == other.reliableLatLon && disabled == other.disabled && archived == other.archived && listId == other.listId && - owner.equalsIgnoreCase(other.owner) && - ownerReal.equalsIgnoreCase(other.ownerReal) && - (description != null ? description.equalsIgnoreCase(other.description) : null == other.description) && - (personalNote != null ? personalNote.equalsIgnoreCase(other.personalNote) : null == other.personalNote) && - shortdesc.equalsIgnoreCase(other.shortdesc) && - latlon.equalsIgnoreCase(other.latlon) && - location.equalsIgnoreCase(other.location) && + StringUtils.equalsIgnoreCase(owner, other.owner) && + StringUtils.equalsIgnoreCase(ownerReal, other.ownerReal) && + StringUtils.equalsIgnoreCase(description, other.description) && + StringUtils.equalsIgnoreCase(personalNote, other.personalNote) && + StringUtils.equalsIgnoreCase(shortdesc, other.shortdesc) && + StringUtils.equalsIgnoreCase(latlon, other.latlon) && + StringUtils.equalsIgnoreCase(location, other.location) && favorite == other.favorite && favoritePoints == other.favoritePoints && onWatchlist == other.onWatchlist && - (hidden != null ? hidden.compareTo(other.hidden) == 0 : hidden == other.hidden) && - guid.equalsIgnoreCase(other.guid) && - hint.equalsIgnoreCase(other.hint) && - cacheId.equalsIgnoreCase(other.cacheId) && + (hidden != null ? hidden.equals(other.hidden) : null == other.hidden) && + StringUtils.equalsIgnoreCase(guid, other.guid) && + StringUtils.equalsIgnoreCase(hint, other.hint) && + StringUtils.equalsIgnoreCase(cacheId, other.cacheId) && (direction != null ? direction.equals(other.direction) : null == other.direction) && (distance != null ? distance.equals(other.distance) : null == other.distance) && (elevation != null ? elevation.equals(other.elevation) : null == other.elevation) && @@ -351,10 +347,7 @@ public class cgCache implements ICache, IWaypoint { inventory == other.inventory && logCounts == other.logCounts && logOffline == other.logOffline && - finalDefined == other.finalDefined) { - return true; - } - return false; + finalDefined == other.finalDefined; } public boolean hasTrackables() { @@ -393,7 +386,7 @@ public class cgCache implements ICache, IWaypoint { * * @return true: page contains guid of cache, false: otherwise */ - boolean isGuidContainedInPage(final String page) { + public boolean isGuidContainedInPage(final String page) { if (StringUtils.isBlank(page)) { return false; } @@ -404,17 +397,16 @@ public class cgCache implements ICache, IWaypoint { Pattern patternOk = Pattern.compile(guid, Pattern.CASE_INSENSITIVE); Matcher matcherOk = patternOk.matcher(page); if (matcherOk.find()) { - Log.i(Settings.tag, "cgCache.isGuidContainedInPage: guid '" + guid + "' found"); + Log.i("cgCache.isGuidContainedInPage: guid '" + guid + "' found"); return true; } else { - Log.i(Settings.tag, "cgCache.isGuidContainedInPage: guid '" + guid + "' not found"); + Log.i("cgCache.isGuidContainedInPage: guid '" + guid + "' not found"); return false; } } public boolean isEventCache() { - return CacheType.EVENT == cacheType || CacheType.MEGA_EVENT == cacheType - || CacheType.CITO == cacheType || CacheType.LOSTANDFOUND == cacheType; + return cacheType.isEvent(); } public boolean logVisit(IAbstractActivity fromActivity) { @@ -534,16 +526,6 @@ public class cgCache implements ICache, IWaypoint { } @Override - public String getLatitude() { - return coords != null ? coords.format(GeopointFormatter.Format.LAT_DECMINUTE) : null; - } - - @Override - public String getLongitude() { - return coords != null ? coords.format(GeopointFormatter.Format.LON_DECMINUTE) : null; - } - - @Override public String getOwner() { return owner; } @@ -956,7 +938,7 @@ public class cgCache implements ICache, IWaypoint { return false; } - public List<cgLog> getLogs() { + public List<LogEntry> getLogs() { return getLogs(true); } @@ -965,15 +947,15 @@ public class cgCache implements ICache, IWaypoint { * true for all logs, false for friend logs only * @return the logs with all entries or just the entries of the friends, never <code>null</code> */ - public List<cgLog> getLogs(boolean allLogs) { + public List<LogEntry> getLogs(boolean allLogs) { if (logs == null) { return Collections.emptyList(); } if (allLogs) { return logs; } - ArrayList<cgLog> friendLogs = new ArrayList<cgLog>(); - for (cgLog log : logs) { + ArrayList<LogEntry> friendLogs = new ArrayList<LogEntry>(); + for (LogEntry log : logs) { if (log.friend) { friendLogs.add(log); } @@ -985,7 +967,7 @@ public class cgCache implements ICache, IWaypoint { * @param logs * the log entries */ - public void setLogs(List<cgLog> logs) { + public void setLogs(List<LogEntry> logs) { this.logs = logs; } @@ -1361,7 +1343,7 @@ public class cgCache implements ICache, IWaypoint { matcher = coordPattern.matcher(note); } } catch (Exception e) { - Log.e(Settings.tag, "cgCache.parseWaypointsFromNote: " + e.toString()); + Log.e("cgCache.parseWaypointsFromNote: " + e.toString()); } } @@ -1376,16 +1358,16 @@ public class cgCache implements ICache, IWaypoint { return attributes != null && attributes.size() > 0; } - public void prependLog(final cgLog log) { + public void prependLog(final LogEntry log) { if (logs == null) { - logs = new ArrayList<cgLog>(); + logs = new ArrayList<LogEntry>(); } logs.add(0, log); } - public void appendLog(final cgLog log) { + public void appendLog(final LogEntry log) { if (logs == null) { - logs = new ArrayList<cgLog>(); + logs = new ArrayList<LogEntry>(); } logs.add(log); } @@ -1414,17 +1396,13 @@ public class cgCache implements ICache, IWaypoint { if (!(obj instanceof cgCache)) { return false; } - // just compare the geocode even if that is not what "equals" normaly does - return geocode != null ? geocode.compareTo(((cgCache) obj).geocode) == 0 : false; + // just compare the geocode even if that is not what "equals" normally does + return StringUtils.isNotBlank(geocode) ? geocode.equals(((cgCache) obj).geocode) : false; } public void store(Activity activity, CancellableHandler handler) { final int listId = Math.max(getListId(), StoredList.STANDARD_LIST_ID); - cgBase.storeCache(activity, this, null, listId, false, handler); - } - - public int getZoomlevel() { - return this.zoomlevel; + storeCache(activity, this, null, listId, false, handler); } public void setZoomlevel(int zoomlevel) { @@ -1445,4 +1423,171 @@ public class cgCache implements ICache, IWaypoint { public String getCoordType() { return "cache"; } + + public void drop(Handler handler) { + try { + cgeoapplication.getInstance().markDropped(getGeocode()); + cgeoapplication.getInstance().removeCache(getGeocode(), EnumSet.of(RemoveFlag.REMOVE_CACHE)); + + handler.sendMessage(Message.obtain()); + } catch (Exception e) { + Log.e("cache.drop: ", e); + } + } + + public void checkFields() { + if (StringUtils.isBlank(getGeocode())) { + Log.e("cgBase.loadLogsFromDetails: geo code not parsed correctly"); + } + if (StringUtils.isBlank(getName())) { + Log.e("name not parsed correctly"); + } + if (StringUtils.isBlank(getGuid())) { + Log.e("guid not parsed correctly"); + } + if (getTerrain() == 0.0) { + Log.e("terrain not parsed correctly"); + } + if (getDifficulty() == 0.0) { + Log.e("difficulty not parsed correctly"); + } + if (StringUtils.isBlank(getOwner())) { + Log.e("owner not parsed correctly"); + } + if (StringUtils.isBlank(getOwnerReal())) { + Log.e("owner real not parsed correctly"); + } + if (getHiddenDate() == null) { + Log.e("hidden not parsed correctly"); + } + if (getFavoritePoints() < 0) { + Log.e("favoriteCount not parsed correctly"); + } + if (getSize() == null) { + Log.e("size not parsed correctly"); + } + if (getType() == null || getType() == CacheType.UNKNOWN) { + Log.e("type not parsed correctly"); + } + if (getCoords() == null) { + Log.e("coordinates not parsed correctly"); + } + if (StringUtils.isBlank(getLocation())) { + Log.e("location not parsed correctly"); + } + } + + public void refresh(Activity activity, int newListId, CancellableHandler handler) { + cgeoapplication.getInstance().removeCache(geocode, EnumSet.of(RemoveFlag.REMOVE_CACHE)); + storeCache(activity, null, geocode, newListId, true, handler); + } + + public static void storeCache(Activity activity, cgCache origCache, String geocode, int listId, boolean forceRedownload, CancellableHandler handler) { + try { + cgCache cache; + // get cache details, they may not yet be complete + if (origCache != null) { + // only reload the cache if it was already stored or doesn't have full details (by checking the description) + if (origCache.getListId() >= StoredList.STANDARD_LIST_ID || StringUtils.isBlank(origCache.getDescription())) { + final SearchResult search = searchByGeocode(origCache.getGeocode(), null, listId, false, handler); + cache = search.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB); + } else { + cache = origCache; + } + } else if (StringUtils.isNotBlank(geocode)) { + final SearchResult search = searchByGeocode(geocode, null, listId, forceRedownload, handler); + cache = search.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB); + } else { + cache = null; + } + + if (cache == null) { + if (handler != null) { + handler.sendMessage(Message.obtain()); + } + + return; + } + + if (CancellableHandler.isCancelled(handler)) { + return; + } + + final HtmlImage imgGetter = new HtmlImage(activity, cache.getGeocode(), false, listId, true); + + // store images from description + if (StringUtils.isNotBlank(cache.getDescription())) { + Html.fromHtml(cache.getDescription(), imgGetter, null); + } + + if (CancellableHandler.isCancelled(handler)) { + return; + } + + // store spoilers + if (CollectionUtils.isNotEmpty(cache.getSpoilers())) { + for (cgImage oneSpoiler : cache.getSpoilers()) { + imgGetter.getDrawable(oneSpoiler.getUrl()); + } + } + + if (CancellableHandler.isCancelled(handler)) { + return; + } + + // store images from logs + if (Settings.isStoreLogImages()) { + for (LogEntry log : cache.getLogs(true)) { + if (log.hasLogImages()) { + for (cgImage oneLogImg : log.getLogImages()) { + imgGetter.getDrawable(oneLogImg.getUrl()); + } + } + } + } + + if (CancellableHandler.isCancelled(handler)) { + return; + } + + // store map previews + StaticMapsProvider.downloadMaps(cache, activity); + + if (CancellableHandler.isCancelled(handler)) { + return; + } + + cache.setListId(listId); + cgeoapplication.getInstance().saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); + + if (handler != null) { + handler.sendMessage(Message.obtain()); + } + } catch (Exception e) { + Log.e("cgBase.storeCache"); + } + } + + public static SearchResult searchByGeocode(final String geocode, final String guid, final int listId, final boolean forceReload, final CancellableHandler handler) { + if (StringUtils.isBlank(geocode) && StringUtils.isBlank(guid)) { + Log.e("cgeoBase.searchByGeocode: No geocode nor guid given"); + return null; + } + + cgeoapplication app = cgeoapplication.getInstance(); + if (!forceReload && listId == StoredList.TEMPORARY_LIST_ID && (app.isOffline(geocode, guid) || app.isThere(geocode, guid, true, true))) { + final SearchResult search = new SearchResult(); + final String realGeocode = StringUtils.isNotBlank(geocode) ? geocode : app.getGeocode(guid); + search.addGeocode(realGeocode); + return search; + } + + // if we have no geocode, we can't dynamically select the handler, but must explicitly use GC + if (geocode == null && guid != null) { + return GCConnector.getInstance().searchByGeocode(null, guid, app, handler); + } + + return ConnectorFactory.getConnector(geocode).searchByGeocode(geocode, guid, app, handler); + } + } diff --git a/main/src/cgeo/geocaching/cgData.java b/main/src/cgeo/geocaching/cgData.java index 24f1e22..604137a 100644 --- a/main/src/cgeo/geocaching/cgData.java +++ b/main/src/cgeo/geocaching/cgData.java @@ -10,6 +10,7 @@ import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.WaypointType; import cgeo.geocaching.files.LocalStorage; import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; @@ -28,6 +29,7 @@ import android.database.sqlite.SQLiteStatement; import java.io.File; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.EnumSet; @@ -57,6 +59,8 @@ public class cgData { "inventoryunknown", "onWatchlist", "personal_note", "reliable_latlon", "coordsChanged", "finalDefined" // reason is replaced by listId in cgCache }; + /** The list of fields needed for mapping. */ + private static final String[] WAYPOINT_COLUMNS = new String[] { "_id", "geocode", "updated", "type", "prefix", "lookup", "name", "latlon", "latitude", "longitude", "note", "own" }; /** Number of days (as ms) after temporarily saved caches are deleted */ private static long DAYS_AFTER_CACHE_IS_DELETED = 3 * 24 * 60 * 60 * 1000; @@ -265,16 +269,16 @@ public class cgData { databaseRW = dbHelper.getWritableDatabase(); if (databaseRW != null && databaseRW.isOpen()) { - Log.i(Settings.tag, "Connection to RW database established."); + Log.i("Connection to RW database established."); } else { - Log.e(Settings.tag, "Failed to open connection to RW database."); + Log.e("Failed to open connection to RW database."); } if (databaseRW != null && databaseRW.inTransaction()) { databaseRW.endTransaction(); } } catch (Exception e) { - Log.e(Settings.tag, "cgData.openDb.RW: " + e.toString()); + Log.e("cgData.openDb.RW: " + e.toString()); } } @@ -290,16 +294,16 @@ public class cgData { } if (databaseRO != null && databaseRO.isOpen()) { - Log.i(Settings.tag, "Connection to RO database established."); + Log.i("Connection to RO database established."); } else { - Log.e(Settings.tag, "Failed to open connection to RO database."); + Log.e("Failed to open connection to RO database."); } if (databaseRO != null && databaseRO.inTransaction()) { databaseRO.endTransaction(); } } catch (Exception e) { - Log.e(Settings.tag, "cgData.openDb.RO: " + e.toString()); + Log.e("cgData.openDb.RO: " + e.toString()); } } @@ -324,7 +328,7 @@ public class cgData { databaseRO = null; SQLiteDatabase.releaseMemory(); - Log.d(Settings.tag, "Closing RO database"); + Log.d("Closing RO database"); } if (databaseRW != null) { @@ -338,7 +342,7 @@ public class cgData { databaseRW = null; SQLiteDatabase.releaseMemory(); - Log.d(Settings.tag, "Closing RW database"); + Log.d("Closing RW database"); } if (dbHelper != null) { @@ -359,7 +363,7 @@ public class cgData { public String backupDatabase() { if (!LocalStorage.isExternalStorageAvailable()) { - Log.w(Settings.tag, "Database wasn't backed up: no external memory"); + Log.w("Database wasn't backed up: no external memory"); return null; } @@ -369,10 +373,10 @@ public class cgData { init(); if (backupDone) { - Log.i(Settings.tag, "Database was copied to " + target); + Log.i("Database was copied to " + target); return target.getPath(); } else { - Log.e(Settings.tag, "Database could not be copied to " + target); + Log.e("Database could not be copied to " + target); return null; } } @@ -388,7 +392,7 @@ public class cgData { public boolean restoreDatabase() { if (!LocalStorage.isExternalStorageAvailable()) { - Log.w(Settings.tag, "Database wasn't restored: no external memory"); + Log.w("Database wasn't restored: no external memory"); return false; } @@ -398,9 +402,9 @@ public class cgData { init(); if (restoreDone) { - Log.i(Settings.tag, "Database succesfully restored from " + sourceFile.getPath()); + Log.i("Database succesfully restored from " + sourceFile.getPath()); } else { - Log.e(Settings.tag, "Could not restore database from " + sourceFile.getPath()); + Log.e("Could not restore database from " + sourceFile.getPath()); } return restoreDone; @@ -451,7 +455,7 @@ public class cgData { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - Log.i(Settings.tag, "Upgrade database from ver. " + oldVersion + " to ver. " + newVersion + ": start"); + Log.i("Upgrade database from ver. " + oldVersion + " to ver. " + newVersion + ": start"); try { if (db.isReadOnly()) { @@ -464,284 +468,19 @@ public class cgData { dropDatabase(db); onCreate(db); - Log.i(Settings.tag, "Database structure created."); + Log.i("Database structure created."); } if (oldVersion > 0) { db.execSQL("delete from " + dbTableCaches + " where reason = 0"); - if (oldVersion < 34) { // upgrade to 34 - try { - db.execSQL("create index if not exists in_a on " + dbTableCaches + " (geocode)"); - db.execSQL("create index if not exists in_b on " + dbTableCaches + " (guid)"); - db.execSQL("create index if not exists in_c on " + dbTableCaches + " (reason)"); - db.execSQL("create index if not exists in_d on " + dbTableCaches + " (detailed)"); - db.execSQL("create index if not exists in_e on " + dbTableCaches + " (type)"); - db.execSQL("create index if not exists in_a on " + dbTableAttributes + " (geocode)"); - db.execSQL("create index if not exists in_a on " + dbTableWaypoints + " (geocode)"); - db.execSQL("create index if not exists in_b on " + dbTableWaypoints + " (geocode, type)"); - db.execSQL("create index if not exists in_a on " + dbTableSpoilers + " (geocode)"); - db.execSQL("create index if not exists in_a on " + dbTableLogs + " (geocode)"); - db.execSQL("create index if not exists in_a on " + dbTableTrackables + " (geocode)"); - - Log.i(Settings.tag, "Indexes added."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 34: " + e.toString()); - } - } - - if (oldVersion < 37) { // upgrade to 37 - try { - db.execSQL("alter table " + dbTableCaches + " add column direction text"); - db.execSQL("alter table " + dbTableCaches + " add column distance double"); - - Log.i(Settings.tag, "Columns direction and distance added to " + dbTableCaches + "."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 37: " + e.toString()); - } - } - - if (oldVersion < 38) { // upgrade to 38 - try { - db.execSQL("drop table " + dbTableLogs); - db.execSQL(dbCreateLogs); - - Log.i(Settings.tag, "Changed type column in " + dbTableLogs + " to integer."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 38: " + e.toString()); - } - } - - if (oldVersion < 39) { // upgrade to 39 - try { - db.execSQL(dbCreateLists); - - Log.i(Settings.tag, "Created lists table."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 39: " + e.toString()); - } - } - - if (oldVersion < 40) { // upgrade to 40 - try { - db.execSQL("drop table " + dbTableTrackables); - db.execSQL(dbCreateTrackables); - - Log.i(Settings.tag, "Changed type of geocode column in trackables table."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 40: " + e.toString()); - } - } - - if (oldVersion < 41) { // upgrade to 41 - try { - db.execSQL("alter table " + dbTableCaches + " add column rating float"); - db.execSQL("alter table " + dbTableCaches + " add column votes integer"); - db.execSQL("alter table " + dbTableCaches + " add column vote integer"); - - Log.i(Settings.tag, "Added columns for GCvote."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 41: " + e.toString()); - } - } - - if (oldVersion < 42) { // upgrade to 42 - try { - db.execSQL(dbCreateLogsOffline); - - Log.i(Settings.tag, "Added table for offline logs"); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 42: " + e.toString()); - } - } - - if (oldVersion < 43) { // upgrade to 43 - try { - final String dbTableCachesTemp = dbTableCaches + "_temp"; - final String dbCreateCachesTemp = "" - + "create temporary table " + dbTableCachesTemp + " (" - + "_id integer primary key autoincrement, " - + "updated long not null, " - + "detailed integer not null default 0, " - + "detailedupdate long, " - + "geocode text unique not null, " - + "reason integer not null default 0, " // cached, favourite... - + "cacheid text, " - + "guid text, " - + "type text, " - + "name text, " - + "owner text, " - + "hidden long, " - + "hint text, " - + "size text, " - + "difficulty float, " - + "terrain float, " - + "latlon text, " - + "latitude_string text, " - + "longitude_string text, " - + "location text, " - + "distance double, " - + "latitude double, " - + "longitude double, " - + "shortdesc text, " - + "description text, " - + "rating float, " - + "votes integer, " - + "vote integer, " - + "disabled integer not null default 0, " - + "archived integer not null default 0, " - + "members integer not null default 0, " - + "found integer not null default 0, " - + "favourite integer not null default 0, " - + "inventorycoins integer default 0, " - + "inventorytags integer default 0, " - + "inventoryunknown integer default 0 " - + "); "; - final String dbCreateCachesNew = "" - + "create table " + dbTableCaches + " (" - + "_id integer primary key autoincrement, " - + "updated long not null, " - + "detailed integer not null default 0, " - + "detailedupdate long, " - + "geocode text unique not null, " - + "reason integer not null default 0, " // cached, favourite... - + "cacheid text, " - + "guid text, " - + "type text, " - + "name text, " - + "owner text, " - + "hidden long, " - + "hint text, " - + "size text, " - + "difficulty float, " - + "terrain float, " - + "latlon text, " - + "latitude_string text, " - + "longitude_string text, " - + "location text, " - + "direction double, " - + "distance double, " - + "latitude double, " - + "longitude double, " - + "shortdesc text, " - + "description text, " - + "rating float, " - + "votes integer, " - + "vote integer, " - + "disabled integer not null default 0, " - + "archived integer not null default 0, " - + "members integer not null default 0, " - + "found integer not null default 0, " - + "favourite integer not null default 0, " - + "inventorycoins integer default 0, " - + "inventorytags integer default 0, " - + "inventoryunknown integer default 0 " - + "); "; - - db.beginTransaction(); - db.execSQL(dbCreateCachesTemp); - db.execSQL("insert into " + dbTableCachesTemp + " select _id, updated, detailed, detailedupdate, geocode, reason, cacheid, guid, type, name, owner, hidden, hint, size, difficulty, terrain, latlon, latitude_string, longitude_string, location, distance, latitude, longitude, shortdesc, description, rating, votes, vote, disabled, archived, members, found, favourite, inventorycoins, inventorytags, inventoryunknown from " + dbTableCaches); - db.execSQL("drop table " + dbTableCaches); - db.execSQL(dbCreateCachesNew); - db.execSQL("insert into " + dbTableCaches + " select _id, updated, detailed, detailedupdate, geocode, reason, cacheid, guid, type, name, owner, hidden, hint, size, difficulty, terrain, latlon, latitude_string, longitude_string, location, null, distance, latitude, longitude, shortdesc, description, rating, votes, vote, disabled, archived, members, found, favourite, inventorycoins, inventorytags, inventoryunknown from " + dbTableCachesTemp); - db.execSQL("drop table " + dbTableCachesTemp); - db.setTransactionSuccessful(); - - Log.i(Settings.tag, "Changed direction column"); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 43: " + e.toString()); - } finally { - db.endTransaction(); - } - } - - if (oldVersion < 44) { // upgrade to 44 - try { - db.execSQL("alter table " + dbTableCaches + " add column favourite_cnt integer"); - - Log.i(Settings.tag, "Column favourite_cnt added to " + dbTableCaches + "."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 44: " + e.toString()); - } - } - - if (oldVersion < 45) { // upgrade to 45 - try { - db.execSQL("alter table " + dbTableCaches + " add column owner_real text"); - - Log.i(Settings.tag, "Column owner_real added to " + dbTableCaches + "."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 45: " + e.toString()); - } - } - - if (oldVersion < 46) { // upgrade to 46 - try { - db.execSQL("alter table " + dbTableCaches + " add column visiteddate long"); - db.execSQL("create index if not exists in_f on " + dbTableCaches + " (visiteddate, detailedupdate)"); - - Log.i(Settings.tag, "Added column for date of visit."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 46: " + e.toString()); - } - } - if (oldVersion < 47) { // upgrade to 47 - try { - db.execSQL("alter table " + dbTableCaches + " add column own integer not null default 0"); - - Log.i(Settings.tag, "Added column own."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 47: " + e.toString()); - } - } - - if (oldVersion < 48) { // upgrade to 48 - try { - db.execSQL("alter table " + dbTableCaches + " add column elevation double"); - - Log.i(Settings.tag, "Column elevation added to " + dbTableCaches + "."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 48: " + e.toString()); - } - } - - if (oldVersion < 49) { // upgrade to 49 - try { - db.execSQL(dbCreateLogCount); - - Log.i(Settings.tag, "Created table " + dbTableLogCount + "."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 49: " + e.toString()); - } - } - - if (oldVersion < 50) { // upgrade to 50 - try { - db.execSQL("alter table " + dbTableCaches + " add column myvote float"); - - Log.i(Settings.tag, "Added float column for votes to " + dbTableCaches + "."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 50: " + e.toString()); - } - } - - if (oldVersion < 51) { // upgrade to 51 - try { - db.execSQL("alter table " + dbTableCaches + " add column reliable_latlon integer"); - - Log.i(Settings.tag, "Column reliable_latlon added to " + dbTableCaches + "."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 51: " + e.toString()); - } - } - if (oldVersion < 52) { // upgrade to 52 try { db.execSQL(dbCreateSearchDestinationHistory); - Log.i(Settings.tag, "Added table " + dbTableSearchDestionationHistory + "."); + Log.i("Added table " + dbTableSearchDestionationHistory + "."); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 52", e); + Log.e("Failed to upgrade to ver. 52", e); } } @@ -749,9 +488,9 @@ public class cgData { try { db.execSQL("alter table " + dbTableCaches + " add column onWatchlist integer"); - Log.i(Settings.tag, "Column onWatchlist added to " + dbTableCaches + "."); + Log.i("Column onWatchlist added to " + dbTableCaches + "."); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 53", e); + Log.e("Failed to upgrade to ver. 53", e); } } @@ -759,7 +498,7 @@ public class cgData { try { db.execSQL(dbCreateLogImages); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 54: " + e.toString()); + Log.e("Failed to upgrade to ver. 54: " + e.toString()); } } @@ -768,7 +507,7 @@ public class cgData { try { db.execSQL("alter table " + dbTableCaches + " add column personal_note text"); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 55: " + e.toString()); + Log.e("Failed to upgrade to ver. 55: " + e.toString()); } } @@ -780,7 +519,7 @@ public class cgData { "lower(attribute) where attribute like \"%_yes\" " + "or attribute like \"%_no\""); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 56: " + e.toString()); + Log.e("Failed to upgrade to ver. 56: " + e.toString()); } } @@ -795,7 +534,7 @@ public class cgData { db.execSQL("drop index in_f"); createIndices(db); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 57: " + e.toString()); + Log.e("Failed to upgrade to ver. 57: " + e.toString()); } } @@ -883,9 +622,9 @@ public class cgData { db.setTransactionSuccessful(); - Log.i(Settings.tag, "Removed latitude_string and longitude_string columns"); + Log.i("Removed latitude_string and longitude_string columns"); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 58", e); + Log.e("Failed to upgrade to ver. 58", e); } finally { db.endTransaction(); } @@ -897,7 +636,7 @@ public class cgData { createIndices(db); removeObsoleteCacheDirectories(db); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 59", e); + Log.e("Failed to upgrade to ver. 59", e); } } @@ -905,7 +644,7 @@ public class cgData { try { removeSecEmptyDirs(); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 60", e); + Log.e("Failed to upgrade to ver. 60", e); } } if (oldVersion < 61) { @@ -913,7 +652,7 @@ public class cgData { db.execSQL("alter table " + dbTableLogs + " add column friend integer"); db.execSQL("alter table " + dbTableCaches + " add column coordsChanged integer default 0"); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 61: " + e.toString()); + Log.e("Failed to upgrade to ver. 61: " + e.toString()); } } @@ -924,7 +663,7 @@ public class cgData { db.execSQL("alter table " + dbTableWaypoints + " add column own integer default 0"); db.execSQL("update " + dbTableWaypoints + " set own = 1 where type = 'own'"); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 62: " + e.toString()); + Log.e("Failed to upgrade to ver. 62: " + e.toString()); } } @@ -935,7 +674,7 @@ public class cgData { db.endTransaction(); } - Log.i(Settings.tag, "Upgrade database from ver. " + oldVersion + " to ver. " + newVersion + ": completed"); + Log.i("Upgrade database from ver. " + oldVersion + " to ver. " + newVersion + ": completed"); } } @@ -968,7 +707,7 @@ public class cgData { @Override public void run() { for (final File dir : toRemove) { - Log.i(Settings.tag, "Removing obsolete cache directory for " + dir.getName()); + Log.i("Removing obsolete cache directory for " + dir.getName()); LocalStorage.deleteDirectory(dir); } } @@ -1032,7 +771,7 @@ public class cgData { } } } catch (Exception e) { - Log.e(Settings.tag, "cgData.allDetailedThere: " + e.toString()); + Log.e("cgData.allDetailedThere: " + e.toString()); } if (cursor != null) { @@ -1093,7 +832,7 @@ public class cgData { } } } catch (Exception e) { - Log.e(Settings.tag, "cgData.isThere: " + e.toString()); + Log.e("cgData.isThere: " + e.toString()); } if (cursor != null) { @@ -1171,7 +910,7 @@ public class cgData { cursor.close(); } } catch (Exception e) { - Log.e(Settings.tag, "cgData.isOffline: " + e.toString()); + Log.e("cgData.isOffline: " + e.toString()); } return listId >= StoredList.STANDARD_LIST_ID; @@ -1192,7 +931,7 @@ public class cgData { } catch (SQLiteDoneException e) { // Do nothing, it only means we have no information on the cache } catch (Exception e) { - Log.e(Settings.tag, "cgData.getGeocodeForGuid", e); + Log.e("cgData.getGeocodeForGuid", e); } return null; @@ -1213,7 +952,7 @@ public class cgData { } catch (SQLiteDoneException e) { // Do nothing, it only means we have no information on the cache } catch (Exception e) { - Log.e(Settings.tag, "cgData.getCacheidForGeocode", e); + Log.e("cgData.getCacheidForGeocode", e); } return null; @@ -1254,7 +993,7 @@ public class cgData { cache.addStorageLocation(StorageLocation.DATABASE); cacheCache.putCacheInCache(cache); - Log.d(Settings.tag, "Saving " + cache.toString() + " (" + cache.getListId() + ") to DB"); + Log.d("Saving " + cache.toString() + " (" + cache.getListId() + ") to DB"); ContentValues values = new ContentValues(); @@ -1412,37 +1151,25 @@ public class cgData { /** * Persists the given <code>destination</code> into the database. * - * @param destinations - * @return <code>true</code> if the given destination was successfully - * persisted <code>false</code> otherwise. + * @param destination + * a destination to save */ - public boolean saveSearchedDestination(cgDestination destination) { - boolean success = true; - - if (destination == null) { - success = false; - } else { - init(); - - databaseRW.beginTransaction(); + public void saveSearchedDestination(final Destination destination) { + init(); - try { - ContentValues values = new ContentValues(); - values.put("date", destination.getDate()); - putCoords(values, destination.getCoords()); + databaseRW.beginTransaction(); - long id = databaseRW.insert(dbTableSearchDestionationHistory, null, values); - destination.setId(id); - databaseRW.setTransactionSuccessful(); - } catch (Exception e) { - success = false; - Log.e(Settings.tag, "Updating searchedDestinations db failed", e); - } finally { - databaseRW.endTransaction(); - } + try { + ContentValues values = new ContentValues(); + values.put("date", destination.getDate()); + putCoords(values, destination.getCoords()); + databaseRW.insert(dbTableSearchDestionationHistory, null, values); + databaseRW.setTransactionSuccessful(); + } catch (Exception e) { + Log.e("Updating searchedDestinations db failed", e); + } finally { + databaseRW.endTransaction(); } - - return success; } public boolean saveWaypoints(String geocode, List<cgWaypoint> waypoints, boolean drop) { @@ -1452,7 +1179,7 @@ public class cgData { init(); - Log.d(Settings.tag, "cgData.saveWaypoints(drop=" + drop + ")"); + Log.d("cgData.saveWaypoints(drop=" + drop + ")"); boolean ok = false; databaseRW.beginTransaction(); @@ -1618,11 +1345,11 @@ public class cgData { return true; } - public boolean saveLogs(String geocode, List<cgLog> logs) { + public boolean saveLogs(String geocode, List<LogEntry> logs) { return saveLogs(geocode, logs, true); } - public boolean saveLogs(String geocode, List<cgLog> logs, boolean drop) { + public boolean saveLogs(String geocode, List<LogEntry> logs, boolean drop) { if (StringUtils.isBlank(geocode) || logs == null) { return false; } @@ -1639,7 +1366,7 @@ public class cgData { if (!logs.isEmpty()) { InsertHelper helper = new InsertHelper(databaseRW, dbTableLogs); long timeStamp = System.currentTimeMillis(); - for (cgLog log : logs) { + for (LogEntry log : logs) { helper.prepareForInsert(); helper.bind(LOGS_GEOCODE, geocode); @@ -1653,9 +1380,9 @@ public class cgData { long log_id = helper.execute(); - if (CollectionUtils.isNotEmpty(log.logImages)) { + if (log.hasLogImages()) { ContentValues values = new ContentValues(); - for (cgImage img : log.logImages) { + for (cgImage img : log.getLogImages()) { values.clear(); values.put("log_id", log_id); values.put("title", img.getTitle()); @@ -1759,34 +1486,13 @@ public class cgData { return true; } - public List<Number> getBounds(Set<String> geocodes) { + public Viewport getBounds(final Set<String> geocodes) { if (CollectionUtils.isEmpty(geocodes)) { return null; } final Set<cgCache> caches = loadCaches(geocodes, LoadFlags.LOAD_CACHE_OR_DB); - - double latMin = 360.0; - double latMax = -360.0; - double lonMin = 360.0; - double lonMax = -360.0; - for (cgCache cache : caches) { - final Geopoint coords = cache.getCoords(); - double latitude = coords.getLatitude(); - latMin = Math.min(latitude, latMin); - latMax = Math.max(latitude, latMax); - double longitude = coords.getLongitude(); - lonMin = Math.min(longitude, lonMin); - lonMax = Math.max(longitude, lonMax); - } - - final List<Number> viewport = new ArrayList<Number>(); - viewport.add(caches.size()); - viewport.add(latMin); - viewport.add(latMax); - viewport.add(lonMin); - viewport.add(lonMax); - return viewport; + return Viewport.containing(caches); } /** @@ -1801,14 +1507,8 @@ public class cgData { throw new IllegalArgumentException("geocode must not be empty"); } - Set<String> geocodes = new HashSet<String>(); - geocodes.add(geocode); - - Set<cgCache> caches = loadCaches(geocodes, loadFlags); - if (caches != null && caches.size() >= 1) { - return (cgCache) caches.toArray()[0]; - } - return null; + final Set<cgCache> caches = loadCaches(Collections.singleton(geocode), loadFlags); + return caches.isEmpty() ? null : caches.iterator().next(); } /** @@ -1843,12 +1543,10 @@ public class cgData { loadFlags.contains(LoadFlag.LOAD_INVENTORY) || loadFlags.contains(LoadFlag.LOAD_OFFLINE_LOG)) { - Set<cgCache> cachesFromDB = loadCaches(remaining, null, null, null, null, loadFlags); - if (cachesFromDB != null) { - result.addAll(cachesFromDB); - for (cgCache cache : cachesFromDB) { - remaining.remove(cache.getGeocode()); - } + final Set<cgCache> cachesFromDB = loadCachesFromGeocodes(remaining, loadFlags); + result.addAll(cachesFromDB); + for (final cgCache cache : cachesFromDB) { + remaining.remove(cache.getGeocode()); } } @@ -1863,7 +1561,7 @@ public class cgData { } if (remaining.size() >= 1) { - Log.e(Settings.tag, "cgData.loadCaches(" + remaining.toString() + ") failed"); + Log.e("cgData.loadCaches(" + remaining.toString() + ") failed"); } return result; } @@ -1872,150 +1570,107 @@ public class cgData { * Load caches. * * @param geocodes - * OR - * @param centerLat - * @param centerLon - * @param spanLat - * @param spanLon * @param loadFlags * @return Set of loaded caches. Never null. */ - public Set<cgCache> loadCaches(final Set<String> geocodes, final Long centerLat, final Long centerLon, final Long spanLat, final Long spanLon, final EnumSet<LoadFlag> loadFlags) { - final Set<cgCache> caches = new HashSet<cgCache>(); + private Set<cgCache> loadCachesFromGeocodes(final Set<String> geocodes, final EnumSet<LoadFlag> loadFlags) { if (CollectionUtils.isEmpty(geocodes)) { - return caches; - } - // Using more than one of the parametersets results in overly comlex wheres - if (CollectionUtils.isNotEmpty(geocodes) - && centerLat != null - && centerLon != null - && spanLat != null - && spanLon != null) { - throw new IllegalArgumentException("Please use only one parameter"); + return Collections.emptySet(); } - Log.d(Settings.tag, "cgData.loadCaches(" + geocodes.toString() + ") from DB"); + + Log.d("cgData.loadCachesFromGeocodes(" + geocodes.toString() + ") from DB"); init(); - Cursor cursor = null; + final Cursor cursor = databaseRO.query( + dbTableCaches, + CACHE_COLUMNS, + cgData.whereGeocodeIn(geocodes), + null, + null, + null, + null, + null); try { - StringBuilder where = cgData.whereGeocodeIn(geocodes); - - // viewport limitation - if (centerLat != null && centerLon != null && spanLat != null && spanLon != null) { - double latMin = (centerLat / 1e6) - ((spanLat / 1e6) / 2) - ((spanLat / 1e6) / 4); - double latMax = (centerLat / 1e6) + ((spanLat / 1e6) / 2) + ((spanLat / 1e6) / 4); - double lonMin = (centerLon / 1e6) - ((spanLon / 1e6) / 2) - ((spanLon / 1e6) / 4); - double lonMax = (centerLon / 1e6) + ((spanLon / 1e6) / 2) + ((spanLon / 1e6) / 4); - double llCache; - - if (latMin > latMax) { - llCache = latMax; - latMax = latMin; - latMin = llCache; - } - if (lonMin > lonMax) { - llCache = lonMax; - lonMax = lonMin; - lonMin = llCache; - } - - if (where.length() > 0) { - where.append(" and "); - } - where.append("(latitude >= "); - where.append(String.format((Locale) null, "%.6f", latMin)); - where.append(" and latitude <= "); - where.append(String.format((Locale) null, "%.6f", latMax)); - where.append(" and longitude >= "); - where.append(String.format((Locale) null, "%.6f", lonMin)); - where.append(" and longitude <= "); - where.append(String.format((Locale) null, "%.6f", lonMax)); - where.append(')'); - } - cursor = databaseRO.query( - dbTableCaches, - CACHE_COLUMNS, - where.toString(), - null, - null, - null, - null, - null); - - if (cursor != null) { - if (cursor.getCount() > 0) { - cursor.moveToFirst(); - - do { - //Extracted Method = LOADDBMINIMAL - cgCache cache = cgData.createCacheFromDatabaseContent(cursor); + if (cursor.moveToFirst()) { + final Set<cgCache> caches = new HashSet<cgCache>(); + do { + //Extracted Method = LOADDBMINIMAL + cgCache cache = cgData.createCacheFromDatabaseContent(cursor); - if (loadFlags.contains(LoadFlag.LOAD_ATTRIBUTES)) { - cache.setAttributes(loadAttributes(cache.getGeocode())); - } + if (loadFlags.contains(LoadFlag.LOAD_ATTRIBUTES)) { + cache.setAttributes(loadAttributes(cache.getGeocode())); + } - if (loadFlags.contains(LoadFlag.LOAD_WAYPOINTS)) { - final List<cgWaypoint> waypoints = loadWaypoints(cache.getGeocode()); - if (CollectionUtils.isNotEmpty(waypoints)) { - cache.setWaypoints(waypoints, false); - } + if (loadFlags.contains(LoadFlag.LOAD_WAYPOINTS)) { + final List<cgWaypoint> waypoints = loadWaypoints(cache.getGeocode()); + if (CollectionUtils.isNotEmpty(waypoints)) { + cache.setWaypoints(waypoints, false); } + } - if (loadFlags.contains(LoadFlag.LOAD_SPOILERS)) { - final List<cgImage> spoilers = loadSpoilers(cache.getGeocode()); - if (CollectionUtils.isNotEmpty(spoilers)) { - if (cache.getSpoilers() == null) { - cache.setSpoilers(new ArrayList<cgImage>()); - } else { - cache.getSpoilers().clear(); - } - cache.getSpoilers().addAll(spoilers); + if (loadFlags.contains(LoadFlag.LOAD_SPOILERS)) { + final List<cgImage> spoilers = loadSpoilers(cache.getGeocode()); + if (CollectionUtils.isNotEmpty(spoilers)) { + if (cache.getSpoilers() == null) { + cache.setSpoilers(new ArrayList<cgImage>()); + } else { + cache.getSpoilers().clear(); } + cache.getSpoilers().addAll(spoilers); } + } - if (loadFlags.contains(LoadFlag.LOAD_LOGS)) { - cache.setLogs(loadLogs(cache.getGeocode())); - final Map<LogType, Integer> logCounts = loadLogCounts(cache.getGeocode()); - if (MapUtils.isNotEmpty(logCounts)) { - cache.getLogCounts().clear(); - cache.getLogCounts().putAll(logCounts); - } + if (loadFlags.contains(LoadFlag.LOAD_LOGS)) { + cache.setLogs(loadLogs(cache.getGeocode())); + final Map<LogType, Integer> logCounts = loadLogCounts(cache.getGeocode()); + if (MapUtils.isNotEmpty(logCounts)) { + cache.getLogCounts().clear(); + cache.getLogCounts().putAll(logCounts); } + } - if (loadFlags.contains(LoadFlag.LOAD_INVENTORY)) { - final List<cgTrackable> inventory = loadInventory(cache.getGeocode()); - if (CollectionUtils.isNotEmpty(inventory)) { - if (cache.getInventory() == null) { - cache.setInventory(new ArrayList<cgTrackable>()); - } else { - cache.getInventory().clear(); - } - cache.getInventory().addAll(inventory); + if (loadFlags.contains(LoadFlag.LOAD_INVENTORY)) { + final List<cgTrackable> inventory = loadInventory(cache.getGeocode()); + if (CollectionUtils.isNotEmpty(inventory)) { + if (cache.getInventory() == null) { + cache.setInventory(new ArrayList<cgTrackable>()); + } else { + cache.getInventory().clear(); } + cache.getInventory().addAll(inventory); } + } - if (loadFlags.contains(LoadFlag.LOAD_OFFLINE_LOG)) { - cache.setLogOffline(hasLogOffline(cache.getGeocode())); - } - cache.addStorageLocation(StorageLocation.DATABASE); - cacheCache.putCacheInCache(cache); + if (loadFlags.contains(LoadFlag.LOAD_OFFLINE_LOG)) { + cache.setLogOffline(hasLogOffline(cache.getGeocode())); + } + cache.addStorageLocation(StorageLocation.DATABASE); + cacheCache.putCacheInCache(cache); - caches.add(cache); - } while (cursor.moveToNext()); - } + caches.add(cache); + } while (cursor.moveToNext()); + return caches; + } else { + return Collections.emptySet(); } - } catch (Exception e) { - Log.e(Settings.tag, "cgData.getCaches: " + e.toString()); - } - - if (cursor != null) { + } finally { cursor.close(); } + } + + /** + * Builds a where for a viewport with the size enhanced by 50%. + * + * @param dbTable + * @param viewport + * @return + */ - return caches; + private static String buildCoordinateWhere(final String dbTable, final Viewport viewport) { + return viewport.resize(1.5).sqlWhere(dbTable); } /** @@ -2134,7 +1789,7 @@ public class cgData { cache.setUserModifiedCoords(cursor.getInt(cacheColumnIndex[37]) > 0); cache.setFinalDefined(cursor.getInt(cacheColumnIndex[40]) > 0); - Log.d(Settings.tag, "Loading " + cache.toString() + " (" + cache.getListId() + ") from DB"); + Log.d("Loading " + cache.toString() + " (" + cache.getListId() + ") from DB"); return cache; } @@ -2185,7 +1840,7 @@ public class cgData { Cursor cursor = databaseRO.query( dbTableWaypoints, - new String[] { "_id", "geocode", "updated", "type", "prefix", "lookup", "name", "latlon", "latitude", "longitude", "note", "own" }, + WAYPOINT_COLUMNS, "_id = ?", new String[] { Integer.toString(id) }, null, @@ -2193,7 +1848,7 @@ public class cgData { null, "1"); - Log.d(Settings.tag, "cgData.loadWaypoint(" + id + ")"); + Log.d("cgData.loadWaypoint(" + id + ")"); if (cursor != null && cursor.getCount() > 0) { cursor.moveToFirst(); @@ -2219,7 +1874,7 @@ public class cgData { Cursor cursor = databaseRO.query( dbTableWaypoints, - new String[] { "_id", "geocode", "updated", "type", "prefix", "lookup", "name", "latlon", "latitude", "longitude", "note", "own" }, + WAYPOINT_COLUMNS, "geocode = ?", new String[] { geocode }, null, @@ -2262,7 +1917,7 @@ public class cgData { return waypoint; } - public List<cgImage> loadSpoilers(String geocode) { + private List<cgImage> loadSpoilers(String geocode) { if (StringUtils.isBlank(geocode)) { return null; } @@ -2307,7 +1962,7 @@ public class cgData { * * @return A list of previously entered destinations or an empty list. */ - public List<cgDestination> loadHistoryOfSearchedLocations() { + public List<Destination> loadHistoryOfSearchedLocations() { init(); Cursor cursor = databaseRO.query(dbTableSearchDestionationHistory, @@ -2319,7 +1974,7 @@ public class cgData { "date desc", "100"); - final List<cgDestination> destinations = new LinkedList<cgDestination>(); + final List<Destination> destinations = new LinkedList<Destination>(); if (cursor != null && cursor.getCount() > 0) { cursor.moveToFirst(); @@ -2329,10 +1984,7 @@ public class cgData { int indexLongitude = cursor.getColumnIndex("longitude"); do { - final cgDestination dest = new cgDestination(); - dest.setId(cursor.getLong(indexId)); - dest.setDate(cursor.getLong(indexDate)); - dest.setCoords(getCoords(cursor, indexLatitude, indexLongitude)); + final Destination dest = new Destination(cursor.getLong(indexId), cursor.getLong(indexDate), getCoords(cursor, indexLatitude, indexLongitude)); // If coordinates are non-existent or invalid, do not consider // this point. @@ -2359,7 +2011,7 @@ public class cgData { databaseRW.setTransactionSuccessful(); } catch (Exception e) { success = false; - Log.e(Settings.tag, "Unable to clear searched destinations", e); + Log.e("Unable to clear searched destinations", e); } finally { databaseRW.endTransaction(); } @@ -2367,14 +2019,14 @@ public class cgData { return success; } - public List<cgLog> loadLogs(String geocode) { + public List<LogEntry> loadLogs(String geocode) { if (StringUtils.isBlank(geocode)) { return null; } init(); - List<cgLog> logs = new ArrayList<cgLog>(); + List<LogEntry> logs = new ArrayList<LogEntry>(); Cursor cursor = databaseRO.rawQuery( "SELECT cg_logs._id as cg_logs_id, type, author, log, date, found, friend, " + dbTableLogImages + "._id as cg_logImages_id, log_id, title, url FROM " @@ -2382,7 +2034,7 @@ public class cgData { + " ON ( cg_logs._id = log_id ) WHERE geocode = ? ORDER BY date desc, cg_logs._id asc", new String[] { geocode }); if (cursor != null && cursor.getCount() > 0) { - cgLog log = null; + LogEntry log = null; int indexLogsId = cursor.getColumnIndex("cg_logs_id"); int indexType = cursor.getColumnIndex("type"); int indexAuthor = cursor.getColumnIndex("author"); @@ -2395,7 +2047,7 @@ public class cgData { int indexUrl = cursor.getColumnIndex("url"); while (cursor.moveToNext() && logs.size() < 100) { if (log == null || log.id != cursor.getInt(indexLogsId)) { - log = new cgLog(); + log = new LogEntry(); log.id = cursor.getInt(indexLogsId); log.type = LogType.getById(cursor.getInt(indexType)); log.author = cursor.getString(indexAuthor); @@ -2408,11 +2060,7 @@ public class cgData { if (!cursor.isNull(indexLogImagesId)) { String title = cursor.getString(indexTitle); String url = cursor.getString(indexUrl); - if (log.logImages == null) { - log.logImages = new ArrayList<cgImage>(); - } - final cgImage log_img = new cgImage(url, title); - log.logImages.add(log_img); + log.addLogImage(new cgImage(url, title)); } } } @@ -2463,7 +2111,7 @@ public class cgData { return logCounts; } - public List<cgTrackable> loadInventory(String geocode) { + private List<cgTrackable> loadInventory(String geocode) { if (StringUtils.isBlank(geocode)) { return null; } @@ -2594,7 +2242,7 @@ public class cgData { count = (int) compiledStmnt.simpleQueryForLong(); compiledStmnt.close(); } catch (Exception e) { - Log.e(Settings.tag, "cgData.loadAllStoredCachesCount: " + e.toString()); + Log.e("cgData.loadAllStoredCachesCount: " + e.toString()); } return count; @@ -2610,16 +2258,23 @@ public class cgData { count = (int) sqlCount.simpleQueryForLong(); sqlCount.close(); } catch (Exception e) { - Log.e(Settings.tag, "cgData.getAllHistoricCachesCount: " + e.toString()); + Log.e("cgData.getAllHistoricCachesCount: " + e.toString()); } return count; } + /** + * Return a batch of stored geocodes. + * + * @param detailedOnly + * @param coords + * the current coordinates to sort by distance, or null to sort by geocode + * @param cacheType + * @param listId + * @return + */ public Set<String> loadBatchOfStoredGeocodes(final boolean detailedOnly, final Geopoint coords, final CacheType cacheType, final int listId) { - if (coords == null) { - throw new IllegalArgumentException("coords must not be null"); - } if (cacheType == null) { throw new IllegalArgumentException("cacheType must not be null"); } @@ -2643,7 +2298,9 @@ public class cgData { } try { - Cursor cursor = databaseRO.query( + Cursor cursor; + if (coords != null) { + cursor = databaseRO.query( dbTableCaches, new String[] { "geocode", "(abs(latitude-" + String.format((Locale) null, "%.6f", coords.getLatitude()) + ") + abs(longitude-" + String.format((Locale) null, "%.6f", coords.getLongitude()) + ")) as dif" }, @@ -2653,22 +2310,29 @@ public class cgData { null, "dif", null); + } else { + cursor = databaseRO.query( + dbTableCaches, + new String[] { "geocode" }, + specifySql.toString(), + null, + null, + null, + "geocode"); + } - if (cursor != null) { - if (cursor.getCount() > 0) { - cursor.moveToFirst(); - int index = cursor.getColumnIndex("geocode"); - - do { - geocodes.add(cursor.getString(index)); - } while (cursor.moveToNext()); - } + if (cursor.moveToFirst()) { + final int index = cursor.getColumnIndex("geocode"); - cursor.close(); + do { + geocodes.add(cursor.getString(index)); + } while (cursor.moveToNext()); } + cursor.close(); + } catch (Exception e) { - Log.e(Settings.tag, "cgData.loadBatchOfStoredGeocodes: " + e.toString()); + Log.e("cgData.loadBatchOfStoredGeocodes: " + e.toString()); } return geocodes; @@ -2718,58 +2382,46 @@ public class cgData { cursor.close(); } } catch (Exception e) { - Log.e(Settings.tag, "cgData.loadBatchOfHistoricGeocodes: " + e.toString()); + Log.e("cgData.loadBatchOfHistoricGeocodes: " + e.toString()); } return geocodes; } /** Retrieve all stored caches from DB */ - public Set<String> loadCachedInViewport(final Long centerLat, final Long centerLon, final Long spanLat, final Long spanLon, final CacheType cacheType) { - return loadInViewport(false, centerLat, centerLon, spanLat, spanLon, cacheType); + public Set<String> loadCachedInViewport(final Viewport viewport, final CacheType cacheType) { + return loadInViewport(false, viewport, cacheType); } /** Retrieve stored caches from DB with listId >= 1 */ - public Set<String> loadStoredInViewport(final Long centerLat, final Long centerLon, final Long spanLat, final Long spanLon, final CacheType cacheType) { - return loadInViewport(true, centerLat, centerLon, spanLat, spanLon, cacheType); + public Set<String> loadStoredInViewport(final Viewport viewport, final CacheType cacheType) { + return loadInViewport(true, viewport, cacheType); } - public Set<String> loadInViewport(final boolean stored, final Long centerLat, final Long centerLon, final Long spanLat, final Long spanLon, final CacheType cacheType) { - if (centerLat == null || centerLon == null || spanLat == null || spanLon == null) { - return null; - } - + /** + * Loads the geocodes of caches in a viewport from CacheCache and/or Database + * + * @param stored + * True - query only stored caches, False - query cached ones as well + * @param centerLat + * @param centerLon + * @param spanLat + * @param spanLon + * @param cacheType + * @return Set with geocodes + */ + private Set<String> loadInViewport(final boolean stored, final Viewport viewport, final CacheType cacheType) { init(); - Set<String> geocodes = new HashSet<String>(); + final Set<String> geocodes = new HashSet<String>(); + + // if not stored only, get codes from CacheCache as well + if (!stored) { + geocodes.addAll(CacheCache.getInstance().getInViewport(viewport, cacheType)); + } // viewport limitation - double latMin = (centerLat / 1e6) - ((spanLat / 1e6) / 2) - ((spanLat / 1e6) / 4); - double latMax = (centerLat / 1e6) + ((spanLat / 1e6) / 2) + ((spanLat / 1e6) / 4); - double lonMin = (centerLon / 1e6) - ((spanLon / 1e6) / 2) - ((spanLon / 1e6) / 4); - double lonMax = (centerLon / 1e6) + ((spanLon / 1e6) / 2) + ((spanLon / 1e6) / 4); - double llCache; - - if (latMin > latMax) { - llCache = latMax; - latMax = latMin; - latMin = llCache; - } - if (lonMin > lonMax) { - llCache = lonMax; - lonMax = lonMin; - lonMin = llCache; - } - - StringBuilder where = new StringBuilder(); - where.append("latitude >= "); - where.append(String.format((Locale) null, "%.6f", latMin)); - where.append(" and latitude <= "); - where.append(String.format((Locale) null, "%.6f", latMax)); - where.append(" and longitude >= "); - where.append(String.format((Locale) null, "%.6f", lonMin)); - where.append(" and longitude <= "); - where.append(String.format((Locale) null, "%.6f", lonMax)); + final StringBuilder where = new StringBuilder(buildCoordinateWhere(dbTableCaches, viewport)); // cacheType limitation if (cacheType != CacheType.ALL) { @@ -2784,7 +2436,7 @@ public class cgData { } try { - Cursor cursor = databaseRO.query( + final Cursor cursor = databaseRO.query( dbTableCaches, new String[] { "geocode" }, where.toString(), @@ -2794,75 +2446,16 @@ public class cgData { null, "500"); - if (cursor != null) { - if (cursor.getCount() > 0) { - cursor.moveToFirst(); - int index = cursor.getColumnIndex("geocode"); - - do { - geocodes.add(cursor.getString(index)); - } while (cursor.moveToNext()); - } else { - cursor.close(); - return null; - } - - cursor.close(); - } - } catch (Exception e) { - Log.e(Settings.tag, "cgData.loadInViewport: " + e.toString()); - } - - return geocodes; - } - - public List<String> getOfflineAll(CacheType cacheType) { - init(); - - List<String> geocodes = new ArrayList<String>(); - - StringBuilder where = new StringBuilder(); - - // cacheType limitation - if (cacheType != CacheType.ALL) { - where.append(cacheType); - where.append('"'); - } - - // offline caches only - if (where.length() > 0) { - where.append(" and "); - } - where.append("reason >= 1"); - - try { - Cursor cursor = databaseRO.query( - dbTableCaches, - new String[] { "geocode" }, - where.toString(), - null, - null, - null, - null, - "5000"); - - if (cursor != null) { - if (cursor.getCount() > 0) { - cursor.moveToFirst(); - int index = cursor.getColumnIndex("geocode"); - - do { - geocodes.add(cursor.getString(index)); - } while (cursor.moveToNext()); - } else { - cursor.close(); - return null; - } + if (cursor.moveToFirst()) { + final int index = cursor.getColumnIndex("geocode"); - cursor.close(); + do { + geocodes.add(cursor.getString(index)); + } while (cursor.moveToNext()); } + cursor.close(); } catch (Exception e) { - Log.e(Settings.tag, "cgData.getOfflineAll: " + e.toString()); + Log.e("cgData.loadInViewport: " + e.toString()); } return geocodes; @@ -2912,7 +2505,7 @@ public class cgData { public void clean(boolean more) { init(); - Log.d(Settings.tag, "Database clean: started"); + Log.d("Database clean: started"); Cursor cursor = null; Set<String> geocodes = new HashSet<String>(); @@ -2957,7 +2550,7 @@ public class cgData { final int size = geocodes.size(); if (size > 0) { - Log.d(Settings.tag, "Database clean: removing " + size + " geocaches from listId=0"); + Log.d("Database clean: removing " + size + " geocaches from listId=0"); removeCaches(geocodes, LoadFlags.REMOVE_ALL); } @@ -2965,13 +2558,13 @@ public class cgData { final SQLiteStatement countSql = databaseRO.compileStatement("select count(_id) from " + dbTableCaches + " where reason = 0"); final int count = (int) countSql.simpleQueryForLong(); countSql.close(); - Log.d(Settings.tag, "Database clean: " + count + " geocaches remaining for listId=0"); + Log.d("Database clean: " + count + " geocaches remaining for listId=0"); } catch (Exception e) { - Log.w(Settings.tag, "cgData.clean: " + e.toString()); + Log.w("cgData.clean: " + e.toString()); } - Log.d(Settings.tag, "Database clean: finished"); + Log.d("Database clean: finished"); } /** @@ -2987,7 +2580,7 @@ public class cgData { values.put("reason", StoredList.TEMPORARY_LIST_ID); databaseRW.update(dbTableCaches, values, "reason = ?", new String[] { Integer.toString(listId) }); } catch (Exception e) { - Log.e(Settings.tag, "cgData.dropList: error when updating reason", e); + Log.e("cgData.dropList: error when updating reason", e); } } @@ -3084,20 +2677,20 @@ public class cgData { } } } catch (Exception e) { - Log.e(Settings.tag, "cgData.saveLogOffline: " + e.toString()); + Log.e("cgData.saveLogOffline: " + e.toString()); } return status; } - public cgLog loadLogOffline(String geocode) { + public LogEntry loadLogOffline(String geocode) { if (StringUtils.isBlank(geocode)) { return null; } init(); - cgLog log = null; + LogEntry log = null; Cursor cursor = databaseRO.query( dbTableLogsOffline, @@ -3112,7 +2705,7 @@ public class cgData { if (cursor != null && cursor.getCount() > 0) { cursor.moveToFirst(); - log = new cgLog(); + log = new LogEntry(); log.id = cursor.getInt(cursor.getColumnIndex("_id")); log.type = LogType.getById(cursor.getInt(cursor.getColumnIndex("type"))); log.log = cursor.getString(cursor.getColumnIndex("log")); @@ -3166,7 +2759,7 @@ public class cgData { return logCount.simpleQueryForLong() > 0; } } catch (Exception e) { - Log.e(Settings.tag, "cgData.hasLogOffline", e); + Log.e("cgData.hasLogOffline", e); } return false; @@ -3209,7 +2802,7 @@ public class cgData { lists.addAll(storedLists); } catch (Exception e) { - Log.e(Settings.tag, "cgData.readLists: " + e.toString()); + Log.e("cgData.readLists: " + e.toString()); } return lists; } @@ -3386,7 +2979,7 @@ public class cgData { return true; } - public boolean removeSearchedDestination(cgDestination destination) { + public boolean removeSearchedDestination(Destination destination) { boolean success = true; if (destination == null) { success = false; @@ -3398,7 +2991,7 @@ public class cgData { databaseRW.delete(dbTableSearchDestionationHistory, "_id = " + destination.getId(), null); databaseRW.setTransactionSuccessful(); } catch (Exception e) { - Log.e(Settings.tag, "Unable to remove searched destination", e); + Log.e("Unable to remove searched destination", e); success = false; } finally { databaseRW.endTransaction(); @@ -3435,7 +3028,7 @@ public class cgData { } catch (SQLiteDoneException e) { // Do nothing, it only means we have no information on the cache } catch (Exception e) { - Log.e(Settings.tag, "cgData.getCacheDescription", e); + Log.e("cgData.getCacheDescription", e); } return null; @@ -3457,7 +3050,7 @@ public class cgData { newlyCreatedDatabase = false; } - private static StringBuilder whereGeocodeIn(Set<String> geocodes) { + private static String whereGeocodeIn(Set<String> geocodes) { final StringBuilder where = new StringBuilder(); if (geocodes != null && geocodes.size() > 0) { @@ -3476,7 +3069,59 @@ public class cgData { where.append(')'); } - return where; + return where.toString(); + } + + /** + * Loads all Waypoints in the coordinate rectangle. + * + * @param centerLat + * @param centerLon + * @param spanLat + * @param spanLon + * @param excludeDisabled + * @param excludeMine + * @return + */ + + public Collection<? extends cgWaypoint> loadWaypoints(final Viewport viewport, boolean excludeMine, boolean excludeDisabled) { + final StringBuilder where = new StringBuilder(buildCoordinateWhere(dbTableWaypoints, viewport)); + if (excludeMine) + { + where.append("and " + dbTableCaches + ".own == 0 and " + dbTableCaches + ".found == 0 "); + } + if (excludeDisabled) + { + where.append("and " + dbTableCaches + ".disabled == 0 "); + } + init(); + + List<cgWaypoint> waypoints = new ArrayList<cgWaypoint>(); + + String query = "SELECT "; + for (int i = 0; i < WAYPOINT_COLUMNS.length; i++) { + query += (i > 0 ? ", " : "") + dbTableWaypoints + "." + WAYPOINT_COLUMNS[i] + " "; + } + query += " FROM " + dbTableWaypoints + ", " + dbTableCaches + " WHERE " + dbTableWaypoints + "._id == " + dbTableCaches + "._id and " + where; + Cursor cursor = databaseRO.rawQuery( + query, null); + + if (cursor != null && cursor.getCount() > 0) { + cursor.moveToFirst(); + + do { + + cgWaypoint waypoint = createWaypointFromDatabaseContent(cursor); + + waypoints.add(waypoint); + } while (cursor.moveToNext()); + } + + if (cursor != null) { + cursor.close(); + } + + return waypoints; } } diff --git a/main/src/cgeo/geocaching/cgDestination.java b/main/src/cgeo/geocaching/cgDestination.java deleted file mode 100644 index cf9a8ef..0000000 --- a/main/src/cgeo/geocaching/cgDestination.java +++ /dev/null @@ -1,74 +0,0 @@ -package cgeo.geocaching; - -import cgeo.geocaching.geopoint.Geopoint; - -public class cgDestination { - - private long id; - - private long date; - - private Geopoint coords; - - public cgDestination() { - } - - public cgDestination(long id, long date, final Geopoint coords) { - super(); - this.id = id; - this.date = date; - this.coords = coords; - } - - public long getDate() { - return date; - } - - public void setDate(long date) { - this.date = date; - } - - public Geopoint getCoords() { - return coords; - } - - public void setCoords(final Geopoint coords) { - this.coords = coords; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - long temp; - temp = Double.doubleToLongBits(coords.getLatitude()); - result = prime * result + (int) (temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(coords.getLongitude()); - result = prime * result + (int) (temp ^ (temp >>> 32)); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof cgDestination)) { - return false; - } - cgDestination other = (cgDestination) obj; - return coords.isEqualTo(other.coords); - } - - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - -} diff --git a/main/src/cgeo/geocaching/cgGeo.java b/main/src/cgeo/geocaching/cgGeo.java index a8748c0..c5ab556 100644 --- a/main/src/cgeo/geocaching/cgGeo.java +++ b/main/src/cgeo/geocaching/cgGeo.java @@ -45,7 +45,7 @@ public class cgGeo { try { geoManager.requestLocationUpdates(listener.locationProvider, 0, 0, listener); } catch (Exception e) { - Log.w(Settings.tag, "There is no location provider " + listener.locationProvider); + Log.w("There is no location provider " + listener.locationProvider); } } } @@ -244,7 +244,7 @@ public class cgGeo { lastLocation.setProvider(LAST_LOCATION_PSEUDO_PROVIDER); assign(lastLocation); - Log.i(Settings.tag, "Using last location from " + provider); + Log.i("Using last location from " + provider); break; } } diff --git a/main/src/cgeo/geocaching/cgLog.java b/main/src/cgeo/geocaching/cgLog.java deleted file mode 100644 index 2b3568d..0000000 --- a/main/src/cgeo/geocaching/cgLog.java +++ /dev/null @@ -1,39 +0,0 @@ -package cgeo.geocaching; - -import cgeo.geocaching.enumerations.LogType; - -import java.util.List; - -public class cgLog { - public int id = 0; - public LogType type = LogType.LOG_NOTE; // note - public String author = ""; - public String log = ""; - public long date = 0; - public int found = -1; - /** Friend's logentry */ - public boolean friend = false; - public List<cgImage> logImages = null; - public String cacheName = ""; // used for trackables - public String cacheGuid = ""; // used for trackables - - @Override - public int hashCode() { - return (int) date * type.hashCode() * author.hashCode() * log.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof cgLog)) { - return false; - } - final cgLog otherLog = (cgLog) obj; - return date == otherLog.date && - type == otherLog.type && - author.compareTo(otherLog.author) == 0 && - log.compareTo(otherLog.log) == 0 ? true : false; - } -} diff --git a/main/src/cgeo/geocaching/cgSearchHandler.java b/main/src/cgeo/geocaching/cgSearchHandler.java index 5f94d32..6d38ea1 100644 --- a/main/src/cgeo/geocaching/cgSearchHandler.java +++ b/main/src/cgeo/geocaching/cgSearchHandler.java @@ -99,7 +99,7 @@ public class cgSearchHandler extends Handler { imgHandler.sendEmptyMessage(0); } catch (IOException e) { - Log.e(Settings.tag, "Failed to download reCAPTCHA image"); + Log.e("Failed to download reCAPTCHA image"); } } } diff --git a/main/src/cgeo/geocaching/cgSearchThread.java b/main/src/cgeo/geocaching/cgSearchThread.java index 99ab685..ff73a66 100644 --- a/main/src/cgeo/geocaching/cgSearchThread.java +++ b/main/src/cgeo/geocaching/cgSearchThread.java @@ -23,7 +23,7 @@ abstract public class cgSearchThread extends Thread { try { wait(); } catch (InterruptedException e) { - Log.w(Settings.tag, "searchThread is not waiting for user..."); + Log.w("searchThread is not waiting for user..."); } } diff --git a/main/src/cgeo/geocaching/cgTrackable.java b/main/src/cgeo/geocaching/cgTrackable.java index 1e11b43..f46e39b 100644 --- a/main/src/cgeo/geocaching/cgTrackable.java +++ b/main/src/cgeo/geocaching/cgTrackable.java @@ -34,7 +34,7 @@ public class cgTrackable implements ILogable { private String goal = null; private String details = null; private String image = null; - private List<cgLog> logs = new ArrayList<cgLog>(); + private List<LogEntry> logs = new ArrayList<LogEntry>(); private String trackingcode = null; public String getUrl() { @@ -44,7 +44,7 @@ public class cgTrackable implements ILogable { int id = Integer.parseInt(hex, 16); return "http://geokrety.org/konkret.php?id=" + id; } catch (NumberFormatException e) { - Log.e(Settings.tag, "cgTrackable.getUrl", e); + Log.e("cgTrackable.getUrl", e); return null; } } @@ -188,11 +188,11 @@ public class cgTrackable implements ILogable { this.image = image; } - public List<cgLog> getLogs() { + public List<LogEntry> getLogs() { return logs; } - public void setLogs(List<cgLog> logs) { + public void setLogs(List<LogEntry> logs) { this.logs = logs; } diff --git a/main/src/cgeo/geocaching/cgTrackableLog.java b/main/src/cgeo/geocaching/cgTrackableLog.java deleted file mode 100644 index ee134da..0000000 --- a/main/src/cgeo/geocaching/cgTrackableLog.java +++ /dev/null @@ -1,11 +0,0 @@ -package cgeo.geocaching; - -import cgeo.geocaching.enumerations.LogTypeTrackable; - -public class cgTrackableLog { - public int ctl = -1; - public int id = -1; - public String trackCode = null; - public String name = null; - public LogTypeTrackable action = LogTypeTrackable.DO_NOTHING; // base.logTrackablesAction - no action -} diff --git a/main/src/cgeo/geocaching/cgWaypoint.java b/main/src/cgeo/geocaching/cgWaypoint.java index d70e5ae..ee865ee 100644 --- a/main/src/cgeo/geocaching/cgWaypoint.java +++ b/main/src/cgeo/geocaching/cgWaypoint.java @@ -179,10 +179,6 @@ public class cgWaypoint implements IWaypoint, Comparable<cgWaypoint> { return waypointType; } - public void setWaypointType(WaypointType type) { - this.waypointType = type; - } - public String getLookup() { return lookup; } @@ -223,14 +219,6 @@ public class cgWaypoint implements IWaypoint, Comparable<cgWaypoint> { this.note = note; } - public int getCachedOrder() { - return cachedOrder; - } - - public void setCachedOrder(int cachedOrder) { - this.cachedOrder = cachedOrder; - } - @Override public String toString() { return name + " " + waypointType.getL10n(); diff --git a/main/src/cgeo/geocaching/cgeo.java b/main/src/cgeo/geocaching/cgeo.java index ba7d725..86f8824 100644 --- a/main/src/cgeo/geocaching/cgeo.java +++ b/main/src/cgeo/geocaching/cgeo.java @@ -2,17 +2,13 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.activity.ActivityMixin; -import cgeo.geocaching.enumerations.CacheSize; +import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.enumerations.CacheType; -import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy; -import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.StatusCode; -import cgeo.geocaching.enumerations.WaypointType; 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 cgeo.geocaching.utils.Log; @@ -151,9 +147,9 @@ public class cgeo extends AbstractActivity { final int satellitesFixed = msg.arg1; final int satellitesVisible = msg.arg2; if (satellitesFixed > 0) { - satellites = res.getString(R.string.loc_sat) + ": " + satellitesFixed + "/" + satellitesVisible; + satellites = res.getString(R.string.loc_sat) + ": " + satellitesFixed + '/' + satellitesVisible; } else if (satellitesVisible >= 0) { - satellites = res.getString(R.string.loc_sat) + ": 0/" + geo.satellitesVisible; + satellites = res.getString(R.string.loc_sat) + ": 0/" + satellitesVisible; } break; } @@ -184,7 +180,7 @@ public class cgeo extends AbstractActivity { showToast(res.getString(reason == StatusCode.MAINTENANCE ? reason.getErrorString() : R.string.err_login_failed_toast)); } } catch (Exception e) { - Log.w(Settings.tag, "cgeo.fisrtLoginHander: " + e.toString()); + Log.w("cgeo.firstLoginHander: " + e.toString()); } } }; @@ -226,12 +222,12 @@ public class cgeo extends AbstractActivity { version = info.versionCode; - Log.i(Settings.tag, "Starting " + info.packageName + " " + info.versionCode + " a.k.a " + info.versionName + "..."); + Log.i("Starting " + info.packageName + " " + info.versionCode + " a.k.a " + info.versionName + "..."); info = null; manager = null; } catch (Exception e) { - Log.i(Settings.tag, "No info."); + Log.i("No info."); } try { @@ -517,29 +513,6 @@ public class cgeo extends AbstractActivity { initialized = true; Settings.setLanguage(Settings.isUseEnglish()); - - /* - * "update" the cache size/type. For a better performance - * the resource strings are stored in the enum's. In case of a - * locale change the resource strings don't get updated automatically. - * That's why we have to do it on our own. - */ - for (CacheSize cacheSize : CacheSize.values()) { - cacheSize.setL10n(); - } - for (CacheType cacheType : CacheType.values()) { - cacheType.setL10n(); - } - for (LogType logType : LogType.values()) { - logType.setL10n(); - } - for (WaypointType waypointType : WaypointType.values()) { - waypointType.setL10n(); - } - for (Strategy strategy : Strategy.values()) { - strategy.setL10n(); - } - Settings.getLogin(); if (app.firstRun) { @@ -702,7 +675,7 @@ public class cgeo extends AbstractActivity { navLocation.setText(res.getString(R.string.loc_trying)); } } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); + Log.w("Failed to update location."); } } } @@ -792,7 +765,7 @@ public class cgeo extends AbstractActivity { countBubble.setVisibility(View.VISIBLE); } } catch (Exception e) { - Log.w(Settings.tag, "cgeo.countBubbleHander: " + e.toString()); + Log.w("cgeo.countBubbleHander: " + e.toString()); } } }; @@ -836,7 +809,7 @@ public class cgeo extends AbstractActivity { boolean more = false; if (version != Settings.getVersion()) { - Log.i(Settings.tag, "Initializing hard cleanup - version changed from " + Settings.getVersion() + " to " + version + "."); + Log.i("Initializing hard cleanup - version changed from " + Settings.getVersion() + " to " + version + "."); more = true; } @@ -874,9 +847,7 @@ public class cgeo extends AbstractActivity { // invoke settings activity to insert login details if (status == StatusCode.NO_LOGIN_INFO_STORED) { - final Context context = cgeo.this; - final Intent initIntent = new Intent(context, cgeoinit.class); - context.startActivity(initIntent); + cgeoinit.startActivity(cgeo.this); } } } @@ -903,7 +874,7 @@ public class cgeo extends AbstractActivity { addresses = geocoder.getFromLocation(geo.coordsNow.getLatitude(), geo.coordsNow.getLongitude(), 1); } catch (Exception e) { - Log.i(Settings.tag, "Failed to obtain address"); + Log.i("Failed to obtain address"); } obtainAddressHandler.sendEmptyMessage(0); diff --git a/main/src/cgeo/geocaching/cgeoabout.java b/main/src/cgeo/geocaching/cgeoabout.java index c1f7e83..0c812f0 100644 --- a/main/src/cgeo/geocaching/cgeoabout.java +++ b/main/src/cgeo/geocaching/cgeoabout.java @@ -37,7 +37,7 @@ public class cgeoabout extends AbstractActivity { ((TextView) findViewById(R.id.contributors)).setMovementMethod(LinkMovementMethod.getInstance()); ((TextView) findViewById(R.id.changelog)).setMovementMethod(LinkMovementMethod.getInstance()); } catch (Exception e) { - Log.e(Settings.tag, "cgeoabout.init: Failed to obtain package version."); + Log.e("cgeoabout.init: Failed to obtain package version."); } } diff --git a/main/src/cgeo/geocaching/cgeoadvsearch.java b/main/src/cgeo/geocaching/cgeoadvsearch.java index 2086c7d..194fdbb 100644 --- a/main/src/cgeo/geocaching/cgeoadvsearch.java +++ b/main/src/cgeo/geocaching/cgeoadvsearch.java @@ -146,7 +146,7 @@ public class cgeoadvsearch extends AbstractActivity { } } catch (Exception e) { - Log.w(Settings.tag, "cgeoadvsearch.instantSearch: " + e.toString()); + Log.w("cgeoadvsearch.instantSearch: " + e.toString()); } return false; @@ -271,7 +271,7 @@ public class cgeoadvsearch extends AbstractActivity { } } } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); + Log.w("Failed to update location."); } } } @@ -313,7 +313,7 @@ public class cgeoadvsearch extends AbstractActivity { } } else { try { - cgeocaches.startActivityCoordinates(this, GeopointParser.parseLatitude(latText), GeopointParser.parseLongitude(lonText)); + cgeocaches.startActivityCoordinates(this, GeopointParser.parse(latText, lonText)); } catch (GeopointParser.ParseException e) { showToast(res.getString(e.resource)); } diff --git a/main/src/cgeo/geocaching/cgeoapplication.java b/main/src/cgeo/geocaching/cgeoapplication.java index 6418d86..8b5eb57 100644 --- a/main/src/cgeo/geocaching/cgeoapplication.java +++ b/main/src/cgeo/geocaching/cgeoapplication.java @@ -7,6 +7,7 @@ import cgeo.geocaching.enumerations.LoadFlags.LoadFlag; import cgeo.geocaching.enumerations.LoadFlags.RemoveFlag; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; @@ -21,9 +22,10 @@ import android.os.Message; import java.io.File; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.EnumSet; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -54,14 +56,14 @@ public class cgeoapplication extends Application { @Override public void onLowMemory() { - Log.i(Settings.tag, "Cleaning applications cache."); + Log.i("Cleaning applications cache."); storage.removeAllFromCache(); } @Override public void onTerminate() { - Log.d(Settings.tag, "Terminating c:geo..."); + Log.d("Terminating c:geo..."); cleanGeo(); cleanDir(); @@ -135,7 +137,7 @@ public class cgeoapplication extends Application { public cgGeo startGeo(UpdateLocationCallback geoUpdate) { if (geo == null) { geo = new cgGeo(); - Log.i(Settings.tag, "Location service started"); + Log.i("Location service started"); } geo.replaceUpdate(geoUpdate); @@ -171,7 +173,7 @@ public class cgeoapplication extends Application { if (!geoInUse && geo != null) { cleanGeo(); - Log.i(Settings.tag, "Location service stopped"); + Log.i("Location service stopped"); } } } @@ -180,7 +182,7 @@ public class cgeoapplication extends Application { if (dir == null) { dir = new cgDirection(context, dirUpdate); - Log.i(Settings.tag, "Direction service started"); + Log.i("Direction service started"); } dir.replaceUpdate(dirUpdate); @@ -212,7 +214,7 @@ public class cgeoapplication extends Application { if (!dirInUse && dir != null) { cleanDir(); - Log.i(Settings.tag, "Direction service stopped"); + Log.i("Direction service stopped"); } } } @@ -275,19 +277,16 @@ public class cgeoapplication extends Application { return storage.allDetailedThere(); } - public List<Number> getBounds(String geocode) { + public Viewport getBounds(String geocode) { if (geocode == null) { return null; } - Set<String> geocodeList = new HashSet<String>(); - geocodeList.add(geocode); - - return getBounds(geocodeList); + return getBounds(Collections.singleton(geocode)); } /** {@link cgData#getBounds(Set)} */ - public List<Number> getBounds(final Set<String> geocodes) { + public Viewport getBounds(final Set<String> geocodes) { return storage.getBounds(geocodes); } @@ -298,7 +297,7 @@ public class cgeoapplication extends Application { } /** {@link cgData#loadHistoryOfSearchedLocations()} */ - public List<cgDestination> getHistoryOfSearchedLocations() { + public List<Destination> getHistoryOfSearchedLocations() { return storage.loadHistoryOfSearchedLocations(); } @@ -307,15 +306,15 @@ public class cgeoapplication extends Application { return new SearchResult(geocodes, getAllHistoricCachesCount()); } - /** {@link cgData#loadCachedInViewport(Long, Long, Long, Long, CacheType)} */ - public SearchResult getCachedInViewport(final Long centerLat, final Long centerLon, final Long spanLat, final Long spanLon, final CacheType cacheType) { - final Set<String> geocodes = storage.loadCachedInViewport(centerLat, centerLon, spanLat, spanLon, cacheType); + /** {@link cgData#loadCachedInViewport(long, long, long, long, CacheType)} */ + public SearchResult getCachedInViewport(final Viewport viewport, final CacheType cacheType) { + final Set<String> geocodes = storage.loadCachedInViewport(viewport, cacheType); return new SearchResult(geocodes); } - /** {@link cgData#loadStoredInViewport(Long, Long, Long, Long, CacheType)} */ - public SearchResult getStoredInViewport(final Long centerLat, final Long centerLon, final Long spanLat, final Long spanLon, final CacheType cacheType) { - final Set<String> geocodes = storage.loadStoredInViewport(centerLat, centerLon, spanLat, spanLon, cacheType); + /** {@link cgData#loadStoredInViewport(long, long, long, long, CacheType)} */ + public SearchResult getStoredInViewport(final Viewport viewport, final CacheType cacheType) { + final Set<String> geocodes = storage.loadStoredInViewport(viewport, cacheType); return new SearchResult(geocodes); } @@ -349,9 +348,9 @@ public class cgeoapplication extends Application { return storage.clearSearchedDestinations(); } - /** {@link cgData#saveSearchedDestination(cgDestination)} */ - public boolean saveSearchedDestination(cgDestination destination) { - return storage.saveSearchedDestination(destination); + /** {@link cgData#saveSearchedDestination(Destination)} */ + public void saveSearchedDestination(Destination destination) { + storage.saveSearchedDestination(destination); } /** {@link cgData#saveWaypoints(String, List, boolean)} */ @@ -384,21 +383,11 @@ public class cgeoapplication extends Application { storage.dropList(listId); } - /** {@link cgData#loadInventory(String)} */ - public List<cgTrackable> loadInventory(String geocode) { - return storage.loadInventory(geocode); - } - /** {@link cgData#loadLogCounts(String)} */ public Map<LogType, Integer> loadLogCounts(String geocode) { return storage.loadLogCounts(geocode); } - /** {@link cgData#loadSpoilers(String)} */ - public List<cgImage> loadSpoilers(String geocode) { - return storage.loadSpoilers(geocode); - } - /** {@link cgData#loadWaypoint(int)} */ public cgWaypoint loadWaypoint(int id) { return storage.loadWaypoint(id); @@ -423,7 +412,7 @@ public class cgeoapplication extends Application { return StringUtils.defaultString(action); } - public boolean addLog(String geocode, cgLog log) { + public boolean addLog(String geocode, LogEntry log) { if (StringUtils.isBlank(geocode)) { return false; } @@ -431,7 +420,7 @@ public class cgeoapplication extends Application { return false; } - List<cgLog> list = new ArrayList<cgLog>(); + List<LogEntry> list = new ArrayList<LogEntry>(); list.add(log); return storage.saveLogs(geocode, list, false); @@ -451,7 +440,7 @@ public class cgeoapplication extends Application { } /** {@link cgData#loadLogOffline(String)} */ - public cgLog loadLogOffline(String geocode) { + public LogEntry loadLogOffline(String geocode) { return storage.loadLogOffline(geocode); } @@ -495,8 +484,8 @@ public class cgeoapplication extends Application { return storage.removeList(id); } - /** {@link cgData#removeSearchedDestination(cgDestination)} */ - public boolean removeSearchedDestinations(cgDestination destination) { + /** {@link cgData#removeSearchedDestination(Destination)} */ + public boolean removeSearchedDestinations(Destination destination) { return storage.removeSearchedDestination(destination); } @@ -520,11 +509,6 @@ public class cgeoapplication extends Application { return storage.loadCaches(geocodes, loadFlags); } - /** {@link cgData#loadCaches} */ - public Set<cgCache> loadCaches(Long centerLat, Long centerLon, Long spanLat, Long spanLon, final EnumSet<LoadFlag> loadFlags) { - return storage.loadCaches(null, centerLat, centerLon, spanLat, spanLon, loadFlags); - } - /** {@link cgData#saveCache} */ public boolean saveCache(cgCache cache, EnumSet<LoadFlags.SaveFlag> saveFlags) { return storage.saveCache(cache, saveFlags); @@ -540,4 +524,8 @@ public class cgeoapplication extends Application { storage.removeCaches(geocodes, removeFlags); } + public Collection<? extends cgWaypoint> getWaypointsInViewport(final Viewport viewport, boolean excludeMine, boolean excludeDisabled) { + return storage.loadWaypoints(viewport, excludeMine, excludeDisabled); + } + } diff --git a/main/src/cgeo/geocaching/cgeocaches.java b/main/src/cgeo/geocaching/cgeocaches.java index 63b9a2e..70bf892 100644 --- a/main/src/cgeo/geocaching/cgeocaches.java +++ b/main/src/cgeo/geocaching/cgeocaches.java @@ -6,21 +6,19 @@ import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.activity.Progress; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; import cgeo.geocaching.apps.cachelist.CacheListAppFactory; +import cgeo.geocaching.connector.gc.GCParser; import cgeo.geocaching.enumerations.CacheListType; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.StatusCode; +import cgeo.geocaching.export.ExportFactory; import cgeo.geocaching.files.GPXImporter; -import cgeo.geocaching.filter.AttributeFilter; +import cgeo.geocaching.filter.FilterUserInterface; import cgeo.geocaching.filter.IFilter; -import cgeo.geocaching.filter.ModifiedFilter; -import cgeo.geocaching.filter.SizeFilter; -import cgeo.geocaching.filter.StateFilter; -import cgeo.geocaching.filter.TrackablesFilter; -import cgeo.geocaching.filter.TypeFilter; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.maps.CGeoMap; +import cgeo.geocaching.network.Cookies; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.sorting.CacheComparator; @@ -54,7 +52,6 @@ import android.content.Intent; import android.content.res.Configuration; import android.net.Uri; import android.os.Bundle; -import android.os.Environment; import android.os.Handler; import android.os.Message; import android.view.ContextMenu; @@ -66,23 +63,15 @@ import android.view.MenuItem; import android.view.SubMenu; import android.view.View; import android.widget.AdapterView.AdapterContextMenuInfo; -import android.widget.EditText; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -91,6 +80,7 @@ public class cgeocaches extends AbstractListActivity { private static final int MAX_LIST_ITEMS = 1000; private static final String EXTRAS_LIST_TYPE = "type"; + private static final String EXTRAS_COORDS = "coords"; private static final int MENU_REFRESH_STORED = 2; private static final int MENU_CACHE_DETAILS = 4; private static final int MENU_DROP_CACHES = 5; @@ -110,20 +100,15 @@ public class cgeocaches extends AbstractListActivity { private static final int MENU_SORT_VOTE = 19; private static final int MENU_SORT_INVENTORY = 20; private static final int MENU_IMPORT_WEB = 21; - private static final int MENU_EXPORT_NOTES = 22; + private static final int MENU_EXPORT = 22; private static final int MENU_REMOVE_FROM_HISTORY = 23; private static final int MENU_DROP_CACHE = 24; private static final int MENU_MOVE_TO_LIST = 25; - private static final int MENU_FILTER_CLEAR = 26; - private static final int MENU_FILTER_TRACKABLES = 27; - private static final int SUBMENU_FILTER_SIZE = 28; - private static final int SUBMENU_FILTER_TYPE = 29; private static final int MENU_SWITCH_SELECT_MODE = 52; private static final int SUBMENU_SHOW_MAP = 54; private static final int SUBMENU_MANAGE_LISTS = 55; private static final int SUBMENU_MANAGE_OFFLINE = 56; private static final int SUBMENU_SORT = 57; - private static final int SUBMENU_FILTER = 58; private static final int SUBMENU_IMPORT = 59; private static final int SUBMENU_MANAGE_HISTORY = 60; private static final int MENU_SORT_DATE = 61; @@ -132,10 +117,9 @@ public class cgeocaches extends AbstractListActivity { private static final int MENU_RENAME_LIST = 64; private static final int MENU_DROP_CACHES_AND_LIST = 65; private static final int MENU_DEFAULT_NAVIGATION = 66; - private static final int SUBMENU_FILTER_ATTRIBUTES = 67; - private static final int SUBMENU_FILTER_STATE = 68; private static final int MENU_NAVIGATION = 69; - private static final int MENU_FILTER_MODIFIED = 70; + private static final int MENU_STORE_CACHE = 73; + private static final int MENU_FILTER = 74; private static final int MSG_DONE = -1; private static final int MSG_CANCEL = -99; @@ -166,10 +150,8 @@ public class cgeocaches extends AbstractListActivity { private LoadDetailsThread threadDetails = null; private LoadFromWebThread threadWeb = null; private DropDetailsThread threadR = null; - private ExportFieldNotesThread threadF = null; private RemoveFromHistoryThread threadH = null; private int listId = StoredList.TEMPORARY_LIST_ID; - private List<StoredList> lists = null; private GeocodeComparator gcComparator = new GeocodeComparator(); private Handler loadCachesHandler = new Handler() { @@ -206,14 +188,14 @@ public class cgeocaches extends AbstractListActivity { dialog.setNegativeButton(res.getString(R.string.license_dismiss), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { - Network.clearCookies(); + Cookies.clearCookies(); dialog.cancel(); } }); dialog.setPositiveButton(res.getString(R.string.license_show), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { - Network.clearCookies(); + Cookies.clearCookies(); startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/software/agreement.aspx?ID=0"))); } }); @@ -236,7 +218,7 @@ public class cgeocaches extends AbstractListActivity { } } catch (Exception e) { showToast(res.getString(R.string.err_detail_cache_find_any)); - Log.e(Settings.tag, "cgeocaches.loadCachesHandler: " + e.toString()); + Log.e("cgeocaches.loadCachesHandler: " + e.toString()); hideLoading(); showProgress(false); @@ -249,7 +231,7 @@ public class cgeocaches extends AbstractListActivity { hideLoading(); showProgress(false); } catch (Exception e2) { - Log.e(Settings.tag, "cgeocaches.loadCachesHandler.2: " + e2.toString()); + Log.e("cgeocaches.loadCachesHandler.2: " + e2.toString()); } if (adapter != null) { @@ -303,7 +285,7 @@ public class cgeocaches extends AbstractListActivity { } } catch (Exception e) { showToast(res.getString(R.string.err_detail_cache_find_next)); - Log.e(Settings.tag, "cgeocaches.loadNextPageHandler: " + e.toString()); + Log.e("cgeocaches.loadNextPageHandler: " + e.toString()); } hideLoading(); @@ -469,39 +451,6 @@ public class cgeocaches extends AbstractListActivity { } } }; - private Handler exportFieldNotesHandler = new Handler() { - - @Override - public void handleMessage(Message msg) - { - setAdapter(); - - if (msg.what > -1) - { - cacheList.get(msg.what).setStatusChecked(false); - progress.setProgress(detailProgress); - } - else if (-2 == msg.what) - { - showToast(res.getString(R.string.info_fieldnotes_exported_to) + ": " + msg.obj.toString()); - } - else if (-3 == msg.what) - { - showToast(res.getString(R.string.err_fieldnotes_export_failed)); - } else if (msg.what == MSG_CANCEL) { - if (threadF != null) { - threadF.kill(); - } - } else { - if (adapter != null) - { - adapter.setSelectMode(false, true); - } - - progress.dismiss(); - } - } - }; private Handler importGpxAttachementFinishedHandler = new Handler() { @Override @@ -537,7 +486,7 @@ public class cgeocaches extends AbstractListActivity { if (extras != null) { Object typeObject = extras.get(EXTRAS_LIST_TYPE); type = (typeObject instanceof CacheListType) ? (CacheListType) typeObject : CacheListType.OFFLINE; - coords = new Geopoint(extras.getDouble("latitude"), extras.getDouble("longitude")); + coords = (Geopoint) extras.getParcelable(EXTRAS_COORDS); cacheType = Settings.getCacheType(); keyword = extras.getString("keyword"); address = extras.getString("address"); @@ -546,7 +495,7 @@ public class cgeocaches extends AbstractListActivity { if (Intent.ACTION_VIEW.equals(getIntent().getAction())) { type = CacheListType.OFFLINE; if (coords == null) { - coords = new Geopoint(0, 0); + coords = new Geopoint(0.0, 0.0); } } @@ -666,7 +615,7 @@ public class cgeocaches extends AbstractListActivity { default: title = "caches"; setTitle(title); - Log.e(Settings.tag, "cgeocaches.onCreate: No action or unknown action specified"); + Log.e("cgeocaches.onCreate: No action or unknown action specified"); break; } prepareFilterBar(); @@ -726,7 +675,7 @@ public class cgeocaches extends AbstractListActivity { // refresh standard list if it has changed (new caches downloaded) if (type == CacheListType.OFFLINE && listId >= StoredList.STANDARD_LIST_ID && search != null) { - SearchResult newSearch = cgBase.searchByStored(coords, cacheType, listId); + SearchResult newSearch = cgeoapplication.getInstance().getBatchOfStoredCaches(true, coords, cacheType, listId); if (newSearch != null && newSearch.getTotal() != search.getTotal()) { refreshCurrentList(); } @@ -760,17 +709,7 @@ public class cgeocaches extends AbstractListActivity { @Override public boolean onCreateOptionsMenu(Menu menu) { - SubMenu subMenuFilter = menu.addSubMenu(0, SUBMENU_FILTER, 0, res.getString(R.string.caches_filter)).setIcon(R.drawable.ic_menu_filter); - subMenuFilter.setHeaderTitle(res.getString(R.string.caches_filter_title)); - if (Settings.getCacheType() == CacheType.ALL) { - subMenuFilter.add(0, SUBMENU_FILTER_TYPE, 0, res.getString(R.string.caches_filter_type)); - } - subMenuFilter.add(0, SUBMENU_FILTER_SIZE, 0, res.getString(R.string.caches_filter_size)); - subMenuFilter.add(0, SUBMENU_FILTER_ATTRIBUTES, 0, res.getString(R.string.cache_attributes)); - subMenuFilter.add(0, SUBMENU_FILTER_STATE, 0, res.getString(R.string.cache_status)); - subMenuFilter.add(0, MENU_FILTER_TRACKABLES, 0, res.getString(R.string.caches_filter_track)); - subMenuFilter.add(0, MENU_FILTER_MODIFIED, 0, res.getString(R.string.caches_filter_modified)); - subMenuFilter.add(0, MENU_FILTER_CLEAR, 0, res.getString(R.string.caches_filter_clear)); + menu.add(0, MENU_FILTER, 0, res.getString(R.string.caches_filter)).setIcon(R.drawable.ic_menu_filter); SubMenu subMenuSort = menu.addSubMenu(0, SUBMENU_SORT, 0, res.getString(R.string.caches_sort)).setIcon(android.R.drawable.ic_menu_sort_alphabetically); subMenuSort.setHeaderTitle(res.getString(R.string.caches_sort_title)); @@ -808,9 +747,8 @@ public class cgeocaches extends AbstractListActivity { subMenu.add(0, MENU_DROP_CACHES_AND_LIST, 0, res.getString(R.string.caches_drop_all_and_list)); subMenu.add(0, MENU_REFRESH_STORED, 0, res.getString(R.string.cache_offline_refresh)); // download details for all caches subMenu.add(0, MENU_MOVE_TO_LIST, 0, res.getString(R.string.cache_menu_move_list)); - subMenu.add(0, MENU_EXPORT_NOTES, 0, res.getString(R.string.cache_export_fieldnote)); // export field notes - if (Settings.getWebDeviceCode() == null) - { + subMenu.add(0, MENU_EXPORT, 0, res.getString(R.string.export)); // export caches + if (Settings.getWebDeviceCode() == null) { menu.add(0, MENU_IMPORT_GPX, 0, res.getString(R.string.gpx_import_title)).setIcon(android.R.drawable.ic_menu_upload); // import gpx file } else { SubMenu subMenuImport = menu.addSubMenu(0, SUBMENU_IMPORT, 0, res.getString(R.string.import_title)).setIcon(android.R.drawable.ic_menu_upload); // import @@ -818,11 +756,10 @@ public class cgeocaches extends AbstractListActivity { subMenuImport.add(1, MENU_IMPORT_WEB, 0, res.getString(R.string.web_import_title)).setCheckable(false).setChecked(false); } } else { - if (type == CacheListType.HISTORY) - { + if (type == CacheListType.HISTORY) { SubMenu subMenu = menu.addSubMenu(0, SUBMENU_MANAGE_HISTORY, 0, res.getString(R.string.caches_manage)).setIcon(android.R.drawable.ic_menu_save); subMenu.add(0, MENU_REMOVE_FROM_HISTORY, 0, res.getString(R.string.cache_clear_history)); // remove from history - subMenu.add(0, MENU_EXPORT_NOTES, 0, res.getString(R.string.cache_export_fieldnote)); // export field notes + subMenu.add(0, MENU_EXPORT, 0, res.getString(R.string.export)); // export caches } menu.add(0, MENU_REFRESH_STORED, 0, res.getString(R.string.caches_store_offline)).setIcon(android.R.drawable.ic_menu_set_as); // download details for all caches } @@ -859,30 +796,12 @@ public class cgeocaches extends AbstractListActivity { boolean isNonDefaultList = listId != StoredList.STANDARD_LIST_ID; if (type == CacheListType.OFFLINE) { // only offline list - if (hasSelection) { - menu.findItem(MENU_DROP_CACHES).setTitle(res.getString(R.string.caches_drop_selected) + " (" + adapter.getChecked() + ")"); - } else { - menu.findItem(MENU_DROP_CACHES).setTitle(res.getString(R.string.caches_drop_all)); - } + setMenuItemLabel(menu, MENU_DROP_CACHES, R.string.caches_drop_selected, R.string.caches_drop_all); menu.findItem(MENU_DROP_CACHES_AND_LIST).setVisible(!hasSelection && isNonDefaultList); - - if (hasSelection) { - menu.findItem(MENU_REFRESH_STORED).setTitle(res.getString(R.string.caches_refresh_selected) + " (" + adapter.getChecked() + ")"); - } else { - menu.findItem(MENU_REFRESH_STORED).setTitle(res.getString(R.string.caches_refresh_all)); - } - - if (hasSelection) { - menu.findItem(MENU_MOVE_TO_LIST).setTitle(res.getString(R.string.caches_move_selected) + " (" + adapter.getChecked() + ")"); - } else { - menu.findItem(MENU_MOVE_TO_LIST).setTitle(res.getString(R.string.caches_move_all)); - } + setMenuItemLabel(menu, MENU_REFRESH_STORED, R.string.caches_refresh_selected, R.string.caches_refresh_all); + setMenuItemLabel(menu, MENU_MOVE_TO_LIST, R.string.caches_move_selected, R.string.caches_move_all); } else { // search and history list (all other than offline) - if (hasSelection) { - menu.findItem(MENU_REFRESH_STORED).setTitle(res.getString(R.string.caches_store_selected) + " (" + adapter.getChecked() + ")"); - } else { - menu.findItem(MENU_REFRESH_STORED).setTitle(res.getString(R.string.caches_store_offline)); - } + setMenuItemLabel(menu, MENU_REFRESH_STORED, R.string.caches_store_selected, R.string.caches_store_offline); } // Hide menus if cache-list is empty @@ -925,39 +844,28 @@ public class cgeocaches extends AbstractListActivity { item.setVisible(multipleLists); } - item = menu.findItem(MENU_REMOVE_FROM_HISTORY); - if (null != item) { - if (hasSelection) { - item.setTitle(res.getString(R.string.cache_remove_from_history) + " (" + adapter.getChecked() + ")"); - } else { - item.setTitle(res.getString(R.string.cache_clear_history)); - } - } - - item = menu.findItem(MENU_EXPORT_NOTES); - if (null != item) { - // Hide Field Notes export if there are no caches with logs - item.setVisible(false); - for (cgCache cache : cacheList) { - if (cache.isLogOffline()) { - item.setVisible(true); - if (hasSelection) { - item.setTitle(res.getString(R.string.cache_export_fieldnote) + " (" + adapter.getChecked() + ")"); - } else { - item.setTitle(res.getString(R.string.cache_export_fieldnote)); - } - break; - } - } - } - + setMenuItemLabel(menu, MENU_REMOVE_FROM_HISTORY, R.string.cache_remove_from_history, R.string.cache_clear_history); + setMenuItemLabel(menu, MENU_EXPORT, R.string.export, R.string.export); } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.onPrepareOptionsMenu: " + e.toString()); + Log.e("cgeocaches.onPrepareOptionsMenu", e); } return true; } + private void setMenuItemLabel(final Menu menu, final int menuId, final int resIdSelection, final int resId) { + final MenuItem menuItem = menu.findItem(menuId); + if (menuItem == null) { + return; + } + boolean hasSelection = adapter != null && adapter.getChecked() > 0; + if (hasSelection) { + menuItem.setTitle(res.getString(resIdSelection) + " (" + adapter.getChecked() + ")"); + } else { + menuItem.setTitle(res.getString(resId)); + } + } + @Override public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); @@ -985,7 +893,7 @@ public class cgeocaches extends AbstractListActivity { invalidateOptionsMenuCompatible(); return false; case MENU_CREATE_LIST: - createList(null); + new StoredList.UserInterface(this).promptForListCreation(null); invalidateOptionsMenuCompatible(); return false; case MENU_DROP_LIST: @@ -1044,34 +952,27 @@ public class cgeocaches extends AbstractListActivity { case MENU_SORT_STATE: setComparator(item, new StateComparator()); return true; - case SUBMENU_FILTER_TYPE: - showFilterMenu(TypeFilter.getAllFilters(), res.getString(R.string.caches_filter_type_title)); - return true; - case SUBMENU_FILTER_SIZE: - showFilterMenu(SizeFilter.getAllFilters(), res.getString(R.string.caches_filter_size_title)); - return true; - case SUBMENU_FILTER_ATTRIBUTES: - showFilterMenu(AttributeFilter.getAllFilters(), res.getString(R.string.cache_attributes)); - return true; - case SUBMENU_FILTER_STATE: - showFilterMenu(StateFilter.getAllFilters(), res.getString(R.string.cache_status)); - return true; - case MENU_FILTER_TRACKABLES: - setFilter(new TrackablesFilter(res.getString(R.string.caches_filter_track))); - return true; - case MENU_FILTER_MODIFIED: - setFilter(new ModifiedFilter(res.getString(R.string.caches_filter_modified))); + case MENU_FILTER: + new FilterUserInterface(this).selectFilter(new RunnableWithArgument<IFilter>() { + @Override + public void run(IFilter selectedFilter) { + if (selectedFilter != null) { + setFilter(selectedFilter); + } + else { + // clear filter + if (adapter != null) { + setFilter(null); + } + } + } + }); return true; - case MENU_FILTER_CLEAR: - if (adapter != null) { - setFilter(null); - } - return false; case MENU_IMPORT_WEB: importWeb(); return false; - case MENU_EXPORT_NOTES: - exportFieldNotes(); + case MENU_EXPORT: + exportCaches(); return false; case MENU_REMOVE_FROM_HISTORY: removeFromHistoryCheck(); @@ -1086,23 +987,6 @@ public class cgeocaches extends AbstractListActivity { return CacheListAppFactory.onMenuItemSelected(item, geo, cacheList, this, search); } - private void showFilterMenu(final IFilter[] filters, final String menuTitle) { - final AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(menuTitle); - - final String[] names = new String[filters.length]; - for (int i = 0; i < filters.length; i++) { - names[i] = filters[i].getName(); - } - builder.setItems(names, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int item) { - setFilter(filters[item]); - } - }); - - builder.create().show(); - } - private void setComparator(MenuItem item, CacheComparator comparator) { if (adapter != null) { @@ -1123,7 +1007,7 @@ public class cgeocaches extends AbstractListActivity { try { adapterInfo = (AdapterContextMenuInfo) info; } catch (Exception e) { - Log.w(Settings.tag, "cgeocaches.onCreateContextMenu: " + e.toString()); + Log.w("cgeocaches.onCreateContextMenu: " + e.toString()); } if (adapterInfo == null || adapterInfo.position >= adapter.getCount()) { @@ -1153,36 +1037,27 @@ public class cgeocaches extends AbstractListActivity { menu.add(0, MENU_MOVE_TO_LIST, 0, res.getString(R.string.cache_menu_move_list)); } } + else { + menu.add(0, MENU_STORE_CACHE, 0, res.getString(R.string.cache_offline_store)); + } } private void moveCachesToOtherList() { - final List<StoredList> cacheLists = app.getLists(); - ArrayList<String> listNames = new ArrayList<String>(); - for (StoredList list : cacheLists) { - listNames.add(list.getTitleAndCount()); - } + new StoredList.UserInterface(this).promptForListSelection(R.string.cache_menu_move_list, new RunnableWithArgument<Integer>() { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(res.getString(R.string.cache_menu_move_list)); - builder.setItems(listNames.toArray(new String[listNames.size()]), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int item) { - moveCachesToList(cacheLists.get(item)); - } - }); - builder.create().show(); - } + @Override + public void run(Integer newListId) { + final boolean moveAll = adapter.getChecked() == 0; + for (final cgCache c : Collections.unmodifiableList(cacheList)) { + if (moveAll || c.isStatusChecked()) { + app.moveToList(c.getGeocode(), newListId); + } + } + adapter.resetChecks(); - private void moveCachesToList(final StoredList list) { - int newListId = list.id; - final boolean moveAll = adapter.getChecked() == 0; - for (final cgCache c : Collections.unmodifiableList(cacheList)) { - if (moveAll || c.isStatusChecked()) { - app.moveToList(c.getGeocode(), newListId); + refreshCurrentList(); } - } - adapter.resetChecks(); - - refreshCurrentList(); + }); } @Override @@ -1201,7 +1076,7 @@ public class cgeocaches extends AbstractListActivity { try { adapterInfo = (AdapterContextMenuInfo) info; } catch (Exception e) { - Log.w(Settings.tag, "cgeocaches.onContextItemSelected: " + e.toString()); + Log.w("cgeocaches.onContextItemSelected: " + e.toString()); } if (id == MENU_DEFAULT_NAVIGATION) { @@ -1223,7 +1098,7 @@ public class cgeocaches extends AbstractListActivity { return true; } else if (id == MENU_DROP_CACHE) { - cgBase.dropCache(getCacheFromAdapter(adapterInfo), new Handler() { + getCacheFromAdapter(adapterInfo).drop(new Handler() { @Override public void handleMessage(Message msg) { refreshCurrentList(); @@ -1232,23 +1107,20 @@ public class cgeocaches extends AbstractListActivity { return true; } else if (id == MENU_MOVE_TO_LIST) { final String geocode = getCacheFromAdapter(adapterInfo).getGeocode(); - final List<StoredList> cacheLists = app.getLists(); - ArrayList<String> listNames = new ArrayList<String>(); - for (StoredList list : cacheLists) { - listNames.add(list.getTitleAndCount()); - } + new StoredList.UserInterface(this).promptForListSelection(R.string.cache_menu_move_list, new RunnableWithArgument<Integer>() { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(res.getString(R.string.cache_menu_move_list)); - builder.setItems(listNames.toArray(new String[listNames.size()]), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int item) { - final int newListId = cacheLists.get(item).id; + @Override + public void run(Integer newListId) { app.moveToList(geocode, newListId); adapter.resetChecks(); refreshCurrentList(); } }); - builder.create().show(); + return true; + } else if (id == MENU_STORE_CACHE) { + final cgCache cache = getCacheFromAdapter(adapterInfo); + //FIXME: this must use the same handler like in the CacheDetailActivity. Will be done by moving the handler into the store method. + cache.store(this, null); return true; } @@ -1463,8 +1335,7 @@ public class cgeocaches extends AbstractListActivity { threadDetails.start(); } - public void removeFromHistoryCheck() - { + public void removeFromHistoryCheck() { AlertDialog.Builder dialog = new AlertDialog.Builder(this); dialog.setCancelable(true); dialog.setTitle(res.getString(R.string.caches_removing_from_history)); @@ -1486,8 +1357,7 @@ public class cgeocaches extends AbstractListActivity { alert.show(); } - public void removeFromHistory() - { + public void removeFromHistory() { if (adapter != null && adapter.getChecked() > 0) { // there are some checked caches @@ -1508,27 +1378,22 @@ public class cgeocaches extends AbstractListActivity { threadH.start(); } - public void exportFieldNotes() - { - if (adapter != null && adapter.getChecked() > 0) - { - // there are some checked caches - detailTotal = adapter.getChecked(); - } - else - { - // no checked caches, export all - detailTotal = cacheList.size(); + public void exportCaches() { + List<cgCache> caches; + if (adapter != null && adapter.getChecked() > 0) { + // there are some caches checked + caches = new LinkedList<cgCache>(); + for (cgCache cache : cacheList) { + if (cache.isStatusChecked()) { + caches.add(cache); + } + } + } else { + // no caches checked, export all + caches = cacheList; } - detailProgress = 0; - showProgress(false); - - progress.show(this, null, res.getString(R.string.caches_exporting_fieldnote), ProgressDialog.STYLE_HORIZONTAL, exportFieldNotesHandler.obtainMessage(MSG_CANCEL)); - progress.setMaxProgressAndReset(detailTotal); - - threadF = new ExportFieldNotesThread(exportFieldNotesHandler); - threadF.start(); + ExportFactory.showExportMenu(caches, this); } public void importWeb() { @@ -1604,7 +1469,7 @@ public class cgeocaches extends AbstractListActivity { } } } catch (Exception e) { - Log.w(Settings.tag, "Failed to UpdateLocation location."); + Log.w("Failed to UpdateLocation location."); } } } @@ -1641,7 +1506,7 @@ public class cgeocaches extends AbstractListActivity { @Override public void run() { - search = cgBase.searchByStored(coords, Settings.getCacheType(), listId); + search = cgeoapplication.getInstance().getBatchOfStoredCaches(true, coords, Settings.getCacheType(), listId); handler.sendMessage(Message.obtain()); } } @@ -1671,7 +1536,7 @@ public class cgeocaches extends AbstractListActivity { @Override public void run() { - search = cgBase.searchByNextPage(this, search, Settings.isShowCaptcha()); + search = GCParser.searchByNextPage(this, search, Settings.isShowCaptcha()); handler.sendMessage(Message.obtain()); } @@ -1698,7 +1563,7 @@ public class cgeocaches extends AbstractListActivity { @Override public void run() { - search = cgBase.searchByCoords(this, coords, cacheType, Settings.isShowCaptcha()); + search = GCParser.searchByCoords(this, coords, cacheType, Settings.isShowCaptcha()); handler.sendMessage(Message.obtain()); } @@ -1725,7 +1590,7 @@ public class cgeocaches extends AbstractListActivity { @Override public void run() { - search = cgBase.searchByKeyword(this, keyword, cacheType, Settings.isShowCaptcha()); + search = GCParser.searchByKeyword(this, keyword, cacheType, Settings.isShowCaptcha()); handler.sendMessage(Message.obtain()); } } @@ -1751,7 +1616,7 @@ public class cgeocaches extends AbstractListActivity { @Override public void run() { - search = cgBase.searchByUsername(this, username, cacheType, Settings.isShowCaptcha()); + search = GCParser.searchByUsername(this, username, cacheType, Settings.isShowCaptcha()); handler.sendMessage(Message.obtain()); } } @@ -1783,7 +1648,7 @@ public class cgeocaches extends AbstractListActivity { params.put("cacheType", cacheType.id); } - search = cgBase.searchByOwner(this, username, cacheType, Settings.isShowCaptcha()); + search = GCParser.searchByOwner(this, username, cacheType, Settings.isShowCaptcha()); handler.sendMessage(Message.obtain()); } @@ -1829,7 +1694,7 @@ public class cgeocaches extends AbstractListActivity { try { if (needToStop) { - Log.i(Settings.tag, "Stopped storing process."); + Log.i("Stopped storing process."); break; } @@ -1840,26 +1705,26 @@ public class cgeocaches extends AbstractListActivity { delay = 500; } - Log.i(Settings.tag, "Waiting for next cache " + delay + " ms"); + Log.i("Waiting for next cache " + delay + " ms"); sleep(delay); } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.LoadDetailsThread.sleep: " + e.toString()); + Log.e("cgeocaches.LoadDetailsThread.sleep: " + e.toString()); } } if (needToStop) { - Log.i(Settings.tag, "Stopped storing process."); + Log.i("Stopped storing process."); break; } detailProgress++; - cgBase.refreshCache(cgeocaches.this, cache.getGeocode(), listIdLD, null); + cache.refresh(cgeocaches.this, listIdLD, null); handler.sendEmptyMessage(cacheList.indexOf(cache)); yield(); } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.LoadDetailsThread: " + e.toString()); + Log.e("cgeocaches.LoadDetailsThread: " + e.toString()); } last = System.currentTimeMillis(); @@ -1904,7 +1769,7 @@ public class cgeocaches extends AbstractListActivity { deviceCode = ""; } final Parameters params = new Parameters("code", deviceCode); - HttpResponse responseFromWeb = Network.request("http://send2.cgeo.org/read.html", params, true); + HttpResponse responseFromWeb = Network.getRequest("http://send2.cgeo.org/read.html", params); if (responseFromWeb != null && responseFromWeb.getStatusLine().getStatusCode() == 200) { final String response = Network.getResponseData(responseFromWeb); @@ -1916,7 +1781,7 @@ public class cgeocaches extends AbstractListActivity { handler.sendMessage(handler.obtainMessage(1, GCcode)); yield(); - cgBase.storeCache(cgeocaches.this, null, GCcode, listIdLFW, false, null); + cgCache.storeCache(cgeocaches.this, null, GCcode, listIdLFW, false, null); handler.sendMessage(handler.obtainMessage(2, GCcode)); yield(); @@ -1949,7 +1814,7 @@ public class cgeocaches extends AbstractListActivity { times = 0; } } catch (InterruptedException e) { - Log.e(Settings.tag, "cgeocaches.LoadFromWebThread.sleep: " + e.toString()); + Log.e("cgeocaches.LoadFromWebThread.sleep: " + e.toString()); } } @@ -1989,13 +1854,13 @@ public class cgeocaches extends AbstractListActivity { try { if (needToStop) { - Log.i(Settings.tag, "Stopped dropping process."); + Log.i("Stopped dropping process."); break; } app.markDropped(cache.getGeocode()); } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.DropDetailsThread: " + e.toString()); + Log.e("cgeocaches.DropDetailsThread: " + e.toString()); } } cacheListTemp.clear(); @@ -2036,7 +1901,7 @@ public class cgeocaches extends AbstractListActivity { try { if (needToStop) { - Log.i(Settings.tag, "Stopped removing process."); + Log.i("Stopped removing process."); break; } @@ -2047,128 +1912,7 @@ public class cgeocaches extends AbstractListActivity { yield(); } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.RemoveFromHistoryThread: " + e.toString()); - } - } - - handler.sendEmptyMessage(MSG_DONE); - } - } - - private class ExportFieldNotesThread extends Thread - { - private final Handler handler; - private volatile boolean needToStop = false; - private int checked = 0; - - public ExportFieldNotesThread(Handler handlerIn) - { - setPriority(Thread.MIN_PRIORITY); - - handler = handlerIn; - - if (adapter != null) - { - checked = adapter.getChecked(); - } - } - - public void kill() - { - needToStop = true; - } - - @Override - public void run() - { - SimpleDateFormat fieldNoteDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); - StringBuilder fieldNoteBuffer = new StringBuilder(500); - - // We need our own HashMap because LogType will give us localized and maybe - // different strings than gc.com expects in the field note - // We only need such logtypes that are possible to log via c:geo - Map<LogType, String> logTypes = new HashMap<LogType, String>(); - logTypes.put(LogType.LOG_FOUND_IT, "Found it"); - logTypes.put(LogType.LOG_DIDNT_FIND_IT, "Didn't find it"); - logTypes.put(LogType.LOG_NOTE, "Write Note"); - logTypes.put(LogType.LOG_NEEDS_ARCHIVE, "Needs archived"); - logTypes.put(LogType.LOG_NEEDS_MAINTENANCE, "Needs Maintenance"); - logTypes.put(LogType.LOG_WILL_ATTEND, "Will Attend"); - logTypes.put(LogType.LOG_ATTENDED, "Attended"); - logTypes.put(LogType.LOG_WEBCAM_PHOTO_TAKEN, "Webcam Photo Taken"); - - for (cgCache cache : cacheList) { - if (checked > 0 && !cache.isStatusChecked()) { - handler.sendEmptyMessage(0); - - yield(); - continue; - } - - try { - if (needToStop) - { - Log.i(Settings.tag, "Stopped exporting process."); - break; - } - - if (cache.isLogOffline()) - { - cgLog log = app.loadLogOffline(cache.getGeocode()); - - if (null != logTypes.get(log.type)) - { - fieldNoteBuffer.append(cache.getGeocode()) - .append(',') - .append(fieldNoteDateFormat.format(new Date(log.date))) - .append(',') - .append(logTypes.get(log.type)) - .append(",\"") - .append(StringUtils.replaceChars(log.log, '"', '\'')) - .append("\"\n"); - } - } - - detailProgress++; - - handler.sendEmptyMessage(cacheList.indexOf(cache)); - - yield(); - } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.ExportFieldNotesThread: " + e.toString()); - } - } - - if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) - { - File exportLocation = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/field-notes"); - exportLocation.mkdirs(); - - SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); - File exportFile = new File(exportLocation + "/" + fileNameDateFormat.format(new Date()) + ".txt"); - - OutputStream os = null; - Writer fw = null; - try - { - os = new FileOutputStream(exportFile); - fw = new OutputStreamWriter(os, "ISO-8859-1"); // TODO: gc.com doesn't support UTF-8 - fw.write(fieldNoteBuffer.toString()); - - Message.obtain(handler, -2, exportFile).sendToTarget(); - } catch (IOException e) { - Log.e(Settings.tag, "cgeocaches.ExportFieldNotesThread: " + e.toString()); - handler.sendEmptyMessage(-3); - } finally - { - if (fw != null) - { - try { - fw.close(); - } catch (IOException e) { - Log.e(Settings.tag, "cgeocaches.ExportFieldNotesThread: " + e.toString()); - } - } + Log.e("cgeocaches.RemoveFromHistoryThread: " + e.toString()); } } @@ -2209,41 +1953,13 @@ public class cgeocaches extends AbstractListActivity { if (type != CacheListType.OFFLINE) { return; } + new StoredList.UserInterface(this).promptForListSelection(R.string.list_title, new RunnableWithArgument<Integer>() { - lists = app.getLists(); - - if (lists == null) { - return; - } - - final List<CharSequence> listsTitle = new ArrayList<CharSequence>(); - for (StoredList list : lists) { - listsTitle.add(list.getTitleAndCount()); - } - listsTitle.add("<" + res.getString(R.string.list_menu_create) + ">"); - - final CharSequence[] items = new CharSequence[listsTitle.size()]; - - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(res.getString(R.string.list_title)); - builder.setItems(listsTitle.toArray(items), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialogInterface, int itemId) { - if (itemId >= lists.size()) { - // create new list on the fly - createList(new RunnableWithArgument<Integer>() { - - @Override - public void run(final Integer arg) { - switchListById(arg.intValue()); - } - }); - } - else { - switchListById(lists.get(itemId).id); - } + @Override + public void run(final Integer selectedListId) { + switchListById(selectedListId.intValue()); } }); - builder.create().show(); } public void switchListById(int id) { @@ -2301,58 +2017,11 @@ public class cgeocaches extends AbstractListActivity { } } - private void handleListNameInput(final String defaultValue, int dialogTitle, int buttonTitle, final RunnableWithArgument<String> runnable) { - final AlertDialog.Builder alert = new AlertDialog.Builder(this); - final View view = inflater.inflate(R.layout.list_create_dialog, null); - final EditText input = (EditText) view.findViewById(R.id.text); - input.setText(defaultValue); - - alert.setTitle(dialogTitle); - alert.setView(view); - alert.setPositiveButton(buttonTitle, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - // remove whitespaces added by autocompletion of Android keyboard - String listName = StringUtils.trim(input.getText().toString()); - if (StringUtils.isNotBlank(listName)) { - runnable.run(listName); - } - } - }); - alert.setNegativeButton(res.getString(R.string.list_dialog_cancel), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - dialog.dismiss(); - } - }); - - alert.show(); - } - - private void createList(final RunnableWithArgument<Integer> runAfterwards) { - handleListNameInput("", R.string.list_dialog_create_title, R.string.list_dialog_create, new RunnableWithArgument<String>() { - - @Override - public void run(final String listName) { - final int newId = app.createList(listName); - - if (newId >= 10) { - showToast(res.getString(R.string.list_dialog_create_ok)); - if (runAfterwards != null) { - runAfterwards.run(newId); - } - } else { - showToast(res.getString(R.string.list_dialog_create_err)); - } - } - }); - } - private void renameList() { - final StoredList list = app.getList(listId); - handleListNameInput(list.title, R.string.list_dialog_rename_title, R.string.list_dialog_rename, new RunnableWithArgument<String>() { + new StoredList.UserInterface(this).promptForListRename(listId, new Runnable() { @Override - public void run(final String listName) { - app.renameList(listId, listName); + public void run() { refreshCurrentList(); } }); @@ -2461,8 +2130,7 @@ public class cgeocaches extends AbstractListActivity { Intent cachesIntent = new Intent(context, cachesActivity.getClass()); cachesIntent.putExtra(EXTRAS_LIST_TYPE, CacheListType.COORDINATE); - cachesIntent.putExtra("latitude", coords.getLatitude()); - cachesIntent.putExtra("longitude", coords.getLongitude()); + cachesIntent.putExtra(EXTRAS_COORDS, coords); context.startActivity(cachesIntent); } @@ -2529,8 +2197,7 @@ public class cgeocaches extends AbstractListActivity { public static void startActivityNearest(final Context context, final Geopoint coordsNow) { final Intent cachesIntent = new Intent(context, cgeocaches.class); cachesIntent.putExtra(EXTRAS_LIST_TYPE, CacheListType.NEAREST); - cachesIntent.putExtra("latitude", coordsNow.getLatitude()); - cachesIntent.putExtra("longitude", coordsNow.getLongitude()); + cachesIntent.putExtra(EXTRAS_COORDS, coordsNow); context.startActivity(cachesIntent); } @@ -2540,20 +2207,18 @@ public class cgeocaches extends AbstractListActivity { context.startActivity(cachesIntent); } - public static void startActivityAddress(Context context, double latitude, double longitude, String address) { + public static void startActivityAddress(final Context context, final Geopoint coords, final String address) { Intent addressIntent = new Intent(context, cgeocaches.class); addressIntent.putExtra(EXTRAS_LIST_TYPE, CacheListType.ADDRESS); - addressIntent.putExtra("latitude", latitude); - addressIntent.putExtra("longitude", longitude); + addressIntent.putExtra(EXTRAS_COORDS, coords); addressIntent.putExtra("address", address); context.startActivity(addressIntent); } - public static void startActivityCoordinates(final Context context, double latitude, double longitude) { + public static void startActivityCoordinates(final Context context, final Geopoint coords) { final Intent cachesIntent = new Intent(context, cgeocaches.class); cachesIntent.putExtra(EXTRAS_LIST_TYPE, CacheListType.COORDINATE); - cachesIntent.putExtra("latitude", latitude); - cachesIntent.putExtra("longitude", longitude); + cachesIntent.putExtra(EXTRAS_COORDS, coords); context.startActivity(cachesIntent); } diff --git a/main/src/cgeo/geocaching/cgeocoords.java b/main/src/cgeo/geocaching/cgeocoords.java index b4868ce..fdedfda 100644 --- a/main/src/cgeo/geocaching/cgeocoords.java +++ b/main/src/cgeo/geocaching/cgeocoords.java @@ -419,7 +419,7 @@ public class cgeocoords extends Dialog { if (geo != null && geo.coordsNow != null) { gp = geo.coordsNow; } else { - gp = new Geopoint(0, 0); + gp = new Geopoint(0.0, 0.0); } } } diff --git a/main/src/cgeo/geocaching/cgeoimages.java b/main/src/cgeo/geocaching/cgeoimages.java index 6f12bed..bac0cad 100644 --- a/main/src/cgeo/geocaching/cgeoimages.java +++ b/main/src/cgeo/geocaching/cgeoimages.java @@ -207,7 +207,7 @@ public class cgeoimages extends AbstractActivity { image.getBitmap().compress(CompressFormat.JPEG, 100, fos); fos.close(); } catch (Exception e) { - Log.e(Settings.tag, "cgeoimages.handleMessage.onClick: " + e.toString()); + Log.e("cgeoimages.handleMessage.onClick: " + e.toString()); return; } diff --git a/main/src/cgeo/geocaching/cgeoinit.java b/main/src/cgeo/geocaching/cgeoinit.java index cb5808f..2269ad7 100644 --- a/main/src/cgeo/geocaching/cgeoinit.java +++ b/main/src/cgeo/geocaching/cgeoinit.java @@ -4,13 +4,15 @@ import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory.NavigationAppsEnum; import cgeo.geocaching.compatibility.Compatibility; +import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.maps.MapProviderFactory; -import cgeo.geocaching.network.Login; +import cgeo.geocaching.network.Cookies; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.twitter.TwitterAuthorizationActivity; +import cgeo.geocaching.ui.Formatter; import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.LogTemplateProvider; import cgeo.geocaching.utils.LogTemplateProvider.LogTemplate; @@ -20,6 +22,7 @@ import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.http.HttpResponse; import android.app.ProgressDialog; +import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.graphics.drawable.Drawable; @@ -73,7 +76,7 @@ public class cgeoinit extends AbstractActivity { } catch (Exception e) { showToast(res.getString(R.string.err_login_failed)); - Log.e(Settings.tag, "cgeoinit.logInHandler: " + e.toString()); + Log.e("cgeoinit.logInHandler: " + e.toString()); } if (loginDialog != null && loginDialog.isShowing()) { @@ -101,7 +104,7 @@ public class cgeoinit extends AbstractActivity { } catch (Exception e) { showToast(res.getString(R.string.init_sendToCgeo_register_fail)); - Log.e(Settings.tag, "cgeoinit.webHandler: " + e.toString()); + Log.e("cgeoinit.webHandler: " + e.toString()); } if (webDialog != null && webDialog.isShowing()) { @@ -731,7 +734,7 @@ public class cgeoinit extends AbstractActivity { TextView lastBackup = (TextView) findViewById(R.id.backup_last); File lastBackupFile = cgeoapplication.isRestoreFile(); if (lastBackupFile != null) { - lastBackup.setText(res.getString(R.string.init_backup_last) + " " + cgBase.formatTime(lastBackupFile.lastModified()) + ", " + cgBase.formatDate(lastBackupFile.lastModified())); + lastBackup.setText(res.getString(R.string.init_backup_last) + " " + Formatter.formatTime(lastBackupFile.lastModified()) + ", " + Formatter.formatDate(lastBackupFile.lastModified())); } else { lastBackup.setText(res.getString(R.string.init_backup_last_no)); } @@ -821,7 +824,7 @@ public class cgeoinit extends AbstractActivity { loginDialog.setCancelable(false); Settings.setLogin(username, password); - Network.clearCookies(); + Cookies.clearCookies(); (new Thread() { @@ -863,7 +866,7 @@ public class cgeoinit extends AbstractActivity { final String cod = StringUtils.defaultString(deviceCode); final Parameters params = new Parameters("name", nam, "code", cod); - HttpResponse response = Network.request("http://send2.cgeo.org/auth.html", params, true); + HttpResponse response = Network.getRequest("http://send2.cgeo.org/auth.html", params); if (response != null && response.getStatusLine().getStatusCode() == 200) { @@ -872,7 +875,7 @@ public class cgeoinit extends AbstractActivity { try { pin = Integer.parseInt(strings[1].trim()); } catch (Exception e) { - Log.e(Settings.tag, "webDialog: " + e.toString()); + Log.e("webDialog: " + e.toString()); } String code = strings[0]; Settings.setWebNameCode(nam, code); @@ -892,9 +895,18 @@ public class cgeoinit extends AbstractActivity { if (resultCode == RESULT_OK) { if (data.hasExtra("mapfile")) { Settings.setMapFile(data.getStringExtra("mapfile")); + if (!Settings.isValidMapFile(Settings.getMapFile())) { + showToast(res.getString(R.string.warn_invalid_mapfile)); + } } } initMapfileEdittext(true); } } + + public static void startActivity(Context fromActivity) { + final Intent initIntent = new Intent(fromActivity, cgeoinit.class); + fromActivity.startActivity(initIntent); + } + } diff --git a/main/src/cgeo/geocaching/cgeonavigate.java b/main/src/cgeo/geocaching/cgeonavigate.java index f5da2a1..869b9dd 100644 --- a/main/src/cgeo/geocaching/cgeonavigate.java +++ b/main/src/cgeo/geocaching/cgeonavigate.java @@ -26,8 +26,7 @@ import java.util.List; public class cgeonavigate extends AbstractActivity { - private static final String EXTRAS_LONGITUDE = "longitude"; - private static final String EXTRAS_LATITUDE = "latitude"; + private static final String EXTRAS_COORDS = "coords"; private static final String EXTRAS_NAME = "name"; private static final String EXTRAS_GEOCODE = "geocode"; private static final List<IWaypoint> coordinates = new ArrayList<IWaypoint>(); @@ -88,7 +87,7 @@ public class cgeonavigate extends AbstractActivity { geocode = extras.getString(EXTRAS_GEOCODE); title = geocode; name = extras.getString(EXTRAS_NAME); - dstCoords = new Geopoint(extras.getDouble(EXTRAS_LATITUDE), extras.getDouble(EXTRAS_LONGITUDE)); + dstCoords = (Geopoint) extras.getParcelable(EXTRAS_COORDS); if (StringUtils.isNotBlank(name)) { if (StringUtils.isNotBlank(title)) { @@ -271,7 +270,7 @@ public class cgeonavigate extends AbstractActivity { setDestCoords(); updateDistanceInfo(); - Log.d(Settings.tag, "destination set: " + title + " (" + dstCoords + ")"); + Log.d("destination set: " + title + " (" + dstCoords + ")"); return true; } @@ -294,23 +293,6 @@ public class cgeonavigate extends AbstractActivity { ((TextView) findViewById(R.id.destination)).setText(dstCoords.toString()); } - public void setDest(final Geopoint coords) { - if (coords == null) { - return; - } - - title = "some place"; - setTitle(); - setDestCoords(); - - dstCoords = coords; - updateDistanceInfo(); - } - - public Geopoint getCoordinatesNow() { - return geo.coordsNow; - } - private void updateDistanceInfo() { if (geo == null || geo.coordsNow == null || dstCoords == null) { return; @@ -384,7 +366,7 @@ public class cgeonavigate extends AbstractActivity { northHeading = geo.bearingNow; } } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); + Log.w("Failed to update location."); } } } @@ -410,8 +392,7 @@ public class cgeonavigate extends AbstractActivity { } final Intent navigateIntent = new Intent(context, cgeonavigate.class); - navigateIntent.putExtra(EXTRAS_LATITUDE, coords.getLatitude()); - navigateIntent.putExtra(EXTRAS_LONGITUDE, coords.getLongitude()); + navigateIntent.putExtra(EXTRAS_COORDS, coords); navigateIntent.putExtra(EXTRAS_GEOCODE, geocode.toUpperCase()); if (null != displayedName) { navigateIntent.putExtra(EXTRAS_NAME, displayedName); diff --git a/main/src/cgeo/geocaching/cgeopoint.java b/main/src/cgeo/geocaching/cgeopoint.java index d3e5fba..0335453 100644 --- a/main/src/cgeo/geocaching/cgeopoint.java +++ b/main/src/cgeo/geocaching/cgeopoint.java @@ -6,6 +6,7 @@ import cgeo.geocaching.geopoint.DistanceParser; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter; import cgeo.geocaching.geopoint.GeopointParser; +import cgeo.geocaching.ui.Formatter; import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; @@ -40,18 +41,18 @@ public class cgeopoint extends AbstractActivity { private static final int MENU_CACHES_AROUND = 5; private static final int MENU_CLEAR_HISTORY = 6; - private static class DestinationHistoryAdapter extends ArrayAdapter<cgDestination> { + private static class DestinationHistoryAdapter extends ArrayAdapter<Destination> { private LayoutInflater inflater = null; public DestinationHistoryAdapter(Context context, - List<cgDestination> objects) { + List<Destination> objects) { super(context, 0, objects); } @Override public View getView(final int position, final View convertView, final ViewGroup parent) { - cgDestination loc = getItem(position); + Destination loc = getItem(position); View v = convertView; @@ -70,7 +71,7 @@ public class cgeopoint extends AbstractActivity { longitude.setText(lonString); latitude.setText(latString); - date.setText(cgBase.formatShortDateTime(getContext(), loc.getDate())); + date.setText(Formatter.formatShortDateTime(getContext(), loc.getDate())); return v; } @@ -89,7 +90,7 @@ public class cgeopoint extends AbstractActivity { private Button latButton = null; private Button lonButton = null; private boolean changed = false; - private List<cgDestination> historyOfSearchedLocations; + private List<Destination> historyOfSearchedLocations; private DestinationHistoryAdapter destionationHistoryAdapter; private ListView historyListView; private TextView historyFooter; @@ -137,8 +138,8 @@ public class cgeopoint extends AbstractActivity { public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { final Object selection = arg0.getItemAtPosition(arg2); - if (selection instanceof cgDestination) { - navigateTo(((cgDestination) selection).getCoords()); + if (selection instanceof Destination) { + navigateTo(((Destination) selection).getCoords()); } } }); @@ -163,21 +164,21 @@ public class cgeopoint extends AbstractActivity { switch (item.getItemId()) { case CONTEXT_MENU_NAVIGATE: contextMenuItemPosition = position; - if (destination instanceof cgDestination) { - NavigationAppFactory.showNavigationMenu(geo, this, null, null, ((cgDestination) destination).getCoords()); + if (destination instanceof Destination) { + NavigationAppFactory.showNavigationMenu(geo, this, null, null, ((Destination) destination).getCoords()); return true; } break; case CONTEXT_MENU_DELETE_WAYPOINT: - if (destination instanceof cgDestination) { - removeFromHistory((cgDestination) destination); + if (destination instanceof Destination) { + removeFromHistory((Destination) destination); } return true; case CONTEXT_MENU_EDIT_WAYPOINT: - if (destination instanceof cgDestination) { - final Geopoint gp = ((cgDestination) destination).getCoords(); + if (destination instanceof Destination) { + final Geopoint gp = ((Destination) destination).getCoords(); latButton.setText(gp.format(GeopointFormatter.Format.LAT_DECMINUTE)); lonButton.setText(gp.format(GeopointFormatter.Format.LON_DECMINUTE)); } @@ -205,7 +206,7 @@ public class cgeopoint extends AbstractActivity { return destionationHistoryAdapter; } - private List<cgDestination> getHistoryOfSearchedLocations() { + private List<Destination> getHistoryOfSearchedLocations() { if (historyOfSearchedLocations == null) { // Load from database historyOfSearchedLocations = app.getHistoryOfSearchedLocations(); @@ -382,8 +383,7 @@ public class cgeopoint extends AbstractActivity { final Geopoint coords = getDestination(); - if (coords != null) - { + if (coords != null) { addToHistory(coords); } @@ -410,12 +410,9 @@ public class cgeopoint extends AbstractActivity { private void addToHistory(final Geopoint coords) { // Add locations to history - cgDestination loc = new cgDestination(); - loc.setCoords(coords); + final Destination loc = new Destination(coords); - if (!getHistoryOfSearchedLocations().contains(loc)) - { - loc.setDate(System.currentTimeMillis()); + if (!getHistoryOfSearchedLocations().contains(loc)) { getHistoryOfSearchedLocations().add(0, loc); // Save location @@ -426,7 +423,7 @@ public class cgeopoint extends AbstractActivity { } } - private void removeFromHistory(cgDestination destination) { + private void removeFromHistory(Destination destination) { if (getHistoryOfSearchedLocations().contains(destination)) { getHistoryOfSearchedLocations().remove(destination); @@ -483,7 +480,7 @@ public class cgeopoint extends AbstractActivity { return; } - cgeocaches.startActivityCoordinates(this, coords.getLatitude(), coords.getLongitude()); + cgeocaches.startActivityCoordinates(this, coords); finish(); } @@ -500,7 +497,7 @@ public class cgeopoint extends AbstractActivity { latButton.setHint(geo.coordsNow.format(GeopointFormatter.Format.LAT_DECMINUTE_RAW)); lonButton.setHint(geo.coordsNow.format(GeopointFormatter.Format.LON_DECMINUTE_RAW)); } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); + Log.w("Failed to update location."); } } } diff --git a/main/src/cgeo/geocaching/cgeopopup.java b/main/src/cgeo/geocaching/cgeopopup.java index 8ad07bb..99e75d8 100644 --- a/main/src/cgeo/geocaching/cgeopopup.java +++ b/main/src/cgeo/geocaching/cgeopopup.java @@ -16,6 +16,7 @@ import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import android.app.ProgressDialog; +import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.net.Uri; @@ -74,7 +75,7 @@ public class cgeopopup extends AbstractActivity { } catch (Exception e) { showToast(res.getString(R.string.err_store)); - Log.e(Settings.tag, "cgeopopup.storeCacheHandler: " + e.toString()); + Log.e("cgeopopup.storeCacheHandler: " + e.toString()); } if (storeDialog != null) { @@ -97,7 +98,7 @@ public class cgeopopup extends AbstractActivity { } catch (Exception e) { showToast(res.getString(R.string.err_drop)); - Log.e(Settings.tag, "cgeopopup.dropCacheHandler: " + e.toString()); + Log.e("cgeopopup.dropCacheHandler: " + e.toString()); } if (dropDialog != null) { @@ -452,7 +453,7 @@ public class cgeopopup extends AbstractActivity { offlineStore.setOnClickListener(new storeCache()); } } catch (Exception e) { - Log.e(Settings.tag, "cgeopopup.init: " + e.toString()); + Log.e("cgeopopup.init: " + e.toString()); } if (geo != null) { @@ -515,7 +516,7 @@ public class cgeopopup extends AbstractActivity { cacheDistance.bringToFront(); } } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); + Log.w("Failed to update location."); } } } @@ -595,7 +596,7 @@ public class cgeopopup extends AbstractActivity { @Override public void run() { - cgBase.dropCache(cache, handler); + cache.drop(handler); } } @@ -657,4 +658,10 @@ public class cgeopopup extends AbstractActivity { super.goManual(view); finish(); } + + public static void startActivity(final Context context, final String geocode) { + final Intent popupIntent = new Intent(context, cgeopopup.class); + popupIntent.putExtra("geocode", geocode); + context.startActivity(popupIntent); + } } diff --git a/main/src/cgeo/geocaching/cgeotouch.java b/main/src/cgeo/geocaching/cgeotouch.java index 09857a2..56b5ba1 100644 --- a/main/src/cgeo/geocaching/cgeotouch.java +++ b/main/src/cgeo/geocaching/cgeotouch.java @@ -1,13 +1,15 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.connector.gc.GCParser; +import cgeo.geocaching.connector.gc.Login; 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 cgeo.geocaching.ui.Formatter; import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; @@ -63,7 +65,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog setType((LogType) msg.obj); showToast(res.getString(R.string.info_log_type_changed)); } else { - if (cgBase.isEmpty(viewstates) && attempts < 2) { + if (Login.isEmpty(viewstates) && attempts < 2) { showToast(res.getString(R.string.err_log_load_data_again)); loadData thread; @@ -71,7 +73,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog thread.start(); return; - } else if (cgBase.isEmpty(viewstates) && attempts >= 2) { + } else if (Login.isEmpty(viewstates) && attempts >= 2) { showToast(res.getString(R.string.err_log_load_data)); showProgress(false); @@ -203,8 +205,8 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog textContent = text.getText().toString(); final long now = System.currentTimeMillis(); - dateString = cgBase.formatDate(now); - timeString = cgBase.formatTime(now); + dateString = Formatter.formatDate(now); + timeString = Formatter.formatTime(now); if ((id & 0x4) == 0x4) { addText += dateString; @@ -287,7 +289,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog }); Button dateButton = (Button) findViewById(R.id.date); - dateButton.setText(cgBase.formatShortDate(date.getTime().getTime())); + dateButton.setText(Formatter.formatShortDate(date.getTime().getTime())); dateButton.setOnClickListener(new cgeotouchDateListener()); if (tweetBox == null) { @@ -299,7 +301,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog tweetCheck.setChecked(true); Button buttonPost = (Button) findViewById(R.id.post); - if (cgBase.isEmpty(viewstates)) { + if (Login.isEmpty(viewstates)) { buttonPost.setEnabled(false); buttonPost.setOnTouchListener(null); buttonPost.setOnClickListener(null); @@ -319,7 +321,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog date = dateIn; final Button dateButton = (Button) findViewById(R.id.date); - dateButton.setText(cgBase.formatShortDate(date.getTime().getTime())); + dateButton.setText(Formatter.formatShortDate(date.getTime().getTime())); } public void setType(LogType type) { @@ -392,11 +394,11 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog return; } - final String page = Network.getResponseData(Network.request("http://www.geocaching.com/track/log.aspx", params, false, false, false)); + final String page = Network.getResponseData(Network.getRequest("http://www.geocaching.com/track/log.aspx", params)); viewstates = Login.getViewstates(page); - final List<LogType> typesPre = cgBase.parseTypes(page); + final List<LogType> typesPre = GCParser.parseTypes(page); if (typesPre.size() > 0) { logTypes.clear(); logTypes.addAll(typesPre); @@ -408,7 +410,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog loadDataHandler.obtainMessage(MSG_UPDATE_TYPE, typeSelected).sendToTarget(); } } catch (Exception e) { - Log.e(Settings.tag, "cgeotouch.loadData.run: " + e.toString()); + Log.e("cgeotouch.loadData.run: " + e.toString()); } loadDataHandler.sendEmptyMessage(0); @@ -442,7 +444,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog tweetCheck = (CheckBox) findViewById(R.id.tweet); } - final StatusCode status = cgBase.postLogTrackable(guid, tracking, viewstates, typeSelected, date.get(Calendar.YEAR), (date.get(Calendar.MONTH) + 1), date.get(Calendar.DATE), log); + final StatusCode status = GCParser.postLogTrackable(guid, tracking, viewstates, typeSelected, date.get(Calendar.YEAR), (date.get(Calendar.MONTH) + 1), date.get(Calendar.DATE), log); if (status == StatusCode.NO_ERROR && Settings.isUseTwitter() && Settings.isTwitterLoginValid() && @@ -452,7 +454,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog return status; } catch (Exception e) { - Log.e(Settings.tag, "cgeotouch.postLogFn: " + e.toString()); + Log.e("cgeotouch.postLogFn: " + e.toString()); } return StatusCode.LOG_POST_ERROR; diff --git a/main/src/cgeo/geocaching/cgeotrackable.java b/main/src/cgeo/geocaching/cgeotrackable.java index 7b310ed..923e420 100644 --- a/main/src/cgeo/geocaching/cgeotrackable.java +++ b/main/src/cgeo/geocaching/cgeotrackable.java @@ -1,11 +1,12 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.connector.gc.GCParser; import cgeo.geocaching.geopoint.HumanDistance; import cgeo.geocaching.network.HtmlImage; +import cgeo.geocaching.ui.Formatter; import cgeo.geocaching.utils.Log; -import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import android.app.ProgressDialog; @@ -155,7 +156,7 @@ public class cgeotrackable extends AbstractActivity { // trackable released if (trackable.getReleased() != null) { - addDetail(R.string.trackable_released, cgBase.formatDate(trackable.getReleased().getTime())); + addDetail(R.string.trackable_released, Formatter.formatDate(trackable.getReleased().getTime())); } // trackable distance @@ -221,7 +222,7 @@ public class cgeotrackable extends AbstractActivity { Message message = handler.obtainMessage(0, image); handler.sendMessage(message); } catch (Exception e) { - Log.e(Settings.tag, "cgeospoilers.onCreate.onClick.run: " + e.toString()); + Log.e("cgeospoilers.onCreate.onClick.run: " + e.toString()); } } }.start(); @@ -229,7 +230,7 @@ public class cgeotrackable extends AbstractActivity { imgView.addView(trackableImage); } } catch (Exception e) { - Log.e(Settings.tag, "cgeotrackable.loadTrackableHandler: " + e.toString() + Arrays.toString(e.getStackTrace())); + Log.e("cgeotrackable.loadTrackableHandler: " + e.toString() + Arrays.toString(e.getStackTrace())); } displayLogs(); @@ -428,7 +429,7 @@ public class cgeotrackable extends AbstractActivity { trackable = cgeoapplication.getInstance().getTrackableByGeocode(geocode); if ((trackable == null || trackable.isLoggable()) && !StringUtils.startsWithIgnoreCase(geocode, "GK")) { - trackable = cgBase.searchTrackable(geocode, guid, id); + trackable = GCParser.searchTrackable(geocode, guid, id); } handler.sendMessage(Message.obtain()); } @@ -442,11 +443,11 @@ public class cgeotrackable extends AbstractActivity { RelativeLayout rowView; if (trackable != null && trackable.getLogs() != null) { - for (cgLog log : trackable.getLogs()) { + for (LogEntry log : trackable.getLogs()) { rowView = (RelativeLayout) inflater.inflate(R.layout.trackable_logs_item, null); if (log.date > 0) { - ((TextView) rowView.findViewById(R.id.added)).setText(cgBase.formatShortDate(log.date)); + ((TextView) rowView.findViewById(R.id.added)).setText(Formatter.formatShortDate(log.date)); } ((TextView) rowView.findViewById(R.id.type)).setText(log.type.getL10n()); @@ -460,10 +461,7 @@ public class cgeotrackable extends AbstractActivity { final String cacheName = log.cacheName; ((TextView) rowView.findViewById(R.id.location)).setOnClickListener(new View.OnClickListener() { public void onClick(View arg0) { - Intent cacheIntent = new Intent(cgeotrackable.this, CacheDetailActivity.class); - cacheIntent.putExtra("guid", cacheGuid); - cacheIntent.putExtra("name", Html.fromHtml(cacheName).toString()); - startActivity(cacheIntent); + CacheDetailActivity.startActivityGuid(cgeotrackable.this, cacheGuid, Html.fromHtml(cacheName).toString()); } }); } @@ -475,9 +473,9 @@ public class cgeotrackable extends AbstractActivity { // add LogImages LinearLayout logLayout = (LinearLayout) rowView.findViewById(R.id.log_layout); - if (CollectionUtils.isNotEmpty(log.logImages)) { + if (log.hasLogImages()) { - final ArrayList<cgImage> logImages = new ArrayList<cgImage>(log.logImages); + final ArrayList<cgImage> logImages = new ArrayList<cgImage>(log.getLogImages()); final View.OnClickListener listener = new View.OnClickListener() { @Override @@ -487,8 +485,8 @@ public class cgeotrackable extends AbstractActivity { }; ArrayList<String> titles = new ArrayList<String>(); - for (int i_img_cnt = 0; i_img_cnt < log.logImages.size(); i_img_cnt++) { - String img_title = log.logImages.get(i_img_cnt).getTitle(); + for (cgImage image : log.getLogImages()) { + String img_title = image.getTitle(); if (!StringUtils.isBlank(img_title)) { titles.add(img_title); } @@ -525,7 +523,7 @@ public class cgeotrackable extends AbstractActivity { registerForContextMenu(view); openContextMenu(view); } catch (Exception e) { - Log.e(Settings.tag, "cgeotrackable.userActions.onClick ", e); + Log.e("cgeotrackable.userActions.onClick ", e); } } } @@ -573,7 +571,7 @@ public class cgeotrackable extends AbstractActivity { Message message = handler.obtainMessage(0, image); handler.sendMessage(message); } catch (Exception e) { - Log.e(Settings.tag, "cgeotrackable.tbIconThread.run: " + e.toString()); + Log.e("cgeotrackable.tbIconThread.run: " + e.toString()); } } } diff --git a/main/src/cgeo/geocaching/cgeowaypoint.java b/main/src/cgeo/geocaching/cgeowaypoint.java index 89450ec..2c14601 100644 --- a/main/src/cgeo/geocaching/cgeowaypoint.java +++ b/main/src/cgeo/geocaching/cgeowaypoint.java @@ -9,6 +9,7 @@ import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import android.app.ProgressDialog; +import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; @@ -111,7 +112,7 @@ public class cgeowaypoint extends AbstractActivity { waitDialog.dismiss(); waitDialog = null; } - Log.e(Settings.tag, "cgeowaypoint.loadWaypointHandler: " + e.toString()); + Log.e("cgeowaypoint.loadWaypointHandler: " + e.toString()); } } @@ -295,7 +296,7 @@ public class cgeowaypoint extends AbstractActivity { loadWaypointHandler.sendMessage(Message.obtain()); } catch (Exception e) { - Log.e(Settings.tag, "cgeowaypoint.loadWaypoint.run: " + e.toString()); + Log.e("cgeowaypoint.loadWaypoint.run: " + e.toString()); } } } @@ -383,4 +384,10 @@ public class cgeowaypoint extends AbstractActivity { } return NavigationAppFactory.onMenuItemSelected(item, geo, this, null, waypoint, null); } + + public static void startActivity(final Context context, final int waypointId) { + Intent popupIntent = new Intent(context, cgeowaypoint.class); + popupIntent.putExtra("waypoint", waypointId); + context.startActivity(popupIntent); + } } diff --git a/main/src/cgeo/geocaching/cgeowaypointadd.java b/main/src/cgeo/geocaching/cgeowaypointadd.java index 4bc5be0..196a8b3 100644 --- a/main/src/cgeo/geocaching/cgeowaypointadd.java +++ b/main/src/cgeo/geocaching/cgeowaypointadd.java @@ -9,6 +9,7 @@ import cgeo.geocaching.geopoint.DistanceParser; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter; import cgeo.geocaching.geopoint.GeopointParser; +import cgeo.geocaching.utils.BaseUtils; import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; @@ -72,7 +73,12 @@ public class cgeowaypointadd extends AbstractActivity { ((Button) findViewById(R.id.buttonLongitude)).setText(waypoint.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE)); } ((EditText) findViewById(R.id.name)).setText(Html.fromHtml(StringUtils.trimToEmpty(waypoint.getName())).toString()); - ((EditText) findViewById(R.id.note)).setText(Html.fromHtml(StringUtils.trimToEmpty(waypoint.getNote())).toString()); + if (BaseUtils.containsHtml(waypoint.getNote())) { + ((EditText) findViewById(R.id.note)).setText(Html.fromHtml(StringUtils.trimToEmpty(waypoint.getNote())).toString()); + } + else { + ((EditText) findViewById(R.id.note)).setText(StringUtils.trimToEmpty(waypoint.getNote())); + } } if (own) { @@ -81,7 +87,7 @@ public class cgeowaypointadd extends AbstractActivity { initializeDistanceUnitSelector(); } catch (Exception e) { - Log.e(Settings.tag, "cgeowaypointadd.loadWaypointHandler: " + e.toString()); + Log.e("cgeowaypointadd.loadWaypointHandler: " + e.toString()); } finally { if (waitDialog != null) { waitDialog.dismiss(); @@ -136,7 +142,10 @@ public class cgeowaypointadd extends AbstractActivity { Button addWaypoint = (Button) findViewById(R.id.add_waypoint); addWaypoint.setOnClickListener(new coordsListener()); - List<String> wayPointNames = new ArrayList<String>(WaypointType.ALL_TYPES_EXCEPT_OWN.values()); + List<String> wayPointNames = new ArrayList<String>(); + for (WaypointType wpt : WaypointType.ALL_TYPES_EXCEPT_OWN) { + wayPointNames.add(wpt.getL10n()); + } AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.name); ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, wayPointNames); textView.setAdapter(adapter); @@ -208,7 +217,7 @@ public class cgeowaypointadd extends AbstractActivity { Spinner waypointTypeSelector = (Spinner) findViewById(R.id.type); - wpTypes = new ArrayList<WaypointType>(WaypointType.ALL_TYPES_EXCEPT_OWN.keySet()); + wpTypes = new ArrayList<WaypointType>(WaypointType.ALL_TYPES_EXCEPT_OWN); ArrayAdapter<WaypointType> wpAdapter = new ArrayAdapter<WaypointType>(this, android.R.layout.simple_spinner_item, wpTypes.toArray(new WaypointType[wpTypes.size()])); wpAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); waypointTypeSelector.setAdapter(wpAdapter); @@ -245,7 +254,7 @@ public class cgeowaypointadd extends AbstractActivity { @Override public void updateLocation(cgGeo geo) { - Log.d(Settings.tag, "cgeowaypointadd.updateLocation called"); + Log.d("cgeowaypointadd.updateLocation called"); if (geo == null || geo.coordsNow == null) { return; } @@ -256,7 +265,7 @@ public class cgeowaypointadd extends AbstractActivity { bLat.setHint(geo.coordsNow.format(GeopointFormatter.Format.LAT_DECMINUTE_RAW)); bLon.setHint(geo.coordsNow.format(GeopointFormatter.Format.LON_DECMINUTE_RAW)); } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); + Log.w("Failed to update location."); } } } @@ -270,7 +279,7 @@ public class cgeowaypointadd extends AbstractActivity { loadWaypointHandler.sendMessage(Message.obtain()); } catch (Exception e) { - Log.e(Settings.tag, "cgeowaypoint.loadWaypoint.run: " + e.toString()); + Log.e("cgeowaypoint.loadWaypoint.run: " + e.toString()); } } } diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java index 72058cd..0fc9624 100644 --- a/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java +++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java @@ -1,6 +1,5 @@ package cgeo.geocaching.compatibility; -import cgeo.geocaching.Settings; import cgeo.geocaching.utils.Log; import android.app.Activity; @@ -15,7 +14,7 @@ public class AndroidLevel8 implements AndroidLevel8Interface { } public void dataChanged(final String name) { - Log.i(Settings.tag, "Requesting settings backup with settings manager"); + Log.i("Requesting settings backup with settings manager"); BackupManager.dataChanged(name); } } diff --git a/main/src/cgeo/geocaching/compatibility/Compatibility.java b/main/src/cgeo/geocaching/compatibility/Compatibility.java index bfc491e..6086604 100644 --- a/main/src/cgeo/geocaching/compatibility/Compatibility.java +++ b/main/src/cgeo/geocaching/compatibility/Compatibility.java @@ -1,6 +1,5 @@ package cgeo.geocaching.compatibility; -import cgeo.geocaching.Settings; import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.utils.Log; @@ -54,7 +53,7 @@ public final class Compatibility { } } catch (final Exception e) { // This should never happen: IllegalArgumentException, IllegalAccessException or InvocationTargetException - Log.e(Settings.tag, "Cannot call getRotation()", e); + Log.e("Cannot call getRotation()", e); } } else { final Display display = activity.getWindowManager() @@ -95,7 +94,7 @@ public final class Compatibility { try { MethodUtils.invokeMethod(activity, "overridePendingTransition", enterAnim, exitAnim); } catch (Exception e) { - Log.e(Settings.tag, "cannot call overridePendingTransition", e); + Log.e("cannot call overridePendingTransition", e); } } diff --git a/main/src/cgeo/geocaching/concurrent/Task.java b/main/src/cgeo/geocaching/concurrent/Task.java deleted file mode 100644 index 2472538..0000000 --- a/main/src/cgeo/geocaching/concurrent/Task.java +++ /dev/null @@ -1,16 +0,0 @@ -package cgeo.geocaching.concurrent; - -/** - * Basic class for Runnables added to ThreadPool. - */ -public abstract class Task implements Runnable { - private String name = null; - - public Task(String name) { - this.name = name; - } - - public String getName() { - return this.name; - } -} diff --git a/main/src/cgeo/geocaching/connector/gc/GCBase.java b/main/src/cgeo/geocaching/connector/gc/GCBase.java index 871e75a..2f22c52 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCBase.java +++ b/main/src/cgeo/geocaching/connector/gc/GCBase.java @@ -2,7 +2,6 @@ package cgeo.geocaching.connector.gc; import cgeo.geocaching.SearchResult; import cgeo.geocaching.Settings; -import cgeo.geocaching.cgBase; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.CacheSize; @@ -13,11 +12,11 @@ import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.IConversion; import cgeo.geocaching.geopoint.Viewport; -import cgeo.geocaching.network.Login; import cgeo.geocaching.network.Network; +import cgeo.geocaching.network.Parameters; import cgeo.geocaching.ui.Formatter; import cgeo.geocaching.utils.BaseUtils; -import cgeo.geocaching.utils.LeastRecentlyUsedCache; +import cgeo.geocaching.utils.LeastRecentlyUsedMap; import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; @@ -31,6 +30,7 @@ import android.graphics.Bitmap; import java.text.ParseException; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -52,6 +52,9 @@ public class GCBase { protected final static long GC_BASE31 = 31; protected final static long GC_BASE16 = 16; + private final static LeastRecentlyUsedMap<Integer, Tile> tileCache = new LeastRecentlyUsedMap.LruCache<Integer, Tile>(64); + private static Viewport lastSearchViewport = null; + /** * Searches the view port on the live map with Strategy.AUTO * @@ -84,6 +87,17 @@ public class GCBase { } } + public static void removeFromTileCache(Geopoint coords) { + if (coords != null) { + Collection<Tile> tiles = new ArrayList<Tile>(tileCache.values()); + for (Tile tile : tiles) { + if (tile.containsPoint(coords)) { + tileCache.remove(tile.hashCode()); + } + } + } + } + /** * Searches the view port on the live map for caches. * The strategy dictates if only live map information is used or if an additional @@ -98,7 +112,7 @@ public class GCBase { * @return */ private static SearchResult searchByViewport(final Viewport viewport, final String[] tokens, Strategy strategy) { - Log.d(Settings.tag, "GCBase.searchByViewport" + viewport.toString()); + Log.d("GCBase.searchByViewport" + viewport.toString()); String referer = GCConstants.URL_LIVE_MAP; @@ -110,58 +124,76 @@ public class GCBase { for (Tile tile : tiles) { - StringBuilder url = new StringBuilder(); - url.append("?x=").append(tile.getX()) // x tile - .append("&y=").append(tile.getY()) // y tile - .append("&z=").append(tile.getZoomlevel()); // zoom level - if (tokens != null) { - url.append("&k=").append(tokens[0]); // user session - url.append("&st=").append(tokens[1]); // session token - } - url.append("&ep=1"); - if (Settings.isExcludeMyCaches()) { - url.append("&hf=1").append("&hh=1"); // hide found, hide hidden - } - if (Settings.getCacheType() == CacheType.TRADITIONAL) { - url.append("&ect=9,5,3,6,453,13,1304,137,11,4,8,1858"); // 2 = tradi 3 = multi 8 = mystery - } - if (Settings.getCacheType() == CacheType.MULTI) { - url.append("&ect=9,5,2,6,453,13,1304,137,11,4,8,1858"); - } - if (Settings.getCacheType() == CacheType.MYSTERY) { - url.append("&ect=9,5,3,6,453,13,1304,137,11,4,2,1858"); - } - if (tile.getZoomlevel() != 14) { - url.append("&_=").append(String.valueOf(System.currentTimeMillis())); - } - // other types t.b.d - final String urlString = url.toString(); + if (!tileCache.containsKey(tile.hashCode())) { + final Parameters params = new Parameters( + "x", String.valueOf(tile.getX()), + "y", String.valueOf(tile.getY()), + "z", String.valueOf(tile.getZoomlevel()), + "ep", "1"); + if (tokens != null) { + params.put("k", tokens[0], "st", tokens[1]); + } + if (Settings.isExcludeMyCaches()) { + params.put("hf", "1", "hh", "1"); // hide found, hide hidden + } + if (Settings.getCacheType() == CacheType.TRADITIONAL) { + params.put("ect", "9,5,3,6,453,13,1304,137,11,4,8,1858"); // 2 = tradi 3 = multi 8 = mystery + } else if (Settings.getCacheType() == CacheType.MULTI) { + params.put("ect", "9,5,2,6,453,13,1304,137,11,4,8,1858"); + } else if (Settings.getCacheType() == CacheType.MYSTERY) { + params.put("ect", "9,5,3,6,453,13,1304,137,11,4,2,1858"); + } + if (tile.getZoomlevel() != 14) { + params.put("_", String.valueOf(System.currentTimeMillis())); + } + // TODO: other types t.b.d - // The PNG must be request before ! Else the following request would return with 204 - No Content - Bitmap bitmap = Tile.requestMapTile(GCConstants.URL_MAP_TILE + urlString, referer); + // The PNG must be requested first, otherwise the following request would always return with 204 - No Content + Bitmap bitmap = Tile.requestMapTile(GCConstants.URL_MAP_TILE, params, referer); - assert bitmap.getWidth() == Tile.TILE_SIZE : "Bitmap has wrong width"; - assert bitmap.getHeight() == Tile.TILE_SIZE : "Bitmap has wrong height"; + // Check bitmap size + if (bitmap != null && (bitmap.getWidth() != Tile.TILE_SIZE || + bitmap.getHeight() != Tile.TILE_SIZE)) { + bitmap.recycle(); + bitmap = null; + } - 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 { - final SearchResult search = parseMapJSON(data, tile, bitmap, strategy); - if (search == null || CollectionUtils.isEmpty(search.getGeocodes())) { - Log.e(Settings.tag, "GCBase.searchByViewport: No cache parsed for viewport " + viewport); + String data = Tile.requestMapInfo(GCConstants.URL_MAP_INFO, params, referer); + if (StringUtils.isEmpty(data)) { + Log.e("GCBase.searchByViewport: No data from server for tile (" + tile.getX() + "/" + tile.getY() + ")"); + } else { + final SearchResult search = parseMapJSON(data, tile, bitmap, strategy); + if (search == null || CollectionUtils.isEmpty(search.getGeocodes())) { + Log.e("GCBase.searchByViewport: No cache parsed for viewport " + viewport); + } + else { + searchResult.addGeocodes(search.getGeocodes()); + } + tileCache.put(tile.hashCode(), tile); } - else { - searchResult.addGeocodes(search.getGeocodes()); + + // release native bitmap memory + if (bitmap != null) { + bitmap.recycle(); } + } } } if (strategy.flags.contains(StrategyFlag.SEARCH_NEARBY)) { - SearchResult search = cgBase.searchByCoords(null, viewport.getCenter(), Settings.getCacheType(), false); - if (search != null) { - searchResult.addGeocodes(search.getGeocodes()); + Geopoint center = viewport.getCenter(); + if ((lastSearchViewport == null) || !lastSearchViewport.contains(center)) { + SearchResult search = GCParser.searchByCoords(null, center, Settings.getCacheType(), false); + if (search != null && !search.isEmpty()) { + final Set<String> geocodes = search.getGeocodes(); + if (Settings.isPremiumMember()) { + lastSearchViewport = cgeoapplication.getInstance().getBounds(geocodes); + } else { + lastSearchViewport = new Viewport(center, 0.01, 0.01); + } + searchResult.addGeocodes(geocodes); + } } } @@ -180,7 +212,7 @@ public class GCBase { try { - final LeastRecentlyUsedCache<String, String> nameCache = new LeastRecentlyUsedCache<String, String>(2000); // JSON id, cache name + final LeastRecentlyUsedMap<String, String> nameCache = new LeastRecentlyUsedMap.LruCache<String, String>(2000); // JSON id, cache name if (StringUtils.isEmpty(data)) { throw new JSONException("No page given"); @@ -265,7 +297,7 @@ public class GCBase { cache.setName(nameCache.get(id)); cache.setZoomlevel(tile.getZoomlevel()); cache.setCoords(tile.getCoord(xy)); - if (strategy.flags.contains(StrategyFlag.PARSE_TILES) && positions.size() < 64) { + if (strategy.flags.contains(StrategyFlag.PARSE_TILES) && positions.size() < 64 && bitmap != null) { // 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 { @@ -273,10 +305,10 @@ public class GCBase { } searchResult.addCache(cache); } - Log.d(Settings.tag, "Retrieved " + searchResult.getCount() + " caches for tile " + tile.toString()); + Log.d("Retrieved " + searchResult.getCount() + " caches for tile " + tile.toString()); } catch (Exception e) { - Log.e(Settings.tag, "GCBase.parseMapJSON", e); + Log.e("GCBase.parseMapJSON", e); } return searchResult; @@ -325,65 +357,9 @@ public class GCBase { return gcid; } - private static String modulo(final long value, final long base, final String sequence) { - String result = ""; - long rest = 0; - long divResult = value; - do - { - rest = divResult % base; - divResult = (int) Math.floor(divResult / base); - result = sequence.charAt((int) rest) + result; - } while (divResult != 0); - return result; - } - - /** - * Convert (old) GCIds to GCCode (geocode) - * - * Based on http://www.geoclub.de/viewtopic.php?f=111&t=54859&start=40 - */ - public static String gcidToGCCode(final long gcid) { - String gccode = modulo(gcid + 411120, GC_BASE31, SEQUENCE_GCID); - if ((gccode.length() < 4) || (gccode.length() == 4 && SEQUENCE_GCID.indexOf(gccode.charAt(0)) < 16)) { - gccode = modulo(gcid, GC_BASE16, SEQUENCE_GCID); - } - return "GC" + gccode; - } - - /** - * Convert ids from the live map to (old) GCIds - * - * Based on http://www.geoclub.de/viewtopic.php?f=111&t=54859&start=40 - */ - public static long newidToGCId(final String newid) { - long gcid = 0; - for (int p = 0; p < newid.length(); p++) { - gcid = GC_BASE57 * gcid + SEQUENCE_NEWID.indexOf(newid.charAt(p)); - } - return gcid; - } - - /** - * Convert (old) GCIds to ids used in the live map - * - * Based on http://www.geoclub.de/viewtopic.php?f=111&t=54859&start=40 - */ - public static String gcidToNewId(final long gcid) { - return modulo(gcid, GC_BASE57, SEQUENCE_NEWID); - } - - /** - * Convert ids from the live map into GCCode (geocode) - */ - public static String newidToGeocode(final String newid) { - long gcid = GCBase.newidToGCId(newid); - return GCBase.gcidToGCCode(gcid); - } - /** Get user session & session token from the Live Map. Needed for following requests */ public static String[] getTokens() { - final HttpResponse response = Network.request(GCConstants.URL_LIVE_MAP, null, false); + final HttpResponse response = Network.getRequest(GCConstants.URL_LIVE_MAP); final String data = Network.getResponseData(response); String userSession = BaseUtils.getMatch(data, GCConstants.PATTERN_USERSESSION, ""); String sessionToken = BaseUtils.getMatch(data, GCConstants.PATTERN_SESSIONTOKEN, ""); @@ -392,18 +368,14 @@ public class GCBase { public static SearchResult searchByGeocodes(final Set<String> geocodes) { - SearchResult result = new SearchResult(); + final SearchResult result = new SearchResult(); final String geocodeList = StringUtils.join(geocodes.toArray(), "|"); - - String referer = GCConstants.URL_LIVE_MAP_DETAILS; - - StringBuilder url = new StringBuilder(); - url.append("?i=").append(geocodeList).append("&_=").append(String.valueOf(System.currentTimeMillis())); - final String urlString = url.toString(); + final String referer = GCConstants.URL_LIVE_MAP_DETAILS; try { - String data = Tile.requestMapInfo(referer + urlString, referer); + final Parameters params = new Parameters("i", geocodeList, "_", String.valueOf(System.currentTimeMillis())); + final String data = Tile.requestMapInfo(referer, params, referer); // Example JSON information // {"status":"success", diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java index d955418..a431359 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java +++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java @@ -3,13 +3,11 @@ package cgeo.geocaching.connector.gc; import cgeo.geocaching.R; import cgeo.geocaching.SearchResult; import cgeo.geocaching.Settings; -import cgeo.geocaching.cgBase; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.connector.AbstractConnector; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.geopoint.Viewport; -import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.utils.CancellableHandler; import cgeo.geocaching.utils.Log; @@ -17,7 +15,6 @@ import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; - import java.util.Set; import java.util.regex.Pattern; @@ -90,7 +87,7 @@ public class GCConnector extends AbstractConnector { public SearchResult searchByGeocode(final String geocode, final String guid, final cgeoapplication app, final CancellableHandler handler) { if (app == null) { - Log.e(Settings.tag, "cgeoBase.searchByGeocode: No application found"); + Log.e("cgeoBase.searchByGeocode: No application found"); return null; } @@ -103,15 +100,15 @@ public class GCConnector extends AbstractConnector { params.put("log", "y"); params.put("numlogs", String.valueOf(GCConstants.NUMBER_OF_LOGS)); - cgBase.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_loadpage); + CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_loadpage); - final String page = Network.requestLogged("http://www.geocaching.com/seek/cache_details.aspx", params, false, false, false); + final String page = Login.getRequestLogged("http://www.geocaching.com/seek/cache_details.aspx", params); if (StringUtils.isEmpty(page)) { 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."); + Log.i("Loading old cache from cache."); search.addGeocode(app.getGeocode(guid)); } else { @@ -121,15 +118,15 @@ public class GCConnector extends AbstractConnector { return search; } - Log.e(Settings.tag, "cgeoBase.searchByGeocode: No data from server"); + Log.e("cgeoBase.searchByGeocode: No data from server"); search.setError(StatusCode.COMMUNICATION_ERROR); return search; } - final SearchResult searchResult = cgBase.parseCache(page, handler); + final SearchResult searchResult = GCParser.parseCache(page, handler); if (searchResult == null || CollectionUtils.isEmpty(searchResult.getGeocodes())) { - Log.e(Settings.tag, "cgeoBase.searchByGeocode: No cache parsed"); + Log.e("cgeoBase.searchByGeocode: No cache parsed"); return searchResult; } diff --git a/main/src/cgeo/geocaching/cgBase.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java index 090bffc..cf7c762 100644 --- a/main/src/cgeo/geocaching/cgBase.java +++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java @@ -1,14 +1,19 @@ -// $codepro.audit.disable logExceptions -package cgeo.geocaching; - -import cgeo.geocaching.activity.ActivityMixin; -import cgeo.geocaching.connector.ConnectorFactory; -import cgeo.geocaching.connector.gc.GCConnector; -import cgeo.geocaching.connector.gc.GCConstants; +package cgeo.geocaching.connector.gc; + +import cgeo.geocaching.LogEntry; +import cgeo.geocaching.R; +import cgeo.geocaching.SearchResult; +import cgeo.geocaching.Settings; +import cgeo.geocaching.TrackableLog; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgImage; +import cgeo.geocaching.cgSearchThread; +import cgeo.geocaching.cgTrackable; +import cgeo.geocaching.cgWaypoint; +import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LoadFlags; -import cgeo.geocaching.enumerations.LoadFlags.RemoveFlag; import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.LogTypeTrackable; @@ -19,8 +24,6 @@ import cgeo.geocaching.gcvote.GCVote; import cgeo.geocaching.gcvote.GCVoteRating; import cgeo.geocaching.geopoint.DistanceParser; import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.network.HtmlImage; -import cgeo.geocaching.network.Login; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.ui.DirectionImage; @@ -36,20 +39,10 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.res.Resources; import android.net.Uri; -import android.os.Handler; -import android.os.Message; import android.text.Html; import android.text.Spannable; import android.text.Spanned; -import android.text.format.DateUtils; import android.text.style.StrikethroughSpan; import java.net.URLDecoder; @@ -57,74 +50,20 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; +import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.regex.Matcher; -public class cgBase { - +public abstract class GCParser { 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; - public static Resources res; - - public static final int UPDATE_LOAD_PROGRESS_DETAIL = 42186; - - private cgBase() { - //initialize(app); - throw new UnsupportedOperationException(); // static class, not to be instantiated - } - - /** - * Called from AbstractActivity.onCreate() and AbstractListActivity.onCreate() - * - * @param app - */ - public static void initialize(final cgeoapplication app) { - context = app.getBaseContext(); - res = app.getBaseContext().getResources(); - - try { - final PackageManager manager = app.getPackageManager(); - final PackageInfo info = manager.getPackageInfo(app.getPackageName(), 0); - version = info.versionName; - } catch (PackageManager.NameNotFoundException e) { - Log.e(Settings.tag, "unable to get version information", e); - version = null; - } - } - - public static void sendLoadProgressDetail(final Handler handler, final int str) { - if (null != handler) { - handler.obtainMessage(UPDATE_LOAD_PROGRESS_DETAIL, cgeoapplication.getInstance().getString(str)).sendToTarget(); - } - } - - /** - * checks if an Array of Strings is empty or not. Empty means: - * - Array is null - * - or all elements are null or empty strings - */ - public static boolean isEmpty(String[] a) { - if (a == null) { - return true; - } - - for (String s : a) { - if (StringUtils.isNotEmpty(s)) { - return false; - } - } - return true; - } 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"); + Log.e("cgeoBase.parseSearch: No page given"); return null; } @@ -144,7 +83,7 @@ public class cgBase { if (recaptchaJsParam != null) { final Parameters params = new Parameters("k", recaptchaJsParam.trim()); - final String recaptchaJs = Network.getResponseData(Network.request("http://www.google.com/recaptcha/api/challenge", params, true)); + final String recaptchaJs = Network.getResponseData(Network.getRequest("http://www.google.com/recaptcha/api/challenge", params)); if (StringUtils.isNotBlank(recaptchaJs)) { recaptchaChallenge = BaseUtils.getMatch(recaptchaJs, GCConstants.PATTERN_SEARCH_RECAPTCHACHALLENGE, true, 1, null, true); @@ -163,7 +102,7 @@ public class cgBase { int startPos = page.indexOf("<div id=\"ctl00_ContentBody_ResultsPanel\""); if (startPos == -1) { - Log.e(Settings.tag, "cgeoBase.parseSearch: ID \"ctl00_ContentBody_dlResults\" not found on page"); + Log.e("cgeoBase.parseSearch: ID \"ctl00_ContentBody_dlResults\" not found on page"); return null; } @@ -172,7 +111,7 @@ public class cgBase { startPos = page.indexOf('>'); int endPos = page.indexOf("ctl00_ContentBody_UnitTxt"); if (startPos == -1 || endPos == -1) { - Log.e(Settings.tag, "cgeoBase.parseSearch: ID \"ctl00_ContentBody_UnitTxt\" not found on page"); + Log.e("cgeoBase.parseSearch: ID \"ctl00_ContentBody_UnitTxt\" not found on page"); return null; } @@ -215,7 +154,7 @@ public class cgBase { } } catch (Exception e) { // failed to parse GUID and/or Disabled - Log.w(Settings.tag, "cgeoBase.parseSearch: Failed to parse GUID and/or Disabled data"); + Log.w("cgeoBase.parseSearch: Failed to parse GUID and/or Disabled data"); } if (Settings.isExcludeDisabledCaches() && (cache.isDisabled() || cache.isArchived())) { @@ -276,14 +215,14 @@ public class cgBase { cids.add(cache.getCacheId()); } - // favourite count + // favorite count try { result = BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_FAVORITE, false, 1, null, true); if (null != result) { cache.setFavoritePoints(Integer.parseInt(result)); } } catch (NumberFormatException e) { - Log.w(Settings.tag, "cgeoBase.parseSearch: Failed to parse favourite count"); + Log.w("cgeoBase.parseSearch: Failed to parse favourite count"); } if (cache.getNameSp() == null) { @@ -303,7 +242,7 @@ public class cgBase { searchResult.setTotal(Integer.parseInt(result)); } } catch (NumberFormatException e) { - Log.w(Settings.tag, "cgeoBase.parseSearch: Failed to parse cache count"); + Log.w("cgeoBase.parseSearch: Failed to parse cache count"); } if (thread != null && recaptchaChallenge != null) { @@ -315,7 +254,7 @@ public class cgBase { } if (cids.size() > 0 && (Settings.isPremiumMember() || showCaptcha) && (recaptchaChallenge == null || StringUtils.isNotBlank(recaptchaText))) { - Log.i(Settings.tag, "Trying to get .loc for " + cids.size() + " caches"); + Log.i("Trying to get .loc for " + cids.size() + " caches"); try { // get coordinates for parsed caches @@ -345,7 +284,7 @@ public class cgBase { 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")) { - Log.i(Settings.tag, "User has not agreed to the license agreement. Can\'t download .loc file."); + Log.i("User has not agreed to the license agreement. Can\'t download .loc file."); searchResult.setError(StatusCode.UNAPPROVED_LICENSE); @@ -356,7 +295,7 @@ public class cgBase { LocParser.parseLoc(searchResult, coordinates); } catch (Exception e) { - Log.e(Settings.tag, "cgBase.parseSearch.CIDs: " + e.toString()); + Log.e("cgBase.parseSearch.CIDs: " + e.toString()); } } @@ -386,7 +325,7 @@ public class cgBase { } // update progress message so user knows we're still working. Otherwise it will remain on whatever was set // in getExtraOnlineInfo (which could be logs, gcvote, or elevation) - sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_render); + CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_render); // save full detailed caches cgeoapplication.getInstance().saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); } @@ -394,10 +333,10 @@ public class cgBase { } static SearchResult parseCacheFromText(final String page, final CancellableHandler handler) { - sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_details); + CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_details); if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.parseCache: No page given"); + Log.e("cgeoBase.parseCache: No page given"); return null; } @@ -457,7 +396,7 @@ public class cgBase { int pos = tableInside.indexOf("id=\"cacheDetails\""); if (pos == -1) { - Log.e(Settings.tag, "cgeoBase.parseCache: ID \"cacheDetails\" not found on page"); + Log.e("cgeoBase.parseCache: ID \"cacheDetails\" not found on page"); return null; } @@ -465,7 +404,7 @@ public class cgBase { pos = tableInside.indexOf("<div class=\"CacheInformationTable\""); if (pos == -1) { - Log.e(Settings.tag, "cgeoBase.parseCache: class \"CacheInformationTable\" not found on page"); + Log.e("cgeoBase.parseCache: class \"CacheInformationTable\" not found on page"); return null; } @@ -502,7 +441,7 @@ public class cgBase { } } catch (ParseException e) { // failed to parse cache hidden date - Log.w(Settings.tag, "cgeoBase.parseCache: Failed to parse cache hidden (event) date"); + Log.w("cgeoBase.parseCache: Failed to parse cache hidden (event) date"); } // favourite @@ -528,7 +467,7 @@ public class cgBase { cache.setCoords(new Geopoint(cache.getLatlon())); cache.setReliableLatLon(true); } catch (Geopoint.GeopointException e) { - Log.w(Settings.tag, "cgeoBase.parseCache: Failed to parse cache coordinates: " + e.toString()); + Log.w("cgeoBase.parseCache: Failed to parse cache coordinates: " + e.toString()); } } @@ -545,7 +484,7 @@ public class cgBase { } } - checkFields(cache); + cache.checkFields(); // cache personal note cache.setPersonalNote(BaseUtils.getMatch(page, GCConstants.PATTERN_PERSONALNOTE, true, cache.getPersonalNote())); @@ -582,7 +521,7 @@ public class cgBase { } } catch (Exception e) { // failed to parse cache attributes - Log.w(Settings.tag, "cgeoBase.parseCache: Failed to parse cache attributes"); + Log.w("cgeoBase.parseCache: Failed to parse cache attributes"); } // cache spoilers @@ -592,7 +531,7 @@ public class cgBase { if (CancellableHandler.isCancelled(handler)) { return null; } - sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_spoilers); + CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_spoilers); final Matcher matcherSpoilersInside = GCConstants.PATTERN_SPOILERSINSIDE.matcher(spoilers); @@ -619,7 +558,7 @@ public class cgBase { } } catch (Exception e) { // failed to parse cache spoilers - Log.w(Settings.tag, "cgeoBase.parseCache: Failed to parse cache spoilers"); + Log.w("cgeoBase.parseCache: Failed to parse cache spoilers"); } // cache inventory @@ -653,7 +592,7 @@ public class cgBase { } } catch (Exception e) { // failed to parse cache inventory - Log.w(Settings.tag, "cgeoBase.parseCache: Failed to parse cache inventory (2)"); + Log.w("cgeoBase.parseCache: Failed to parse cache inventory (2)"); } // cache logs counts @@ -678,7 +617,7 @@ public class cgBase { } catch (Exception e) { // failed to parse logs - Log.w(Settings.tag, "cgeoBase.parseCache: Failed to parse cache log count"); + Log.w("cgeoBase.parseCache: Failed to parse cache log count"); } // add waypoint for original coordinates in case of user-modified listing-coordinates @@ -686,8 +625,7 @@ public class cgBase { final String originalCoords = BaseUtils.getMatch(page, GCConstants.PATTERN_LATLON_ORIG, false, null); if (null != originalCoords) { - // res is null during the unit tests - final cgWaypoint waypoint = new cgWaypoint(res != null ? res.getString(R.string.cache_coordinates_original) : "res = null", WaypointType.WAYPOINT, false); + final cgWaypoint waypoint = new cgWaypoint(cgeoapplication.getInstance().getString(R.string.cache_coordinates_original), WaypointType.WAYPOINT, false); waypoint.setCoords(new Geopoint(originalCoords)); cache.addWaypoint(waypoint, false); cache.setUserModifiedCoords(true); @@ -704,8 +642,7 @@ public class cgBase { if (CancellableHandler.isCancelled(handler)) { return null; } - sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_waypoints); - + CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_waypoints); String wpList = page.substring(wpBegin); @@ -732,7 +669,7 @@ public class cgBase { // waypoint name // res is null during the unit tests - final String name = BaseUtils.getMatch(wp[6], GCConstants.PATTERN_WPNAME, true, 1, res != null ? res.getString(R.string.waypoint) : "res = null", true); + final String name = BaseUtils.getMatch(wp[6], GCConstants.PATTERN_WPNAME, true, 1, cgeoapplication.getInstance().getString(R.string.waypoint), true); // waypoint type final String resulttype = BaseUtils.getMatch(wp[3], GCConstants.PATTERN_WPTYPE, null); @@ -780,485 +717,6 @@ public class cgBase { return searchResult; } - private static void getExtraOnlineInfo(final cgCache cache, final String page, final CancellableHandler handler) { - if (CancellableHandler.isCancelled(handler)) { - return; - } - - //cache.setLogs(loadLogsFromDetails(page, cache, false)); - if (Settings.isFriendLogsWanted()) { - sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_logs); - List<cgLog> allLogs = cache.getLogs(); - List<cgLog> friendLogs = loadLogsFromDetails(page, cache, true, false); - if (friendLogs != null) { - for (cgLog log : friendLogs) { - if (allLogs.contains(log)) { - allLogs.get(allLogs.indexOf(log)).friend = true; - } else { - allLogs.add(log); - } - } - } - } - - if (Settings.isElevationWanted()) { - if (CancellableHandler.isCancelled(handler)) { - return; - } - sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_elevation); - if (cache.getCoords() != null) { - cache.setElevation(cache.getCoords().getElevation()); - } - } - - if (Settings.isRatingWanted()) { - if (CancellableHandler.isCancelled(handler)) { - return; - } - sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_gcvote); - final GCVoteRating rating = GCVote.getRating(cache.getGuid(), cache.getGeocode()); - if (rating != null) { - cache.setRating(rating.getRating()); - cache.setVotes(rating.getVotes()); - cache.setMyVote(rating.getMyVote()); - } - } - } - - /** - * Load logs from a cache details page. - * - * @param page - * the text of the details page - * @param cache - * the cache object to put the logs in - * @param friends - * retrieve friend logs - */ - private static List<cgLog> loadLogsFromDetails(final String page, final cgCache cache, final boolean friends, final boolean getDataFromPage) { - String rawResponse = null; - - if (!getDataFromPage) { - final Matcher userTokenMatcher = GCConstants.PATTERN_USERTOKEN2.matcher(page); - if (!userTokenMatcher.find()) { - Log.e(Settings.tag, "cgBase.loadLogsFromDetails: unable to extract userToken"); - return null; - } - - final String userToken = userTokenMatcher.group(1); - final Parameters params = new Parameters( - "tkn", userToken, - "idx", "1", - "num", String.valueOf(GCConstants.NUMBER_OF_LOGS), - "decrypt", "true", - // "sp", Boolean.toString(personal), // personal logs - "sf", Boolean.toString(friends)); - - 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; - } - final int statusCode = response.getStatusLine().getStatusCode(); - if (statusCode != 200) { - Log.e(Settings.tag, "cgBase.loadLogsFromDetails: error " + statusCode + " when requesting log information"); - return null; - } - rawResponse = Network.getResponseData(response); - if (rawResponse == null) { - Log.e(Settings.tag, "cgBase.loadLogsFromDetails: unable to read whole response"); - return null; - } - } else { - // extract embedded JSON data from page - rawResponse = BaseUtils.getMatch(page, GCConstants.PATTERN_LOGBOOK, ""); - } - - List<cgLog> logs = new ArrayList<cgLog>(); - - try { - final JSONObject resp = new JSONObject(rawResponse); - if (!resp.getString("status").equals("success")) { - Log.e(Settings.tag, "cgBase.loadLogsFromDetails: status is " + resp.getString("status")); - return null; - } - - final JSONArray data = resp.getJSONArray("data"); - - for (int index = 0; index < data.length(); index++) { - final JSONObject entry = data.getJSONObject(index); - final cgLog logDone = new cgLog(); - logDone.friend = friends; - - // FIXME: use the "LogType" field instead of the "LogTypeImage" one. - final String logIconNameExt = entry.optString("LogTypeImage", ".gif"); - final String logIconName = logIconNameExt.substring(0, logIconNameExt.length() - 4); - logDone.type = LogType.getByIconName(logIconName); - - try { - logDone.date = Login.parseGcCustomDate(entry.getString("Visited")).getTime(); - } catch (ParseException e) { - Log.e(Settings.tag, "cgBase.loadLogsFromDetails: failed to parse log date."); - } - - logDone.author = entry.getString("UserName"); - logDone.found = entry.getInt("GeocacheFindCount"); - logDone.log = entry.getString("LogText"); - - final JSONArray images = entry.getJSONArray("Images"); - for (int i = 0; i < images.length(); i++) { - final JSONObject image = images.getJSONObject(i); - String url = "http://img.geocaching.com/cache/log/" + image.getString("FileName"); - String title = image.getString("Name"); - final cgImage logImage = new cgImage(url, title); - if (logDone.logImages == null) { - logDone.logImages = new ArrayList<cgImage>(); - } - logDone.logImages.add(logImage); - } - - logs.add(logDone); - } - } catch (JSONException e) { - // failed to parse logs - Log.w(Settings.tag, "cgBase.loadLogsFromDetails: Failed to parse cache logs", e); - } - - return logs; - } - - private static void checkFields(cgCache cache) { - if (StringUtils.isBlank(cache.getGeocode())) { - Log.e(Settings.tag, "cgBase.loadLogsFromDetails: geo code not parsed correctly"); - } - if (StringUtils.isBlank(cache.getName())) { - Log.e(Settings.tag, "name not parsed correctly"); - } - if (StringUtils.isBlank(cache.getGuid())) { - Log.e(Settings.tag, "guid not parsed correctly"); - } - if (cache.getTerrain() == 0.0) { - Log.e(Settings.tag, "terrain not parsed correctly"); - } - if (cache.getDifficulty() == 0.0) { - Log.e(Settings.tag, "difficulty not parsed correctly"); - } - if (StringUtils.isBlank(cache.getOwner())) { - Log.e(Settings.tag, "owner not parsed correctly"); - } - if (StringUtils.isBlank(cache.getOwnerReal())) { - Log.e(Settings.tag, "owner real not parsed correctly"); - } - if (cache.getHiddenDate() == null) { - Log.e(Settings.tag, "hidden not parsed correctly"); - } - if (cache.getFavoritePoints() < 0) { - Log.e(Settings.tag, "favoriteCount not parsed correctly"); - } - if (cache.getSize() == null) { - Log.e(Settings.tag, "size not parsed correctly"); - } - if (cache.getType() == null || cache.getType() == CacheType.UNKNOWN) { - Log.e(Settings.tag, "type not parsed correctly"); - } - if (cache.getCoords() == null) { - Log.e(Settings.tag, "coordinates not parsed correctly"); - } - if (StringUtils.isBlank(cache.getLocation())) { - Log.e(Settings.tag, "location not parsed correctly"); - } - } - - /** - * Parse a trackable HTML description into a cgTrackable object - * - * @param page - * the HTML page to parse, already processed through {@link BaseUtils#replaceWhitespace} - * @param app - * if not null, the application to use to save the trackable - * @return the parsed trackable, or null if none could be parsed - */ - public static cgTrackable parseTrackable(final String page, final cgeoapplication app, final String possibleTrackingcode) { - if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.parseTrackable: No page given"); - return null; - } - - final cgTrackable trackable = new cgTrackable(); - - // trackable geocode - trackable.setGeocode(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GEOCODE, true, trackable.getGeocode()).toUpperCase()); - - // trackable id - trackable.setGuid(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GUID, true, trackable.getGuid())); - - // trackable icon - trackable.setIconUrl(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_ICON, true, trackable.getIconUrl())); - - // trackable name - trackable.setName(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_NAME, true, trackable.getName())); - - // trackable type - if (StringUtils.isNotBlank(trackable.getName())) { - trackable.setType(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_TYPE, true, trackable.getType())); - } - - // trackable owner name - try { - final Matcher matcherOwner = GCConstants.PATTERN_TRACKABLE_OWNER.matcher(page); - if (matcherOwner.find() && matcherOwner.groupCount() > 0) { - trackable.setOwnerGuid(matcherOwner.group(1)); - trackable.setOwner(matcherOwner.group(2).trim()); - } - } catch (Exception e) { - // failed to parse trackable owner name - Log.w(Settings.tag, "cgeoBase.parseTrackable: Failed to parse trackable owner name"); - } - - // trackable origin - trackable.setOrigin(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_ORIGIN, true, trackable.getOrigin())); - - // trackable spotted - try { - final Matcher matcherSpottedCache = GCConstants.PATTERN_TRACKABLE_SPOTTEDCACHE.matcher(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); - if (matcherSpottedUser.find() && matcherSpottedUser.groupCount() > 0) { - trackable.setSpottedGuid(matcherSpottedUser.group(1)); - trackable.setSpottedName(matcherSpottedUser.group(2).trim()); - trackable.setSpottedType(cgTrackable.SPOTTED_USER); - } - - if (BaseUtils.matches(page, GCConstants.PATTERN_TRACKABLE_SPOTTEDUNKNOWN)) { - trackable.setSpottedType(cgTrackable.SPOTTED_UNKNOWN); - } - - if (BaseUtils.matches(page, GCConstants.PATTERN_TRACKABLE_SPOTTEDOWNER)) { - trackable.setSpottedType(cgTrackable.SPOTTED_OWNER); - } - } catch (Exception e) { - // failed to parse trackable last known place - Log.w(Settings.tag, "cgeoBase.parseTrackable: Failed to parse trackable last known place"); - } - - // released date - can be missing on the page - try { - String releaseString = BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_RELEASES, false, null); - if (releaseString != null) { - trackable.setReleased(dateTbIn1.parse(releaseString)); - if (trackable.getReleased() == null) { - trackable.setReleased(dateTbIn2.parse(releaseString)); - } - } - } catch (ParseException e1) { - trackable.setReleased(null); - } - - - // trackable distance - try { - final String distance = BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_DISTANCE, false, null); - if (null != distance) { - trackable.setDistance(DistanceParser.parseDistance(distance, Settings.isUseMetricUnits())); - } - } catch (NumberFormatException e) { - throw e; - } - - // trackable goal - trackable.setGoal(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GOAL, true, trackable.getGoal())); - - // trackable details & image - try { - final Matcher matcherDetailsImage = GCConstants.PATTERN_TRACKABLE_DETAILSIMAGE.matcher(page); - if (matcherDetailsImage.find() && matcherDetailsImage.groupCount() > 0) { - final String image = StringUtils.trim(matcherDetailsImage.group(3)); - final String details = StringUtils.trim(matcherDetailsImage.group(4)); - - if (StringUtils.isNotEmpty(image)) { - trackable.setImage(image); - } - if (StringUtils.isNotEmpty(details) && !StringUtils.equals(details, "No additional details available.")) { - trackable.setDetails(details); - } - } - } catch (Exception e) { - // failed to parse trackable details & image - Log.w(Settings.tag, "cgeoBase.parseTrackable: Failed to parse trackable details & image"); - } - - // trackable logs - try - { - final Matcher matcherLogs = GCConstants.PATTERN_TRACKABLE_LOG.matcher(page); - /* - * 1. Type (img) - * 2. Date - * 3. Author - * 4. Cache-GUID - * 5. <ignored> (strike-through property for ancien caches) - * 6. Cache-name - * 7. Logtext - */ - while (matcherLogs.find()) - { - final cgLog logDone = new cgLog(); - - logDone.type = LogType.getByIconName(matcherLogs.group(1)); - logDone.author = Html.fromHtml(matcherLogs.group(3)).toString().trim(); - - try - { - logDone.date = Login.parseGcCustomDate(matcherLogs.group(2)).getTime(); - } catch (ParseException e) { - } - - logDone.log = matcherLogs.group(7).trim(); - - if (matcherLogs.group(4) != null && matcherLogs.group(6) != null) - { - logDone.cacheGuid = matcherLogs.group(4); - logDone.cacheName = matcherLogs.group(6); - } - - // Apply the pattern for images in a trackable log entry against each full log (group(0)) - final Matcher matcherLogImages = GCConstants.PATTERN_TRACKABLE_LOG_IMAGES.matcher(matcherLogs.group(0)); - /* - * 1. Image URL - * 2. Image title - */ - while (matcherLogImages.find()) - { - final cgImage logImage = new cgImage(matcherLogImages.group(1), matcherLogImages.group(2)); - if (logDone.logImages == null) { - logDone.logImages = new ArrayList<cgImage>(); - } - logDone.logImages.add(logImage); - } - - trackable.getLogs().add(logDone); - } - } catch (Exception e) { - // failed to parse logs - Log.w(Settings.tag, "cgeoBase.parseCache: Failed to parse cache logs" + e.toString()); - } - - // trackingcode - if (!StringUtils.equalsIgnoreCase(trackable.getGeocode(), possibleTrackingcode)) { - trackable.setTrackingcode(possibleTrackingcode); - } - - if (app != null) { - app.saveTrackable(trackable); - } - - return trackable; - } - - public static List<LogType> parseTypes(String page) { - if (StringUtils.isEmpty(page)) { - return null; - } - - final List<LogType> types = new ArrayList<LogType>(); - - final Matcher typeBoxMatcher = GCConstants.PATTERN_TYPEBOX.matcher(page); - String typesText = null; - if (typeBoxMatcher.find()) { - if (typeBoxMatcher.groupCount() > 0) { - typesText = typeBoxMatcher.group(1); - } - } - - if (typesText != null) { - - final Matcher typeMatcher = GCConstants.PATTERN_TYPE2.matcher(typesText); - while (typeMatcher.find()) { - if (typeMatcher.groupCount() > 1) { - final int type = Integer.parseInt(typeMatcher.group(2)); - - if (type > 0) { - types.add(LogType.getById(type)); - } - } - } - } - - return types; - } - - public static List<cgTrackableLog> parseTrackableLog(final String page) { - if (StringUtils.isEmpty(page)) { - return null; - } - - final List<cgTrackableLog> trackables = new ArrayList<cgTrackableLog>(); - - String table = StringUtils.substringBetween(page, "<table id=\"tblTravelBugs\"", "</table>"); - - // if no trackables are currently in the account, the table is not available, so return an empty list instead of null - if (StringUtils.isBlank(table)) { - return trackables; - } - - table = StringUtils.substringBetween(table, "<tbody>", "</tbody>"); - if (StringUtils.isBlank(table)) { - Log.e(Settings.tag, "cgeoBase.parseTrackableLog: tbody not found on page"); - return null; - } - - final Matcher trackableMatcher = GCConstants.PATTERN_TRACKABLE.matcher(page); - while (trackableMatcher.find()) { - if (trackableMatcher.groupCount() > 0) { - final cgTrackableLog trackableLog = new cgTrackableLog(); - - if (trackableMatcher.group(1) != null) { - trackableLog.trackCode = trackableMatcher.group(1); - } else { - continue; - } - if (trackableMatcher.group(2) != null) { - trackableLog.name = Html.fromHtml(trackableMatcher.group(2)).toString(); - } else { - continue; - } - if (trackableMatcher.group(3) != null) { - trackableLog.ctl = Integer.valueOf(trackableMatcher.group(3)); - } else { - continue; - } - if (trackableMatcher.group(5) != null) { - trackableLog.id = Integer.valueOf(trackableMatcher.group(5)); - } else { - continue; - } - - Log.i(Settings.tag, "Trackable in inventory (#" + trackableLog.ctl + "/" + trackableLog.id + "): " + trackableLog.trackCode + " - " + trackableLog.name); - - trackables.add(trackableLog); - } - } - - return trackables; - } - - /** - * Insert the right cache type restriction in parameters - * - * @param params - * the parameters to insert the restriction into - * @param cacheType - * the type of cache, or null to include everything - */ - static private void insertCacheType(final Parameters params, final CacheType cacheType) { - params.put("tx", cacheType.guid); - } - public static SearchResult searchByNextPage(cgSearchThread thread, final SearchResult search, boolean showCaptcha) { if (search == null) { return search; @@ -1268,12 +726,12 @@ public class cgBase { final String url = search.getUrl(); if (StringUtils.isBlank(url)) { - Log.e(Settings.tag, "cgeoBase.searchByNextPage: No url found"); + Log.e("cgeoBase.searchByNextPage: No url found"); return search; } - if (isEmpty(viewstates)) { - Log.e(Settings.tag, "cgeoBase.searchByNextPage: No viewstate given"); + if (Login.isEmpty(viewstates)) { + Log.e("cgeoBase.searchByNextPage: No viewstate given"); return search; } @@ -1291,22 +749,22 @@ public class cgBase { if (loginState == StatusCode.NO_ERROR) { page = Network.getResponseData(Network.postRequest(uri, params)); } else if (loginState == StatusCode.NO_LOGIN_INFO_STORED) { - Log.i(Settings.tag, "Working as guest."); + Log.i("Working as guest."); } else { search.setError(loginState); - Log.e(Settings.tag, "cgeoBase.searchByNextPage: Can not log in geocaching"); + Log.e("cgeoBase.searchByNextPage: Can not log in geocaching"); return search; } } if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.searchByNextPage: No data from server"); + Log.e("cgeoBase.searchByNextPage: No data from server"); return search; } final SearchResult searchResult = parseSearch(thread, url, page, showCaptcha); if (searchResult == null || CollectionUtils.isEmpty(searchResult.getGeocodes())) { - Log.e(Settings.tag, "cgeoBase.searchByNextPage: No cache parsed"); + Log.e("cgeoBase.searchByNextPage: No cache parsed"); return search; } @@ -1319,30 +777,25 @@ public class cgBase { return search; } - public static SearchResult searchByGeocode(final String geocode, final String guid, final int listId, final boolean forceReload, final CancellableHandler handler) { - if (StringUtils.isBlank(geocode) && StringUtils.isBlank(guid)) { - Log.e(Settings.tag, "cgeoBase.searchByGeocode: No geocode nor guid given"); - return null; - } - - cgeoapplication app = cgeoapplication.getInstance(); - if (!forceReload && listId == StoredList.TEMPORARY_LIST_ID && (app.isOffline(geocode, guid) || app.isThere(geocode, guid, true, true))) { - final SearchResult search = new SearchResult(); - final String realGeocode = StringUtils.isNotBlank(geocode) ? geocode : app.getGeocode(guid); - search.addGeocode(realGeocode); - return search; - } - - // if we have no geocode, we can't dynamically select the handler, but must explicitly use GC - if (geocode == null && guid != null) { - return GCConnector.getInstance().searchByGeocode(null, guid, app, handler); + /** + * Possibly hide caches found or hidden by user. This mutates its params argument when possible. + * + * @param params + * the parameters to mutate, or null to create a new Parameters if needed + * @param my + * @param addF + * @return the original params if not null, maybe augmented with f=1, or a new Parameters with f=1 or null otherwise + */ + public static Parameters addFToParams(final Parameters params, final boolean my, final boolean addF) { + if (!my && Settings.isExcludeMyCaches() && addF) { + if (params == null) { + return new Parameters("f", "1"); + } + params.put("f", "1"); + Log.i("Skipping caches found or hidden by user."); } - return ConnectorFactory.getConnector(geocode).searchByGeocode(geocode, guid, app, handler); - } - - public static SearchResult searchByStored(final Geopoint coords, final CacheType cacheType, final int list) { - return cgeoapplication.getInstance().getBatchOfStoredCaches(true, coords, cacheType, list); + return params; } /** @@ -1360,16 +813,16 @@ public class cgBase { final String uri = "http://www.geocaching.com/seek/nearest.aspx"; final String fullUri = uri + "?" + addFToParams(params, false, true); - String page = Network.requestLogged(uri, params, false, my, true); + final String page = Login.getRequestLogged(uri, addFToParams(params, my, true)); if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.searchByAny: No data from server"); + Log.e("cgeoBase.searchByAny: No data from server"); return null; } final SearchResult searchResult = parseSearch(thread, fullUri, page, showCaptcha); if (searchResult == null || CollectionUtils.isEmpty(searchResult.getGeocodes())) { - Log.e(Settings.tag, "cgeoBase.searchByAny: No cache parsed"); + Log.e("cgeoBase.searchByAny: No cache parsed"); return searchResult; } @@ -1387,7 +840,7 @@ public class cgBase { public static SearchResult searchByKeyword(final cgSearchThread thread, final String keyword, final CacheType cacheType, final boolean showCaptcha) { if (StringUtils.isBlank(keyword)) { - Log.e(Settings.tag, "cgeoBase.searchByKeyword: No keyword given"); + Log.e("cgeoBase.searchByKeyword: No keyword given"); return null; } @@ -1397,7 +850,7 @@ public class cgBase { public static SearchResult searchByUsername(final cgSearchThread thread, final String userName, final CacheType cacheType, final boolean showCaptcha) { if (StringUtils.isBlank(userName)) { - Log.e(Settings.tag, "cgeoBase.searchByUsername: No user name given"); + Log.e("cgeoBase.searchByUsername: No user name given"); return null; } @@ -1406,7 +859,7 @@ public class cgBase { boolean my = false; if (userName.equalsIgnoreCase(Settings.getLogin().left)) { my = true; - Log.i(Settings.tag, "cgBase.searchByUsername: Overriding users choice, downloading all caches."); + Log.i("cgBase.searchByUsername: Overriding users choice, downloading all caches."); } return searchByAny(thread, cacheType, my, showCaptcha, params); @@ -1414,7 +867,7 @@ public class cgBase { public static SearchResult searchByOwner(final cgSearchThread thread, final String userName, final CacheType cacheType, final boolean showCaptcha) { if (StringUtils.isBlank(userName)) { - Log.e(Settings.tag, "cgeoBase.searchByOwner: No user name given"); + Log.e("cgeoBase.searchByOwner: No user name given"); return null; } @@ -1424,7 +877,7 @@ public class cgBase { 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"); + Log.w("cgeoBase.searchTrackable: No geocode nor guid nor id given"); return null; } @@ -1440,16 +893,16 @@ public class cgBase { params.put("id", id); } - String page = Network.requestLogged("http://www.geocaching.com/track/details.aspx", params, false, false, false); + final String page = Login.getRequestLogged("http://www.geocaching.com/track/details.aspx", params); if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.searchTrackable: No data from server"); + Log.e("cgeoBase.searchTrackable: No data from server"); return trackable; } trackable = parseTrackable(page, cgeoapplication.getInstance(), geocode); if (trackable == null) { - Log.e(Settings.tag, "cgeoBase.searchTrackable: No trackable parsed"); + Log.e("cgeoBase.searchTrackable: No trackable parsed"); return null; } @@ -1458,14 +911,14 @@ public class cgBase { public static StatusCode postLog(final String geocode, final String cacheid, final String[] viewstates, final LogType logType, final int year, final int month, final int day, - final String log, final List<cgTrackableLog> trackables) { - if (isEmpty(viewstates)) { - Log.e(Settings.tag, "cgeoBase.postLog: No viewstate given"); + final String log, final List<TrackableLog> trackables) { + if (Login.isEmpty(viewstates)) { + Log.e("cgeoBase.postLog: No viewstate given"); return StatusCode.LOG_POST_ERROR; } if (StringUtils.isBlank(log)) { - Log.e(Settings.tag, "cgeoBase.postLog: No log text given"); + Log.e("cgeoBase.postLog: No log text given"); return StatusCode.NO_LOG_TEXT; } @@ -1488,9 +941,9 @@ public class cgBase { final String logInfo = logUpdated.toString().replace("\n", "\r\n").trim(); // windows' eol and remove leading and trailing whitespaces if (trackables != null) { - Log.i(Settings.tag, "Trying to post log for cache #" + cacheid + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + logInfo + "; trackables: " + trackables.size()); + Log.i("Trying to post log for cache #" + cacheid + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + logInfo + "; trackables: " + trackables.size()); } else { - Log.i(Settings.tag, "Trying to post log for cache #" + cacheid + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + logInfo + "; trackables: 0"); + Log.i("Trying to post log for cache #" + cacheid + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + logInfo + "; trackables: 0"); } final Parameters params = new Parameters( @@ -1509,7 +962,7 @@ public class cgBase { if (trackables != null && !trackables.isEmpty()) { // we have some trackables to proceed final StringBuilder hdnSelected = new StringBuilder(); - for (final cgTrackableLog tb : trackables) { + for (final TrackableLog tb : trackables) { if (tb.action != LogTypeTrackable.DO_NOTHING) { hdnSelected.append(Integer.toString(tb.id)); hdnSelected.append(tb.action.action); @@ -1528,13 +981,13 @@ public class cgBase { if (loginState == StatusCode.NO_ERROR) { page = Network.getResponseData(Network.postRequest(uri, params)); } else { - Log.e(Settings.tag, "cgeoBase.postLog: Can not log in geocaching (error: " + loginState + ")"); + Log.e("cgeoBase.postLog: Can not log in geocaching (error: " + loginState + ")"); return loginState; } } if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.postLog: No data from server"); + Log.e("cgeoBase.postLog: No data from server"); return StatusCode.NO_DATA_FROM_SERVER; } @@ -1546,8 +999,8 @@ public class cgBase { if (matcher.find() && matcher.groupCount() > 0) { final String[] viewstatesConfirm = Login.getViewstates(page); - if (isEmpty(viewstatesConfirm)) { - Log.e(Settings.tag, "cgeoBase.postLog: No viewstate for confirm log"); + if (Login.isEmpty(viewstatesConfirm)) { + Log.e("cgeoBase.postLog: No viewstate for confirm log"); return StatusCode.LOG_POST_ERROR; } @@ -1562,7 +1015,7 @@ public class cgBase { if (trackables != null && !trackables.isEmpty()) { // we have some trackables to proceed final StringBuilder hdnSelected = new StringBuilder(); - for (cgTrackableLog tb : trackables) { + for (TrackableLog tb : trackables) { String ctl = null; final String action = Integer.toString(tb.id) + tb.action.action; @@ -1586,14 +1039,14 @@ public class cgBase { page = Network.getResponseData(Network.postRequest(uri, params)); } } catch (Exception e) { - Log.e(Settings.tag, "cgeoBase.postLog.confim: " + e.toString()); + Log.e("cgeoBase.postLog.confim: " + e.toString()); } try { final Matcher matcherOk = GCConstants.PATTERN_OK1.matcher(page); if (matcherOk.find()) { - Log.i(Settings.tag, "Log successfully posted to cache #" + cacheid); + Log.i("Log successfully posted to cache #" + cacheid); if (geocode != null) { cgeoapplication.getInstance().saveVisitDate(geocode); @@ -1607,26 +1060,26 @@ public class cgBase { return StatusCode.NO_ERROR; } } catch (Exception e) { - Log.e(Settings.tag, "cgeoBase.postLog.check: " + e.toString()); + Log.e("cgeoBase.postLog.check: " + e.toString()); } - Log.e(Settings.tag, "cgeoBase.postLog: Failed to post log because of unknown error"); + Log.e("cgeoBase.postLog: Failed to post log because of unknown error"); return StatusCode.LOG_POST_ERROR; } public static StatusCode postLogTrackable(final String tbid, final String trackingCode, final String[] viewstates, final LogType logType, final int year, final int month, final int day, final String log) { - if (isEmpty(viewstates)) { - Log.e(Settings.tag, "cgeoBase.postLogTrackable: No viewstate given"); + if (Login.isEmpty(viewstates)) { + Log.e("cgeoBase.postLogTrackable: No viewstate given"); return StatusCode.LOG_POST_ERROR; } if (StringUtils.isBlank(log)) { - Log.e(Settings.tag, "cgeoBase.postLogTrackable: No log text given"); + Log.e("cgeoBase.postLogTrackable: No log text given"); return StatusCode.NO_LOG_TEXT; } - Log.i(Settings.tag, "Trying to post log for trackable #" + trackingCode + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + log); + Log.i("Trying to post log for trackable #" + trackingCode + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + log); final String logInfo = log.replace("\n", "\r\n"); // windows' eol @@ -1658,13 +1111,13 @@ public class cgBase { if (loginState == StatusCode.NO_ERROR) { page = Network.getResponseData(Network.postRequest(uri, params)); } else { - Log.e(Settings.tag, "cgeoBase.postLogTrackable: Can not log in geocaching (error: " + loginState + ")"); + Log.e("cgeoBase.postLogTrackable: Can not log in geocaching (error: " + loginState + ")"); return loginState; } } if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.postLogTrackable: No data from server"); + Log.e("cgeoBase.postLogTrackable: No data from server"); return StatusCode.NO_DATA_FROM_SERVER; } @@ -1672,14 +1125,14 @@ public class cgBase { final Matcher matcherOk = GCConstants.PATTERN_OK2.matcher(page); if (matcherOk.find()) { - Log.i(Settings.tag, "Log successfully posted to trackable #" + trackingCode); + Log.i("Log successfully posted to trackable #" + trackingCode); return StatusCode.NO_ERROR; } } catch (Exception e) { - Log.e(Settings.tag, "cgeoBase.postLogTrackable.check: " + e.toString()); + Log.e("cgeoBase.postLogTrackable.check: " + e.toString()); } - Log.e(Settings.tag, "cgeoBase.postLogTrackable: Failed to post log because of unknown error"); + Log.e("cgeoBase.postLogTrackable: Failed to post log because of unknown error"); return StatusCode.LOG_POST_ERROR; } @@ -1692,19 +1145,19 @@ 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 = Network.postRequestLogged(uri); + String page = Login.postRequestLogged(uri); if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgBase.addToWatchlist: No data from server"); + Log.e("cgBase.addToWatchlist: No data from server"); return -1; // error } boolean guidOnPage = cache.isGuidContainedInPage(page); if (guidOnPage) { - Log.i(Settings.tag, "cgBase.addToWatchlist: cache is on watchlist"); + Log.i("cgBase.addToWatchlist: cache is on watchlist"); cache.setOnWatchlist(true); } else { - Log.e(Settings.tag, "cgBase.addToWatchlist: cache is not on watchlist"); + Log.e("cgBase.addToWatchlist: cache is not on watchlist"); } return guidOnPage ? 1 : -1; // on watchlist (=added) / else: error } @@ -1718,10 +1171,10 @@ 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 = Network.postRequestLogged(uri); + String page = Login.postRequestLogged(uri); if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgBase.removeFromWatchlist: No data from server"); + Log.e("cgBase.removeFromWatchlist: No data from server"); return -1; // error } @@ -1735,278 +1188,431 @@ public class cgBase { page = Network.getResponseData(Network.postRequest(uri, params)); boolean guidOnPage = cache.isGuidContainedInPage(page); if (!guidOnPage) { - Log.i(Settings.tag, "cgBase.removeFromWatchlist: cache removed from watchlist"); + Log.i("cgBase.removeFromWatchlist: cache removed from watchlist"); cache.setOnWatchlist(false); } else { - Log.e(Settings.tag, "cgBase.removeFromWatchlist: cache not removed from watchlist"); + Log.e("cgBase.removeFromWatchlist: cache not removed from watchlist"); } return guidOnPage ? -1 : 0; // on watchlist (=error) / not on watchlist } /** - * Possibly hide caches found or hidden by user. This mutates its params argument when possible. + * Parse a trackable HTML description into a cgTrackable object * - * @param params - * the parameters to mutate, or null to create a new Parameters if needed - * @param my - * @param addF - * @return the original params if not null, maybe augmented with f=1, or a new Parameters with f=1 or null otherwise + * @param page + * the HTML page to parse, already processed through {@link BaseUtils#replaceWhitespace} + * @param app + * if not null, the application to use to save the trackable + * @return the parsed trackable, or null if none could be parsed */ - public static Parameters addFToParams(final Parameters params, final boolean my, final boolean addF) { - if (!my && Settings.isExcludeMyCaches() && addF) { - if (params == null) { - return new Parameters("f", "1"); - } - params.put("f", "1"); - Log.i(Settings.tag, "Skipping caches found or hidden by user."); + public static cgTrackable parseTrackable(final String page, final cgeoapplication app, final String possibleTrackingcode) { + if (StringUtils.isBlank(page)) { + Log.e("cgeoBase.parseTrackable: No page given"); + return null; } - return params; - } + final cgTrackable trackable = new cgTrackable(); + + // trackable geocode + trackable.setGeocode(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GEOCODE, true, trackable.getGeocode()).toUpperCase()); + + // trackable id + trackable.setGuid(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GUID, true, trackable.getGuid())); + + // trackable icon + trackable.setIconUrl(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_ICON, true, trackable.getIconUrl())); + + // trackable name + trackable.setName(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_NAME, true, trackable.getName())); + + // trackable type + if (StringUtils.isNotBlank(trackable.getName())) { + trackable.setType(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_TYPE, true, trackable.getType())); + } - public static void storeCache(Activity activity, cgCache origCache, String geocode, int listId, boolean forceRedownload, CancellableHandler handler) { + // trackable owner name try { - cgCache cache; - // get cache details, they may not yet be complete - if (origCache != null) { - // only reload the cache if it was already stored or doesn't have full details (by checking the description) - if (origCache.getListId() >= StoredList.STANDARD_LIST_ID || StringUtils.isBlank(origCache.getDescription())) { - final SearchResult search = searchByGeocode(origCache.getGeocode(), null, listId, false, handler); - cache = search.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB); - } else { - cache = origCache; - } - } else if (StringUtils.isNotBlank(geocode)) { - final SearchResult search = searchByGeocode(geocode, null, listId, forceRedownload, handler); - cache = search.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB); - } else { - cache = null; + final Matcher matcherOwner = GCConstants.PATTERN_TRACKABLE_OWNER.matcher(page); + if (matcherOwner.find() && matcherOwner.groupCount() > 0) { + trackable.setOwnerGuid(matcherOwner.group(1)); + trackable.setOwner(matcherOwner.group(2).trim()); } + } catch (Exception e) { + // failed to parse trackable owner name + Log.w("cgeoBase.parseTrackable: Failed to parse trackable owner name"); + } - if (cache == null) { - if (handler != null) { - handler.sendMessage(Message.obtain()); - } + // trackable origin + trackable.setOrigin(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_ORIGIN, true, trackable.getOrigin())); - return; + // trackable spotted + try { + final Matcher matcherSpottedCache = GCConstants.PATTERN_TRACKABLE_SPOTTEDCACHE.matcher(page); + if (matcherSpottedCache.find() && matcherSpottedCache.groupCount() > 0) { + trackable.setSpottedGuid(matcherSpottedCache.group(1)); + trackable.setSpottedName(matcherSpottedCache.group(2).trim()); + trackable.setSpottedType(cgTrackable.SPOTTED_CACHE); } - if (CancellableHandler.isCancelled(handler)) { - return; + final Matcher matcherSpottedUser = GCConstants.PATTERN_TRACKABLE_SPOTTEDUSER.matcher(page); + if (matcherSpottedUser.find() && matcherSpottedUser.groupCount() > 0) { + trackable.setSpottedGuid(matcherSpottedUser.group(1)); + trackable.setSpottedName(matcherSpottedUser.group(2).trim()); + trackable.setSpottedType(cgTrackable.SPOTTED_USER); } - final HtmlImage imgGetter = new HtmlImage(activity, cache.getGeocode(), false, listId, true); - - // store images from description - if (StringUtils.isNotBlank(cache.getDescription())) { - Html.fromHtml(cache.getDescription(), imgGetter, null); + if (BaseUtils.matches(page, GCConstants.PATTERN_TRACKABLE_SPOTTEDUNKNOWN)) { + trackable.setSpottedType(cgTrackable.SPOTTED_UNKNOWN); } - if (CancellableHandler.isCancelled(handler)) { - return; + if (BaseUtils.matches(page, GCConstants.PATTERN_TRACKABLE_SPOTTEDOWNER)) { + trackable.setSpottedType(cgTrackable.SPOTTED_OWNER); } + } catch (Exception e) { + // failed to parse trackable last known place + Log.w("cgeoBase.parseTrackable: Failed to parse trackable last known place"); + } - // store spoilers - if (CollectionUtils.isNotEmpty(cache.getSpoilers())) { - for (cgImage oneSpoiler : cache.getSpoilers()) { - imgGetter.getDrawable(oneSpoiler.getUrl()); + // released date - can be missing on the page + try { + String releaseString = BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_RELEASES, false, null); + if (releaseString != null) { + trackable.setReleased(dateTbIn1.parse(releaseString)); + if (trackable.getReleased() == null) { + trackable.setReleased(dateTbIn2.parse(releaseString)); } } + } catch (ParseException e1) { + trackable.setReleased(null); + } - if (CancellableHandler.isCancelled(handler)) { - return; + // trackable distance + try { + final String distance = BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_DISTANCE, false, null); + if (null != distance) { + trackable.setDistance(DistanceParser.parseDistance(distance, Settings.isUseMetricUnits())); } + } catch (NumberFormatException e) { + throw e; + } - // store images from logs - if (Settings.isStoreLogImages()) { - for (cgLog log : cache.getLogs(true)) { - if (CollectionUtils.isNotEmpty(log.logImages)) { - for (cgImage oneLogImg : log.logImages) { - imgGetter.getDrawable(oneLogImg.getUrl()); - } - } + // trackable goal + trackable.setGoal(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GOAL, true, trackable.getGoal())); + + // trackable details & image + try { + final Matcher matcherDetailsImage = GCConstants.PATTERN_TRACKABLE_DETAILSIMAGE.matcher(page); + if (matcherDetailsImage.find() && matcherDetailsImage.groupCount() > 0) { + final String image = StringUtils.trim(matcherDetailsImage.group(3)); + final String details = StringUtils.trim(matcherDetailsImage.group(4)); + + if (StringUtils.isNotEmpty(image)) { + trackable.setImage(image); + } + if (StringUtils.isNotEmpty(details) && !StringUtils.equals(details, "No additional details available.")) { + trackable.setDetails(details); } } + } catch (Exception e) { + // failed to parse trackable details & image + Log.w("cgeoBase.parseTrackable: Failed to parse trackable details & image"); + } - if (CancellableHandler.isCancelled(handler)) { - return; - } + // trackable logs + try + { + final Matcher matcherLogs = GCConstants.PATTERN_TRACKABLE_LOG.matcher(page); + /* + * 1. Type (img) + * 2. Date + * 3. Author + * 4. Cache-GUID + * 5. <ignored> (strike-through property for ancien caches) + * 6. Cache-name + * 7. Logtext + */ + while (matcherLogs.find()) + { + final LogEntry logDone = new LogEntry(); - // store map previews - StaticMapsProvider.downloadMaps(cache, activity); + logDone.type = LogType.getByIconName(matcherLogs.group(1)); + logDone.author = Html.fromHtml(matcherLogs.group(3)).toString().trim(); - if (CancellableHandler.isCancelled(handler)) { - return; - } + try + { + logDone.date = Login.parseGcCustomDate(matcherLogs.group(2)).getTime(); + } catch (ParseException e) { + } - cache.setListId(listId); - cgeoapplication.getInstance().saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); + logDone.log = matcherLogs.group(7).trim(); - if (handler != null) { - handler.sendMessage(Message.obtain()); + if (matcherLogs.group(4) != null && matcherLogs.group(6) != null) + { + logDone.cacheGuid = matcherLogs.group(4); + logDone.cacheName = matcherLogs.group(6); + } + + // Apply the pattern for images in a trackable log entry against each full log (group(0)) + final Matcher matcherLogImages = GCConstants.PATTERN_TRACKABLE_LOG_IMAGES.matcher(matcherLogs.group(0)); + /* + * 1. Image URL + * 2. Image title + */ + while (matcherLogImages.find()) + { + final cgImage logImage = new cgImage(matcherLogImages.group(1), matcherLogImages.group(2)); + logDone.addLogImage(logImage); + } + + trackable.getLogs().add(logDone); } } catch (Exception e) { - Log.e(Settings.tag, "cgBase.storeCache"); + // failed to parse logs + Log.w("cgeoBase.parseCache: Failed to parse cache logs" + e.toString()); } - } - public static void refreshCache(Activity activity, String geocode, int listId, CancellableHandler handler) { - cgeoapplication.getInstance().removeCache(geocode, EnumSet.of(RemoveFlag.REMOVE_CACHE)); - storeCache(activity, null, geocode, listId, true, handler); + // trackingcode + if (!StringUtils.equalsIgnoreCase(trackable.getGeocode(), possibleTrackingcode)) { + trackable.setTrackingcode(possibleTrackingcode); + } + + if (app != null) { + app.saveTrackable(trackable); + } + + return trackable; } - public static void dropCache(final cgCache cache, final Handler handler) { + /** + * Load logs from a cache details page. + * + * @param page + * the text of the details page + * @param cache + * the cache object to put the logs in + * @param friends + * retrieve friend logs + */ + private static List<LogEntry> loadLogsFromDetails(final String page, final cgCache cache, final boolean friends, final boolean getDataFromPage) { + String rawResponse = null; + + if (!getDataFromPage) { + final Matcher userTokenMatcher = GCConstants.PATTERN_USERTOKEN2.matcher(page); + if (!userTokenMatcher.find()) { + Log.e("cgBase.loadLogsFromDetails: unable to extract userToken"); + return null; + } + + final String userToken = userTokenMatcher.group(1); + final Parameters params = new Parameters( + "tkn", userToken, + "idx", "1", + "num", String.valueOf(GCConstants.NUMBER_OF_LOGS), + "decrypt", "true", + // "sp", Boolean.toString(personal), // personal logs + "sf", Boolean.toString(friends)); + + final HttpResponse response = Network.getRequest("http://www.geocaching.com/seek/geocache.logbook", params); + if (response == null) { + Log.e("cgBase.loadLogsFromDetails: cannot log logs, response is null"); + return null; + } + final int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode != 200) { + Log.e("cgBase.loadLogsFromDetails: error " + statusCode + " when requesting log information"); + return null; + } + rawResponse = Network.getResponseData(response); + if (rawResponse == null) { + Log.e("cgBase.loadLogsFromDetails: unable to read whole response"); + return null; + } + } else { + // extract embedded JSON data from page + rawResponse = BaseUtils.getMatch(page, GCConstants.PATTERN_LOGBOOK, ""); + } + + List<LogEntry> logs = new ArrayList<LogEntry>(); + try { - cgeoapplication.getInstance().markDropped(cache.getGeocode()); - cgeoapplication.getInstance().removeCache(cache.getGeocode(), EnumSet.of(RemoveFlag.REMOVE_CACHE)); + final JSONObject resp = new JSONObject(rawResponse); + if (!resp.getString("status").equals("success")) { + Log.e("cgBase.loadLogsFromDetails: status is " + resp.getString("status")); + return null; + } - handler.sendMessage(Message.obtain()); - } catch (Exception e) { - Log.e(Settings.tag, "cgBase.dropCache: " + e.toString()); + final JSONArray data = resp.getJSONArray("data"); + + for (int index = 0; index < data.length(); index++) { + final JSONObject entry = data.getJSONObject(index); + final LogEntry logDone = new LogEntry(); + logDone.friend = friends; + + // FIXME: use the "LogType" field instead of the "LogTypeImage" one. + final String logIconNameExt = entry.optString("LogTypeImage", ".gif"); + final String logIconName = logIconNameExt.substring(0, logIconNameExt.length() - 4); + logDone.type = LogType.getByIconName(logIconName); + + try { + logDone.date = Login.parseGcCustomDate(entry.getString("Visited")).getTime(); + } catch (ParseException e) { + Log.e("cgBase.loadLogsFromDetails: failed to parse log date."); + } + + logDone.author = entry.getString("UserName"); + logDone.found = entry.getInt("GeocacheFindCount"); + logDone.log = entry.getString("LogText"); + + final JSONArray images = entry.getJSONArray("Images"); + for (int i = 0; i < images.length(); i++) { + final JSONObject image = images.getJSONObject(i); + String url = "http://img.geocaching.com/cache/log/" + image.getString("FileName"); + String title = image.getString("Name"); + final cgImage logImage = new cgImage(url, title); + logDone.addLogImage(logImage); + } + + logs.add(logDone); + } + } catch (JSONException e) { + // failed to parse logs + Log.w("cgBase.loadLogsFromDetails: Failed to parse cache logs", e); } - } - public static boolean runNavigation(Activity activity, Resources res, Settings settings, final Geopoint coords) { - return runNavigation(activity, res, settings, coords, null); + return logs; } - public static boolean runNavigation(Activity activity, Resources res, Settings settings, final Geopoint coords, final Geopoint coordsNow) { - if (activity == null) { - return false; - } - if (settings == null) { - return false; + public static List<LogType> parseTypes(String page) { + if (StringUtils.isEmpty(page)) { + return null; } - // Google Navigation - if (Settings.isUseGoogleNavigation()) { - try { - activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("google.navigation:ll=" + coords.getLatitude() + "," + coords.getLongitude()))); + final List<LogType> types = new ArrayList<LogType>(); - return true; - } catch (Exception e) { - // nothing + final Matcher typeBoxMatcher = GCConstants.PATTERN_TYPEBOX.matcher(page); + String typesText = null; + if (typeBoxMatcher.find()) { + if (typeBoxMatcher.groupCount() > 0) { + typesText = typeBoxMatcher.group(1); } } - // Google Maps Directions - try { - if (coordsNow != null) { - activity.startActivity(new Intent(Intent.ACTION_VIEW, - Uri.parse("http://maps.google.com/maps?f=d&saddr=" + coordsNow.getLatitude() + "," + coordsNow.getLongitude() + - "&daddr=" + coords.getLatitude() + "," + coords.getLongitude()))); - } else { - activity.startActivity(new Intent(Intent.ACTION_VIEW, - Uri.parse("http://maps.google.com/maps?f=d&daddr=" + coords.getLatitude() + "," + coords.getLongitude()))); + if (typesText != null) { + + final Matcher typeMatcher = GCConstants.PATTERN_TYPE2.matcher(typesText); + while (typeMatcher.find()) { + if (typeMatcher.groupCount() > 1) { + final int type = Integer.parseInt(typeMatcher.group(2)); + + if (type > 0) { + types.add(LogType.getById(type)); + } + } } + } - return true; - } catch (Exception e) { - // nothing + return types; + } + + public static List<TrackableLog> parseTrackableLog(final String page) { + if (StringUtils.isEmpty(page)) { + return null; } - Log.i(Settings.tag, "cgBase.runNavigation: No navigation application available."); + String table = StringUtils.substringBetween(page, "<table id=\"tblTravelBugs\"", "</table>"); - if (res != null) { - ActivityMixin.showToast(activity, res.getString(R.string.err_navigation_no)); + // if no trackables are currently in the account, the table is not available, so return an empty list instead of null + if (StringUtils.isBlank(table)) { + return Collections.emptyList(); } - return false; - } + table = StringUtils.substringBetween(table, "<tbody>", "</tbody>"); + if (StringUtils.isBlank(table)) { + Log.e("cgeoBase.parseTrackableLog: tbody not found on page"); + return null; + } - /** - * Generate a time string according to system-wide settings (locale, 12/24 hour) - * such as "13:24". - * - * @param date - * milliseconds since the epoch - * @return the formatted string - */ - public static String formatTime(long date) { - return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_TIME); - } + final List<TrackableLog> trackableLogs = new ArrayList<TrackableLog>(); - /** - * Generate a date string according to system-wide settings (locale, date format) - * such as "20 December" or "20 December 2010". The year will only be included when necessary. - * - * @param date - * milliseconds since the epoch - * @return the formatted string - */ - public static String formatDate(long date) { - return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE); - } + final Matcher trackableMatcher = GCConstants.PATTERN_TRACKABLE.matcher(page); + while (trackableMatcher.find()) { + if (trackableMatcher.groupCount() > 0) { - /** - * Generate a date string according to system-wide settings (locale, date format) - * such as "20 December 2010". The year will always be included, making it suitable - * to generate long-lived log entries. - * - * @param date - * milliseconds since the epoch - * @return the formatted string - */ - public static String formatFullDate(long date) { - return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE - | DateUtils.FORMAT_SHOW_YEAR); - } + final String trackCode = trackableMatcher.group(1); + final String name = Html.fromHtml(trackableMatcher.group(2)).toString(); + try { + final Integer ctl = Integer.valueOf(trackableMatcher.group(3)); + final Integer id = Integer.valueOf(trackableMatcher.group(5)); + if (trackCode != null && name != null && ctl != null && id != null) { + final TrackableLog entry = new TrackableLog(trackCode, name, id.intValue(), ctl.intValue()); - /** - * Generate a numeric date string according to system-wide settings (locale, date format) - * such as "10/20/2010". - * - * @param date - * milliseconds since the epoch - * @return the formatted string - */ - public static String formatShortDate(long date) { - return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE - | DateUtils.FORMAT_NUMERIC_DATE); + Log.i("Trackable in inventory (#" + entry.ctl + "/" + entry.id + "): " + entry.trackCode + " - " + entry.name); + trackableLogs.add(entry); + } + } catch (NumberFormatException e) { + Log.e("GCParser.parseTrackableLog", e); + } + } + } + + return trackableLogs; } /** - * Generate a numeric date and time string according to system-wide settings (locale, - * date format) such as "7 sept. at 12:35". + * Insert the right cache type restriction in parameters * - * @param context - * a Context - * @param date - * milliseconds since the epoch - * @return the formatted string + * @param params + * the parameters to insert the restriction into + * @param cacheType + * the type of cache, or null to include everything */ - public static String formatShortDateTime(Context context, long date) { - return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL); + static private void insertCacheType(final Parameters params, final CacheType cacheType) { + params.put("tx", cacheType.guid); } - /** - * 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. - * - * @param context - * The application's environment. - * @param action - * The Intent action to check for availability. - * @param uri - * The Intent URI 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, Uri uri) { - final PackageManager packageManager = context.getPackageManager(); - final Intent intent; - if (uri == null) { - intent = new Intent(action); - } else { - intent = new Intent(action, uri); + private static void getExtraOnlineInfo(final cgCache cache, final String page, final CancellableHandler handler) { + if (CancellableHandler.isCancelled(handler)) { + return; + } + + //cache.setLogs(loadLogsFromDetails(page, cache, false)); + if (Settings.isFriendLogsWanted()) { + CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_logs); + List<LogEntry> allLogs = cache.getLogs(); + List<LogEntry> friendLogs = loadLogsFromDetails(page, cache, true, false); + if (friendLogs != null) { + for (LogEntry log : friendLogs) { + if (allLogs.contains(log)) { + allLogs.get(allLogs.indexOf(log)).friend = true; + } else { + allLogs.add(log); + } + } + } + } + + if (Settings.isElevationWanted()) { + if (CancellableHandler.isCancelled(handler)) { + return; + } + CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_elevation); + if (cache.getCoords() != null) { + cache.setElevation(cache.getCoords().getElevation()); + } + } + + if (Settings.isRatingWanted()) { + if (CancellableHandler.isCancelled(handler)) { + return; + } + CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_gcvote); + final GCVoteRating rating = GCVote.getRating(cache.getGuid(), cache.getGeocode()); + if (rating != null) { + cache.setRating(rating.getRating()); + cache.setVotes(rating.getVotes()); + cache.setMyVote(rating.getMyVote()); + } } - List<ResolveInfo> list = packageManager.queryIntentActivities(intent, - PackageManager.MATCH_DEFAULT_ONLY); - return list.size() > 0; } } - diff --git a/main/src/cgeo/geocaching/network/Login.java b/main/src/cgeo/geocaching/connector/gc/Login.java index d5f511d..1e614df 100644 --- a/main/src/cgeo/geocaching/network/Login.java +++ b/main/src/cgeo/geocaching/connector/gc/Login.java @@ -1,10 +1,13 @@ -package cgeo.geocaching.network; +package cgeo.geocaching.connector.gc; import cgeo.geocaching.R; import cgeo.geocaching.Settings; -import cgeo.geocaching.cgBase; -import cgeo.geocaching.connector.gc.GCConstants; +import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.StatusCode; +import cgeo.geocaching.network.Cookies; +import cgeo.geocaching.network.HtmlImage; +import cgeo.geocaching.network.Network; +import cgeo.geocaching.network.Parameters; import cgeo.geocaching.utils.BaseUtils; import cgeo.geocaching.utils.Log; @@ -32,7 +35,6 @@ public abstract class Login { // 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 = ""; @@ -61,33 +63,30 @@ public abstract class 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"); + Login.setActualStatus(cgeoapplication.getInstance().getString(R.string.err_login)); + Log.e("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); + Login.setActualStatus(cgeoapplication.getInstance().getString(R.string.init_login_popup_working)); + HttpResponse loginResponse = Network.getRequest("https://www.geocaching.com/login/default.aspx"); 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)"); + Log.e("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); + Log.i("Already logged in Geocaching.com as " + login.left); Login.switchToEnglish(loginData); return StatusCode.NO_ERROR; // logged in } - Network.clearCookies(); + Cookies.clearCookies(); Settings.setCookieStore(null); final Parameters params = new Parameters( @@ -98,8 +97,8 @@ public abstract class Login { "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"); + if (isEmpty(viewstates)) { + Log.e("cgeoBase.login: Failed to find viewstates"); return StatusCode.LOGIN_PARSE_ERROR; // no viewstates } Login.putViewstates(params, viewstates); @@ -109,36 +108,36 @@ public abstract class Login { if (StringUtils.isNotBlank(loginData)) { if (Login.getLoginStatus(loginData)) { - Log.i(Settings.tag, "Successfully logged in Geocaching.com as " + login.left); + Log.i("Successfully logged in Geocaching.com as " + login.left); Login.switchToEnglish(loginData); - Settings.setCookieStore(Network.dumpCookieStore()); + Settings.setCookieStore(Cookies.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"); + Log.i("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"); + Log.i("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)"); + Log.e("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); + HttpResponse logoutResponse = Network.getRequest("https://www.geocaching.com/login/default.aspx?RESET=Y&redir=http%3a%2f%2fwww.geocaching.com%2fdefault.aspx%3f"); String logoutData = Network.getResponseData(logoutResponse); if (logoutResponse != null && logoutResponse.getStatusLine().getStatusCode() == 503 && BaseUtils.matches(logoutData, GCConstants.PATTERN_MAINTENANCE)) { return StatusCode.MAINTENANCE; } - Network.clearCookies(); + Cookies.clearCookies(); Settings.setCookieStore(null); return StatusCode.NO_ERROR; } @@ -171,14 +170,6 @@ public abstract class Login { actualUserName = userName; } - public static String getActualMemberStatus() { - return actualMemberStatus; - } - - public static void setActualMemberStatus(final String memberStatus) { - actualMemberStatus = memberStatus; - } - public static int getActualCachesFound() { return actualCachesFound; } @@ -191,20 +182,16 @@ public abstract class Login { */ public static boolean getLoginStatus(final String page) { if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.checkLogin: No page given"); + Log.e("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)); - } + setActualStatus(cgeoapplication.getInstance().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; } @@ -213,28 +200,24 @@ public abstract class Login { 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)); - } + setActualStatus(cgeoapplication.getInstance().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"); + Log.i("Geocaching.com language already set to English"); // get find count - getLoginStatus(Network.getResponseData(Network.request("http://www.geocaching.com/email/", null, false))); + getLoginStatus(Network.getResponseData(Network.getRequest("http://www.geocaching.com/email/"))); } else { - final String page = Network.getResponseData(Network.request("http://www.geocaching.com/default.aspx", null, false)); + final String page = Network.getResponseData(Network.getRequest("http://www.geocaching.com/default.aspx")); getLoginStatus(page); if (page == null) { - Log.e(Settings.tag, "Failed to read viewstates to set geocaching.com language"); + Log.e("Failed to read viewstates to set geocaching.com language"); } final Parameters params = new Parameters( "__EVENTTARGET", "ctl00$uxLocaleList$uxLocaleList$ctl00$uxLocaleItem", // switch to english @@ -242,14 +225,14 @@ public abstract class Login { 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"); + Log.e("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))); + final String profile = BaseUtils.replaceWhitespace(Network.getResponseData(Network.getRequest("http://www.geocaching.com/my/"))); Settings.setMemberStatus(BaseUtils.getMatch(profile, GCConstants.PATTERN_MEMBER_STATUS, true, null)); @@ -261,9 +244,9 @@ public abstract class Login { return imgGetter.getDrawable(avatarURL); } // No match? There may be no avatar set by user. - Log.d(Settings.tag, "No avatar set for user"); + Log.d("No avatar set for user"); } catch (Exception e) { - Log.w(Settings.tag, "Error when retrieving user avatar", e); + Log.w("Error when retrieving user avatar", e); } return null; } @@ -273,10 +256,10 @@ public abstract class Login { */ public static void detectGcCustomDate() { - final String result = Network.getResponseData(Network.request("http://www.geocaching.com/account/ManagePreferences.aspx", null, false, false, false)); + final String result = Network.getResponseData(Network.getRequest("http://www.geocaching.com/account/ManagePreferences.aspx")); if (null == result) { - Log.w(Settings.tag, "cgeoBase.detectGcCustomDate: result is null"); + Log.w("cgeoBase.detectGcCustomDate: result is null"); return; } @@ -315,6 +298,24 @@ public abstract class Login { } /** + * checks if an Array of Strings is empty or not. Empty means: + * - Array is null + * - or all elements are null or empty strings + */ + public static boolean isEmpty(String[] a) { + if (a == null) { + return true; + } + + for (String s : a) { + if (StringUtils.isNotEmpty(s)) { + return false; + } + } + return true; + } + + /** * read all viewstates from page * * @return String[] with all view states @@ -333,7 +334,7 @@ public abstract class Login { try { count = Integer.parseInt(matcherViewstateCount.group(1)); } catch (NumberFormatException e) { - Log.e(Settings.tag, "getViewStates", e); + Log.e("getViewStates", e); } } @@ -351,7 +352,7 @@ public abstract class Login { try { no = Integer.parseInt(sno); } catch (NumberFormatException e) { - Log.e(Settings.tag, "getViewStates", e); + Log.e("getViewStates", e); no = 0; } } @@ -389,10 +390,45 @@ public abstract class Login { 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); + /** + * 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 = Network.postRequest(uri, null); + String data = Network.getResponseData(response); + + if (!getLoginStatus(data)) { + if (login() == StatusCode.NO_ERROR) { + response = Network.postRequest(uri, null); + data = Network.getResponseData(response); + } else { + Log.i("Working as guest."); + } + } + return data; + } - return getViewstates(Network.getResponseData(response)); + /** + * GET HTTP request. Do the request a second time if the user is not logged in + * + * @param uri + * @param params + * @return + */ + public static String getRequestLogged(final String uri, final Parameters params) { + final String data = Network.getResponseData(Network.getRequest(uri, params)); + + if (!getLoginStatus(data)) { + if (login() == StatusCode.NO_ERROR) { + return Network.getResponseData(Network.getRequest(uri, params)); + } else { + Log.i("Working as guest."); + } + } + return data; } } diff --git a/main/src/cgeo/geocaching/connector/gc/Tile.java b/main/src/cgeo/geocaching/connector/gc/Tile.java index 2a146cc..289c9db 100644 --- a/main/src/cgeo/geocaching/connector/gc/Tile.java +++ b/main/src/cgeo/geocaching/connector/gc/Tile.java @@ -1,12 +1,12 @@ package cgeo.geocaching.connector.gc; -import cgeo.geocaching.Settings; import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.network.Network; +import cgeo.geocaching.network.Parameters; import cgeo.geocaching.utils.Log; import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpGet; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -45,22 +45,16 @@ public class Tile { private final int tileX; private final int tileY; private final int zoomlevel; + private final Viewport viewPort; public Tile(Geopoint origin, int zoomlevel) { - assert zoomlevel >= ZOOMLEVEL_MIN && zoomlevel <= ZOOMLEVEL_MAX : "zoomlevel out of range"; this.zoomlevel = Math.max(Math.min(zoomlevel, ZOOMLEVEL_MAX), ZOOMLEVEL_MIN); tileX = calcX(origin); tileY = calcY(origin); - } - - public Tile(int tileX, int tileY, int zoomlevel) { - assert zoomlevel >= ZOOMLEVEL_MIN && zoomlevel <= ZOOMLEVEL_MAX : "zoomlevel out of range"; - this.zoomlevel = zoomlevel; - this.tileX = tileX; - this.tileY = tileY; + viewPort = new Viewport(getCoord(new UTFGridPosition(0, 0)), getCoord(new UTFGridPosition(63, 63))); } public int getZoomlevel() { @@ -161,7 +155,7 @@ public class Tile { public static int calcZoomLat(final Geopoint bottom, final Geopoint top) { int zoom = (int) Math.ceil( - Math.log(2 * Math.PI / + Math.log(2.0 * Math.PI / Math.abs( asinh(tanGrad(bottom.getLatitude())) - asinh(tanGrad(top.getLatitude())) @@ -213,26 +207,23 @@ public class Tile { } /** 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); + public static String requestMapInfo(final String url, final Parameters params, final String referer) { + return Network.getResponseData(Network.getRequest(url, params, new Parameters("Referer", referer))); } /** 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); + public static Bitmap requestMapTile(final String url, final Parameters params, final String referer) { + final HttpResponse response = Network.getRequest(url, params, new Parameters("Referer", referer)); try { return response != null ? BitmapFactory.decodeStream(response.getEntity().getContent()) : null; } catch (IOException e) { - Log.e(Settings.tag, "cgBase.requestMapTile() " + e.getMessage()); + Log.e("cgBase.requestMapTile() " + e.getMessage()); } return null; } + + public boolean containsPoint(Geopoint coords) { + + return viewPort.contains(coords); + } } diff --git a/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java b/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java index 7c1138a..4e4d9f7 100644 --- a/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java +++ b/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java @@ -1,9 +1,8 @@ package cgeo.geocaching.connector.opencaching; -import cgeo.geocaching.Settings; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgImage; -import cgeo.geocaching.cgLog; +import cgeo.geocaching.LogEntry; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.IConnector; @@ -114,7 +113,7 @@ final public class OkapiClient { return caches; } } catch (JSONException e) { - Log.e(Settings.tag, "OkapiClient.parseCaches", e); + Log.e("OkapiClient.parseCaches", e); } return null; } @@ -181,7 +180,7 @@ final public class OkapiClient { // save full detailed caches cgeoapplication.getInstance().saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); } catch (JSONException e) { - Log.e(Settings.tag, "OkapiClient.parseCache", e); + Log.e("OkapiClient.parseCache", e); } return cache; } @@ -203,22 +202,22 @@ final public class OkapiClient { return user.getString(USER_USERNAME); } - private static List<cgLog> parseLogs(JSONArray logsJSON) { - List<cgLog> result = null; + private static List<LogEntry> parseLogs(JSONArray logsJSON) { + List<LogEntry> result = null; for (int i = 0; i < logsJSON.length(); i++) { try { JSONObject logResponse = logsJSON.getJSONObject(i); - cgLog log = new cgLog(); + LogEntry log = new LogEntry(); log.date = parseDate(logResponse.getString(LOG_DATE)).getTime(); log.log = logResponse.getString(LOG_COMMENT).trim(); log.type = parseLogType(logResponse.getString(LOG_TYPE)); log.author = parseUser(logResponse.getJSONObject(LOG_USER)); if (result == null) { - result = new ArrayList<cgLog>(); + result = new ArrayList<LogEntry>(); } result.add(log); } catch (JSONException e) { - Log.e(Settings.tag, "OkapiClient.parseLogs", e); + Log.e("OkapiClient.parseLogs", e); } } return result; @@ -240,7 +239,7 @@ final public class OkapiClient { try { return ISO8601DATEFORMAT.parse(strippedDate); } catch (ParseException e) { - Log.e(Settings.tag, "OkapiClient.parseDate", e); + Log.e("OkapiClient.parseDate", e); } return null; } @@ -260,7 +259,7 @@ final public class OkapiClient { try { size = response.getDouble(CACHE_SIZE); } catch (JSONException e) { - Log.e(Settings.tag, "OkapiClient.getCacheSize", e); + Log.e("OkapiClient.getCacheSize", e); } switch ((int) Math.round(size)) { case 1: diff --git a/main/src/cgeo/geocaching/enumerations/CacheAttribute.java b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java new file mode 100644 index 0000000..46e198f --- /dev/null +++ b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java @@ -0,0 +1,139 @@ +package cgeo.geocaching.enumerations; + +import cgeo.geocaching.cgeoapplication; + +import android.content.res.Resources; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + + +public enum CacheAttribute { + UNKNOWN(0, ""), + DOGS(1, "dogs"), + FEE(2, "fee"), + RAPPELLING(3, "rappelling"), + BOAT(4, "boat"), + SCUBA(5, "scuba"), + KIDS(6, "kids"), + ONEHOUR(7, "onehour"), + SCENIC(8, "scenic"), + HIKING(9, "hiking"), + CLIMBING(10, "climbing"), + WADING(11, "wading"), + SWIMMING(12, "swimming"), + AVAILABLE(13, "available"), + NIGHT(14, "night"), + WINTER(15, "winter"), + POISONOAK(17, "poisonoak"), + DANGEROUSANIMALS(18, "dangerousanimals"), + TICKS(19, "ticks"), + MINE(29, "mine"), + CLIFF(21, "cliff"), + HUNTING(22, "hunting"), + DANGER(23, "danger"), + WHEELCHAIR(24, "wheelchair"), + PARKING(25, "parking"), + PUBLIC(26, "public"), + WATER(27, "water"), + RESTROOMS(28, "restrooms"), + PHONE(29, "phone"), + PICNIC(30, "picnic"), + CAMPING(31, "camping"), + BICYCLES(32, "bicycles"), + MOTORCYCLES(33, "motorcycles"), + QUADS(34, "quads"), + JEEPS(35, "jeeps"), + SNOWMOBILES(36, "snowmobiles"), + HORSES(37, "horses"), + CAMPFIRES(38, "campfires"), + THORN(39, "thorn"), + STEALTH(40, "stealth"), + STROLLER(41, "stroller"), + FIRSTAID(42, "firstaid"), + COW(43, "cow"), + FLASHLIGHT(44, "flashlight"), + LANDF(45, "landf"), + RV(46, "rv"), + FIELD_PUZZLE(47, "field_puzzle"), + UV(48, "uv"), + SNOWSHOES(49, "snowshoes"), + SKIIS(50, "skiis"), + SPECIAL_TOOLS(51, "s_tool"), + NIGHTCACHE(52, "nightcache"), + PARKNGRAB(53, "parkngrab"), + ABANDONED_BUILDING(54, "abandonedbuilding"), + HIKE_SHORT(55, "hike_short"), + HIKE_MED(56, "hike_med"), + HIKE_LONG(57, "hike_long"), + FUEL(58, "fuel"), + FOOD(59, "food"), + WIRELESS_BEACON(60, "wirelessbeacon"), + PARTNERSHIP(61, "partnership"), + SEASONAL(62, "seasonal"), + TOURIST_OK(63, "touristok"), + TREECLIMBING(64, "treeclimbing"), + FRONTYARD(65, "frontyard"), + TEAMWORK(66, "teamwork"); + + public static final String INTERNAL_PRE = "attribute_"; + public static final String INTERNAL_YES = "_yes"; + public static final String INTERNAL_NO = "_no"; + + public final int id; + public final String gcRawName; + + private CacheAttribute(final int id, final String gcRawName) { + this.id = id; + this.gcRawName = gcRawName; + } + + public String getL10n(final boolean enabled) { + final String attributeDescriptor = INTERNAL_PRE + gcRawName + (enabled ? INTERNAL_YES : INTERNAL_NO); + + cgeoapplication instance = cgeoapplication.getInstance(); + if (instance != null) { + Resources res = instance.getResources(); + int id = res.getIdentifier(attributeDescriptor, "string", instance.getBaseContext().getPackageName()); + + return (id > 0) ? res.getString(id) : attributeDescriptor; + } else { + return attributeDescriptor; + } + } + + private final static Map<String, CacheAttribute> FIND_BY_GCRAWNAME; + + static { + final HashMap<String, CacheAttribute> mapGcRawNames = new HashMap<String, CacheAttribute>(); + for (CacheAttribute attr : values()) { + mapGcRawNames.put(attr.gcRawName, attr); + } + FIND_BY_GCRAWNAME = Collections.unmodifiableMap(mapGcRawNames); + } + + public static CacheAttribute getById(final int id) { + for (CacheAttribute attr : values()) { + if (attr.id == id) { + return attr; + } + } + return UNKNOWN; + } + + public static CacheAttribute getByGcRawName(final String gcRawName) { + final CacheAttribute result = gcRawName != null ? FIND_BY_GCRAWNAME.get(gcRawName) : null; + if (result == null) { + return UNKNOWN; + } + return result; + } + + public static String trimAttributeName(String attributeName) { + if (null == attributeName) { + return ""; + } + return attributeName.replace(INTERNAL_PRE, "").replace(INTERNAL_YES, "").replace(INTERNAL_NO, "").trim(); + } +} diff --git a/main/src/cgeo/geocaching/enumerations/CacheSize.java b/main/src/cgeo/geocaching/enumerations/CacheSize.java index 9b0a559..b20a227 100644 --- a/main/src/cgeo/geocaching/enumerations/CacheSize.java +++ b/main/src/cgeo/geocaching/enumerations/CacheSize.java @@ -25,13 +25,11 @@ public enum CacheSize { public final String id; public final int comparable; private final int stringId; - private String l10n; // not final because the locale can be changed private CacheSize(String id, int comparable, int stringId) { this.id = id; this.comparable = comparable; this.stringId = stringId; - setL10n(); } final private static Map<String, CacheSize> FIND_BY_ID; @@ -61,12 +59,7 @@ public enum CacheSize { } public final String getL10n() { - return l10n; + return cgeoapplication.getInstance().getBaseContext().getResources().getString(stringId); } - - public void setL10n() { - this.l10n = cgeoapplication.getInstance().getBaseContext().getResources().getString(stringId); - } - } diff --git a/main/src/cgeo/geocaching/enumerations/CacheType.java b/main/src/cgeo/geocaching/enumerations/CacheType.java index 96e7eb5..482418e 100644 --- a/main/src/cgeo/geocaching/enumerations/CacheType.java +++ b/main/src/cgeo/geocaching/enumerations/CacheType.java @@ -37,7 +37,6 @@ public enum CacheType { public final String pattern; public final String guid; private final int stringId; - private String l10n; // not final because the locale can be changed public final int markerId; private CacheType(String id, String pattern, String guid, int stringId, int markerId) { @@ -45,7 +44,6 @@ public enum CacheType { this.pattern = pattern; this.guid = guid; this.stringId = stringId; - setL10n(); this.markerId = markerId; } @@ -63,7 +61,7 @@ public enum CacheType { } public final static CacheType getById(final String id) { - final CacheType result = id != null ? CacheType.FIND_BY_ID.get(id.toLowerCase().trim()) : null; + final CacheType result = (id != null) ? CacheType.FIND_BY_ID.get(id.toLowerCase().trim()) : null; if (result == null) { return UNKNOWN; } @@ -71,7 +69,7 @@ public enum CacheType { } public final static CacheType getByPattern(final String pattern) { - final CacheType result = pattern != null ? CacheType.FIND_BY_PATTERN.get(pattern.toLowerCase().trim()) : null; + final CacheType result = (pattern != null) ? CacheType.FIND_BY_PATTERN.get(pattern.toLowerCase().trim()) : null; if (result == null) { return UNKNOWN; } @@ -79,11 +77,10 @@ public enum CacheType { } public final String getL10n() { - return l10n; + return cgeoapplication.getInstance().getBaseContext().getResources().getString(stringId); } - public void setL10n() { - this.l10n = cgeoapplication.getInstance().getBaseContext().getResources().getString(this.stringId); + public boolean isEvent() { + return CacheType.EVENT == this || CacheType.MEGA_EVENT == this || CacheType.CITO == this || CacheType.LOSTANDFOUND == this; } - } diff --git a/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java b/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java index 0f0b721..c4782d8 100644 --- a/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java +++ b/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java @@ -28,13 +28,11 @@ public interface LiveMapStrategy { public final int id; public final EnumSet<StrategyFlag> flags; private final int stringId; - private String l10n; // not final because the locale can be changed private Strategy(int id, EnumSet<StrategyFlag> flags, int stringId) { this.id = id; this.flags = flags; this.stringId = stringId; - setL10n(); } public final static Strategy getById(final int id) { @@ -47,12 +45,7 @@ public interface LiveMapStrategy { } public final String getL10n() { - return l10n; - } - - public void setL10n() { - this.l10n = cgeoapplication.getInstance().getBaseContext().getResources().getString(this.stringId); + return cgeoapplication.getInstance().getBaseContext().getResources().getString(stringId); } } - } diff --git a/main/src/cgeo/geocaching/enumerations/LogType.java b/main/src/cgeo/geocaching/enumerations/LogType.java index aab4196..14be6a1 100644 --- a/main/src/cgeo/geocaching/enumerations/LogType.java +++ b/main/src/cgeo/geocaching/enumerations/LogType.java @@ -42,17 +42,15 @@ public enum LogType { LOG_UNKNOWN(0, "unknown", "", R.string.err_unknown); // LogType not init. yet public final int id; - private final String iconName; - private final String type; + public final String iconName; + public final String type; private final int stringId; - private String l10n; // not final because the locale can be changed private LogType(int id, String iconName, String type, int stringId) { this.id = id; this.iconName = iconName; this.type = type; this.stringId = stringId; - setL10n(); } private final static Map<String, LogType> FIND_BY_ICONNAME; @@ -94,12 +92,6 @@ public enum LogType { } public final String getL10n() { - return l10n; + return cgeoapplication.getInstance().getBaseContext().getResources().getString(stringId); } - - public void setL10n() { - this.l10n = cgeoapplication.getInstance().getBaseContext().getResources().getString(this.stringId); - } - } - diff --git a/main/src/cgeo/geocaching/enumerations/StatusCode.java b/main/src/cgeo/geocaching/enumerations/StatusCode.java index d49acb2..1a1f05d 100644 --- a/main/src/cgeo/geocaching/enumerations/StatusCode.java +++ b/main/src/cgeo/geocaching/enumerations/StatusCode.java @@ -2,41 +2,34 @@ package cgeo.geocaching.enumerations; import cgeo.geocaching.R; -import android.content.Context; import android.content.res.Resources; public enum StatusCode { - COMMUNICATION_NOT_STARTED(0, R.string.err_start), - NO_ERROR(1, R.string.err_none), - LOG_SAVED(2, R.string.info_log_saved), - LOGIN_PARSE_ERROR(-1, R.string.err_parse), - CONNECTION_FAILED(-2, R.string.err_server), - NO_LOGIN_INFO_STORED(-3, R.string.err_login), - UNKNOWN_ERROR(-4, R.string.err_unknown), - COMMUNICATION_ERROR(-5, R.string.err_comm), - WRONG_LOGIN_DATA(-6, R.string.err_wrong), - UNAPPROVED_LICENSE(-7, R.string.err_license), - UNPUBLISHED_CACHE(-8, R.string.err_unpublished), - PREMIUM_ONLY(-9, R.string.err_premium_only), - MAINTENANCE(-10, R.string.err_maintenance), - LOG_POST_ERROR(1000, R.string.err_log_post_failed), - NO_LOG_TEXT(1001, R.string.warn_log_text_fill), - NO_DATA_FROM_SERVER(1002, R.string.err_log_failed_server), - NOT_LOGGED_IN(-11, R.string.init_login_popup_failed); - - final private int error_code; + COMMUNICATION_NOT_STARTED(R.string.err_start), + NO_ERROR(R.string.err_none), + LOG_SAVED(R.string.info_log_saved), + LOGIN_PARSE_ERROR(R.string.err_parse), + CONNECTION_FAILED(R.string.err_server), + NO_LOGIN_INFO_STORED(R.string.err_login), + UNKNOWN_ERROR(R.string.err_unknown), + COMMUNICATION_ERROR(R.string.err_comm), + WRONG_LOGIN_DATA(R.string.err_wrong), + UNAPPROVED_LICENSE(R.string.err_license), + UNPUBLISHED_CACHE(R.string.err_unpublished), + PREMIUM_ONLY(R.string.err_premium_only), + MAINTENANCE(R.string.err_maintenance), + LOG_POST_ERROR(R.string.err_log_post_failed), + NO_LOG_TEXT(R.string.warn_log_text_fill), + NO_DATA_FROM_SERVER(R.string.err_log_failed_server), + NOT_LOGGED_IN(R.string.init_login_popup_failed); + final private int error_string; - StatusCode(int error_code, int error_string) { - this.error_code = error_code; + StatusCode(int error_string) { this.error_string = error_string; } - public int getCode() { - return error_code; - } - public int getErrorString() { return error_string; } @@ -45,8 +38,4 @@ public enum StatusCode { return res.getString(error_string); } - public String getErrorString(final Context context) { - return getErrorString(context.getResources()); - } - } diff --git a/main/src/cgeo/geocaching/enumerations/WaypointType.java b/main/src/cgeo/geocaching/enumerations/WaypointType.java index 78e5ceb..44004c0 100644 --- a/main/src/cgeo/geocaching/enumerations/WaypointType.java +++ b/main/src/cgeo/geocaching/enumerations/WaypointType.java @@ -5,7 +5,9 @@ import cgeo.geocaching.cgeoapplication; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; /** * Enum listing waypoint types @@ -23,13 +25,11 @@ public enum WaypointType { public final String id; public final int stringId; - private String l10n; // not final because the locale can be changed public final int markerId; private WaypointType(String id, int stringId, int markerId) { this.id = id; this.stringId = stringId; - setL10n(); this.markerId = markerId; } @@ -38,13 +38,13 @@ public enum WaypointType { * non public so that <code>null</code> handling can be handled centrally in the enum type itself */ private static final Map<String, WaypointType> FIND_BY_ID; - public static final Map<WaypointType, String> ALL_TYPES_EXCEPT_OWN = new HashMap<WaypointType, String>(); + public static final Set<WaypointType> ALL_TYPES_EXCEPT_OWN = new HashSet<WaypointType>(); static { final HashMap<String, WaypointType> mapping = new HashMap<String, WaypointType>(); for (WaypointType wt : values()) { mapping.put(wt.id, wt); if (wt != WaypointType.OWN) { - ALL_TYPES_EXCEPT_OWN.put(wt, wt.getL10n()); + ALL_TYPES_EXCEPT_OWN.add(wt); } } FIND_BY_ID = Collections.unmodifiableMap(mapping); @@ -66,15 +66,9 @@ public enum WaypointType { } public final String getL10n() { - return l10n; + return cgeoapplication.getInstance().getBaseContext().getResources().getString(stringId); } - public void setL10n() { - this.l10n = cgeoapplication.getInstance().getBaseContext().getResources().getString(this.stringId); - if (WaypointType.ALL_TYPES_EXCEPT_OWN != null && WaypointType.ALL_TYPES_EXCEPT_OWN.containsKey(this)) { - WaypointType.ALL_TYPES_EXCEPT_OWN.put(this, this.getL10n()); - } - } @Override public final String toString() { diff --git a/main/src/cgeo/geocaching/export/AbstractExport.java b/main/src/cgeo/geocaching/export/AbstractExport.java new file mode 100644 index 0000000..85b060b --- /dev/null +++ b/main/src/cgeo/geocaching/export/AbstractExport.java @@ -0,0 +1,32 @@ +package cgeo.geocaching.export; + +import cgeo.geocaching.cgeoapplication; + +abstract class AbstractExport implements Export { + private final String name; + + protected AbstractExport(final String name) { + this.name = name; + } + + public String getName() { + return name; + } + + /** + * Generates a localized string from a resource id. + * + * @param resourceId + * the resource id of the string + * @return localized string + */ + protected static String getString(int resourceId) { + return cgeoapplication.getInstance().getString(resourceId); + } + + @Override + public String toString() { + // used in the array adapter of the dialog showing the exports + return getName(); + } +} diff --git a/main/src/cgeo/geocaching/export/Export.java b/main/src/cgeo/geocaching/export/Export.java new file mode 100644 index 0000000..7a2b075 --- /dev/null +++ b/main/src/cgeo/geocaching/export/Export.java @@ -0,0 +1,29 @@ +package cgeo.geocaching.export; + +import cgeo.geocaching.cgCache; + +import android.app.Activity; + +import java.util.List; + +/** + * Represents an exporter to export a {@link List} of {@link cgCache} to various formats. + */ +interface Export { + /** + * Export a {@link List} of {@link cgCache} to various formats. + * + * @param caches + * The {@link List} of {@link cgCache} to be exported + * @param activity + * optional: Some exporters might have an UI which requires an {@link Activity} + */ + public void export(List<cgCache> caches, Activity activity); + + /** + * Get the localized name of this exporter. + * + * @return localized name + */ + public String getName(); +} diff --git a/main/src/cgeo/geocaching/export/ExportFactory.java b/main/src/cgeo/geocaching/export/ExportFactory.java new file mode 100644 index 0000000..8b3df58 --- /dev/null +++ b/main/src/cgeo/geocaching/export/ExportFactory.java @@ -0,0 +1,65 @@ +package cgeo.geocaching.export; + +import cgeo.geocaching.R; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.utils.Log; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.widget.ArrayAdapter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Factory to create a dialog with all available exporters. + */ +public abstract class ExportFactory { + + /** + * Contains instances of all available exporter classes. + */ + private static final List<Class<? extends Export>> exporterClasses; + + static { + final ArrayList<Class<? extends Export>> temp = new ArrayList<Class<? extends Export>>(); + temp.add(FieldnoteExport.class); + temp.add(GpxExport.class); + exporterClasses = Collections.unmodifiableList(temp); + } + + /** + * Creates a dialog so that the user can select an exporter. + * + * @param caches + * The {@link List} of {@link cgCache} to be exported + * @param activity + * The {@link Activity} in whose context the dialog should be shown + */ + public static void showExportMenu(final List<cgCache> caches, final Activity activity) { + final AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setTitle(R.string.export).setIcon(android.R.drawable.ic_menu_share); + + final ArrayList<Export> export = new ArrayList<Export>(); + for (Class<? extends Export> exporterClass : exporterClasses) { + try { + export.add(exporterClass.newInstance()); + } catch (Exception ex) { + Log.e("showExportMenu", ex); + } + } + + final ArrayAdapter<Export> adapter = new ArrayAdapter<Export>(activity, android.R.layout.select_dialog_item, export); + + builder.setAdapter(adapter, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int item) { + final Export selectedExport = adapter.getItem(item); + selectedExport.export(caches, activity); + } + }); + + builder.create().show(); + } +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/export/FieldnoteExport.java b/main/src/cgeo/geocaching/export/FieldnoteExport.java new file mode 100644 index 0000000..05fb828 --- /dev/null +++ b/main/src/cgeo/geocaching/export/FieldnoteExport.java @@ -0,0 +1,257 @@ +package cgeo.geocaching.export; + +import cgeo.geocaching.LogEntry; +import cgeo.geocaching.R; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.activity.ActivityMixin; +import cgeo.geocaching.activity.Progress; +import cgeo.geocaching.enumerations.LogType; +import cgeo.geocaching.utils.Log; + +import org.apache.commons.lang3.StringUtils; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.os.AsyncTask; +import android.os.Environment; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Exports offline-logs in the Groundspeak Field Note format.<br> + * <br> + * + * Field Notes are simple plain text files, but poorly documented. Syntax:<br> + * <code>GCxxxxx,yyyy-mm-ddThh:mm:ssZ,Found it,"logtext"</code> + */ +class FieldnoteExport extends AbstractExport { + private static final File exportLocation = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/field-notes"); + private static final SimpleDateFormat fieldNoteDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + + protected FieldnoteExport() { + super(getString(R.string.export_fieldnotes)); + } + + /** + * A dialog to allow the user to set options for the export. + * + * Currently available options are: upload field notes, only new logs since last export/upload + */ + private class ExportOptionsDialog extends AlertDialog { + public ExportOptionsDialog(final List<cgCache> caches, final Activity activity) { + super(activity); + + View layout = activity.getLayoutInflater().inflate(R.layout.fieldnote_export_dialog, null); + setView(layout); + + ((Button) layout.findViewById(R.id.export)).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dismiss(); + new ExportTask( + caches, + activity, + ((CheckBox) findViewById(R.id.upload)).isChecked(), + ((CheckBox) findViewById(R.id.onlynew)).isChecked()) + .execute((Void) null); + } + }); + } + } + + @Override + public void export(final List<cgCache> caches, final Activity activity) { + if (null == activity) { + // No activity given, so no user interaction possible. + // Start export with default parameters. + new ExportTask(caches, null, false, false).execute((Void) null); + } else { + // Show configuration dialog + new ExportOptionsDialog(caches, activity).show(); + } + } + + private class ExportTask extends AsyncTask<Void, Integer, Boolean> { + private final List<cgCache> caches; + private final Activity activity; + private final boolean onlyNew; + private final Progress progress = new Progress(); + private File exportFile; + + private static final int STATUS_UPLOAD = -1; + + /** + * Instantiates and configurates the task for exporting field notes. + * + * @param caches + * The {@link List} of {@link cgCache} to be exported + * @param activity + * optional: Show a progress bar and toasts + * @param upload + * Upload the Field Note to geocaching.com + * @param onlyNew + * Upload/export only new logs since last export + */ + public ExportTask(final List<cgCache> caches, final Activity activity, final boolean upload, final boolean onlyNew) { + this.caches = caches; + this.activity = activity; + this.onlyNew = onlyNew; + } + + @Override + protected void onPreExecute() { + if (null != activity) { + progress.show(activity, null, getString(R.string.export) + ": " + getName(), ProgressDialog.STYLE_HORIZONTAL, null); + progress.setMaxProgressAndReset(caches.size()); + } + } + + @Override + protected Boolean doInBackground(Void... params) { + final StringBuilder fieldNoteBuffer = new StringBuilder(); + + // We need our own HashMap because LogType will give us localized and maybe + // different strings than gc.com expects in the field note + // We only need such logtypes that are possible to log via c:geo + Map<LogType, String> logTypes = new HashMap<LogType, String>(); + logTypes.put(LogType.LOG_FOUND_IT, "Found it"); + logTypes.put(LogType.LOG_DIDNT_FIND_IT, "Didn't find it"); + logTypes.put(LogType.LOG_NOTE, "Write Note"); + logTypes.put(LogType.LOG_NEEDS_ARCHIVE, "Needs archived"); + logTypes.put(LogType.LOG_NEEDS_MAINTENANCE, "Needs Maintenance"); + logTypes.put(LogType.LOG_WILL_ATTEND, "Will Attend"); + logTypes.put(LogType.LOG_ATTENDED, "Attended"); + logTypes.put(LogType.LOG_WEBCAM_PHOTO_TAKEN, "Webcam Photo Taken"); + + for (int i = 0; i < caches.size(); i++) { + try { + final cgCache cache = caches.get(i); + if (cache.isLogOffline()) { + LogEntry log = cgeoapplication.getInstance().loadLogOffline(cache.getGeocode()); + if (null != logTypes.get(log.type)) { + fieldNoteBuffer.append(cache.getGeocode()) + .append(',') + .append(fieldNoteDateFormat.format(new Date(log.date))) + .append(',') + .append(logTypes.get(log.type)) + .append(",\"") + .append(StringUtils.replaceChars(log.log, '"', '\'')) + .append("\"\n"); + } + } + publishProgress(i + 1); + } catch (Exception e) { + Log.e("FieldnoteExport.ExportTask generation", e); + return false; + } + } + + fieldNoteBuffer.append("\n"); + + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + exportLocation.mkdirs(); + + SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); + exportFile = new File(exportLocation.toString() + '/' + fileNameDateFormat.format(new Date()) + ".txt"); + + OutputStream os = null; + Writer fw = null; + try { + os = new FileOutputStream(exportFile); + fw = new OutputStreamWriter(os, "ISO-8859-1"); // TODO: gc.com doesn't support UTF-8 + fw.write(fieldNoteBuffer.toString()); + } catch (IOException e) { + Log.e("FieldnoteExport.ExportTask export", e); + return false; + } finally { + if (fw != null) { + try { + fw.close(); + } catch (IOException e) { + Log.e("FieldnoteExport.ExportTask export", e); + return false; + } + } + } + } else { + return false; + } + + /* + * if (upload) { + * TODO Use multipart POST request for uploading + * publishProgress(STATUS_UPLOAD); + * + * final Parameters uploadParams = new Parameters( + * "__EVENTTARGET", "", + * "__EVENTARGUMENT", "", + * "__VIEWSTATE", "", + * //TODO "ctl00$ContentBody$chkSuppressDate", "on", + * "ctl00$ContentBody$FieldNoteLoader", fieldNoteBuffer.toString(), + * "ctl00$ContentBody$btnUpload", "Upload Field Note"); + * final String uri = "http://www.geocaching.com/my/uploadfieldnotes.aspx"; + * + * String page = Network.getResponseData(Network.postRequest(uri, uploadParams)); + * if (!Login.getLoginStatus(page)) { + * final StatusCode loginState = Login.login(); + * if (loginState == StatusCode.NO_ERROR) { + * page = Network.getResponseData(Network.postRequest(uri, uploadParams)); + * } else { + * Log.e(Settings.tag, "FieldnoteExport.ExportTask upload: No login (error: " + loginState + ")"); + * return false; + * } + * } + * + * if (StringUtils.isBlank(page)) { + * Log.e(Settings.tag, "FieldnoteExport.ExportTask upload: No data from server"); + * return false; + * } + * } + */ + + return true; + } + + @Override + protected void onPostExecute(Boolean result) { + if (null != activity) { + progress.dismiss(); + + if (result) { + if (onlyNew) { + // update last export time in settings + } + ActivityMixin.showToast(activity, getName() + ' ' + getString(R.string.export_exportedto) + ": " + exportFile.toString()); + } else { + ActivityMixin.showToast(activity, getString(R.string.export_failed)); + } + } + } + + @Override + protected void onProgressUpdate(Integer... status) { + if (null != activity) { + if (STATUS_UPLOAD == status[0]) { + progress.setMessage(getString(R.string.export_fieldnotes_uploading)); + } else { + progress.setProgress(status[0]); + } + } + } + } +} diff --git a/main/src/cgeo/geocaching/export/GpxExport.java b/main/src/cgeo/geocaching/export/GpxExport.java new file mode 100644 index 0000000..2c833a2 --- /dev/null +++ b/main/src/cgeo/geocaching/export/GpxExport.java @@ -0,0 +1,301 @@ +package cgeo.geocaching.export; + +import cgeo.geocaching.R; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.LogEntry; +import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.activity.ActivityMixin; +import cgeo.geocaching.activity.Progress; +import cgeo.geocaching.enumerations.CacheAttribute; +import cgeo.geocaching.enumerations.LoadFlags; +import cgeo.geocaching.utils.BaseUtils; +import cgeo.geocaching.utils.Log; + +import org.apache.commons.lang3.StringEscapeUtils; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.os.AsyncTask; +import android.os.Environment; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +class GpxExport extends AbstractExport { + private static final File exportLocation = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/gpx-export"); + private static final SimpleDateFormat dateFormatZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + + protected GpxExport() { + super(getString(R.string.export_gpx)); + } + + @Override + public void export(final List<cgCache> caches, final Activity activity) { + new ExportTask(caches, activity).execute((Void) null); + } + + private class ExportTask extends AsyncTask<Void, Integer, Boolean> { + private final List<cgCache> caches; + private final Activity activity; + private final Progress progress = new Progress(); + private File exportFile; + + /** + * Instantiates and configures the task for exporting field notes. + * + * @param caches + * The {@link List} of {@link cgCache} to be exported + * @param activity + * optional: Show a progress bar and toasts + */ + public ExportTask(final List<cgCache> caches, final Activity activity) { + this.caches = caches; + this.activity = activity; + } + + @Override + protected void onPreExecute() { + if (null != activity) { + progress.show(activity, null, getString(R.string.export) + ": " + getName(), ProgressDialog.STYLE_HORIZONTAL, null); + progress.setMaxProgressAndReset(caches.size()); + } + } + + @Override + protected Boolean doInBackground(Void... params) { + // quick check for being able to write the GPX file + if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + return false; + } + + // FIXME: complete export is created in memory. That should be some file stream instead. + final StringBuilder gpx = new StringBuilder(); + + gpx.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); + gpx.append("<gpx version=\"1.0\" creator=\"c:geo - http://www.cgeo.org\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.topografix.com/GPX/1/0\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.groundspeak.com/cache/1/0/1 http://www.groundspeak.com/cache/1/0/1/cache.xsd\">"); + + try { + for (int i = 0; i < caches.size(); i++) { + cgCache cache = caches.get(i); + + if (!cache.isDetailed()) { + cache = cgeoapplication.getInstance().loadCache(caches.get(i).getGeocode(), LoadFlags.LOAD_ALL_DB_ONLY); + } + + gpx.append("<wpt "); + gpx.append("lat=\"" + cache.getCoords().getLatitude() + "\" "); + gpx.append("lon=\"" + cache.getCoords().getLongitude() + "\">"); + + gpx.append("<time>"); + gpx.append(StringEscapeUtils.escapeXml(dateFormatZ.format(cache.getHiddenDate()))); + gpx.append("</time>"); + + gpx.append("<name>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getGeocode())); + gpx.append("</name>"); + + gpx.append("<desc>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getName())); + gpx.append("</desc>"); + + gpx.append("<sym>"); + gpx.append(cache.isFound() ? "Geocache Found" : "Geocache"); + gpx.append("</sym>"); + + gpx.append("<type>"); + gpx.append(StringEscapeUtils.escapeXml("Geocache|" + cache.getType().toString())); //TODO: Correct (english) string + gpx.append("</type>"); + + gpx.append("<groundspeak:cache "); + gpx.append("available=\"" + (!cache.isDisabled() ? "True" : "False")); + gpx.append("\" archived=\"" + (cache.isArchived() ? "True" : "False") + "\" "); + gpx.append("xmlns:groundspeak=\"http://www.groundspeak.com/cache/1/0/1\">"); + + gpx.append("<groundspeak:name>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getName())); + gpx.append("</groundspeak:name>"); + + gpx.append("<groundspeak:placed_by>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getOwner())); + gpx.append("</groundspeak:placed_by>"); + + gpx.append("<groundspeak:owner>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getOwnerReal())); + gpx.append("</groundspeak:owner>"); + + gpx.append("<groundspeak:type>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getType().toString())); //TODO: Correct (english) string + gpx.append("</groundspeak:type>"); + + gpx.append("<groundspeak:container>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getSize().toString())); //TODO: Correct (english) string + gpx.append("</groundspeak:container>"); + + if (cache.hasAttributes()) { + //TODO: Attribute conversion required: English verbose name, gpx-id + gpx.append("<groundspeak:attributes>"); + + for (String attribute : cache.getAttributes()) { + final CacheAttribute attr = CacheAttribute.getByGcRawName(CacheAttribute.trimAttributeName(attribute)); + final boolean enabled = attribute.endsWith(CacheAttribute.INTERNAL_YES); + + gpx.append("<groundspeak:attribute id=\""); + gpx.append(attr.id); + gpx.append("\" inc=\""); + if (enabled) { + gpx.append('1'); + } else { + gpx.append('0'); + } + gpx.append("\">"); + gpx.append(StringEscapeUtils.escapeXml(attr.getL10n(enabled))); + gpx.append("</groundspeak:attribute>"); + } + + gpx.append("</groundspeak:attributes>"); + } + + gpx.append("<groundspeak:difficulty>"); + gpx.append(Float.toString(cache.getDifficulty())); + gpx.append("</groundspeak:difficulty>"); + + gpx.append("<groundspeak:terrain>"); + gpx.append(Float.toString(cache.getTerrain())); + gpx.append("</groundspeak:terrain>"); + + gpx.append("<groundspeak:country>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getLocation())); + gpx.append("</groundspeak:country>"); + + gpx.append("<groundspeak:state>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getLocation())); + gpx.append("</groundspeak:state>"); + + gpx.append("<groundspeak:short_description html=\""); + if (BaseUtils.containsHtml(cache.getShortDescription())) { + gpx.append("True"); + } else { + gpx.append("False"); + } + gpx.append("\">"); + gpx.append(StringEscapeUtils.escapeXml(cache.getShortDescription())); + gpx.append("</groundspeak:short_description>"); + + gpx.append("<groundspeak:long_description html=\""); + if (BaseUtils.containsHtml(cache.getDescription())) { + gpx.append("True"); + } else { + gpx.append("False"); + } + gpx.append("\">"); + gpx.append(StringEscapeUtils.escapeXml(cache.getDescription())); + gpx.append("</groundspeak:long_description>"); + + gpx.append("<groundspeak:encoded_hints>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getHint())); + gpx.append("</groundspeak:encoded_hints>"); + + gpx.append("</groundspeak:cache>"); + + //TODO: Waypoints + + if (cache.getLogs().size() > 0) { + gpx.append("<groundspeak:logs>"); + + for (LogEntry log : cache.getLogs()) { + gpx.append("<groundspeak:log id=\""); + gpx.append(log.id); + gpx.append("\">"); + + gpx.append("<groundspeak:date>"); + gpx.append(StringEscapeUtils.escapeXml(dateFormatZ.format(new Date(log.date)))); + gpx.append("</groundspeak:date>"); + + gpx.append("<groundspeak:type>"); + gpx.append(StringEscapeUtils.escapeXml(log.type.type)); + gpx.append("</groundspeak:type>"); + + gpx.append("<groundspeak:finder id=\"\">"); + gpx.append(StringEscapeUtils.escapeXml(log.author)); + gpx.append("</groundspeak:finder>"); + + gpx.append("<groundspeak:text encoded=\"False\">"); + gpx.append(StringEscapeUtils.escapeXml(log.log)); + gpx.append("</groundspeak:text>"); + + gpx.append("</groundspeak:log>"); + } + + gpx.append("</groundspeak:logs>"); + } + + gpx.append("</wpt>"); + + publishProgress(i + 1); + } + } catch (Exception e) { + Log.e("GpxExport.ExportTask generation", e); + return false; + } + + gpx.append("</gpx>"); + + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + exportLocation.mkdirs(); + + SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); + exportFile = new File(exportLocation.toString() + '/' + fileNameDateFormat.format(new Date()) + ".gpx"); + + OutputStream os = null; + Writer fw = null; + try { + os = new FileOutputStream(exportFile); + fw = new OutputStreamWriter(os, "UTF-8"); + fw.write(gpx.toString()); + } catch (IOException e) { + Log.e("GpxExport.ExportTask export", e); + return false; + } finally { + if (fw != null) { + try { + fw.close(); + } catch (IOException e) { + Log.e("GpxExport.ExportTask export", e); + return false; + } + } + } + } else { + return false; + } + + return true; + } + + @Override + protected void onPostExecute(Boolean result) { + if (null != activity) { + progress.dismiss(); + if (result) { + ActivityMixin.showToast(activity, getName() + ' ' + getString(R.string.export_exportedto) + ": " + exportFile.toString()); + } else { + ActivityMixin.showToast(activity, getString(R.string.export_failed)); + } + } + } + + @Override + protected void onProgressUpdate(Integer... status) { + if (null != activity) { + progress.setProgress(status[0]); + } + } + } +} diff --git a/main/src/cgeo/geocaching/files/FileList.java b/main/src/cgeo/geocaching/files/FileList.java index dbdea60..576aa2c 100644 --- a/main/src/cgeo/geocaching/files/FileList.java +++ b/main/src/cgeo/geocaching/files/FileList.java @@ -1,7 +1,6 @@ package cgeo.geocaching.files; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; import cgeo.geocaching.StoredList; import cgeo.geocaching.activity.AbstractListActivity; import cgeo.geocaching.utils.Log; @@ -87,7 +86,7 @@ public abstract class FileList<T extends ArrayAdapter<File>> extends AbstractLis if (waitDialog != null) { waitDialog.dismiss(); } - Log.e(Settings.tag, "cgFileList.loadFilesHandler: " + e.toString()); + Log.e("cgFileList.loadFilesHandler: " + e.toString()); } } }; @@ -188,10 +187,10 @@ public abstract class FileList<T extends ArrayAdapter<File>> extends AbstractLis listDir(list, Environment.getExternalStorageDirectory()); } } else { - Log.w(Settings.tag, "No external media mounted."); + Log.w("No external media mounted."); } } catch (Exception e) { - Log.e(Settings.tag, "cgFileList.loadFiles.run: " + e.toString()); + Log.e("cgFileList.loadFiles.run: " + e.toString()); } changeWaitDialogHandler.sendMessage(Message.obtain(changeWaitDialogHandler, 0, "loaded directories")); diff --git a/main/src/cgeo/geocaching/files/GPXImporter.java b/main/src/cgeo/geocaching/files/GPXImporter.java index 8fd099d..ccb71cd 100644 --- a/main/src/cgeo/geocaching/files/GPXImporter.java +++ b/main/src/cgeo/geocaching/files/GPXImporter.java @@ -112,7 +112,7 @@ public class GPXImporter { }
}
- Log.i(Settings.tag, "importGPX: " + uri + ", mimetype=" + mimeType);
+ Log.i("importGPX: " + uri + ", mimetype=" + mimeType);
if (GPX_MIME_TYPES.contains(mimeType)) {
new ImportGpxAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start();
} else if (ZIP_MIME_TYPES.contains(mimeType)) {
@@ -142,7 +142,7 @@ public class GPXImporter { importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_STORE_CACHES, R.string.gpx_import_storing, caches.size()));
SearchResult search = storeParsedCaches(caches);
- Log.i(Settings.tag, "Imported successfully " + caches.size() + " caches.");
+ Log.i("Imported successfully " + caches.size() + " caches.");
if (Settings.isStoreOfflineMaps() || Settings.isStoreOfflineWpMaps()) {
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_STORE_STATIC_MAPS, R.string.gpx_import_store_static_maps, search.getCount()));
@@ -155,16 +155,16 @@ public class GPXImporter { importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED, search.getCount(), 0, search));
} catch (IOException e) {
- Log.i(Settings.tag, "Importing caches failed - error reading data: " + e.getMessage());
+ Log.i("Importing caches failed - error reading data: " + e.getMessage());
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_io, 0, e.getLocalizedMessage()));
} catch (ParserException e) {
- Log.i(Settings.tag, "Importing caches failed - data format error" + e.getMessage());
+ Log.i("Importing caches failed - data format error" + e.getMessage());
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_parser, 0, e.getLocalizedMessage()));
} catch (CancellationException e) {
- Log.i(Settings.tag, "Importing caches canceled");
+ Log.i("Importing caches canceled");
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_CANCELED));
} catch (Exception e) {
- Log.e(Settings.tag, "Importing caches failed - unknown error: ", e);
+ Log.e("Importing caches failed - unknown error: ", e);
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_unexpected, 0, e.getLocalizedMessage()));
}
}
@@ -194,7 +194,7 @@ public class GPXImporter { int storedCacheMaps = 0;
for (String geocode : importedCaches.getGeocodes()) {
cgCache cache = app.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS);
- Log.d(Settings.tag, "GPXImporter.ImportThread.importStaticMaps start downloadMaps for cache " + geocode);
+ Log.d("GPXImporter.ImportThread.importStaticMaps start downloadMaps for cache " + geocode);
StaticMapsProvider.downloadMaps(cache, app);
storedCacheMaps++;
if (progressHandler.isCancelled()) {
@@ -216,7 +216,7 @@ public class GPXImporter { @Override
protected Collection<cgCache> doImport() throws IOException, ParserException {
- Log.i(Settings.tag, "Import LOC file: " + file.getAbsolutePath());
+ Log.i("Import LOC file: " + file.getAbsolutePath());
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) file.length()));
LocParser parser = new LocParser(listId);
return parser.parse(file, progressHandler);
@@ -253,7 +253,7 @@ public class GPXImporter { @Override
protected Collection<cgCache> doImport(GPXParser parser) throws IOException, ParserException {
- Log.i(Settings.tag, "Import GPX file: " + cacheFile.getAbsolutePath());
+ Log.i("Import GPX file: " + cacheFile.getAbsolutePath());
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) cacheFile.length()));
Collection<cgCache> caches = parser.parse(cacheFile, progressHandler);
@@ -261,7 +261,7 @@ public class GPXImporter { if (wptsFilename != null) {
final File wptsFile = new File(cacheFile.getParentFile(), wptsFilename);
if (wptsFile.canRead()) {
- Log.i(Settings.tag, "Import GPX waypoint file: " + wptsFile.getAbsolutePath());
+ Log.i("Import GPX waypoint file: " + wptsFile.getAbsolutePath());
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_WPT_FILE, R.string.gpx_import_loading_waypoints, (int) wptsFile.length()));
caches = parser.parse(wptsFile, progressHandler);
}
@@ -282,7 +282,7 @@ public class GPXImporter { @Override
protected Collection<cgCache> doImport(GPXParser parser) throws IOException, ParserException {
- Log.i(Settings.tag, "Import GPX from uri: " + uri);
+ Log.i("Import GPX from uri: " + uri);
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, -1));
InputStream is = contentResolver.openInputStream(uri);
try {
@@ -347,7 +347,7 @@ public class GPXImporter { public ImportGpxZipFileThread(final File file, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
super(listId, importStepHandler, progressHandler);
this.cacheFile = file;
- Log.i(Settings.tag, "Import zipped GPX: " + file);
+ Log.i("Import zipped GPX: " + file);
}
@Override
@@ -364,7 +364,7 @@ public class GPXImporter { super(listId, importStepHandler, progressHandler);
this.uri = uri;
this.contentResolver = contentResolver;
- Log.i(Settings.tag, "Import zipped GPX from uri: " + uri);
+ Log.i("Import zipped GPX from uri: " + uri);
}
@Override
diff --git a/main/src/cgeo/geocaching/files/GPXParser.java b/main/src/cgeo/geocaching/files/GPXParser.java index 0a8137e..051a49b 100644 --- a/main/src/cgeo/geocaching/files/GPXParser.java +++ b/main/src/cgeo/geocaching/files/GPXParser.java @@ -1,10 +1,9 @@ package cgeo.geocaching.files; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; import cgeo.geocaching.StoredList; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgLog; +import cgeo.geocaching.LogEntry; import cgeo.geocaching.cgTrackable; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.cgeoapplication; @@ -77,7 +76,7 @@ public abstract class GPXParser extends FileParser { private cgCache cache; private cgTrackable trackable = new cgTrackable(); - private cgLog log = new cgLog(); + private LogEntry log = new LogEntry(); private String type = null; private String sym = null; @@ -259,7 +258,7 @@ public abstract class GPXParser extends FileParser { Double.valueOf(attrs.getValue("lon")))); } } catch (Exception e) { - Log.w(Settings.tag, "Failed to parse waypoint's latitude and/or longitude."); + Log.w("Failed to parse waypoint's latitude and/or longitude."); } } }); @@ -295,7 +294,7 @@ public abstract class GPXParser extends FileParser { final String key = cache.getGeocode(); if (result.containsKey(key)) { - Log.w(Settings.tag, "Duplicate geocode during GPX import: " + key); + Log.w("Duplicate geocode during GPX import: " + key); } result.put(key, cache); showProgressMessage(progressHandler, progressStream.getProgress()); @@ -346,7 +345,7 @@ public abstract class GPXParser extends FileParser { try { cache.setHidden(parseDate(body)); } catch (Exception e) { - Log.w(Settings.tag, "Failed to parse cache date: " + e.toString()); + Log.w("Failed to parse cache date: " + e.toString()); } } }); @@ -468,7 +467,7 @@ public abstract class GPXParser extends FileParser { cache.setDisabled(!attrs.getValue("available").equalsIgnoreCase("true")); } } catch (Exception e) { - Log.w(Settings.tag, "Failed to parse cache attributes."); + Log.w("Failed to parse cache attributes."); } } }); @@ -548,7 +547,7 @@ public abstract class GPXParser extends FileParser { try { cache.setDifficulty(Float.parseFloat(body)); } catch (NumberFormatException e) { - Log.w(Settings.tag, "Failed to parse difficulty: " + e.toString()); + Log.w("Failed to parse difficulty: " + e.toString()); } } }); @@ -561,7 +560,7 @@ public abstract class GPXParser extends FileParser { try { cache.setTerrain(Float.parseFloat(body)); } catch (NumberFormatException e) { - Log.w(Settings.tag, "Failed to parse terrain: " + e.toString()); + Log.w("Failed to parse terrain: " + e.toString()); } } }); @@ -675,7 +674,7 @@ public abstract class GPXParser extends FileParser { @Override public void start(Attributes attrs) { - log = new cgLog(); + log = new LogEntry(); try { if (attrs.getIndex("id") > -1) { @@ -705,7 +704,7 @@ public abstract class GPXParser extends FileParser { try { log.date = parseDate(body).getTime(); } catch (Exception e) { - Log.w(Settings.tag, "Failed to parse log date: " + e.toString()); + Log.w("Failed to parse log date: " + e.toString()); } } }); @@ -744,7 +743,7 @@ public abstract class GPXParser extends FileParser { Xml.parse(progressStream, Xml.Encoding.UTF_8, root.getContentHandler()); return result.values(); } catch (SAXException e) { - Log.e(Settings.tag, "Cannot parse .gpx file as GPX " + version + ": could not parse XML - " + e.toString()); + Log.e("Cannot parse .gpx file as GPX " + version + ": could not parse XML - " + e.toString()); throw new ParserException("Cannot parse .gpx file as GPX " + version + ": could not parse XML", e); } } diff --git a/main/src/cgeo/geocaching/files/LocParser.java b/main/src/cgeo/geocaching/files/LocParser.java index 3be8da4..ad44dc4 100644 --- a/main/src/cgeo/geocaching/files/LocParser.java +++ b/main/src/cgeo/geocaching/files/LocParser.java @@ -1,7 +1,6 @@ package cgeo.geocaching.files; import cgeo.geocaching.SearchResult; -import cgeo.geocaching.Settings; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.CacheSize; @@ -103,8 +102,7 @@ public final class LocParser extends FileParser { } } - Log.i(Settings.tag, - "Coordinates found in .loc file: " + coords.size()); + Log.i("Coordinates found in .loc file: " + coords.size()); return coords; } @@ -113,7 +111,7 @@ public final class LocParser extends FileParser { try { return new Geopoint(Double.valueOf(latitude), Double.valueOf(longitude)); } catch (NumberFormatException e) { - Log.e(Settings.tag, "LOC format has changed"); + Log.e("LOC format has changed"); } // fall back to parser, just in case the format changes return GeopointParser.parse(latitude, longitude); @@ -144,7 +142,7 @@ public final class LocParser extends FileParser { cache.setListId(listId); cache.setDetailed(true); } - Log.i(Settings.tag, "Caches found in .loc file: " + caches.size()); + Log.i("Caches found in .loc file: " + caches.size()); return caches; } diff --git a/main/src/cgeo/geocaching/files/LocalStorage.java b/main/src/cgeo/geocaching/files/LocalStorage.java index a97c176..f37d22f 100644 --- a/main/src/cgeo/geocaching/files/LocalStorage.java +++ b/main/src/cgeo/geocaching/files/LocalStorage.java @@ -1,6 +1,5 @@ package cgeo.geocaching.files; -import cgeo.geocaching.Settings; import cgeo.geocaching.utils.CryptUtils; import cgeo.geocaching.utils.Log; @@ -159,7 +158,7 @@ public class LocalStorage { saveHeader("last-modified", response, targetFile); return saved; } catch (IOException e) { - Log.e(Settings.tag, "LocalStorage.saveEntityToFile", e); + Log.e("LocalStorage.saveEntityToFile", e); } return false; @@ -203,7 +202,7 @@ public class LocalStorage { } catch (final FileNotFoundException e) { // Do nothing, the file does not exist } catch (final Exception e) { - Log.w(Settings.tag, "could not read saved header " + name + " for " + baseFile, e); + Log.w("could not read saved header " + name + " for " + baseFile, e); } return null; } @@ -234,7 +233,7 @@ public class LocalStorage { inputStream.close(); } } catch (IOException e) { - Log.e(Settings.tag, "LocalStorage.saveToFile", e); + Log.e("LocalStorage.saveToFile", e); } return false; } @@ -257,7 +256,7 @@ public class LocalStorage { input = new FileInputStream(source); output = new FileOutputStream(destination); } catch (FileNotFoundException e) { - Log.e(Settings.tag, "LocalStorage.copy: could not open file", e); + Log.e("LocalStorage.copy: could not open file", e); if (input != null) { try { input.close(); @@ -274,7 +273,7 @@ public class LocalStorage { input.close(); output.close(); } catch (IOException e) { - Log.e(Settings.tag, "LocalStorage.copy: could not close file", e); + Log.e("LocalStorage.copy: could not close file", e); return false; } @@ -291,7 +290,7 @@ public class LocalStorage { // Flushing is only necessary if the stream is not immediately closed afterwards. // We rely on all callers to do that correctly outside of this method } catch (IOException e) { - Log.e(Settings.tag, "LocalStorage.copy: error when copying data", e); + Log.e("LocalStorage.copy: error when copying data", e); return false; } diff --git a/main/src/cgeo/geocaching/filter/AbstractFilter.java b/main/src/cgeo/geocaching/filter/AbstractFilter.java index 49cf84a..e9f9003 100644 --- a/main/src/cgeo/geocaching/filter/AbstractFilter.java +++ b/main/src/cgeo/geocaching/filter/AbstractFilter.java @@ -26,4 +26,14 @@ abstract class AbstractFilter implements IFilter { public String getName() { return name; } + + /* + * show name in array adapter + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return getName(); + } } diff --git a/main/src/cgeo/geocaching/filter/AbstractRangeFilter.java b/main/src/cgeo/geocaching/filter/AbstractRangeFilter.java new file mode 100644 index 0000000..ff3fce5 --- /dev/null +++ b/main/src/cgeo/geocaching/filter/AbstractRangeFilter.java @@ -0,0 +1,16 @@ +package cgeo.geocaching.filter; + +import cgeo.geocaching.cgeoapplication; + + +abstract class AbstractRangeFilter extends AbstractFilter { + + protected final float rangeMin; + protected final float rangeMax; + + public AbstractRangeFilter(int ressourceId, int range) { + super(cgeoapplication.getInstance().getResources().getString(ressourceId) + ' ' + (range == 5 ? '5' : String.valueOf(range) + " + " + String.format("%.1f", range + 0.5))); + this.rangeMin = range; + rangeMax = rangeMin + 1f; + } +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/filter/AttributeFilter.java b/main/src/cgeo/geocaching/filter/AttributeFilter.java index 0ef0787..2565178 100644 --- a/main/src/cgeo/geocaching/filter/AttributeFilter.java +++ b/main/src/cgeo/geocaching/filter/AttributeFilter.java @@ -11,7 +11,7 @@ import android.content.res.Resources; import java.util.EnumSet; -public class AttributeFilter extends AbstractFilter { +class AttributeFilter extends AbstractFilter { private final String attribute; @@ -34,20 +34,27 @@ public class AttributeFilter extends AbstractFilter { @Override public boolean accepts(final cgCache cache) { - final cgCache fullCache = cgeoapplication.getInstance().loadCache(cache.getGeocode(), EnumSet.of(LoadFlag.LOAD_ATTRIBUTES)); + cgCache fullCache = cgeoapplication.getInstance().loadCache(cache.getGeocode(), EnumSet.of(LoadFlag.LOAD_ATTRIBUTES)); + if (fullCache == null) { + fullCache = cache; + } return fullCache.getAttributes().contains(attribute); } - public static IFilter[] getAllFilters() { - final String packageName = cgeoapplication.getInstance().getBaseContext().getPackageName(); - final Resources res = cgeoapplication.getInstance().getResources(); + public static class Factory implements IFilterFactory { + + @Override + public IFilter[] getFilters() { + final String packageName = cgeoapplication.getInstance().getBaseContext().getPackageName(); + final Resources res = cgeoapplication.getInstance().getResources(); - final String[] ids = res.getStringArray(R.array.attribute_ids); - final IFilter[] filters = new IFilter[ids.length]; - for (int i = 0; i < ids.length; i++) { - filters[i] = new AttributeFilter(getName("attribute_" + ids[i], res, packageName), ids[i]); + final String[] ids = res.getStringArray(R.array.attribute_ids); + final IFilter[] filters = new IFilter[ids.length]; + for (int i = 0; i < ids.length; i++) { + filters[i] = new AttributeFilter(getName("attribute_" + ids[i], res, packageName), ids[i]); + } + return filters; } - return filters; - } + } } diff --git a/main/src/cgeo/geocaching/filter/DifficultyFilter.java b/main/src/cgeo/geocaching/filter/DifficultyFilter.java new file mode 100644 index 0000000..368c20f --- /dev/null +++ b/main/src/cgeo/geocaching/filter/DifficultyFilter.java @@ -0,0 +1,31 @@ +package cgeo.geocaching.filter; + +import cgeo.geocaching.R; +import cgeo.geocaching.cgCache; + +import java.util.ArrayList; + +class DifficultyFilter extends AbstractRangeFilter { + + public DifficultyFilter(int difficulty) { + super(R.string.cache_difficulty, difficulty); + } + + @Override + public boolean accepts(cgCache cache) { + return rangeMin <= cache.getDifficulty() && cache.getDifficulty() < rangeMax; + } + + public static class Factory implements IFilterFactory { + + @Override + public IFilter[] getFilters() { + final ArrayList<IFilter> filters = new ArrayList<IFilter>(5); + for (int difficulty = 1; difficulty <= 5; difficulty++) { + filters.add(new DifficultyFilter(difficulty)); + } + return filters.toArray(new IFilter[filters.size()]); + } + + } +} diff --git a/main/src/cgeo/geocaching/filter/FilterUserInterface.java b/main/src/cgeo/geocaching/filter/FilterUserInterface.java new file mode 100644 index 0000000..1d22e52 --- /dev/null +++ b/main/src/cgeo/geocaching/filter/FilterUserInterface.java @@ -0,0 +1,122 @@ +package cgeo.geocaching.filter; + +import cgeo.geocaching.R; +import cgeo.geocaching.Settings; +import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.activity.IAbstractActivity; +import cgeo.geocaching.enumerations.CacheType; +import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.RunnableWithArgument; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.res.Resources; +import android.widget.ArrayAdapter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +public final class FilterUserInterface { + + private static class FactoryEntry { + private final String name; + private final Class<? extends IFilterFactory> filterFactory; + + public FactoryEntry(final String name, final Class<? extends IFilterFactory> filterFactory) { + this.name = name; + this.filterFactory = filterFactory; + } + + @Override + public String toString() { + return name; + } + } + + private final IAbstractActivity activity; + private final ArrayList<FactoryEntry> registry; + private final Resources res; + + public FilterUserInterface(final IAbstractActivity activity) { + this.activity = activity; + this.res = cgeoapplication.getInstance().getResources(); + + registry = new ArrayList<FactoryEntry>(); + if (Settings.getCacheType() == CacheType.ALL) { + register(R.string.caches_filter_type, TypeFilter.Factory.class); + } + register(R.string.caches_filter_size, SizeFilter.Factory.class); + register(R.string.cache_terrain, TerrainFilter.Factory.class); + register(R.string.cache_difficulty, DifficultyFilter.Factory.class); + register(R.string.cache_attributes, AttributeFilter.Factory.class); + register(R.string.cache_status, StateFilter.Factory.class); + register(R.string.caches_filter_track, TrackablesFilter.class); + register(R.string.caches_filter_modified, ModifiedFilter.class); + + // sort by localized names + Collections.sort(registry, new Comparator<FactoryEntry>() { + + @Override + public int compare(FactoryEntry lhs, FactoryEntry rhs) { + return lhs.name.compareToIgnoreCase(rhs.name); + } + }); + + // reset shall be last + register(R.string.caches_filter_clear, null); + } + + private void register(int resourceId, Class<? extends IFilterFactory> factoryClass) { + registry.add(new FactoryEntry(res.getString(resourceId), factoryClass)); + } + + public void selectFilter(final RunnableWithArgument<IFilter> runAfterwards) { + final AlertDialog.Builder builder = new AlertDialog.Builder((Activity) activity); + builder.setTitle(R.string.caches_filter); + + final ArrayAdapter<FactoryEntry> adapter = new ArrayAdapter<FactoryEntry>((Activity) activity, android.R.layout.select_dialog_item, registry); + + builder.setAdapter(adapter, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int itemIndex) { + FactoryEntry entry = adapter.getItem(itemIndex); + // reset? + if (entry.filterFactory == null) { + runAfterwards.run(null); + } + else { + try { + IFilterFactory factoryInstance = entry.filterFactory.newInstance(); + selectFromFactory(factoryInstance, entry.name, runAfterwards); + } catch (Exception e) { + Log.e("selectFilter", e); + } + } + } + }); + + builder.create().show(); + } + + private void selectFromFactory(final IFilterFactory factory, final String menuTitle, final RunnableWithArgument<IFilter> runAfterwards) { + final IFilter[] filters = factory.getFilters(); + if (filters.length == 1) { + runAfterwards.run(filters[0]); + return; + } + + final AlertDialog.Builder builder = new AlertDialog.Builder((Activity) activity); + builder.setTitle(menuTitle); + + final ArrayAdapter<IFilter> adapter = new ArrayAdapter<IFilter>((Activity) activity, android.R.layout.select_dialog_item, filters); + builder.setAdapter(adapter, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int item) { + runAfterwards.run(filters[item]); + } + }); + + builder.create().show(); + } + +} diff --git a/main/src/cgeo/geocaching/filter/IFilterFactory.java b/main/src/cgeo/geocaching/filter/IFilterFactory.java new file mode 100644 index 0000000..3491fd7 --- /dev/null +++ b/main/src/cgeo/geocaching/filter/IFilterFactory.java @@ -0,0 +1,5 @@ +package cgeo.geocaching.filter; + +interface IFilterFactory { + public IFilter[] getFilters(); +} diff --git a/main/src/cgeo/geocaching/filter/ModifiedFilter.java b/main/src/cgeo/geocaching/filter/ModifiedFilter.java index 6063f58..f74bb4d 100644 --- a/main/src/cgeo/geocaching/filter/ModifiedFilter.java +++ b/main/src/cgeo/geocaching/filter/ModifiedFilter.java @@ -1,11 +1,13 @@ package cgeo.geocaching.filter; +import cgeo.geocaching.R; import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgeoapplication; -public class ModifiedFilter extends AbstractFilter { +class ModifiedFilter extends AbstractFilter implements IFilterFactory { - public ModifiedFilter(String name) { - super(name); + public ModifiedFilter() { + super(cgeoapplication.getInstance().getString(R.string.caches_filter_modified)); } @Override @@ -13,4 +15,9 @@ public class ModifiedFilter extends AbstractFilter { // modified on GC return cache.hasUserModifiedCoords() || cache.hasFinalDefined(); } + + @Override + public IFilter[] getFilters() { + return new IFilter[] { this }; + } } diff --git a/main/src/cgeo/geocaching/filter/SizeFilter.java b/main/src/cgeo/geocaching/filter/SizeFilter.java index 4f0d830..b08c2ae 100644 --- a/main/src/cgeo/geocaching/filter/SizeFilter.java +++ b/main/src/cgeo/geocaching/filter/SizeFilter.java @@ -5,7 +5,7 @@ import cgeo.geocaching.enumerations.CacheSize; import java.util.ArrayList; -public class SizeFilter extends AbstractFilter { +class SizeFilter extends AbstractFilter { private final CacheSize cacheSize; public SizeFilter(CacheSize cacheSize) { @@ -23,14 +23,19 @@ public class SizeFilter extends AbstractFilter { return cacheSize.getL10n(); } - public static AbstractFilter[] getAllFilters() { - final CacheSize[] cacheSizes = CacheSize.values(); - ArrayList<SizeFilter> filters = new ArrayList<SizeFilter>(); - for (CacheSize cacheSize : cacheSizes) { - if (cacheSize != CacheSize.UNKNOWN) { - filters.add(new SizeFilter(cacheSize)); + public static class Factory implements IFilterFactory { + + @Override + public IFilter[] getFilters() { + final CacheSize[] cacheSizes = CacheSize.values(); + final ArrayList<SizeFilter> filters = new ArrayList<SizeFilter>(); + for (CacheSize cacheSize : cacheSizes) { + if (cacheSize != CacheSize.UNKNOWN) { + filters.add(new SizeFilter(cacheSize)); + } } + return filters.toArray(new SizeFilter[filters.size()]); } - return filters.toArray(new SizeFilter[filters.size()]); + } } diff --git a/main/src/cgeo/geocaching/filter/StateFilter.java b/main/src/cgeo/geocaching/filter/StateFilter.java index 454cc92..b086477 100644 --- a/main/src/cgeo/geocaching/filter/StateFilter.java +++ b/main/src/cgeo/geocaching/filter/StateFilter.java @@ -10,16 +10,18 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -public abstract class StateFilter extends AbstractFilter { +abstract class StateFilter extends AbstractFilter { - public StateFilter(String name) { + final static Resources res = cgeoapplication.getInstance().getResources(); + + protected StateFilter(String name) { super(name); } - private static class StateFoundFilter extends StateFilter { + static class StateFoundFilter extends StateFilter { - public StateFoundFilter(String name) { - super(name); + public StateFoundFilter() { + super(res.getString(R.string.cache_status_found)); } @Override @@ -29,9 +31,9 @@ public abstract class StateFilter extends AbstractFilter { } - private static class StateArchivedFilter extends StateFilter { - public StateArchivedFilter(String name) { - super(name); + static class StateArchivedFilter extends StateFilter { + public StateArchivedFilter() { + super(res.getString(R.string.cache_status_archived)); } @Override @@ -40,9 +42,9 @@ public abstract class StateFilter extends AbstractFilter { } } - private static class StateDisabledFilter extends StateFilter { - public StateDisabledFilter(String name) { - super(name); + static class StateDisabledFilter extends StateFilter { + public StateDisabledFilter() { + super(res.getString(R.string.cache_status_disabled)); } @Override @@ -51,9 +53,9 @@ public abstract class StateFilter extends AbstractFilter { } } - private static class StatePremiumFilter extends StateFilter { - public StatePremiumFilter(String name) { - super(name); + static class StatePremiumFilter extends StateFilter { + public StatePremiumFilter() { + super(res.getString(R.string.cache_status_premium)); } @Override @@ -63,8 +65,8 @@ public abstract class StateFilter extends AbstractFilter { } private static class StateOfflineLogFilter extends StateFilter { - public StateOfflineLogFilter(String name) { - super(name); + public StateOfflineLogFilter() { + super(res.getString(R.string.cache_status_offline_log)); } @Override @@ -73,24 +75,28 @@ public abstract class StateFilter extends AbstractFilter { } } - public static AbstractFilter[] getAllFilters() { - final Resources res = cgeoapplication.getInstance().getResources(); - final ArrayList<StateFilter> filters = new ArrayList<StateFilter>(); - filters.add(new StateFoundFilter(res.getString(R.string.cache_status_found))); - filters.add(new StateArchivedFilter(res.getString(R.string.cache_status_archived))); - filters.add(new StateDisabledFilter(res.getString(R.string.cache_status_disabled))); - filters.add(new StatePremiumFilter(res.getString(R.string.cache_status_premium))); - filters.add(new StateOfflineLogFilter(res.getString(R.string.cache_status_offline_log))); - - Collections.sort(filters, new Comparator<StateFilter>() { + public static class Factory implements IFilterFactory { - @Override - public int compare(StateFilter filter1, StateFilter filter2) { - return filter1.getName().compareToIgnoreCase(filter2.getName()); - } - }); + @Override + public IFilter[] getFilters() { + final ArrayList<StateFilter> filters = new ArrayList<StateFilter>(); + filters.add(new StateFoundFilter()); + filters.add(new StateArchivedFilter()); + filters.add(new StateDisabledFilter()); + filters.add(new StatePremiumFilter()); + filters.add(new StateOfflineLogFilter()); + + Collections.sort(filters, new Comparator<StateFilter>() { + + @Override + public int compare(StateFilter filter1, StateFilter filter2) { + return filter1.getName().compareToIgnoreCase(filter2.getName()); + } + }); + + return filters.toArray(new StateFilter[filters.size()]); + } - return filters.toArray(new StateFilter[filters.size()]); } } diff --git a/main/src/cgeo/geocaching/filter/TerrainFilter.java b/main/src/cgeo/geocaching/filter/TerrainFilter.java new file mode 100644 index 0000000..5cee87e --- /dev/null +++ b/main/src/cgeo/geocaching/filter/TerrainFilter.java @@ -0,0 +1,31 @@ +package cgeo.geocaching.filter; + + +import cgeo.geocaching.R; +import cgeo.geocaching.cgCache; + +import java.util.ArrayList; + +class TerrainFilter extends AbstractRangeFilter { + + public TerrainFilter(int terrain) { + super(R.string.cache_terrain, terrain); + } + + @Override + public boolean accepts(cgCache cache) { + return rangeMin <= cache.getTerrain() && cache.getTerrain() < rangeMax; + } + + public static class Factory implements IFilterFactory { + @Override + public IFilter[] getFilters() { + final ArrayList<IFilter> filters = new ArrayList<IFilter>(5); + for (int terrain = 1; terrain <= 5; terrain++) { + filters.add(new TerrainFilter(terrain)); + } + return filters.toArray(new IFilter[filters.size()]); + } + } + +} diff --git a/main/src/cgeo/geocaching/filter/TrackablesFilter.java b/main/src/cgeo/geocaching/filter/TrackablesFilter.java index 99d888b..90def5b 100644 --- a/main/src/cgeo/geocaching/filter/TrackablesFilter.java +++ b/main/src/cgeo/geocaching/filter/TrackablesFilter.java @@ -1,14 +1,22 @@ package cgeo.geocaching.filter; +import cgeo.geocaching.R; import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgeoapplication; -public class TrackablesFilter extends AbstractFilter { - public TrackablesFilter(String name) { - super(name); +class TrackablesFilter extends AbstractFilter implements IFilterFactory { + public TrackablesFilter() { + super(cgeoapplication.getInstance().getString(R.string.caches_filter_track)); } @Override public boolean accepts(cgCache cache) { return cache.hasTrackables(); } + + @Override + public IFilter[] getFilters() { + return new IFilter[] { this }; + } + } diff --git a/main/src/cgeo/geocaching/filter/TypeFilter.java b/main/src/cgeo/geocaching/filter/TypeFilter.java index bb32fdd..11321c7 100644 --- a/main/src/cgeo/geocaching/filter/TypeFilter.java +++ b/main/src/cgeo/geocaching/filter/TypeFilter.java @@ -5,7 +5,7 @@ import cgeo.geocaching.enumerations.CacheType; import java.util.ArrayList; -public class TypeFilter extends AbstractFilter { +class TypeFilter extends AbstractFilter { private final CacheType cacheType; public TypeFilter(final CacheType cacheType) { @@ -23,14 +23,19 @@ public class TypeFilter extends AbstractFilter { return cacheType.getL10n(); } - public static IFilter[] getAllFilters() { - final CacheType[] types = CacheType.values(); - ArrayList<IFilter> filters = new ArrayList<IFilter>(types.length); - for (CacheType cacheType : types) { - if (cacheType != CacheType.ALL) { - filters.add(new TypeFilter(cacheType)); + public static class Factory implements IFilterFactory { + + @Override + public IFilter[] getFilters() { + final CacheType[] types = CacheType.values(); + final ArrayList<IFilter> filters = new ArrayList<IFilter>(types.length); + for (CacheType cacheType : types) { + if (cacheType != CacheType.ALL) { + filters.add(new TypeFilter(cacheType)); + } } + return filters.toArray(new TypeFilter[filters.size()]); } - return filters.toArray(new TypeFilter[filters.size()]); + } } diff --git a/main/src/cgeo/geocaching/gcvote/GCVote.java b/main/src/cgeo/geocaching/gcvote/GCVote.java index 2f2f370..070be09 100644 --- a/main/src/cgeo/geocaching/gcvote/GCVote.java +++ b/main/src/cgeo/geocaching/gcvote/GCVote.java @@ -4,14 +4,13 @@ import cgeo.geocaching.Settings; import cgeo.geocaching.cgCache; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; -import cgeo.geocaching.utils.LeastRecentlyUsedCache; +import cgeo.geocaching.utils.LeastRecentlyUsedMap; import cgeo.geocaching.utils.Log; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -29,7 +28,7 @@ public final class GCVote { private static final Pattern patternVoteElement = Pattern.compile("<vote ([^>]+)>", Pattern.CASE_INSENSITIVE); private static final int MAX_CACHED_RATINGS = 1000; - private static LeastRecentlyUsedCache<String, GCVoteRating> ratingsCache = new LeastRecentlyUsedCache<String, GCVoteRating>(MAX_CACHED_RATINGS); + private static LeastRecentlyUsedMap<String, GCVoteRating> ratingsCache = new LeastRecentlyUsedMap.LruCache<String, GCVoteRating>(MAX_CACHED_RATINGS); /** * Get user rating for a given guid or geocode. For a guid first the ratings cache is checked @@ -96,7 +95,7 @@ public final class GCVote { params.put("waypoints", StringUtils.join(geocodes.toArray(), ',')); } params.put("version", "cgeo"); - final String page = Network.getResponseData(Network.request("http://gcvote.com/getVotes.php", params, false, false, false)); + final String page = Network.getResponseData(Network.getRequest("http://gcvote.com/getVotes.php", params)); if (page == null) { return null; } @@ -118,7 +117,7 @@ public final class GCVote { } } } catch (Exception e) { - Log.w(Settings.tag, "GCVote.getRating: Failed to parse guid"); + Log.w("GCVote.getRating: Failed to parse guid"); } if (guid == null) { continue; @@ -135,7 +134,7 @@ public final class GCVote { } } } catch (Exception e) { - Log.w(Settings.tag, "GCVote.getRating: Failed to parse loggedIn"); + Log.w("GCVote.getRating: Failed to parse loggedIn"); } float rating = 0; @@ -145,7 +144,7 @@ public final class GCVote { rating = Float.parseFloat(matcherRating.group(1)); } } catch (Exception e) { - Log.w(Settings.tag, "GCVote.getRating: Failed to parse rating"); + Log.w("GCVote.getRating: Failed to parse rating"); } if (rating <= 0) { continue; @@ -158,7 +157,7 @@ public final class GCVote { votes = Integer.parseInt(matcherVotes.group(1)); } } catch (Exception e) { - Log.w(Settings.tag, "GCVote.getRating: Failed to parse vote count"); + Log.w("GCVote.getRating: Failed to parse vote count"); } if (votes < 0) { continue; @@ -172,7 +171,7 @@ public final class GCVote { myVote = Float.parseFloat(matcherVote.group(1)); } } catch (Exception e) { - Log.w(Settings.tag, "GCVote.getRating: Failed to parse user's vote"); + Log.w("GCVote.getRating: Failed to parse user's vote"); } } @@ -183,7 +182,7 @@ public final class GCVote { } } } catch (Exception e) { - Log.e(Settings.tag, "GCVote.getRating: " + e.toString()); + Log.e("GCVote.getRating: " + e.toString()); } return ratings; @@ -220,7 +219,7 @@ public final class GCVote { "voteUser", String.format("%.1f", vote).replace(',', '.'), "version", "cgeo"); - final String result = Network.getResponseData(Network.request("http://gcvote.com/setVote.php", params, false, false, false)); + final String result = Network.getResponseData(Network.getRequest("http://gcvote.com/setVote.php", params)); return result.trim().equalsIgnoreCase("ok"); } @@ -258,7 +257,7 @@ public final class GCVote { } } } catch (Exception e) { - Log.e(Settings.tag, "GCvote.loadRatings: " + e.toString()); + Log.e("GCvote.loadRatings: " + e.toString()); } } } diff --git a/main/src/cgeo/geocaching/geopoint/Geopoint.java b/main/src/cgeo/geocaching/geopoint/Geopoint.java index ef08401..ff97a4c 100644 --- a/main/src/cgeo/geocaching/geopoint/Geopoint.java +++ b/main/src/cgeo/geocaching/geopoint/Geopoint.java @@ -1,6 +1,6 @@ package cgeo.geocaching.geopoint; -import cgeo.geocaching.Settings; +import cgeo.geocaching.ICoordinates; import cgeo.geocaching.geopoint.GeopointFormatter.Format; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; @@ -11,6 +11,8 @@ import org.json.JSONArray; import org.json.JSONObject; import android.location.Location; +import android.os.Parcel; +import android.os.Parcelable; import java.math.BigDecimal; import java.math.RoundingMode; @@ -18,8 +20,7 @@ import java.math.RoundingMode; /** * Abstraction of geographic point. */ -public final class Geopoint -{ +public final class Geopoint implements ICoordinates, Parcelable { public static final double deg2rad = Math.PI / 180; public static final double rad2deg = 180 / Math.PI; public static final float erad = 6371.0f; @@ -47,19 +48,6 @@ public final class Geopoint } /** - * Creates new Geopoint with given latitude and longitude (both microdegree). - * - * @param lat - * latitude - * @param lon - * longitude - */ - public Geopoint(final int lat, final int lon) - { - this(lat / 1e6, lon / 1e6); - } - - /** * Creates new Geopoint with latitude and longitude parsed from string. * * @param text @@ -98,6 +86,17 @@ public final class Geopoint } /** + * Create new Geopoint from Parcel. + * + * @param in + * a Parcel to read the saved data from + */ + public Geopoint(final Parcel in) { + latitude = in.readDouble(); + longitude = in.readDouble(); + } + + /** * Get latitude in degree. * * @return latitude @@ -114,7 +113,7 @@ public final class Geopoint */ public int getLatitudeE6() { - return (int) (latitude * 1E6); + return (int) Math.round(latitude * 1E6); } /** @@ -134,7 +133,7 @@ public final class Geopoint */ public int getLongitudeE6() { - return (int) (longitude * 1E6); + return (int) Math.round(longitude * 1E6); } /** @@ -200,16 +199,21 @@ public final class Geopoint return new Geopoint(rlat * rad2deg, rlon * rad2deg); } - /** - * Checks if given Geopoint is identical with this Geopoint. - * - * @param gp - * Geopoint to check - * @return true if identical, false otherwise - */ - public boolean isEqualTo(Geopoint gp) - { - return null != gp && gp.latitude == latitude && gp.longitude == longitude; + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null || !(obj instanceof Geopoint)) { + return false; + } + final Geopoint gp = (Geopoint) obj; + return getLatitudeE6() == gp.getLatitudeE6() && getLongitudeE6() == gp.getLongitudeE6(); + } + + @Override + public int hashCode() { + return getLatitudeE6() ^ getLongitudeE6(); } /** @@ -242,7 +246,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 @@ -506,10 +510,38 @@ public final class Geopoint return result.getDouble("elevation"); } } catch (Exception e) { - Log.w(Settings.tag, "cgBase.getElevation: " + e.toString()); + Log.w("cgBase.getElevation: " + e.toString()); } return null; } + //FIXME: this interface implementation is totally confusing as it returns the class itself. + // it can therefore be removed completely (and any invocation of it) without any disadvantages + @Override + public Geopoint getCoords() { + return this; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(final Parcel dest, final int flags) { + dest.writeDouble(latitude); + dest.writeDouble(longitude); + } + + public static final Parcelable.Creator<Geopoint> CREATOR = new Parcelable.Creator<Geopoint>() { + public Geopoint createFromParcel(final Parcel in) { + return new Geopoint(in); + } + + public Geopoint[] newArray(final int size) { + return new Geopoint[size]; + } + }; + } diff --git a/main/src/cgeo/geocaching/geopoint/Viewport.java b/main/src/cgeo/geocaching/geopoint/Viewport.java index 390bdb4..67aed2c 100644 --- a/main/src/cgeo/geocaching/geopoint/Viewport.java +++ b/main/src/cgeo/geocaching/geopoint/Viewport.java @@ -1,7 +1,10 @@ package cgeo.geocaching.geopoint; -import cgeo.geocaching.Settings; -import cgeo.geocaching.utils.Log; +import cgeo.geocaching.ICoordinates; + +import java.util.Locale; +import java.util.Set; + public class Viewport { @@ -10,19 +13,29 @@ public class Viewport { public final Geopoint bottomLeft; public final Geopoint topRight; - public Viewport(final Geopoint bottomLeft, final Geopoint topRight) { - this.bottomLeft = bottomLeft; - this.topRight = topRight; - this.center = new Geopoint((bottomLeft.getLatitude() + topRight.getLatitude()) / 2, - (bottomLeft.getLongitude() + topRight.getLongitude()) / 2); + public Viewport(final ICoordinates point1, final ICoordinates point2) { + final Geopoint gp1 = point1.getCoords(); + final Geopoint gp2 = point2.getCoords(); + this.bottomLeft = new Geopoint(Math.min(gp1.getLatitude(), gp2.getLatitude()), + Math.min(gp1.getLongitude(), gp2.getLongitude())); + this.topRight = new Geopoint(Math.max(gp1.getLatitude(), gp2.getLatitude()), + Math.max(gp1.getLongitude(), gp2.getLongitude())); + this.center = new Geopoint((gp1.getLatitude() + gp2.getLatitude()) / 2, + (gp1.getLongitude() + gp2.getLongitude()) / 2); } - public Viewport(final Geopoint center, final double latSpan, final double lonSpan) { - this.center = center; - final double centerLat = center.getLatitude(); - final double centerLon = center.getLongitude(); - bottomLeft = new Geopoint(centerLat - latSpan / 2, centerLon - lonSpan / 2); - topRight = new Geopoint(centerLat + latSpan / 2, centerLon + lonSpan / 2); + public Viewport(final ICoordinates center, final double latSpan, final double lonSpan) { + this.center = center.getCoords(); + final double centerLat = this.center.getLatitude(); + final double centerLon = this.center.getLongitude(); + final double latHalfSpan = Math.abs(latSpan) / 2; + final double lonHalfSpan = Math.abs(lonSpan) / 2; + bottomLeft = new Geopoint(centerLat - latHalfSpan, centerLon - lonHalfSpan); + topRight = new Geopoint(centerLat + latHalfSpan, centerLon + lonHalfSpan); + } + + public Viewport(final double lat1, final double lat2, final double lon1, final double lon2) { + this(new Geopoint(lat1, lon1), new Geopoint(lat2, lon2)); } public double getLatitudeMin() { @@ -45,78 +58,125 @@ public class Viewport { return center; } + public double getLatitudeSpan() { + return getLatitudeMax() - getLatitudeMin(); + } + + public double getLongitudeSpan() { + return getLongitudeMax() - getLongitudeMin(); + } + + /** + * Check whether a point is contained in this viewport. + * + * @param point + * the coordinates to check + * @return true if the point is contained in this viewport, false otherwise + */ + public boolean contains(final ICoordinates point) { + final Geopoint coords = point.getCoords(); + return coords.getLongitudeE6() >= bottomLeft.getLongitudeE6() + && coords.getLongitudeE6() <= topRight.getLongitudeE6() + && coords.getLatitudeE6() >= bottomLeft.getLatitudeE6() + && coords.getLatitudeE6() <= topRight.getLatitudeE6(); + } + @Override public String toString() { return "(" + bottomLeft.toString() + "," + topRight.toString() + ")"; } /** - * Check if coordinates are located in a viewport (defined by its center and span - * in each direction). + * Check whether another viewport is fully included into the current one. * - * @param centerLat - * the viewport center latitude - * @param centerLon - * the viewport center longitude - * @param spanLat - * the latitude span - * @param spanLon - * the longitude span - * @param coords - * the coordinates to check - * @return true if the coordinates are in the viewport + * @param vp + * the other viewport + * @return true if the vp is fully included into this one, false otherwise */ - public static boolean isCacheInViewPort(int centerLat, int centerLon, int spanLat, int spanLon, final Geopoint coords) { - return 2 * Math.abs(coords.getLatitudeE6() - centerLat) <= Math.abs(spanLat) && - 2 * Math.abs(coords.getLongitudeE6() - centerLon) <= Math.abs(spanLon); + public boolean includes(final Viewport vp) { + return contains(vp.bottomLeft) && contains(vp.topRight); } /** - * Check if an area is located in a viewport (defined by its center and span - * in each direction). - * - * expects coordinates in E6 format + * Return the "where" part of the string appropriate for a SQL query. * - * @param centerLat1 - * @param centerLon1 - * @param centerLat2 - * @param centerLon2 - * @param spanLat1 - * @param spanLon1 - * @param spanLat2 - * @param spanLon2 - * @return + * @param dbTable + * the database table to use as prefix, or null if no prefix is required + * @return the string without the "where" keyword */ - public static boolean isInViewPort(int centerLat1, int centerLon1, int centerLat2, int centerLon2, int spanLat1, int spanLon1, int spanLat2, int spanLon2) { - try { - final int left1 = centerLat1 - (spanLat1 / 2); - final int left2 = centerLat2 - (spanLat2 / 2); - if (left2 <= left1) { - return false; - } + public String sqlWhere(final String dbTable) { + final String prefix = dbTable == null ? "" : (dbTable + "."); + return String.format((Locale) null, + "%slatitude >= %s and %slatitude <= %s and %slongitude >= %s and %slongitude <= %s", + prefix, getLatitudeMin(), prefix, getLatitudeMax(), prefix, getLongitudeMin(), prefix, getLongitudeMax()); + } - final int right1 = centerLat1 + (spanLat1 / 2); - final int right2 = centerLat2 + (spanLat2 / 2); - if (right2 >= right1) { - return false; - } + /** + * Return a widened or shrunk viewport. + * + * @param factor + * multiplicative factor for the latitude and longitude span (> 1 to widen, < 1 to shrink) + * @return a widened or shrunk viewport + */ + public Viewport resize(final double factor) { + return new Viewport(getCenter(), getLatitudeSpan() * factor, getLongitudeSpan() * factor); + } - final int top1 = centerLon1 + (spanLon1 / 2); - final int top2 = centerLon2 + (spanLon2 / 2); - if (top2 >= top1) { - return false; - } + /** + * Return a viewport that contains the current viewport as well as another point. + * + * @param coords + * the point we want in the viewport + * @return either the same or an expanded viewport + */ + public Viewport expand(final ICoordinates point) { + if (contains(point)) { + return this; + } else { + final Geopoint coords = point.getCoords(); + final double latitude = coords.getLatitude(); + final double longitude = coords.getLongitude(); + final double latMin = Math.min(getLatitudeMin(), latitude); + final double latMax = Math.max(getLatitudeMax(), latitude); + final double lonMin = Math.min(getLongitudeMin(), longitude); + final double lonMax = Math.max(getLongitudeMax(), longitude); + return new Viewport(new Geopoint(latMin, lonMin), new Geopoint(latMax, lonMax)); + } + } - final int bottom1 = centerLon1 - (spanLon1 / 2); - final int bottom2 = centerLon2 - (spanLon2 / 2); - if (bottom2 <= bottom1) { - return false; + /** + * Return the smallest viewport containing all the given points. + * + * @param points + * a set of points. Point with null coordinates (or null themselves) will be ignored + * @return the smallest viewport containing the non-null coordinates, or null if no coordinates are non-null + */ + static public Viewport containing(final Set<? extends ICoordinates> points) { + Viewport viewport = null; + for (final ICoordinates point : points) { + final Geopoint coords = point == null ? null : point.getCoords(); + if (coords != null) { + if (viewport == null) { + viewport = new Viewport(coords, coords); + } else { + viewport = viewport.expand(coords); + } } + } + return viewport; + } - return true; - } catch (Exception e) { - Log.e(Settings.tag, "Viewport.isInViewPort: " + e.toString()); + @Override + public boolean equals(final Object other) { + if (other == null || !(other instanceof Viewport)) { return false; } + final Viewport vp = (Viewport) other; + return bottomLeft.equals(vp.bottomLeft) && topRight.equals(vp.topRight); + } + + @Override + public int hashCode() { + return bottomLeft.hashCode() ^ topRight.hashCode(); } } diff --git a/main/src/cgeo/geocaching/go4cache/Go4Cache.java b/main/src/cgeo/geocaching/go4cache/Go4Cache.java index 6271245..b0a7b35 100644 --- a/main/src/cgeo/geocaching/go4cache/Go4Cache.java +++ b/main/src/cgeo/geocaching/go4cache/Go4Cache.java @@ -1,7 +1,6 @@ package cgeo.geocaching.go4cache; import cgeo.geocaching.Settings; -import cgeo.geocaching.cgBase; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter.Format; @@ -16,6 +15,8 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -41,6 +42,7 @@ public final class Go4Cache extends Thread { private final static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 2010-07-25 14:44:01 final private ArrayBlockingQueue<Geopoint> queue = new ArrayBlockingQueue<Geopoint>(1); + private String packageVersion; public static Go4Cache getInstance() { // no need to be synchronized return InstanceHolder.INSTANCE; @@ -48,10 +50,22 @@ public final class Go4Cache extends Thread { private Go4Cache() { // private singleton constructor super("Go4Cache"); + initializeVersion(); setPriority(Thread.MIN_PRIORITY); start(); } + private void initializeVersion() { + try { + final PackageManager manager = cgeoapplication.getInstance().getPackageManager(); + final PackageInfo info = manager.getPackageInfo(cgeoapplication.getInstance().getPackageName(), 0); + packageVersion = info.versionName; + } catch (PackageManager.NameNotFoundException e) { + Log.e("unable to get version information", e); + packageVersion = null; + } + } + /** * Send the coordinates to go4cache.com if the user opted in to do so. * @@ -68,7 +82,7 @@ public final class Go4Cache extends Thread { @Override public void run() { - Log.d(Settings.tag, "Go4Cache task started"); + Log.d("Go4Cache task started"); Geopoint latestCoords = null; String latestAction = null; @@ -96,8 +110,8 @@ public final class Go4Cache extends Thread { "ln", lonStr, "a", currentAction, "s", (CryptUtils.sha1(username + "|" + latStr + "|" + lonStr + "|" + currentAction + "|" + CryptUtils.md5("carnero: developing your dreams"))).toLowerCase()); - if (null != cgBase.version) { - params.put("v", cgBase.version); + if (null != packageVersion) { + params.put("v", packageVersion); } Network.postRequest("http://api.go4cache.com/", params); @@ -108,7 +122,7 @@ public final class Go4Cache extends Thread { latestAction = currentAction; } } catch (InterruptedException e) { - Log.e(Settings.tag, "Go4Cache.run: interrupted", e); + Log.e("Go4Cache.run: interrupted", e); } } @@ -138,7 +152,7 @@ public final class Go4Cache extends Thread { 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"); + Log.e("cgeoBase.getGeocachersInViewport: No data from server"); return null; } @@ -150,7 +164,7 @@ public final class Go4Cache extends Thread { users.add(parseUser(oneUser)); } } catch (Exception e) { - Log.e(Settings.tag, "cgBase.getGeocachersInViewport: " + e.toString()); + Log.e("cgBase.getGeocachersInViewport: " + e.toString()); } return Collections.unmodifiableList(users); diff --git a/main/src/cgeo/geocaching/maps/AbstractMap.java b/main/src/cgeo/geocaching/maps/AbstractMap.java index 4fc99a5..ae5b57b 100644 --- a/main/src/cgeo/geocaching/maps/AbstractMap.java +++ b/main/src/cgeo/geocaching/maps/AbstractMap.java @@ -68,4 +68,6 @@ public abstract class AbstractMap { public abstract void goManual(View view); + public abstract void onSaveInstanceState(final Bundle outState); + } diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java index e424bcc..7c70266 100644 --- a/main/src/cgeo/geocaching/maps/CGeoMap.java +++ b/main/src/cgeo/geocaching/maps/CGeoMap.java @@ -8,7 +8,6 @@ import cgeo.geocaching.Settings; import cgeo.geocaching.StoredList; import cgeo.geocaching.UpdateDirectionCallback; import cgeo.geocaching.UpdateLocationCallback; -import cgeo.geocaching.cgBase; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgDirection; import cgeo.geocaching.cgGeo; @@ -18,6 +17,7 @@ import cgeo.geocaching.cgeocaches; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.gc.GCBase; +import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy; import cgeo.geocaching.enumerations.LoadFlags; @@ -35,9 +35,8 @@ 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.BoundedList; import cgeo.geocaching.utils.CancellableHandler; +import cgeo.geocaching.utils.LeastRecentlyUsedSet; import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; @@ -95,8 +94,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto //Menu private static final String EXTRAS_GEOCODE = "geocode"; - private static final String EXTRAS_LONGITUDE = "longitude"; - private static final String EXTRAS_LATITUDE = "latitude"; + private static final String EXTRAS_COORDS = "coords"; private static final String EXTRAS_WPTTYPE = "wpttype"; private static final String EXTRAS_MAPSTATE = "mapstate"; private static final String EXTRAS_SEARCH = "search"; @@ -115,6 +113,9 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private static final String EXTRAS_MAP_TITLE = "mapTitle"; + private static final String BUNDLE_MAP_SOURCE = "mapSource"; + private static final String BUNDLE_MAP_STATE = "mapState"; + private Resources res = null; private MapProvider mapProvider = null; private Activity activity = null; @@ -136,14 +137,8 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private boolean noMapTokenShowed = false; // map status data private boolean followMyLocation = false; - private Integer centerLatitude = null; - private Integer centerLongitude = null; - private Integer spanLatitude = null; - private Integer spanLongitude = null; - private Integer centerLatitudeUsers = null; - private Integer centerLongitudeUsers = null; - private Integer spanLatitudeUsers = null; - private Integer spanLongitudeUsers = null; + private Viewport viewport = null; + private Viewport viewportUsers = null; private int zoom = -100; // threads private LoadTimer loadTimer = null; @@ -171,7 +166,9 @@ 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 final BoundedList<cgCache> caches = new BoundedList<cgCache>(MAX_CACHES); + private final LeastRecentlyUsedSet<cgCache> caches = new LeastRecentlyUsedSet<cgCache>(MAX_CACHES); + /** List of waypoints in the viewport */ + private final LeastRecentlyUsedSet<cgWaypoint> waypoints = new LeastRecentlyUsedSet<cgWaypoint>(MAX_CACHES); // storing for offline private ProgressDialog waitDialog = null; private int detailTotal = 0; @@ -327,24 +324,23 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto */ private String mapTitle; + /* Current source id */ + private int currentSourceId; + public CGeoMap(MapActivityImpl activity) { super(activity); } protected void countVisibleCaches() { - final ArrayList<cgCache> protectedCaches = new ArrayList<cgCache>(caches); + final List<cgCache> protectedCaches = caches.getAsList(); 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(); + final Viewport viewport = mapView.getViewport(); - for (cgCache cache : protectedCaches) { + for (final cgCache cache : protectedCaches) { if (cache != null && cache.getCoords() != null) { - if (Viewport.isCacheInViewPort(mapCenterLat, mapCenterLon, mapSpanLat, mapSpanLon, cache.getCoords())) { + if (viewport.contains(cache)) { count++; } } @@ -354,6 +350,12 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } @Override + public void onSaveInstanceState(final Bundle outState) { + outState.putInt(BUNDLE_MAP_SOURCE, currentSourceId); + outState.putIntArray(BUNDLE_MAP_STATE, currentMapState()); + } + + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -363,6 +365,34 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto app = (cgeoapplication) activity.getApplication(); mapProvider = Settings.getMapProvider(); + + // Get parameters from the intent + final Bundle extras = activity.getIntent().getExtras(); + if (extras != null) { + searchIntent = (SearchResult) extras.getParcelable(EXTRAS_SEARCH); + geocodeIntent = extras.getString(EXTRAS_GEOCODE); + coordsIntent = (Geopoint) extras.getParcelable(EXTRAS_COORDS); + waypointTypeIntent = WaypointType.findById(extras.getString(EXTRAS_WPTTYPE)); + mapStateIntent = extras.getIntArray(EXTRAS_MAPSTATE); + mapTitle = extras.getString(EXTRAS_MAP_TITLE); + } + if (StringUtils.isBlank(mapTitle)) { + mapTitle = res.getString(R.string.map_map); + } + + // Get fresh map information from the bundle if any + if (savedInstanceState != null) { + currentSourceId = savedInstanceState.getInt(BUNDLE_MAP_SOURCE, Settings.getMapSource()); + mapStateIntent = savedInstanceState.getIntArray(BUNDLE_MAP_STATE); + } else { + currentSourceId = Settings.getMapSource(); + } + + // If recreating from an obsolete map source, we may need a restart + if (changeMapSource(Settings.getMapSource())) { + return; + } + // reset status noMapTokenShowed = false; @@ -420,26 +450,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto dirUpdate.updateDirection(dir); } - // get parameters - Bundle extras = activity.getIntent().getExtras(); - if (extras != null) { - searchIntent = (SearchResult) extras.getParcelable(EXTRAS_SEARCH); - geocodeIntent = extras.getString(EXTRAS_GEOCODE); - final double latitudeIntent = extras.getDouble(EXTRAS_LATITUDE); - final double longitudeIntent = extras.getDouble(EXTRAS_LONGITUDE); - coordsIntent = new Geopoint(latitudeIntent, longitudeIntent); - waypointTypeIntent = WaypointType.findById(extras.getString(EXTRAS_WPTTYPE)); - mapStateIntent = extras.getIntArray(EXTRAS_MAPSTATE); - mapTitle = extras.getString(EXTRAS_MAP_TITLE); - - if (coordsIntent.getLatitude() == 0.0 || coordsIntent.getLongitude() == 0.0) { - coordsIntent = null; - } - } - - if (StringUtils.isBlank(mapTitle)) { - mapTitle = res.getString(R.string.map_map); - } // live map, if no arguments are given live = (searchIntent == null && geocodeIntent == null && coordsIntent == null); @@ -447,7 +457,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (null == mapStateIntent) { followMyLocation = live; } else { - followMyLocation = 1 == mapStateIntent[3] ? true : false; + followMyLocation = 1 == mapStateIntent[3]; } if (geocodeIntent != null || searchIntent != null || coordsIntent != null || mapStateIntent != null) { centerMap(geocodeIntent, searchIntent, coordsIntent, mapStateIntent); @@ -484,6 +494,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto public void onResume() { super.onResume(); + if (changeMapSource(Settings.getMapSource())) { + return; + } + app.setAction(StringUtils.defaultIfBlank(geocodeIntent, null)); if (geo == null) { geo = app.startGeo(geoUpdate); @@ -507,12 +521,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } dirtyCaches.clear(); // Update display - GeoPointImpl mapCenterNow = mapView.getMapViewCenter(); - int centerLatitudeNow = mapCenterNow.getLatitudeE6(); - int centerLongitudeNow = mapCenterNow.getLongitudeE6(); - int spanLatitudeNow = mapView.getLatitudeSpan(); - int spanLongitudeNow = mapView.getLongitudeSpan(); - displayExecutor.execute(new DisplayRunnable(centerLatitudeNow, centerLongitudeNow, spanLatitudeNow, spanLongitudeNow)); + displayExecutor.execute(new DisplayRunnable(mapView.getViewport())); } startTimer(); @@ -671,7 +680,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto menu.findItem(SUBMENU_STRATEGY).setEnabled(live); } catch (Exception e) { - Log.e(Settings.tag, "cgeomap.onPrepareOptionsMenu: " + e.toString()); + Log.e("cgeomap.onPrepareOptionsMenu: " + e.toString()); } return true; @@ -696,25 +705,22 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (live && !isLoading() && CollectionUtils.isNotEmpty(caches)) { final List<String> geocodes = new ArrayList<String>(); - List<cgCache> cachesProtected = new ArrayList<cgCache>(caches); + final List<cgCache> cachesProtected = caches.getAsList(); + try { if (cachesProtected.size() > 0) { - final GeoPointImpl mapCenter = mapView.getMapViewCenter(); - final int mapCenterLat = mapCenter.getLatitudeE6(); - final int mapCenterLon = mapCenter.getLongitudeE6(); - final int mapSpanLat = mapView.getLatitudeSpan(); - final int mapSpanLon = mapView.getLongitudeSpan(); + final Viewport viewport = mapView.getViewport(); - for (cgCache cache : cachesProtected) { + for (final cgCache cache : cachesProtected) { if (cache != null && cache.getCoords() != null) { - if (Viewport.isCacheInViewPort(mapCenterLat, mapCenterLon, mapSpanLat, mapSpanLon, cache.getCoords()) && !app.isOffline(cache.getGeocode(), null)) { + if (viewport.contains(cache) && !app.isOffline(cache.getGeocode(), null)) { geocodes.add(cache.getGeocode()); } } } } } catch (Exception e) { - Log.e(Settings.tag, "cgeomap.onOptionsItemSelected.#4: " + e.toString()); + Log.e("cgeomap.onOptionsItemSelected.#4: " + e.toString()); } detailTotal = geocodes.size(); @@ -748,7 +754,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto dir = app.startDir(activity, dirUpdate); } } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.onPrepareOptionsMenu.onCancel: " + e.toString()); + Log.e("cgeocaches.onPrepareOptionsMenu.onCancel: " + e.toString()); } } }); @@ -807,35 +813,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto item.setChecked(true); int mapSource = MapProviderFactory.getMapSourceFromMenuId(id); - boolean mapRestartRequired = switchMapSource(mapSource); - - if (mapRestartRequired) { - // close old mapview - activity.finish(); - - // prepare information to restart a similar view - Intent mapIntent = new Intent(activity, Settings.getMapProvider().getMapClass()); - - mapIntent.putExtra(EXTRAS_SEARCH, searchIntent); - mapIntent.putExtra(EXTRAS_GEOCODE, geocodeIntent); - if (coordsIntent != null) { - mapIntent.putExtra(EXTRAS_LATITUDE, coordsIntent.getLatitude()); - mapIntent.putExtra(EXTRAS_LONGITUDE, coordsIntent.getLongitude()); - } - mapIntent.putExtra(EXTRAS_WPTTYPE, waypointTypeIntent != null ? waypointTypeIntent.id : null); - int[] mapState = new int[4]; - GeoPointImpl mapCenter = mapView.getMapViewCenter(); - mapState[0] = mapCenter.getLatitudeE6(); - mapState[1] = mapCenter.getLongitudeE6(); - mapState[2] = mapView.getMapZoomLevel(); - mapState[3] = followMyLocation ? 1 : 0; - mapIntent.putExtra(EXTRAS_MAPSTATE, mapState); - mapIntent.putExtra(EXTRAS_MAP_TITLE, mapTitle); - - // start the new map - activity.startActivity(mapIntent); - - } + changeMapSource(mapSource); return true; } @@ -843,16 +821,72 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto return false; } - private boolean switchMapSource(int sourceId) { - boolean mapRestartRequired = !MapProviderFactory.isSameProvider(Settings.getMapSource(), sourceId); + /** + * Restart the current activity if the map provider has changed, or change the map source if needed. + * + * @param mapSource + * the new map source, which can be the same as the current one + * @return true if a restart is needed, false otherwise + */ + private boolean changeMapSource(final int mapSource) { + final boolean restartRequired = !MapProviderFactory.isSameProvider(currentSourceId, mapSource); - Settings.setMapSource(sourceId); + Settings.setMapSource(mapSource); + currentSourceId = mapSource; - if (!mapRestartRequired) { + if (restartRequired) { + mapRestart(); + } else if (mapView != null) { mapView.setMapSource(); } - return mapRestartRequired; + return restartRequired; + } + + /** + * Restart the current activity with the default map source. + */ + private void mapRestart() { + // close old mapview + activity.finish(); + + // prepare information to restart a similar view + Intent mapIntent = new Intent(activity, Settings.getMapProvider().getMapClass()); + + mapIntent.putExtra(EXTRAS_SEARCH, searchIntent); + mapIntent.putExtra(EXTRAS_GEOCODE, geocodeIntent); + if (coordsIntent != null) { + mapIntent.putExtra(EXTRAS_COORDS, coordsIntent); + } + mapIntent.putExtra(EXTRAS_WPTTYPE, waypointTypeIntent != null ? waypointTypeIntent.id : null); + mapIntent.putExtra(EXTRAS_MAP_TITLE, mapTitle); + + final int[] mapState = currentMapState(); + if (mapState != null) { + mapIntent.putExtra(EXTRAS_MAPSTATE, mapState); + } + + // start the new map + activity.startActivity(mapIntent); + } + + /** + * Get the current map state from the map view if it exists or from the mapStateIntent field otherwise. + * + * @return the current map state as an array of int, or null if no map state is available + */ + private int[] currentMapState() { + if (mapView != null) { + int[] mapState = new int[4]; + GeoPointImpl mapCenter = mapView.getMapViewCenter(); + mapState[0] = mapCenter.getLatitudeE6(); + mapState[1] = mapCenter.getLongitudeE6(); + mapState[2] = mapView.getMapZoomLevel(); + mapState[3] = followMyLocation ? 1 : 0; + return mapState; + } else { + return mapStateIntent; + } } private void savePrefs() { @@ -908,7 +942,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); + Log.w("Failed to update location."); } } } @@ -981,11 +1015,8 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (mapView != null) { // get current viewport - GeoPointImpl mapCenterNow = mapView.getMapViewCenter(); - int centerLatitudeNow = mapCenterNow.getLatitudeE6(); - int centerLongitudeNow = mapCenterNow.getLongitudeE6(); - int spanLatitudeNow = mapView.getLatitudeSpan(); - int spanLongitudeNow = mapView.getLongitudeSpan(); + final Viewport viewportNow = mapView.getViewport(); + int zoomNow = mapView.getMapZoomLevel(); // check if map moved or zoomed //TODO Portree Use Rectangle inside with bigger search window. That will stop reloading on every move @@ -995,20 +1026,16 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto moved = true; } else if (live && Settings.isLiveMap() && !downloaded) { moved = true; - } else if (centerLatitude == null || centerLongitude == null) { + } else if (viewport == null) { moved = true; - } else if (spanLatitude == null || spanLongitude == null) { + } else if (zoomNow != zoom) { moved = true; - } else if (((Math.abs(spanLatitudeNow - spanLatitude) > 50) || (Math.abs(spanLongitudeNow - spanLongitude) > 50) || // changed zoom - (Math.abs(centerLatitudeNow - centerLatitude) > (spanLatitudeNow / 4)) || (Math.abs(centerLongitudeNow - centerLongitude) > (spanLongitudeNow / 4)) // map moved - ) && (cachesCnt <= 0 || CollectionUtils.isEmpty(caches) - || !Viewport.isInViewPort(centerLatitude, centerLongitude, centerLatitudeNow, centerLongitudeNow, spanLatitude, spanLongitude, spanLatitudeNow, spanLongitudeNow))) { + } else if (mapMoved(viewport, viewportNow) && (cachesCnt <= 0 || CollectionUtils.isEmpty(caches) || !viewport.includes(viewportNow))) { moved = true; } // update title on any change - int zoomNow = mapView.getMapZoomLevel(); - if (moved || zoomNow != zoom || spanLatitudeNow != spanLatitude || spanLongitudeNow != spanLongitude || centerLatitudeNow != centerLatitude || centerLongitudeNow != centerLongitude) { + if (moved || zoomNow != zoom || !viewportNow.equals(viewport)) { displayHandler.sendEmptyMessage(UPDATE_TITLE); } zoom = zoomNow; @@ -1020,19 +1047,15 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto long currentTime = System.currentTimeMillis(); if (1000 < (currentTime - loadThreadRun)) { - centerLatitude = centerLatitudeNow; - centerLongitude = centerLongitudeNow; - spanLatitude = spanLatitudeNow; - spanLongitude = spanLongitudeNow; - - loadExecutor.execute(new LoadRunnable(centerLatitude, centerLongitude, spanLatitude, spanLongitude)); + viewport = viewportNow; + loadExecutor.execute(new LoadRunnable(viewport)); } } } yield(); } catch (Exception e) { - Log.w(Settings.tag, "cgeomap.LoadTimer.run: " + e.toString()); + Log.w("cgeomap.LoadTimer.run: " + e.toString()); } } } @@ -1069,11 +1092,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (mapView != null) { // get current viewport - GeoPointImpl mapCenterNow = mapView.getMapViewCenter(); - int centerLatitudeNow = mapCenterNow.getLatitudeE6(); - int centerLongitudeNow = mapCenterNow.getLongitudeE6(); - int spanLatitudeNow = mapView.getLatitudeSpan(); - int spanLongitudeNow = mapView.getLongitudeSpan(); + final Viewport viewportNow = mapView.getViewport(); // check if map moved or zoomed boolean moved = false; @@ -1082,30 +1101,22 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (60000 < (currentTime - go4CacheThreadRun)) { moved = true; - } else if (centerLatitudeUsers == null || centerLongitudeUsers == null) { - moved = true; - } else if (spanLatitudeUsers == null || spanLongitudeUsers == null) { + } else if (viewportUsers == null) { moved = true; - } else if (((Math.abs(spanLatitudeNow - spanLatitudeUsers) > 50) || (Math.abs(spanLongitudeNow - spanLongitudeUsers) > 50) || // changed zoom - (Math.abs(centerLatitudeNow - centerLatitudeUsers) > (spanLatitudeNow / 4)) || (Math.abs(centerLongitudeNow - centerLongitudeUsers) > (spanLongitudeNow / 4)) // map moved - ) && !Viewport.isInViewPort(centerLatitudeUsers, centerLongitudeUsers, centerLatitudeNow, centerLongitudeNow, spanLatitudeUsers, spanLongitudeUsers, spanLatitudeNow, spanLongitudeNow)) { + } else if (mapMoved(viewportUsers, viewportNow) && !viewportUsers.includes(viewportNow)) { moved = true; } // save new values if (moved && (1000 < (currentTime - go4CacheThreadRun))) { - centerLatitudeUsers = centerLatitudeNow; - centerLongitudeUsers = centerLongitudeNow; - spanLatitudeUsers = spanLatitudeNow; - spanLongitudeUsers = spanLongitudeNow; - - Go4CacheExecutor.execute(new Go4CacheRunnable(centerLatitudeNow, centerLongitudeNow, spanLatitudeNow, spanLongitudeNow)); + viewportUsers = viewportNow; + Go4CacheExecutor.execute(new Go4CacheRunnable(viewportUsers)); } } yield(); } catch (Exception e) { - Log.w(Settings.tag, "cgeomap.LoadUsersTimer.run: " + e.toString()); + Log.w("cgeomap.LoadUsersTimer.run: " + e.toString()); } } } @@ -1118,8 +1129,8 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private class LoadRunnable extends DoRunnable { - public LoadRunnable(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) { - super(centerLatIn, centerLonIn, spanLatIn, spanLonIn); + public LoadRunnable(final Viewport viewport) { + super(viewport); } @Override @@ -1138,34 +1149,50 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } else { // live map if (!live || !Settings.isLiveMap()) { - search = new SearchResult(app.getStoredInViewport(centerLat, centerLon, spanLat, spanLon, Settings.getCacheType())); + search = new SearchResult(app.getStoredInViewport(viewport, Settings.getCacheType())); } else { - search = new SearchResult(app.getCachedInViewport(centerLat, centerLon, spanLat, spanLon, Settings.getCacheType())); + search = new SearchResult(app.getCachedInViewport(viewport, Settings.getCacheType())); } } if (search != null) { downloaded = true; - caches.addAll(search.getCachesFromSearchResult(LoadFlags.LOAD_WAYPOINTS)); + Set<cgCache> cachesFromSearchResult = search.getCachesFromSearchResult(LoadFlags.LOAD_WAYPOINTS); + caches.addAll(cachesFromSearchResult); } if (live) { final boolean excludeMine = Settings.isExcludeMyCaches(); final boolean excludeDisabled = Settings.isExcludeDisabledCaches(); - final ArrayList<cgCache> tempList = new ArrayList<cgCache>(caches); + final List<cgCache> tempList = caches.getAsList(); + for (cgCache cache : tempList) { if ((cache.isFound() && excludeMine) || (cache.isOwn() && excludeMine) || (cache.isDisabled() && excludeDisabled)) { caches.remove(cache); } } } + countVisibleCaches(); + if (cachesCnt < Settings.getWayPointsThreshold()) + { + waypoints.clear(); + if (searchIntent == null && geocodeIntent == null) { + //All visible waypoints + waypoints.addAll(app.getWaypointsInViewport(viewport, Settings.isExcludeMyCaches(), Settings.isExcludeDisabledCaches())); + } else { + //All waypoints from the viewed caches + for (cgCache c : caches.getAsList()) { + waypoints.addAll(c.getWaypoints()); + } + } + } //render - displayExecutor.execute(new DisplayRunnable(centerLat, centerLon, spanLat, spanLon)); + displayExecutor.execute(new DisplayRunnable(viewport)); if (live && Settings.isLiveMap()) { - downloadExecutor.execute(new DownloadRunnable(centerLat, centerLon, spanLat, spanLon)); + downloadExecutor.execute(new DownloadRunnable(viewport)); } } finally { showProgressHandler.sendEmptyMessage(HIDE_PROGRESS); // hide progress @@ -1180,8 +1207,8 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private class DownloadRunnable extends DoRunnable { - public DownloadRunnable(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) { - super(centerLatIn, centerLonIn, spanLatIn, spanLonIn); + public DownloadRunnable(final Viewport viewport) { + super(viewport); } @Override @@ -1199,8 +1226,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } } - final Viewport viewport = new Viewport(new Geopoint(centerLat / 1e6, centerLon / 1e6), 0.8 * spanLat / 1e6, 0.8 * spanLon / 1e6); - search = ConnectorFactory.searchByViewport(viewport, tokens); + search = ConnectorFactory.searchByViewport(viewport.resize(0.8), tokens); if (search != null) { downloaded = true; if (search.getError() == StatusCode.NOT_LOGGED_IN) { @@ -1222,10 +1248,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } //render - displayExecutor.execute(new DisplayRunnable(centerLat, centerLon, spanLat, spanLon)); + displayExecutor.execute(new DisplayRunnable(viewport)); } catch (ThreadDeath e) { - Log.d(Settings.tag, "DownloadThread stopped"); + Log.d("DownloadThread stopped"); displayHandler.sendEmptyMessage(UPDATE_TITLE); } finally { showProgressHandler.sendEmptyMessage(HIDE_PROGRESS); // hide progress @@ -1238,8 +1264,8 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto */ private class DisplayRunnable extends DoRunnable { - public DisplayRunnable(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) { - super(centerLatIn, centerLonIn, spanLatIn, spanLonIn); + public DisplayRunnable(final Viewport viewport) { + super(viewport); } @Override @@ -1251,29 +1277,28 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } // display caches - final List<cgCache> cachesToDisplay = new ArrayList<cgCache>(caches); + final List<cgCache> cachesToDisplay = caches.getAsList(); + final List<cgWaypoint> waypointsToDisplay = new ArrayList<cgWaypoint>(waypoints); final List<CachesOverlayItemImpl> itemsToDisplay = new ArrayList<CachesOverlayItemImpl>(); if (!cachesToDisplay.isEmpty()) { + // Only show waypoints for single view or setting + // when less than showWaypointsthreshold Caches shown + if (cachesToDisplay.size() == 1 || (cachesCnt < Settings.getWayPointsThreshold())) { + for (cgWaypoint waypoint : waypointsToDisplay) { + + if (waypoint.getCoords() == null) { + continue; + } + + itemsToDisplay.add(getItem(waypoint, null, waypoint)); + } + } for (cgCache cache : cachesToDisplay) { if (cache.getCoords() == null) { continue; } - - // display cache waypoints - if (cache.hasWaypoints() - // Only show waypoints for single view or setting - // when less than showWaypointsthreshold Caches shown - && (cachesToDisplay.size() == 1 || (cachesToDisplay.size() < Settings.getWayPointsThreshold()))) { - for (cgWaypoint waypoint : cache.getWaypoints()) { - if (waypoint.getCoords() == null) { - continue; - } - - itemsToDisplay.add(getItem(waypoint, null, waypoint)); - } - } itemsToDisplay.add(getItem(cache, cache, null)); } @@ -1289,7 +1314,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto displayHandler.sendEmptyMessage(UPDATE_TITLE); } catch (ThreadDeath e) { - Log.d(Settings.tag, "DisplayThread stopped"); + Log.d("DisplayThread stopped"); displayHandler.sendEmptyMessage(UPDATE_TITLE); } finally { showProgressHandler.sendEmptyMessage(HIDE_PROGRESS); @@ -1303,21 +1328,15 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private class Go4CacheRunnable extends DoRunnable { - public Go4CacheRunnable(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) { - super(centerLatIn, centerLonIn, spanLatIn, spanLonIn); + public Go4CacheRunnable(final Viewport viewport) { + super(viewport); } @Override public void run() { - final Geopoint center = new Geopoint((int) centerLat, (int) centerLon); - final Viewport viewport = new Viewport(center, spanLat / 1e6 * 1.5, spanLon / 1e6 * 1.5); - - try { - go4CacheThreadRun = System.currentTimeMillis(); - List<Go4CacheUser> go4CacheUsers = Go4Cache.getGeocachersInViewport(Settings.getUsername(), viewport); - go4CacheDisplayExecutor.execute(new Go4CacheDisplayRunnable(go4CacheUsers, centerLat, centerLon, spanLat, spanLon)); - } finally { - } + go4CacheThreadRun = System.currentTimeMillis(); + List<Go4CacheUser> go4CacheUsers = Go4Cache.getGeocachersInViewport(Settings.getUsername(), viewport.resize(1.5)); + go4CacheDisplayExecutor.execute(new Go4CacheDisplayRunnable(go4CacheUsers, viewport)); } } @@ -1328,8 +1347,8 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private List<Go4CacheUser> users = null; - public Go4CacheDisplayRunnable(List<Go4CacheUser> usersIn, long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) { - super(centerLatIn, centerLonIn, spanLatIn, spanLonIn); + public Go4CacheDisplayRunnable(List<Go4CacheUser> usersIn, final Viewport viewport) { + super(viewport); users = usersIn; } @@ -1397,16 +1416,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private abstract class DoRunnable implements Runnable { - protected long centerLat = 0L; - protected long centerLon = 0L; - protected long spanLat = 0L; - protected long spanLon = 0L; + final protected Viewport viewport; - public DoRunnable(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) { - centerLat = centerLatIn; - centerLon = centerLonIn; - spanLat = spanLatIn; - spanLon = spanLonIn; + public DoRunnable(final Viewport viewport) { + this.viewport = viewport; } public abstract void run(); @@ -1478,15 +1491,15 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } if (handler.isCancelled()) { - Log.i(Settings.tag, "Stopped storing process."); + Log.i("Stopped storing process."); break; } - cgBase.storeCache(activity, null, geocode, StoredList.STANDARD_LIST_ID, false, handler); + cgCache.storeCache(activity, null, geocode, StoredList.STANDARD_LIST_ID, false, handler); } } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.LoadDetails.run: " + e.toString()); + Log.e("cgeocaches.LoadDetails.run: " + e.toString()); } finally { // one more cache over detailProgress++; @@ -1504,6 +1517,13 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } } + private static boolean mapMoved(final Viewport referenceViewport, final Viewport newViewport) { + return Math.abs(newViewport.getLatitudeSpan() - referenceViewport.getLatitudeSpan()) > 50e-6 || + Math.abs(newViewport.getLongitudeSpan() - referenceViewport.getLongitudeSpan()) > 50e-6 || + Math.abs(newViewport.center.getLatitude() - referenceViewport.center.getLatitude()) > referenceViewport.getLatitudeSpan() / 4 || + Math.abs(newViewport.center.getLongitude() - referenceViewport.center.getLongitude()) > referenceViewport.getLongitudeSpan() / 4; + } + // center map to desired location private void centerMap(final Geopoint coords) { if (coords == null) { @@ -1537,46 +1557,21 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto alreadyCentered = true; } else if (!centered && (geocodeCenter != null || searchIntent != null)) { try { - List<Number> viewport = null; + Viewport viewport = null; if (geocodeCenter != null) { viewport = app.getBounds(geocodeCenter); - } else { - if (searchCenter != null) { - viewport = app.getBounds(searchCenter.getGeocodes()); - } - } - - if (viewport == null || viewport.size() < 5) { - return; + } else if (searchCenter != null) { + viewport = app.getBounds(searchCenter.getGeocodes()); } - int cnt = (Integer) viewport.get(0); - if (cnt <= 0) { + if (viewport == null) { return; } - int minLat = (int) ((Double) viewport.get(1) * 1e6); - int maxLat = (int) ((Double) viewport.get(2) * 1e6); - int maxLon = (int) ((Double) viewport.get(3) * 1e6); - int minLon = (int) ((Double) viewport.get(4) * 1e6); - - int centerLat = 0; - int centerLon = 0; - - if ((Math.abs(maxLat) - Math.abs(minLat)) != 0) { - centerLat = minLat + ((maxLat - minLat) / 2); - } else { - centerLat = maxLat; - } - if ((Math.abs(maxLon) - Math.abs(minLon)) != 0) { - centerLon = minLon + ((maxLon - minLon) / 2); - } else { - centerLon = maxLon; - } - mapController.setCenter(mapProvider.getGeoPointBase(new Geopoint(centerLat, centerLon))); - if (Math.abs(maxLat - minLat) != 0 && Math.abs(maxLon - minLon) != 0) { - mapController.zoomToSpan(Math.abs(maxLat - minLat), Math.abs(maxLon - minLon)); + mapController.setCenter(mapProvider.getGeoPointBase(viewport.center)); + if (viewport.getLatitudeSpan() != 0 && viewport.getLongitudeSpan() != 0) { + mapController.zoomToSpan((int) (viewport.getLatitudeSpan() * 1e6), (int) (viewport.getLongitudeSpan() * 1e6)); } } catch (Exception e) { // nothing at all @@ -1666,8 +1661,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto public static void startActivityCoords(final Activity fromActivity, final Geopoint coords, final WaypointType type, final String title) { final Intent mapIntent = newIntent(fromActivity); - mapIntent.putExtra(EXTRAS_LATITUDE, coords.getLatitude()); - mapIntent.putExtra(EXTRAS_LONGITUDE, coords.getLongitude()); + mapIntent.putExtra(EXTRAS_COORDS, coords); if (type != null) { mapIntent.putExtra(EXTRAS_WPTTYPE, type.id); } diff --git a/main/src/cgeo/geocaching/maps/CachesOverlay.java b/main/src/cgeo/geocaching/maps/CachesOverlay.java index ddd6ec6..17c7c0f 100644 --- a/main/src/cgeo/geocaching/maps/CachesOverlay.java +++ b/main/src/cgeo/geocaching/maps/CachesOverlay.java @@ -18,7 +18,6 @@ import org.apache.commons.lang3.StringUtils; import android.app.ProgressDialog; import android.content.Context; -import android.content.Intent; import android.graphics.Canvas; import android.graphics.DashPathEffect; import android.graphics.Paint; @@ -36,11 +35,9 @@ public class CachesOverlay extends AbstractItemizedOverlay { private Context context = null; private boolean displayCircles = false; private ProgressDialog waitDialog = null; - private Point center = new Point(); - private Point left = new Point(); private Paint blockedCircle = null; - private PaintFlagsDrawFilter setfil = null; - private PaintFlagsDrawFilter remfil = null; + private PaintFlagsDrawFilter setFilter = null; + private PaintFlagsDrawFilter removeFilter = null; private MapProvider mapProvider = null; public CachesOverlay(ItemizedOverlayImpl ovlImpl, Context contextIn) { @@ -107,65 +104,91 @@ public class CachesOverlay extends AbstractItemizedOverlay { } private void drawInternal(Canvas canvas, MapProjectionImpl projection) { + if (!displayCircles || items.isEmpty()) { + return; + } // prevent content changes getOverlayImpl().lock(); try { - if (displayCircles) { - if (blockedCircle == null) { - blockedCircle = new Paint(); - blockedCircle.setAntiAlias(true); - blockedCircle.setStrokeWidth(2.0f); - blockedCircle.setARGB(127, 0, 0, 0); - blockedCircle.setPathEffect(new DashPathEffect(new float[] { 3, 2 }, 0)); + lazyInitializeDrawingObjects(); + canvas.setDrawFilter(setFilter); + + final int radius = calculateDrawingRadius(projection); + final Point center = new Point(); + + for (CachesOverlayItemImpl item : items) { + final Geopoint itemCoord = item.getCoord().getCoords(); + final GeoPointImpl itemGeo = mapProvider.getGeoPointBase(itemCoord); + projection.toPixels(itemGeo, center); + + final CacheType type = item.getType(); + if (type == null || type == CacheType.MULTI || type == CacheType.MYSTERY || type == CacheType.VIRTUAL || type.isEvent()) { + blockedCircle.setColor(0x66000000); + blockedCircle.setStyle(Style.STROKE); + canvas.drawCircle(center.x, center.y, radius, blockedCircle); + } else { + blockedCircle.setColor(0x66BB0000); + blockedCircle.setStyle(Style.STROKE); + canvas.drawCircle(center.x, center.y, radius, blockedCircle); + + blockedCircle.setColor(0x44BB0000); + blockedCircle.setStyle(Style.FILL); + canvas.drawCircle(center.x, center.y, radius, blockedCircle); } + } + canvas.setDrawFilter(removeFilter); + } finally { + getOverlayImpl().unlock(); + } + } - if (setfil == null) { - setfil = new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG); - } - if (remfil == null) { - remfil = new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0); - } + /** + * calculate the radius of the circle to be drawn for the first item only. Those circles are only 161 meters in + * reality and therefore the minor changes due to the projection will not make any visible difference at the zoom + * levels which are used to see the circles. + * + * @param projection + * @return + */ + private int calculateDrawingRadius(MapProjectionImpl projection) { + float[] distanceArray = new float[1]; + final Geopoint itemCoord = items.get(0).getCoord().getCoords(); - canvas.setDrawFilter(setfil); + Location.distanceBetween(itemCoord.getLatitude(), itemCoord.getLongitude(), + itemCoord.getLatitude(), itemCoord.getLongitude() + 1, distanceArray); + final float longitudeLineDistance = distanceArray[0]; - for (CachesOverlayItemImpl item : items) { - final IWaypoint itemCoord = item.getCoord(); - float[] result = new float[1]; + final GeoPointImpl itemGeo = mapProvider.getGeoPointBase(itemCoord); - Location.distanceBetween(itemCoord.getCoords().getLatitude(), itemCoord.getCoords().getLongitude(), - itemCoord.getCoords().getLatitude(), itemCoord.getCoords().getLongitude() + 1, result); - final float longitudeLineDistance = result[0]; + final Geopoint leftCoords = new Geopoint(itemCoord.getLatitude(), + itemCoord.getLongitude() - 161 / longitudeLineDistance); + final GeoPointImpl leftGeo = mapProvider.getGeoPointBase(leftCoords); - GeoPointImpl itemGeo = mapProvider.getGeoPointBase(itemCoord.getCoords()); + final Point center = new Point(); + projection.toPixels(itemGeo, center); - final Geopoint leftCoords = new Geopoint(itemCoord.getCoords().getLatitude(), - itemCoord.getCoords().getLongitude() - 161 / longitudeLineDistance); - GeoPointImpl leftGeo = mapProvider.getGeoPointBase(leftCoords); + final Point left = new Point(); + projection.toPixels(leftGeo, left); - projection.toPixels(itemGeo, center); - projection.toPixels(leftGeo, left); - int radius = center.x - left.x; + final int radius = center.x - left.x; + return radius; + } - final CacheType type = item.getType(); - if (type == null || type == CacheType.MULTI || type == CacheType.MYSTERY || type == CacheType.VIRTUAL) { - blockedCircle.setColor(0x66000000); - blockedCircle.setStyle(Style.STROKE); - canvas.drawCircle(center.x, center.y, radius, blockedCircle); - } else { - blockedCircle.setColor(0x66BB0000); - blockedCircle.setStyle(Style.STROKE); - canvas.drawCircle(center.x, center.y, radius, blockedCircle); + private void lazyInitializeDrawingObjects() { + if (blockedCircle == null) { + blockedCircle = new Paint(); + blockedCircle.setAntiAlias(true); + blockedCircle.setStrokeWidth(2.0f); + blockedCircle.setARGB(127, 0, 0, 0); + blockedCircle.setPathEffect(new DashPathEffect(new float[] { 3, 2 }, 0)); + } - blockedCircle.setColor(0x44BB0000); - blockedCircle.setStyle(Style.FILL); - canvas.drawCircle(center.x, center.y, radius, blockedCircle); - } - } - canvas.setDrawFilter(remfil); - } - } finally { - getOverlayImpl().unlock(); + if (setFilter == null) { + setFilter = new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG); + } + if (removeFilter == null) { + removeFilter = new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0); } } @@ -203,19 +226,11 @@ public class CachesOverlay extends AbstractItemizedOverlay { final IWaypoint coordinate = item.getCoord(); if (StringUtils.isNotBlank(coordinate.getCoordType()) && coordinate.getCoordType().equalsIgnoreCase("cache") && StringUtils.isNotBlank(coordinate.getGeocode())) { - Intent popupIntent = new Intent(context, cgeopopup.class); - - popupIntent.putExtra("geocode", coordinate.getGeocode()); - CGeoMap.markCacheAsDirty(coordinate.getGeocode()); - context.startActivity(popupIntent); + cgeopopup.startActivity(context, coordinate.getGeocode()); } else if (coordinate.getCoordType() != null && coordinate.getCoordType().equalsIgnoreCase("waypoint") && coordinate.getId() > 0) { - Intent popupIntent = new Intent(context, cgeowaypoint.class); - - popupIntent.putExtra("waypoint", coordinate.getId()); - CGeoMap.markCacheAsDirty(coordinate.getGeocode()); - context.startActivity(popupIntent); + cgeowaypoint.startActivity(context, coordinate.getId()); } else { waitDialog.dismiss(); return false; @@ -223,7 +238,7 @@ public class CachesOverlay extends AbstractItemizedOverlay { waitDialog.dismiss(); } catch (Exception e) { - Log.e(Settings.tag, "cgMapOverlay.onTap: " + e.toString()); + Log.e("cgMapOverlay.onTap: " + e.toString()); } return false; @@ -234,7 +249,7 @@ public class CachesOverlay extends AbstractItemizedOverlay { try { return items.get(index); } catch (Exception e) { - Log.e(Settings.tag, "cgMapOverlay.createItem: " + e.toString()); + Log.e("cgMapOverlay.createItem: " + e.toString()); } return null; @@ -245,7 +260,7 @@ public class CachesOverlay extends AbstractItemizedOverlay { try { return items.size(); } catch (Exception e) { - Log.e(Settings.tag, "cgMapOverlay.size: " + e.toString()); + Log.e("cgMapOverlay.size: " + e.toString()); } return 0; diff --git a/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java b/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java index 9cc20f1..6ca050e 100644 --- a/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java +++ b/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java @@ -1,7 +1,6 @@ package cgeo.geocaching.maps; import cgeo.geocaching.CacheDetailActivity; -import cgeo.geocaching.Settings; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.go4cache.Go4CacheUser; import cgeo.geocaching.maps.interfaces.ItemizedOverlayImpl; @@ -14,7 +13,6 @@ import org.apache.commons.lang3.StringUtils; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; -import android.content.Intent; import android.graphics.Canvas; import java.util.ArrayList; @@ -92,7 +90,7 @@ public class OtherCachersOverlay extends AbstractItemizedOverlay { return true; } catch (Exception e) { - Log.e(Settings.tag, "cgUsersOverlay.onTap: " + e.toString()); + Log.e("cgUsersOverlay.onTap: " + e.toString()); } return false; @@ -108,7 +106,7 @@ public class OtherCachersOverlay extends AbstractItemizedOverlay { try { return items.get(index); } catch (Exception e) { - Log.e(Settings.tag, "cgUsersOverlay.createItem: " + e.toString()); + Log.e("cgUsersOverlay.createItem: " + e.toString()); } return null; @@ -119,7 +117,7 @@ public class OtherCachersOverlay extends AbstractItemizedOverlay { try { return items.size(); } catch (Exception e) { - Log.e(Settings.tag, "cgUsersOverlay.size: " + e.toString()); + Log.e("cgUsersOverlay.size: " + e.toString()); } return 0; @@ -135,9 +133,7 @@ public class OtherCachersOverlay extends AbstractItemizedOverlay { public void onClick(DialogInterface dialog, int id) { if (geocode != null) { - final Intent detailIntent = new Intent(context, CacheDetailActivity.class); - detailIntent.putExtra("geocode", geocode); - context.startActivity(detailIntent); + CacheDetailActivity.startActivity(context, geocode); } dialog.cancel(); diff --git a/main/src/cgeo/geocaching/maps/ScaleOverlay.java b/main/src/cgeo/geocaching/maps/ScaleOverlay.java index f43ba25..e1d193e 100644 --- a/main/src/cgeo/geocaching/maps/ScaleOverlay.java +++ b/main/src/cgeo/geocaching/maps/ScaleOverlay.java @@ -25,11 +25,6 @@ public class ScaleOverlay implements GeneralOverlay { private Paint scaleShadow = null; private BlurMaskFilter blur = null; private float pixelDensity = 0; - private double pixels = 0d; - private int bottom = 0; - private double distance = 0d; - private double distanceRound = 0d; - private String units = null; private OverlayImpl ovlImpl = null; public ScaleOverlay(Activity activity, OverlayImpl overlayImpl) { @@ -51,64 +46,42 @@ public class ScaleOverlay implements GeneralOverlay { drawInternal(canvas, mapView); } + static private double keepSignificantDigit(final double distance) { + final double scale = Math.pow(10, Math.floor(Math.log10(distance))); + return scale * Math.floor(distance / scale); + } + private void drawInternal(Canvas canvas, MapViewImpl mapView) { final double span = mapView.getLongitudeSpan() / 1e6; final GeoPointImpl center = mapView.getMapViewCenter(); - pixels = mapView.getWidth() * SCALE_WIDTH_FACTOR; // pixels related to following latitude span - bottom = mapView.getHeight() - 14; // pixels from bottom side of screen + final int bottom = mapView.getHeight() - 14; // pixels from bottom side of screen final Geopoint leftCoords = new Geopoint(center.getLatitudeE6() / 1e6, center.getLongitudeE6() / 1e6 - span / 2); final Geopoint rightCoords = new Geopoint(center.getLatitudeE6() / 1e6, center.getLongitudeE6() / 1e6 + span / 2); - distance = leftCoords.distanceTo(rightCoords) * SCALE_WIDTH_FACTOR; - distanceRound = 0d; - - //FIXME: merge with getHumanDistance() + String units; + double distance = leftCoords.distanceTo(rightCoords) * SCALE_WIDTH_FACTOR; if (Settings.isUseMetricUnits()) { - if (distance > 100) { // 100+ km > 1xx km - distanceRound = Math.floor(distance / 100) * 100; + if (distance >= 1) { units = "km"; - } else if (distance > 10) { // 10 - 100 km > 1x km - distanceRound = Math.floor(distance / 10) * 10; - units = "km"; - } else if (distance > 1) { // 1 - 10 km > 1.x km - distanceRound = Math.floor(distance); - units = "km"; - } else if (distance > 0.1) { // 100 m - 1 km > 1xx m - distance *= 1000; - distanceRound = Math.floor(distance / 100) * 100; - units = "m"; - } else { // 1 - 100 m > 1x m + } else { distance *= 1000; - distanceRound = Math.round(distance / 10) * 10; units = "m"; } } else { distance /= IConversion.MILES_TO_KILOMETER; - - if (distance > 100) { // 100+ mi > 1xx mi - distanceRound = Math.floor(distance / 100) * 100; - units = "mi"; - } else if (distance > 10) { // 10 - 100 mi > 1x mi - distanceRound = Math.floor(distance / 10) * 10; + if (distance >= 1) { units = "mi"; - } else if (distance > 1) { // 1 - 10 mi > 1.x mi - distanceRound = Math.floor(distance); - units = "mi"; - } else if (distance > 0.1) { // 0.1 mi - 1.0 mi > 1xx ft - distance *= 5280; - distanceRound = Math.floor(distance / 100) * 100; - units = "ft"; - } else { // 1 - 100 ft > 1x ft + } else { distance *= 5280; - distanceRound = Math.round(distance / 10) * 10; units = "ft"; } } - pixels = Math.round((pixels / distance) * distanceRound); + final double distanceRound = keepSignificantDigit(distance); + final double pixels = Math.round((mapView.getWidth() * SCALE_WIDTH_FACTOR / distance) * distanceRound); if (blur == null) { blur = new BlurMaskFilter(3, BlurMaskFilter.Blur.NORMAL); diff --git a/main/src/cgeo/geocaching/maps/google/GoogleGeoPoint.java b/main/src/cgeo/geocaching/maps/google/GoogleGeoPoint.java index 56bc40c..d5f6385 100644 --- a/main/src/cgeo/geocaching/maps/google/GoogleGeoPoint.java +++ b/main/src/cgeo/geocaching/maps/google/GoogleGeoPoint.java @@ -1,5 +1,6 @@ package cgeo.geocaching.maps.google; +import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.maps.interfaces.GeoPointImpl; import com.google.android.maps.GeoPoint; @@ -10,4 +11,9 @@ public class GoogleGeoPoint extends GeoPoint implements GeoPointImpl { super(latitudeE6, longitudeE6); } + @Override + public Geopoint getCoords() { + return new Geopoint(getLatitudeE6() / 1e6, getLongitudeE6() / 1e6); + } + } diff --git a/main/src/cgeo/geocaching/maps/google/GoogleMapActivity.java b/main/src/cgeo/geocaching/maps/google/GoogleMapActivity.java index ba53003..6cbe9ec 100644 --- a/main/src/cgeo/geocaching/maps/google/GoogleMapActivity.java +++ b/main/src/cgeo/geocaching/maps/google/GoogleMapActivity.java @@ -36,6 +36,11 @@ public class GoogleMapActivity extends MapActivity implements MapActivityImpl { } @Override + protected void onSaveInstanceState(final Bundle outState) { + mapBase.onSaveInstanceState(outState); + } + + @Override protected void onDestroy() { mapBase.onDestroy(); } diff --git a/main/src/cgeo/geocaching/maps/google/GoogleMapView.java b/main/src/cgeo/geocaching/maps/google/GoogleMapView.java index 9c23035..8bf7deb 100644 --- a/main/src/cgeo/geocaching/maps/google/GoogleMapView.java +++ b/main/src/cgeo/geocaching/maps/google/GoogleMapView.java @@ -3,6 +3,7 @@ package cgeo.geocaching.maps.google; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import cgeo.geocaching.Settings; +import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.maps.CachesOverlay; import cgeo.geocaching.maps.OtherCachersOverlay; import cgeo.geocaching.maps.PositionOverlay; @@ -60,7 +61,7 @@ public class GoogleMapView extends MapView implements MapViewImpl { super.draw(canvas); } catch (Exception e) { - Log.e(Settings.tag, "GoogleMapView.draw: " + e.toString()); + Log.e("GoogleMapView.draw: " + e.toString()); } } @@ -74,7 +75,7 @@ public class GoogleMapView extends MapView implements MapViewImpl { super.displayZoomControls(takeFocus); } catch (Exception e) { - Log.e(Settings.tag, "GoogleMapView.displayZoomControls: " + e.toString()); + Log.e("GoogleMapView.displayZoomControls: " + e.toString()); } } @@ -90,6 +91,11 @@ public class GoogleMapView extends MapView implements MapViewImpl { } @Override + public Viewport getViewport() { + return new Viewport(getMapViewCenter(), getLatitudeSpan() / 1e6, getLongitudeSpan() / 1e6); + } + + @Override public void addOverlay(OverlayImpl ovl) { getOverlays().add((Overlay) ovl); } diff --git a/main/src/cgeo/geocaching/maps/interfaces/GeoPointImpl.java b/main/src/cgeo/geocaching/maps/interfaces/GeoPointImpl.java index 55f014b..5636da2 100644 --- a/main/src/cgeo/geocaching/maps/interfaces/GeoPointImpl.java +++ b/main/src/cgeo/geocaching/maps/interfaces/GeoPointImpl.java @@ -1,5 +1,7 @@ package cgeo.geocaching.maps.interfaces; +import cgeo.geocaching.ICoordinates; + /** * Defines the common functions of the provider-specific * GeoPoint implementations @@ -7,7 +9,7 @@ package cgeo.geocaching.maps.interfaces; * @author rsudev * */ -public interface GeoPointImpl { +public interface GeoPointImpl extends ICoordinates { int getLatitudeE6(); diff --git a/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java b/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java index 08e04f1..c567cf2 100644 --- a/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java +++ b/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java @@ -1,5 +1,6 @@ package cgeo.geocaching.maps.interfaces; +import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.maps.CachesOverlay; import cgeo.geocaching.maps.OtherCachersOverlay; import cgeo.geocaching.maps.PositionOverlay; @@ -78,4 +79,6 @@ public interface MapViewImpl { */ boolean needsInvertedColors(); + Viewport getViewport(); + } diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeGeoPoint.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeGeoPoint.java index 19dc7c5..490822b 100644 --- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeGeoPoint.java +++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeGeoPoint.java @@ -1,5 +1,6 @@ package cgeo.geocaching.maps.mapsforge; +import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.maps.interfaces.GeoPointImpl; import org.mapsforge.android.maps.GeoPoint; @@ -9,4 +10,9 @@ public class MapsforgeGeoPoint extends GeoPoint implements GeoPointImpl { public MapsforgeGeoPoint(int latitudeE6, int longitudeE6) { super(latitudeE6, longitudeE6); } + + @Override + public Geopoint getCoords() { + return new Geopoint(getLatitudeE6() / 1e6, getLongitudeE6() / 1e6); + } } diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java index 6ca34d6..06d018c 100644 --- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java +++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java @@ -31,6 +31,11 @@ public class MapsforgeMapActivity extends MapActivity implements MapActivityImpl } @Override + protected void onSaveInstanceState(final Bundle outState) { + mapBase.onSaveInstanceState(outState); + } + + @Override protected void onDestroy() { mapBase.onDestroy(); } diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java index 1929b7b..2e0cc45 100644 --- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java +++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java @@ -12,6 +12,8 @@ import cgeo.geocaching.maps.interfaces.GeoPointImpl; import cgeo.geocaching.maps.interfaces.MapProvider; import cgeo.geocaching.maps.interfaces.OtherCachersOverlayItemImpl; +import org.mapsforge.android.maps.MapDatabase; + import android.app.Activity; import android.content.Context; import android.content.res.Resources; @@ -91,4 +93,8 @@ public class MapsforgeMapProvider implements MapProvider { return baseItem; } + public static boolean isValidMapFile(String mapFileIn) { + return MapDatabase.isValidMapFile(mapFileIn); + } + } diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java index 78bcd54..aaede4d 100644 --- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java +++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java @@ -1,6 +1,8 @@ package cgeo.geocaching.maps.mapsforge; +import cgeo.geocaching.R; import cgeo.geocaching.Settings; +import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.maps.CachesOverlay; import cgeo.geocaching.maps.OtherCachersOverlay; import cgeo.geocaching.maps.PositionOverlay; @@ -16,7 +18,6 @@ import cgeo.geocaching.maps.interfaces.OverlayImpl.overlayType; import cgeo.geocaching.utils.Log; import org.mapsforge.android.maps.GeoPoint; -import org.mapsforge.android.maps.MapDatabase; import org.mapsforge.android.maps.MapView; import org.mapsforge.android.maps.MapViewMode; import org.mapsforge.android.maps.Overlay; @@ -30,6 +31,7 @@ import android.util.AttributeSet; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; +import android.widget.Toast; public class MapsforgeMapView extends MapView implements MapViewImpl { private GestureDetector gestureDetector; @@ -49,7 +51,7 @@ public class MapsforgeMapView extends MapView implements MapViewImpl { super.draw(canvas); } catch (Exception e) { - Log.e(Settings.tag, "MapsforgeMapView.draw: " + e.toString()); + Log.e("MapsforgeMapView.draw: " + e.toString()); } } @@ -70,6 +72,11 @@ public class MapsforgeMapView extends MapView implements MapViewImpl { } @Override + public Viewport getViewport() { + return new Viewport(getMapViewCenter(), getLatitudeSpan() / 1e6, getLongitudeSpan() / 1e6); + } + + @Override public void addOverlay(OverlayImpl ovl) { getOverlays().add((Overlay) ovl); } @@ -170,11 +177,14 @@ public class MapsforgeMapView extends MapView implements MapViewImpl { setMapViewMode(MapViewMode.OPENCYCLEMAP_TILE_DOWNLOAD); break; case MapsforgeMapProvider.OFFLINE: - if (MapDatabase.isValidMapFile(Settings.getMapFile())) { - setMapViewMode(MapViewMode.CANVAS_RENDERER); - super.setMapFile(Settings.getMapFile()); - } else { - setMapViewMode(MapViewMode.MAPNIK_TILE_DOWNLOAD); + setMapViewMode(MapViewMode.CANVAS_RENDERER); + super.setMapFile(Settings.getMapFile()); + if (!Settings.isValidMapFile(Settings.getMapFile())) { + Toast.makeText( + getContext(), + getContext().getResources().getString(R.string.warn_invalid_mapfile), + Toast.LENGTH_LONG) + .show(); } break; default: @@ -196,7 +206,7 @@ public class MapsforgeMapView extends MapView implements MapViewImpl { } } catch (Exception e) { - Log.e(Settings.tag, "MapsforgeMapView.repaintRequired: " + e.toString()); + Log.e("MapsforgeMapView.repaintRequired: " + e.toString()); } } } diff --git a/main/src/cgeo/geocaching/network/Cookies.java b/main/src/cgeo/geocaching/network/Cookies.java new file mode 100644 index 0000000..68310e6 --- /dev/null +++ b/main/src/cgeo/geocaching/network/Cookies.java @@ -0,0 +1,47 @@ +package cgeo.geocaching.network; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.client.CookieStore; +import org.apache.http.cookie.Cookie; +import org.apache.http.impl.client.BasicCookieStore; +import org.apache.http.impl.cookie.BasicClientCookie; + +public abstract class Cookies { + + private static boolean cookieStoreRestored = false; + final static CookieStore cookieStore = new BasicCookieStore(); + + 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(); + } +} diff --git a/main/src/cgeo/geocaching/network/HtmlImage.java b/main/src/cgeo/geocaching/network/HtmlImage.java index 6cb4b86..b6be931 100644 --- a/main/src/cgeo/geocaching/network/HtmlImage.java +++ b/main/src/cgeo/geocaching/network/HtmlImage.java @@ -1,7 +1,6 @@ package cgeo.geocaching.network; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; import cgeo.geocaching.StoredList; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.files.LocalStorage; @@ -72,16 +71,16 @@ public class HtmlImage implements Html.ImageGetter { return new BitmapDrawable(getTransparent1x1Image()); } - Bitmap imagePre = onlySave ? null : loadImageFromStorage(url); + Bitmap imagePre = loadImageFromStorage(url); // Download image and save it to the cache - if (imagePre == null || onlySave) { + if (imagePre == null) { final String absoluteURL = makeAbsoluteURL(url); if (absoluteURL != null) { try { final File file = LocalStorage.getStorageFile(geocode, url, true, true); - final HttpResponse httpResponse = Network.request(absoluteURL, null, false, file); + final HttpResponse httpResponse = Network.getRequest(absoluteURL, null, file); if (httpResponse != null) { final int statusCode = httpResponse.getStatusLine().getStatusCode(); if (statusCode == 200) { @@ -91,7 +90,7 @@ public class HtmlImage implements Html.ImageGetter { } } } catch (Exception e) { - Log.e(Settings.tag, "HtmlImage.getDrawable (downloading from web)", e); + Log.e("HtmlImage.getDrawable (downloading from web)", e); } } } @@ -107,7 +106,7 @@ public class HtmlImage implements Html.ImageGetter { // get image and return if (imagePre == null) { - Log.d(Settings.tag, "HtmlImage.getDrawable: Failed to obtain image"); + Log.d("HtmlImage.getDrawable: Failed to obtain image"); if (returnErrorImage) { imagePre = BitmapFactory.decodeResource(context.getResources(), R.drawable.image_not_loaded); @@ -130,7 +129,7 @@ public class HtmlImage implements Html.ImageGetter { try { imagePre = Bitmap.createScaledBitmap(imagePre, width, height, true); } catch (Exception e) { - Log.d(Settings.tag, "HtmlImage.getDrawable: Failed to scale image"); + Log.d("HtmlImage.getDrawable: Failed to scale image"); return null; } } else { @@ -158,7 +157,7 @@ public class HtmlImage implements Html.ImageGetter { final File fileSec = LocalStorage.getStorageSecFile(geocode, url, true); return loadCachedImage(fileSec); } catch (Exception e) { - Log.w(Settings.tag, "HtmlImage.getDrawable (reading cache): " + e.toString()); + Log.w("HtmlImage.getDrawable (reading cache): " + e.toString()); } return null; } @@ -182,7 +181,7 @@ public class HtmlImage implements Html.ImageGetter { } } } catch (Exception e) { - Log.e(Settings.tag, "HtmlImage.makeAbsoluteURL (parse URL)", e); + Log.e("HtmlImage.makeAbsoluteURL (parse URL)", e); } return null; } @@ -207,7 +206,7 @@ public class HtmlImage implements Html.ImageGetter { fis = new FileInputStream(file); BitmapFactory.decodeStream(fis, null, options); } catch (FileNotFoundException e) { - Log.e(Settings.tag, "HtmlImage.setSampleSize", e); + Log.e("HtmlImage.setSampleSize", e); } finally { if (fis != null) { try { diff --git a/main/src/cgeo/geocaching/network/Network.java b/main/src/cgeo/geocaching/network/Network.java index 502db33..bb5a949 100644 --- a/main/src/cgeo/geocaching/network/Network.java +++ b/main/src/cgeo/geocaching/network/Network.java @@ -1,13 +1,9 @@ package cgeo.geocaching.network; -import cgeo.geocaching.Settings; -import cgeo.geocaching.cgBase; -import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.files.LocalStorage; import cgeo.geocaching.utils.BaseUtils; import cgeo.geocaching.utils.Log; -import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; import org.apache.http.HeaderElement; @@ -18,17 +14,13 @@ 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; @@ -44,11 +36,10 @@ import android.net.Uri; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import java.util.List; import java.util.zip.GZIPInputStream; - public abstract class Network { static class GzipDecompressingEntity extends HttpEntityWrapper { @@ -76,8 +67,6 @@ public abstract class Network { 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); @@ -91,7 +80,7 @@ public abstract class Network { private static HttpClient getHttpClient() { final DefaultHttpClient client = new DefaultHttpClient(); - client.setCookieStore(cookieStore); + client.setCookieStore(Cookies.cookieStore); client.setParams(clientParams); client.addRequestInterceptor(new HttpRequestInterceptor() { @@ -117,7 +106,7 @@ public abstract class Network { HeaderElement[] codecs = ceheader.getElements(); for (int i = 0; i < codecs.length; i++) { if (codecs[i].getName().equalsIgnoreCase("gzip")) { - Log.d(Settings.tag, "Decompressing response"); + Log.d("Decompressing response"); response.setEntity( new Network.GzipDecompressingEntity(response.getEntity())); return; @@ -132,40 +121,6 @@ public abstract class Network { 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 * @@ -173,117 +128,148 @@ public abstract class Network { * @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); + public static HttpResponse postRequest(final String uri, final Parameters params) { + return request("POST", uri, params, null, null); } /** - * GET HTTP request + * Make an HTTP request * + * @param method + * the HTTP method to use ("GET" or "POST") * @param uri + * the URI to request * @param params - * @param xContentType + * the parameters to add the the GET request + * @param headers + * the headers to add to the GET request * @param cacheFile - * the name of the file storing the cached resource, or null not to use one - * @return + * the cache file used to cache this query + * @return the HTTP response, or null in case of an encoding error in a POST request arguments */ - public static HttpResponse request(final String uri, final Parameters params, final boolean xContentType, final File cacheFile) { - final String fullUri = params == null ? uri : Uri.parse(uri).buildUpon().encodedQuery(params.toString()).build().toString(); - final HttpRequestBase request = new HttpGet(fullUri); + private static HttpResponse request(final String method, final String uri, final Parameters params, final Parameters headers, final File cacheFile) { + HttpRequestBase request; + if (method.equals("GET")) { + final String fullUri = params == null ? uri : Uri.parse(uri).buildUpon().encodedQuery(params.toString()).build().toString(); + request = new HttpGet(fullUri); + } else { + request = new HttpPost(uri); + if (params != null) { + try { + ((HttpPost) request).setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8)); + } catch (final UnsupportedEncodingException e) { + Log.e("request", e); + return null; + } + } + } - request.setHeader("X-Requested-With", "XMLHttpRequest"); + for (final NameValuePair header : Parameters.extend(Parameters.merge(headers, cacheHeaders(cacheFile)), + "Accept-Charset", "utf-8,iso-8859-1;q=0.8,utf-16;q=0.8,*;q=0.7", + "Accept-Language", "en-US,*;q=0.9", + "X-Requested-With", "XMLHttpRequest")) { + request.setHeader(header.getName(), header.getValue()); + } + + request.getParams().setParameter(CoreProtocolPNames.USER_AGENT, Network.USER_AGENT); - if (xContentType) { - request.setHeader("Content-Type", "application/x-www-form-urlencoded"); + final String reqLogStr = request.getMethod() + " " + Network.hidePassword(request.getURI().toString()); + Log.d(reqLogStr); + + final HttpClient client = Network.getHttpClient(); + for (int i = 0; i <= Network.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(status + Network.formatTimeSpan(before) + reqLogStr); + } else { + Log.w(status + " [" + response.getStatusLine().getReasonPhrase() + "]" + Network.formatTimeSpan(before) + reqLogStr); + } + return response; + } catch (IOException e) { + final String timeSpan = Network.formatTimeSpan(before); + final String tries = (i + 1) + "/" + (Network.NB_DOWNLOAD_RETRIES + 1); + if (i == Network.NB_DOWNLOAD_RETRIES) { + Log.e("Failure " + tries + timeSpan + reqLogStr, e); + } else { + Log.e("Failure " + tries + " (" + e.toString() + ")" + timeSpan + "- retrying " + reqLogStr); + } + } } + return null; + } + + private static Parameters cacheHeaders(final File cacheFile) { if (cacheFile != null && cacheFile.exists()) { final String etag = LocalStorage.getSavedHeader(cacheFile, "etag"); if (etag != null) { - request.setHeader("If-None-Match", etag); + return new Parameters("If-None-Match", etag); } else { final String lastModified = LocalStorage.getSavedHeader(cacheFile, "last-modified"); if (lastModified != null) { - request.setHeader("If-Modified-Since", lastModified); + return new Parameters("If-Modified-Since", lastModified); } } } - - return Network.request(request); + return null; } /** * GET HTTP request * * @param uri + * the URI to request * @param params - * @param xContentType - * @return + * the parameters to add the the GET request + * @param cacheFile + * the name of the file storing the cached resource, or null not to use one + * @return the HTTP response */ - public static HttpResponse request(final String uri, final Parameters params, final boolean xContentType) { - return request(uri, params, xContentType, null); + public static HttpResponse getRequest(final String uri, final Parameters params, final File cacheFile) { + return request("GET", uri, params, null, cacheFile); } - 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); + /** + * GET HTTP request + * + * @param uri + * the URI to request + * @param params + * the parameters to add the the GET request + * @return the HTTP response + */ + public static HttpResponse getRequest(final String uri, final Parameters params) { + return request("GET", uri, params, null, null); + } - 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); - } - } - } + /** + * GET HTTP request + * + * @param uri + * the URI to request + * @param params + * the parameters to add the the GET request + * @param headers + * the headers to add to the GET request + * @return the HTTP response + */ + public static HttpResponse getRequest(final String uri, final Parameters params, final Parameters headers) { + return request("GET", uri, params, headers, null); + } - return null; + /** + * GET HTTP request + * + * @param uri + * the URI to request + * @return the HTTP response + */ + public static HttpResponse getRequest(final String uri) { + return request("GET", uri, null, null, null); } private static String formatTimeSpan(final long before) { @@ -296,33 +282,24 @@ public abstract class Network { } 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) { + final HttpResponse response = request("GET", uri, params, new Parameters("Accept", "application/json, text/javascript, */*; q=0.01"), null); + if (isSuccess(response)) { try { return new JSONObject(Network.getResponseData(response)); - } catch (JSONException e) { - Log.e(Settings.tag, "Network.requestJSON", e); + } catch (final JSONException e) { + Log.e("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); + Log.e("getResponseData", e); return null; } } @@ -331,59 +308,13 @@ public abstract class Network { return Network.getResponseData(response, true); } - static public String getResponseData(final HttpResponse response, boolean replaceWhitespace) { + public static 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) { return StringUtils.replace(URLEncoder.encode(text).replace("+", "%20"), "%7E", "~"); } diff --git a/main/src/cgeo/geocaching/network/Parameters.java b/main/src/cgeo/geocaching/network/Parameters.java index e65bec2..5c0328a 100644 --- a/main/src/cgeo/geocaching/network/Parameters.java +++ b/main/src/cgeo/geocaching/network/Parameters.java @@ -12,7 +12,7 @@ import java.util.Comparator; /** * List of key/values pairs to be used in a GET or POST request. - * + * */ public class Parameters extends ArrayList<NameValuePair> { @@ -44,14 +44,16 @@ public class Parameters extends ArrayList<NameValuePair> { * list of key/value pairs * @throws InvalidParameterException * if the number of key/values is unbalanced + * @return the object itself to facilitate chaining */ - public void put(final String... keyValues) { + public Parameters put(final String... keyValues) { if (keyValues.length % 2 == 1) { throw new InvalidParameterException("odd number of parameters"); } for (int i = 0; i < keyValues.length; i += 2) { add(new BasicNameValuePair(keyValues[i], keyValues[i + 1])); } + return this; } /** @@ -63,12 +65,46 @@ public class Parameters extends ArrayList<NameValuePair> { Collections.sort(this, comparator); } - /** - * @return the URL encoded string corresponding to those parameters - */ @Override public String toString() { return URLEncodedUtils.format(this, HTTP.UTF_8); } + /** + * Extend or create a Parameters object with new key/value pairs. + * + * @param params + * an existing object or null to create a new one + * @param keyValues + * list of key/value pair + * @throws InvalidParameterException + * if the number of key/values is unbalanced + * @return the object itself if it is non-null, a new one otherwise + */ + public static Parameters extend(final Parameters params, final String... keyValues) { + if (params == null) { + return new Parameters(keyValues); + } else { + return params.put(keyValues); + } + } + + /** + * Merge two (possibly null) Parameters object. + * + * @param params + * the object to merge into if non-null + * @param extra + * the object to merge from if non-null + * @return params with extra data if params was non-null, extra otherwise + */ + public static Parameters merge(final Parameters params, final Parameters extra) { + if (params == null) { + return extra; + } else if (extra != null) { + params.addAll(extra); + } + return params; + } + } diff --git a/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java b/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java index f008528..9c3f15b 100644 --- a/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java +++ b/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java @@ -1,7 +1,6 @@ package cgeo.geocaching.sorting; import cgeo.geocaching.cgCache; -import cgeo.geocaching.Settings; import cgeo.geocaching.utils.Log; @@ -20,7 +19,7 @@ public abstract class AbstractCacheComparator implements CacheComparator { } return compareCaches(cache1, cache2); } catch (Exception e) { - Log.e(Settings.tag, "AbstractCacheComparator.compare: " + e.toString()); + Log.e("AbstractCacheComparator.compare: " + e.toString()); } return 0; } diff --git a/main/src/cgeo/geocaching/twitter/Twitter.java b/main/src/cgeo/geocaching/twitter/Twitter.java index 0696cf1..4a10046 100644 --- a/main/src/cgeo/geocaching/twitter/Twitter.java +++ b/main/src/cgeo/geocaching/twitter/Twitter.java @@ -38,12 +38,12 @@ public final class Twitter { OAuth.signOAuth("api.twitter.com", "/1/statuses/update.json", "POST", false, parameters, Settings.getTokenPublic(), Settings.getTokenSecret()); 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"); + Log.i("Tweet posted"); } else { - Log.e(Settings.tag, "Tweet could not be posted"); + Log.e("Tweet could not be posted"); } } catch (Exception e) { - Log.e(Settings.tag, "cgBase.postTweet: " + e.toString()); + Log.e("cgBase.postTweet: " + e.toString()); } } diff --git a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java index c9710e9..86db2d2 100644 --- a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java +++ b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java @@ -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 = Network.getResponseData(Network.request("https://" + host + pathRequest, params, false)); + final String line = Network.getResponseData(Network.getRequest("https://" + host + pathRequest, params)); if (StringUtils.isNotBlank(line)) { @@ -164,12 +164,12 @@ public class TwitterAuthorizationActivity extends AbstractActivity { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://" + host + pathAuthorize + "?" + encodedParams))); status = 1; } catch (Exception e) { - Log.e(Settings.tag, "TwitterAuthorizationActivity.requestToken(2): " + e.toString()); + Log.e("TwitterAuthorizationActivity.requestToken(2): " + e.toString()); } } } } catch (Exception e) { - Log.e(Settings.tag, "TwitterAuthorizationActivity.requestToken(1): " + e.toString()); + Log.e("TwitterAuthorizationActivity.requestToken(1): " + e.toString()); } requestTokenHandler.sendEmptyMessage(status); @@ -209,7 +209,7 @@ public class TwitterAuthorizationActivity extends AbstractActivity { status = 1; } } catch (Exception e) { - Log.e(Settings.tag, "TwitterAuthorizationActivity.changeToken: " + e.toString()); + Log.e("TwitterAuthorizationActivity.changeToken: " + e.toString()); } changeTokensHandler.sendEmptyMessage(status); diff --git a/main/src/cgeo/geocaching/ui/AddressListAdapter.java b/main/src/cgeo/geocaching/ui/AddressListAdapter.java index e557882..34e751f 100644 --- a/main/src/cgeo/geocaching/ui/AddressListAdapter.java +++ b/main/src/cgeo/geocaching/ui/AddressListAdapter.java @@ -56,7 +56,7 @@ public class AddressListAdapter extends ArrayAdapter<Address> { @Override public void onClick(View v) { Activity activity = (Activity) v.getContext(); - cgeocaches.startActivityAddress(activity, address.getLatitude(), address.getLongitude(), StringUtils.defaultString(address.getAddressLine(0))); + cgeocaches.startActivityAddress(activity, new Geopoint(address.getLatitude(), address.getLongitude()), StringUtils.defaultString(address.getAddressLine(0))); activity.finish(); } }); diff --git a/main/src/cgeo/geocaching/ui/CacheListAdapter.java b/main/src/cgeo/geocaching/ui/CacheListAdapter.java index 6c03889..54f4505 100644 --- a/main/src/cgeo/geocaching/ui/CacheListAdapter.java +++ b/main/src/cgeo/geocaching/ui/CacheListAdapter.java @@ -3,7 +3,6 @@ package cgeo.geocaching.ui; import cgeo.geocaching.CacheDetailActivity; import cgeo.geocaching.R; import cgeo.geocaching.Settings; -import cgeo.geocaching.cgBase; import cgeo.geocaching.cgCache; import cgeo.geocaching.enumerations.CacheListType; import cgeo.geocaching.enumerations.CacheSize; @@ -20,7 +19,6 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.builder.HashCodeBuilder; import android.app.Activity; -import android.content.Intent; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -195,17 +193,6 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { notifyDataSetChanged(); } - public void clearFilter() { - if (originalList != null) { - list.clear(); - list.addAll(originalList); - - currentFilter = null; - } - - notifyDataSetChanged(); - } - public boolean isFilter() { return currentFilter != null; } @@ -375,7 +362,7 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { } if (position > getCount()) { - Log.w(Settings.tag, "CacheListAdapter.getView: Attempt to access missing item #" + position); + Log.w("CacheListAdapter.getView: Attempt to access missing item #" + position); return null; } @@ -590,8 +577,8 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { if (cacheListType == CacheListType.HISTORY && cache.getVisitedDate() > 0) { ArrayList<String> infos = new ArrayList<String>(); infos.add(StringUtils.upperCase(cache.getGeocode())); - infos.add(cgBase.formatDate(cache.getVisitedDate())); - infos.add(cgBase.formatTime(cache.getVisitedDate())); + infos.add(Formatter.formatDate(cache.getVisitedDate())); + infos.add(Formatter.formatTime(cache.getVisitedDate())); holder.info.setText(StringUtils.join(infos, Formatter.SEPARATOR)); } else { ArrayList<String> infos = new ArrayList<String>(); @@ -609,7 +596,7 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { if (cache.getSize() != CacheSize.UNKNOWN && cache.showSize()) { infos.add(cache.getSize().getL10n()); } else if (cache.isEventCache() && cache.getHiddenDate() != null) { - infos.add(cgBase.formatShortDate(cache.getHiddenDate().getTime())); + infos.add(Formatter.formatShortDate(cache.getHiddenDate().getTime())); } if (cache.isPremiumMembersOnly()) { @@ -699,10 +686,7 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { } // load cache details - Intent cachesIntent = new Intent(getContext(), CacheDetailActivity.class); - cachesIntent.putExtra("geocode", geocode); - cachesIntent.putExtra("name", name); - getContext().startActivity(cachesIntent); + CacheDetailActivity.startActivity(getContext(), geocode, name); } // long tap on item @@ -781,7 +765,7 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { return true; } } catch (Exception e) { - Log.w(Settings.tag, "CacheListAdapter.detectGesture.onFling: " + e.toString()); + Log.w("CacheListAdapter.detectGesture.onFling: " + e.toString()); } return false; diff --git a/main/src/cgeo/geocaching/ui/CompassView.java b/main/src/cgeo/geocaching/ui/CompassView.java index 7f6f792..d9e0bfe 100644 --- a/main/src/cgeo/geocaching/ui/CompassView.java +++ b/main/src/cgeo/geocaching/ui/CompassView.java @@ -1,7 +1,6 @@ package cgeo.geocaching.ui; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; import cgeo.geocaching.utils.Log; import android.content.Context; @@ -58,7 +57,7 @@ public class CompassView extends View { try { invalidate(); } catch (Exception e) { - Log.e(Settings.tag, "CompassView.changeHandler: " + e.toString()); + Log.e("CompassView.changeHandler: " + e.toString()); } } }; diff --git a/main/src/cgeo/geocaching/ui/DirectionImage.java b/main/src/cgeo/geocaching/ui/DirectionImage.java index aa01b97..b246718 100644 --- a/main/src/cgeo/geocaching/ui/DirectionImage.java +++ b/main/src/cgeo/geocaching/ui/DirectionImage.java @@ -17,7 +17,7 @@ public class DirectionImage { } final HttpResponse httpResponse = - Network.request("http://www.geocaching.com/ImgGen/seek/CacheDir.ashx", new Parameters("k", code), false); + Network.getRequest("http://www.geocaching.com/ImgGen/seek/CacheDir.ashx", new Parameters("k", code)); if (httpResponse != null) { LocalStorage.saveEntityToFile(httpResponse, getDirectionFile(geocode, true)); } diff --git a/main/src/cgeo/geocaching/ui/Formatter.java b/main/src/cgeo/geocaching/ui/Formatter.java index 661a9a0..6ee1a65 100644 --- a/main/src/cgeo/geocaching/ui/Formatter.java +++ b/main/src/cgeo/geocaching/ui/Formatter.java @@ -1,8 +1,80 @@ package cgeo.geocaching.ui; -public interface Formatter { +import cgeo.geocaching.cgeoapplication; + +import android.content.Context; +import android.text.format.DateUtils; + +public abstract class Formatter { /** Text separator used for formatting texts */ public static final String SEPARATOR = " ยท "; + private static final Context context = cgeoapplication.getInstance().getBaseContext(); + + /** + * Generate a time string according to system-wide settings (locale, 12/24 hour) + * such as "13:24". + * + * @param date + * milliseconds since the epoch + * @return the formatted string + */ + public static String formatTime(long date) { + return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_TIME); + } + + /** + * Generate a date string according to system-wide settings (locale, date format) + * such as "20 December" or "20 December 2010". The year will only be included when necessary. + * + * @param date + * milliseconds since the epoch + * @return the formatted string + */ + public static String formatDate(long date) { + return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE); + } + + /** + * Generate a date string according to system-wide settings (locale, date format) + * such as "20 December 2010". The year will always be included, making it suitable + * to generate long-lived log entries. + * + * @param date + * milliseconds since the epoch + * @return the formatted string + */ + public static String formatFullDate(long date) { + return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE + | DateUtils.FORMAT_SHOW_YEAR); + } + + /** + * Generate a numeric date string according to system-wide settings (locale, date format) + * such as "10/20/2010". + * + * @param date + * milliseconds since the epoch + * @return the formatted string + */ + public static String formatShortDate(long date) { + return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE + | DateUtils.FORMAT_NUMERIC_DATE); + } + + /** + * Generate a numeric date and time string according to system-wide settings (locale, + * date format) such as "7 sept. at 12:35". + * + * @param context + * a Context + * @param date + * milliseconds since the epoch + * @return the formatted string + */ + public static String formatShortDateTime(Context context, long date) { + return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL); + } + } diff --git a/main/src/cgeo/geocaching/ui/GPXListAdapter.java b/main/src/cgeo/geocaching/ui/GPXListAdapter.java index 5a58840..aa2234a 100644 --- a/main/src/cgeo/geocaching/ui/GPXListAdapter.java +++ b/main/src/cgeo/geocaching/ui/GPXListAdapter.java @@ -1,7 +1,6 @@ package cgeo.geocaching.ui; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; import cgeo.geocaching.cgeogpxes; import cgeo.geocaching.files.GPXImporter; import cgeo.geocaching.utils.Log; @@ -34,7 +33,7 @@ public class GPXListAdapter extends ArrayAdapter<File> { } if (position > getCount()) { - Log.w(Settings.tag, "cgGPXListAdapter.getView: Attempt to access missing item #" + position); + Log.w("cgGPXListAdapter.getView: Attempt to access missing item #" + position); return null; } diff --git a/main/src/cgeo/geocaching/ui/MapfileListAdapter.java b/main/src/cgeo/geocaching/ui/MapfileListAdapter.java index c4720d5..e7380f0 100644 --- a/main/src/cgeo/geocaching/ui/MapfileListAdapter.java +++ b/main/src/cgeo/geocaching/ui/MapfileListAdapter.java @@ -1,7 +1,6 @@ package cgeo.geocaching.ui; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; import cgeo.geocaching.cgSelectMapfile; import cgeo.geocaching.utils.Log; @@ -35,7 +34,7 @@ public class MapfileListAdapter extends ArrayAdapter<File> { } if (position > getCount()) { - Log.w(Settings.tag, "cgGPXListAdapter.getView: Attempt to access missing item #" + position); + Log.w("cgGPXListAdapter.getView: Attempt to access missing item #" + position); return null; } diff --git a/main/src/cgeo/geocaching/utils/BaseUtils.java b/main/src/cgeo/geocaching/utils/BaseUtils.java index 44c35a1..d468fc9 100644 --- a/main/src/cgeo/geocaching/utils/BaseUtils.java +++ b/main/src/cgeo/geocaching/utils/BaseUtils.java @@ -3,8 +3,6 @@ */ package cgeo.geocaching.utils; -import java.util.ArrayList; -import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -84,17 +82,6 @@ public final class BaseUtils { return BaseUtils.getMatch(data, p, true, 1, defaultValue, false); } - public static List<String> getMatches(final String data, final Pattern p, int count) { - ArrayList<String> result = new ArrayList<String>(); - final Matcher matcher = p.matcher(data); - while (matcher.find()) { - for (int i = 0; i < count; i++) { - result.add(matcher.group(i)); - } - } - return result; - } - /** * Searches for the pattern p in the data. * diff --git a/main/src/cgeo/geocaching/utils/BoundedList.java b/main/src/cgeo/geocaching/utils/BoundedList.java deleted file mode 100644 index 3fa1112..0000000 --- a/main/src/cgeo/geocaching/utils/BoundedList.java +++ /dev/null @@ -1,46 +0,0 @@ -package cgeo.geocaching.utils; - -import java.util.ArrayList; -import java.util.Collection; - -/** - * Base class for a limited list. - * - * @author blafoo - */ -public class BoundedList<T> extends ArrayList<T> { - - private static final long serialVersionUID = -5077882607489806620L; - private final int maxEntries; - - public BoundedList(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/CancellableHandler.java b/main/src/cgeo/geocaching/utils/CancellableHandler.java index d4915eb..8cf8f28 100644 --- a/main/src/cgeo/geocaching/utils/CancellableHandler.java +++ b/main/src/cgeo/geocaching/utils/CancellableHandler.java @@ -1,5 +1,7 @@ package cgeo.geocaching.utils; +import cgeo.geocaching.cgeoapplication; + import android.os.Handler; import android.os.Message; @@ -9,6 +11,7 @@ import android.os.Message; */ public abstract class CancellableHandler extends Handler { + protected static final int UPDATE_LOAD_PROGRESS_DETAIL = 42186; private volatile boolean cancelled = false; private static class CancelHolder { @@ -109,4 +112,9 @@ public abstract class CancellableHandler extends Handler { return handler != null && handler.isCancelled(); } + public static void sendLoadProgressDetail(final Handler handler, final int resourceId) { + if (null != handler) { + handler.obtainMessage(UPDATE_LOAD_PROGRESS_DETAIL, cgeoapplication.getInstance().getString(resourceId)).sendToTarget(); + } + } } diff --git a/main/src/cgeo/geocaching/utils/CryptUtils.java b/main/src/cgeo/geocaching/utils/CryptUtils.java index 87b37c4..f04327e 100644 --- a/main/src/cgeo/geocaching/utils/CryptUtils.java +++ b/main/src/cgeo/geocaching/utils/CryptUtils.java @@ -1,6 +1,5 @@ package cgeo.geocaching.utils; -import cgeo.geocaching.Settings; import android.text.Spannable; import android.text.SpannableStringBuilder; @@ -74,7 +73,7 @@ public final class CryptUtils { digest.update(text.getBytes(), 0, text.length()); hashed = new BigInteger(1, digest.digest()).toString(16); } catch (Exception e) { - Log.e(Settings.tag, "cgBase.md5: " + e.toString()); + Log.e("cgBase.md5: " + e.toString()); } return hashed; @@ -88,7 +87,7 @@ public final class CryptUtils { digest.update(text.getBytes(), 0, text.length()); hashed = new BigInteger(1, digest.digest()).toString(16); } catch (Exception e) { - Log.e(Settings.tag, "cgBase.sha1: " + e.toString()); + Log.e("cgBase.sha1: " + e.toString()); } return hashed; @@ -103,7 +102,7 @@ public final class CryptUtils { mac.init(secretKeySpec); macBytes = mac.doFinal(text.getBytes()); } catch (Exception e) { - Log.e(Settings.tag, "cgBase.hashHmac: " + e.toString()); + Log.e("cgBase.hashHmac: " + e.toString()); } return macBytes; @@ -136,49 +135,6 @@ public final class CryptUtils { return buffer; } - public static byte[] base64Decode(String text) { - char[] in = text.toCharArray(); - - int iLen = in.length; - if (iLen % 4 != 0) { - throw new IllegalArgumentException("Length of Base64 encoded input string is not a multiple of 4."); - } - while (iLen > 0 && in[iLen - 1] == '=') { - iLen--; - } - int oLen = (iLen * 3) / 4; - byte[] out = new byte[oLen]; - int ip = 0; - int op = 0; - while (ip < iLen) { - int i0 = in[ip++]; - int i1 = in[ip++]; - int i2 = ip < iLen ? in[ip++] : 'A'; - int i3 = ip < iLen ? in[ip++] : 'A'; - if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) { - throw new IllegalArgumentException("Illegal character in Base64 encoded data."); - } - int b0 = base64map2[i0]; - int b1 = base64map2[i1]; - int b2 = base64map2[i2]; - int b3 = base64map2[i3]; - if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) { - throw new IllegalArgumentException("Illegal character in Base64 encoded data."); - } - int o0 = (b0 << 2) | (b1 >>> 4); - int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2); - int o2 = ((b2 & 3) << 6) | b3; - out[op++] = (byte) o0; - if (op < oLen) { - out[op++] = (byte) o1; - } - if (op < oLen) { - out[op++] = (byte) o2; - } - } - return out; - } - public static String base64Encode(byte[] in) { int iLen = in.length; int oDataLen = (iLen * 4 + 2) / 3; // output length without padding diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedCache.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedCache.java deleted file mode 100644 index 6d18cf5..0000000 --- a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedCache.java +++ /dev/null @@ -1,24 +0,0 @@ -package cgeo.geocaching.utils; - -import java.util.LinkedHashMap; - -/** - * Base class for a caching cache. Don't mix up with a geocache ! - * - * @author blafoo - */ -public class LeastRecentlyUsedCache<K, V> extends LinkedHashMap<K, V> { - - private static final long serialVersionUID = -5077882607489806620L; - private final int maxEntries; - - public LeastRecentlyUsedCache(int maxEntries) { - this.maxEntries = maxEntries; - } - - @Override - protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) { - return size() > maxEntries; - } - -} diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java new file mode 100644 index 0000000..5628a4b --- /dev/null +++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java @@ -0,0 +1,139 @@ +package cgeo.geocaching.utils; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Base class for caching objects. Don't mix up with a geocache ! + * + * The LeastRecentlyUsedMap is basically a LinkedHashMap which can be configured to have certain modes of operation: + * <ul> + * <li> LRU_CACHE means that the elements are updated in the LinkedList on every get() access, + * so the objects that are dropped are the ones that haven't been used the longest</li> + * <li> BOUNDED means that objects are updated only when they are put, + * so the objects that are dropped are the ones that haven't been written the longest</li> + * </ul> + * + * @author blafoo + * @author Teschi + */ +public abstract class LeastRecentlyUsedMap<K, V> extends LinkedHashMap<K, V> { + + private static enum OperationModes { + LRU_CACHE, BOUNDED + } + + private static final long serialVersionUID = -5077882607489806620L; + + private final int maxEntries; + private final OperationModes opMode; + private RemoveHandler<V> removeHandler; + + // store the HashMap parameters for serialization, as we can't access the originals in the LinkedHashMap + final int initialCapacity; + final float loadFactor; + + protected LeastRecentlyUsedMap(int maxEntries, int initialCapacity, float loadFactor, OperationModes opMode) { + super(initialCapacity, loadFactor, (opMode==OperationModes.LRU_CACHE)); + this.initialCapacity = initialCapacity; + this.loadFactor = loadFactor; + this.maxEntries = maxEntries; + this.opMode = opMode; + } + + protected LeastRecentlyUsedMap(int maxEntries, OperationModes opMode) { + this(maxEntries, 16, 0.75f, opMode); + } + + @Override + public V put(K key, V value) { + // in case the underlying Map is not running with accessOrder==true, the map won't notice any changes + // of existing keys, so for the normal BOUNDED mode we remove and put the value to get its order updated. + if (opMode == OperationModes.BOUNDED && containsKey(key)) { + // avoid trigger the remove notification + final V oldVal = super.remove(key); + put(key, value); + return oldVal; + } else { + return super.put(key, value); + } + } + + @Override + protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { + return size() > maxEntries; + } + + public int getMaxEntries() { + return maxEntries; + } + + @Override + public V remove(Object key) { + + V removed = super.remove(key); + + if (removed != null && removeHandler != null) { + removeHandler.onRemove(removed); + } + + return removed; + } + + /** + * Sets a handler for remove notifications. Currently only one handler + * instance is supported + * + * @param removeHandler + * The new handler to receive notifications or null to remove a handler + */ + public void setRemoveHandler(RemoveHandler<V> removeHandler) { + this.removeHandler = removeHandler; + } + + public static class LruCache<K, V> extends LeastRecentlyUsedMap<K, V> { + private static final long serialVersionUID = 9028478916221334454L; + + public LruCache(int maxEntries, int initialCapacity, float loadFactor) { + super(maxEntries, initialCapacity, loadFactor, OperationModes.LRU_CACHE); + } + + public LruCache(int maxEntries) { + super(maxEntries, OperationModes.LRU_CACHE); + } + } + + public static class Bounded<K, V> extends LeastRecentlyUsedMap<K, V> { + + private static final long serialVersionUID = -1476389304214398315L; + + public Bounded(int maxEntries, int initialCapacity, float loadFactor) { + super(maxEntries, initialCapacity, loadFactor, OperationModes.BOUNDED); + } + + public Bounded(int maxEntries) { + super(maxEntries, OperationModes.BOUNDED); + } + } + + /** + * Interface for handlers that wish to get notified when items are + * removed from the LRUMap + * + * @author rsudev + * + * @param <V> + */ + public interface RemoveHandler<V> { + + /** + * Method will be called on remove + * + * @param removed + * Item that has been removed + */ + void onRemove(V removed); + + } + +} diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java new file mode 100644 index 0000000..eea7a11 --- /dev/null +++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java @@ -0,0 +1,198 @@ +package cgeo.geocaching.utils; + +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +/** + * Synchronized set wrapper for the LeastRecentlyUsedMap. + * + * This code is heavily based on the HashSet code that represent Map as a Set. + * Unfortunately HashSet does not allow to use a custom Map as its Storage. + * Therefore overriding removeEldestEntry() is impossible for a normal LinkedHashSet. + * + * Synchronization is added to guard against concurrent modification. Iterator + * access has to be guarded externally or the synchronized getAsList method can be used + * to get a clone for iteration + * + * @author Teschi + */ +public class LeastRecentlyUsedSet<E> extends AbstractSet<E> + implements Cloneable, java.io.Serializable { + + private static final long serialVersionUID = -1942301031191419547L; + + private transient LeastRecentlyUsedMap<E, Object> map; + private static final Object PRESENT = new Object(); + + public LeastRecentlyUsedSet(int maxEntries, int initialCapacity, float loadFactor) { + // because we don't use any Map.get() methods from the Set, BOUNDED and LRU_CACHE have the exact same Behaviour + // So we useLRU_CACHE mode because it should perform a bit better (as it doesn't re-add explicitly) + map = new LeastRecentlyUsedMap.LruCache<E, Object>(maxEntries, initialCapacity, loadFactor); + } + + public LeastRecentlyUsedSet(int maxEntries) { + map = new LeastRecentlyUsedMap.LruCache<E, Object>(maxEntries); + } + + /** + * Copy of the HashSet code if iterator() + * Iterator access has to be synchronized externally! + * + * @see HashSet + */ + @Override + public Iterator<E> iterator() { + return map.keySet().iterator(); + } + + /** + * Synchronized access to set size + * Copy of the HashSet code if size() + * + * @see HashSet + */ + @Override + public synchronized int size() { + return map.size(); + } + + /** + * Synchronized check of set emptiness + * Copy of the HashSet code if isEmpty() + * + * @see HashSet + */ + @Override + public synchronized boolean isEmpty() { + return map.isEmpty(); + } + + /** + * Synchronized check for containment + * Copy of the HashSet code if contains() + * + * @see HashSet + */ + @Override + public synchronized boolean contains(Object o) { + return map.containsKey(o); + } + + /** + * Synchronized addition of an item + * Copy of the HashSet code if add() + * + * @see HashSet + */ + @Override + public synchronized boolean add(E e) { + return map.put(e, PRESENT) == null; + } + + /** + * Synchronized removal of a contained item + * Copy of the HashSet code if remove() + * + * @see HashSet + */ + @Override + public synchronized boolean remove(Object o) { + return map.remove(o) == PRESENT; + } + + /** + * Synchronized clearing of the set + * Copy of the HashSet code if clear() + * + * @see HashSet + */ + @Override + public synchronized void clear() { + map.clear(); + } + + /** + * (synchronized) Clone of the set + * Copy of the HashSet code if clone() + * + * @see HashSet + */ + @Override + @SuppressWarnings("unchecked") + public Object clone() { + try { + synchronized (this) { + final LeastRecentlyUsedSet<E> newSet = (LeastRecentlyUsedSet<E>) super.clone(); + newSet.map = (LeastRecentlyUsedMap<E, Object>) map.clone(); + return newSet; + } + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + } + + /** + * Creates a clone as a list in a synchronized fashion. + * + * @return List based clone of the set + */ + public synchronized List<E> getAsList() { + return new ArrayList<E>(this); + } + + /** + * Serialization version of HashSet with the additional parameters for the custom Map + * + * @see HashSet + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + // Write out any hidden serialization magic + s.defaultWriteObject(); + + // Write out HashMap capacity and load factor + s.writeInt(map.initialCapacity); + s.writeFloat(map.loadFactor); + s.writeInt(map.getMaxEntries()); + + // Write out size + s.writeInt(map.size()); + + // Write out all elements in the proper order. + for (final Iterator<E> i = map.keySet().iterator(); i.hasNext();) { + s.writeObject(i.next()); + } + } + + /** + * Serialization version of HashSet with the additional parameters for the custom Map + * + * @see HashSet + */ + @SuppressWarnings("unchecked") + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in any hidden serialization magic + s.defaultReadObject(); + + // Read in HashMap capacity and load factor and create backing HashMap + final int capacity = s.readInt(); + final float loadFactor = s.readFloat(); + final int maxEntries = s.readInt(); + + map = new LeastRecentlyUsedMap.LruCache<E, Object>(maxEntries, capacity, loadFactor); + + // Read in size + final int size = s.readInt(); + + // Read in all elements in the proper order. + for (int i = 0; i < size; i++) { + E e = (E) s.readObject(); + map.put(e, PRESENT); + } + } + +} diff --git a/main/src/cgeo/geocaching/utils/Log.java b/main/src/cgeo/geocaching/utils/Log.java index 42c1705..9f5bd3d 100644 --- a/main/src/cgeo/geocaching/utils/Log.java +++ b/main/src/cgeo/geocaching/utils/Log.java @@ -1,67 +1,69 @@ package cgeo.geocaching.utils; -import cgeo.geocaching.Settings; final public class Log { - public static void v(final String tag, final String msg) { - if (Settings.isDebug()) { - android.util.Log.v(tag, msg); - } + private static final String TAG = "cgeo"; + + private static boolean isDebug = true; + + public static boolean isDebug() { + return isDebug; } - public static void v(final String tag, final String msg, final Throwable t) { - if (Settings.isDebug()) { - android.util.Log.v(tag, msg, t); - } + public static void setDebugUnsaved(boolean isDebug) { + Log.isDebug = isDebug; } - public static void d(final String tag, final String msg) { - if (Settings.isDebug()) { - android.util.Log.d(tag, msg); + public static void v(final String msg) { + if (isDebug) { + android.util.Log.v(TAG, msg); } } - public static void d(final String tag, final String msg, final Throwable t) { - if (Settings.isDebug()) { - android.util.Log.d(tag, msg, t); + public static void v(final String msg, final Throwable t) { + if (isDebug) { + android.util.Log.v(TAG, msg, t); } } - public static void i(final String tag, final String msg) { - if (Settings.isDebug()) { - android.util.Log.i(tag, msg); + public static void d(final String msg) { + if (isDebug) { + android.util.Log.d(TAG, msg); } } - public static void i(final String tag, final String msg, final Throwable t) { - if (Settings.isDebug()) { - android.util.Log.i(tag, msg, t); + public static void d(final String msg, final Throwable t) { + if (isDebug) { + android.util.Log.d(TAG, msg, t); } } - public static void w(final String tag, final String msg) { - android.util.Log.w(tag, msg); + public static void i(final String msg) { + if (isDebug) { + android.util.Log.i(TAG, msg); + } } - public static void w(final String tag, final String msg, final Throwable t) { - android.util.Log.w(tag, msg, t); + public static void i(final String msg, final Throwable t) { + if (isDebug) { + android.util.Log.i(TAG, msg, t); + } } - public static void e(final String tag, final String msg) { - android.util.Log.e(tag, msg); + public static void w(final String msg) { + android.util.Log.w(TAG, msg); } - public static void e(final String tag, final String msg, final Throwable t) { - android.util.Log.e(tag, msg, t); + public static void w(final String msg, final Throwable t) { + android.util.Log.w(TAG, msg, t); } - public static void wtf(final String tag, final String msg) { - android.util.Log.wtf(tag, msg); + public static void e(final String msg) { + android.util.Log.e(TAG, msg); } - public static void wtf(final String tag, final String msg, final Throwable t) { - android.util.Log.wtf(tag, msg, t); + public static void e(final String msg, final Throwable t) { + android.util.Log.e(TAG, msg, t); } - } diff --git a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java index 9a5e422..60866e0 100644 --- a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java +++ b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java @@ -2,10 +2,10 @@ package cgeo.geocaching.utils; 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.connector.gc.Login; import cgeo.geocaching.network.Network; +import cgeo.geocaching.ui.Formatter; import org.apache.commons.lang3.StringUtils; @@ -55,14 +55,14 @@ public class LogTemplateProvider { @Override public String getValue(final boolean offline) { - return cgBase.formatFullDate(System.currentTimeMillis()); + return Formatter.formatFullDate(System.currentTimeMillis()); } }, new LogTemplate("TIME", R.string.init_signature_template_time) { @Override public String getValue(final boolean offline) { - return cgBase.formatTime(System.currentTimeMillis()); + return Formatter.formatTime(System.currentTimeMillis()); } }, new LogTemplate("DATETIME", R.string.init_signature_template_datetime) { @@ -70,7 +70,7 @@ public class LogTemplateProvider { @Override public String getValue(final boolean offline) { final long currentTime = System.currentTimeMillis(); - return cgBase.formatFullDate(currentTime) + " " + cgBase.formatTime(currentTime); + return Formatter.formatFullDate(currentTime) + " " + Formatter.formatTime(currentTime); } }, new LogTemplate("USER", R.string.init_signature_template_user) { @@ -89,7 +89,7 @@ public class LogTemplateProvider { if (offline) { return ""; } - final String page = Network.getResponseData(Network.request("http://www.geocaching.com/email/", null, false, false, false)); + final String page = Network.getResponseData(Network.getRequest("http://www.geocaching.com/email/")); current = parseFindCount(page); } @@ -133,7 +133,7 @@ public class LogTemplateProvider { try { return Integer.parseInt(BaseUtils.getMatch(page, GCConstants.PATTERN_CACHES_FOUND, true, "-1").replaceAll("[,.]", "")); } catch (NumberFormatException e) { - Log.e(Settings.tag, "parseFindCount", e); + Log.e("parseFindCount", e); return -1; } } |
