diff options
Diffstat (limited to 'main/src/cgeo')
184 files changed, 7192 insertions, 6989 deletions
diff --git a/main/src/cgeo/geocaching/AdressListActivity.java b/main/src/cgeo/geocaching/AdressListActivity.java index 5357e9a..a67f4a2 100644 --- a/main/src/cgeo/geocaching/AdressListActivity.java +++ b/main/src/cgeo/geocaching/AdressListActivity.java @@ -2,6 +2,7 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractListActivity; import cgeo.geocaching.ui.AddressListAdapter; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; @@ -10,7 +11,6 @@ import android.location.Address; import android.location.Geocoder; import android.os.AsyncTask; import android.os.Bundle; -import android.util.Log; import java.util.List; import java.util.Locale; @@ -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; } } @@ -57,18 +57,13 @@ public class AdressListActivity extends AbstractListActivity { @Override protected void onPostExecute(final List<Address> addresses) { waitDialog.dismiss(); - try { - if (CollectionUtils.isEmpty(addresses)) { - showToast(res.getString(R.string.err_search_address_no_match)); - finish(); - return; - } else { - for (Address address : addresses) { - adapter.add(address); // don't use addAll, it's only available with API >= 11 - } + if (CollectionUtils.isNotEmpty(addresses)) { + for (final Address address : addresses) { + adapter.add(address); // don't use addAll, it's only available with API >= 11 } - } catch (Exception e) { - Log.e(Settings.tag, "AdressListActivity.onPostExecute", e); + } else { + showToast(res.getString(R.string.err_search_address_no_match)); + finish(); } } diff --git a/main/src/cgeo/geocaching/CacheCache.java b/main/src/cgeo/geocaching/CacheCache.java index a2b5324..1ada88c 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,13 @@ 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; private static CacheCache instance = null; private CacheCache() { - cachesCache = new LeastRecentlyUsedCache<String, cgCache>(MAX_CACHED_CACHES); + cachesCache = new LeastRecentlyUsedMap.LruCache<String, cgCache>(MAX_CACHED_CACHES); + cachesCache.setRemoveHandler(new CacheRemoveHandler()); } public static CacheCache getInstance() { @@ -74,9 +83,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 static class CacheRemoveHandler implements RemoveHandler<cgCache> { + + @Override + public void onRemove(cgCache removed) { + GCBase.removeFromTileCache(removed); + } + } + } diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java index 1be9ed6..54943f9 100644 --- a/main/src/cgeo/geocaching/CacheDetailActivity.java +++ b/main/src/cgeo/geocaching/CacheDetailActivity.java @@ -7,8 +7,9 @@ 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.CacheAttribute; 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; @@ -16,7 +17,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; @@ -24,12 +24,12 @@ import cgeo.geocaching.utils.BaseUtils; import cgeo.geocaching.utils.CancellableHandler; import cgeo.geocaching.utils.ClipboardUtils; import cgeo.geocaching.utils.CryptUtils; +import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.TranslationUtils; import cgeo.geocaching.utils.UnknownTagsHandler; import com.viewpagerindicator.TitlePageIndicator; import com.viewpagerindicator.TitleProvider; - import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; @@ -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; @@ -61,7 +63,6 @@ import android.text.method.LinkMovementMethod; import android.text.style.StrikethroughSpan; import android.text.style.StyleSpan; import android.util.DisplayMetrics; -import android.util.Log; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; @@ -122,7 +123,6 @@ public class CacheDetailActivity extends AbstractActivity { private static final String CALENDAR_ADDON_URI = "market://details?id=cgeo.calendar"; - private cgGeo geolocation; private cgCache cache; private final Progress progress = new Progress(); private SearchResult search; @@ -186,10 +186,6 @@ public class CacheDetailActivity extends AbstractActivity { setContentView(R.layout.cacheview); setTitle(res.getString(R.string.cache)); - if (geolocation == null) { - geolocation = app.startGeo(locationUpdater); - } - String geocode = null; String guid = null; String name = null; @@ -220,9 +216,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")) { @@ -328,9 +324,7 @@ public class CacheDetailActivity extends AbstractActivity { public void onResume() { super.onResume(); - if (geolocation == null) { - geolocation = app.startGeo(locationUpdater); - } + app.addGeoObserver(locationUpdater); if (refreshOnResume) { notifyDataSetChanged(); refreshOnResume = false; @@ -339,19 +333,11 @@ public class CacheDetailActivity extends AbstractActivity { @Override public void onDestroy() { - if (geolocation != null) { - geolocation = app.removeGeo(); - } - super.onDestroy(); } @Override public void onStop() { - if (geolocation != null) { - geolocation = app.removeGeo(); - } - if (cache != null) { cache.setChangeNotificationHandler(null); } @@ -361,9 +347,7 @@ public class CacheDetailActivity extends AbstractActivity { @Override public void onPause() { - if (geolocation != null) { - geolocation = app.removeGeo(); - } + app.deleteGeoObserver(locationUpdater); super.onPause(); } @@ -468,6 +452,7 @@ public class CacheDetailActivity extends AbstractActivity { switch (index) { case MENU_FIELD_COPY: ClipboardUtils.copyToClipboard(clickedItemText); + showToast(res.getString(R.string.clipboard_copy_ok)); return true; case MENU_FIELD_TRANSLATE: TranslationUtils.startActivityTranslate(this, Locale.getDefault().getLanguage(), clickedItemText.toString()); @@ -486,15 +471,16 @@ public class CacheDetailActivity extends AbstractActivity { } break; - case CONTEXT_MENU_WAYPOINT_EDIT: - if (cache.hasWaypoints() && index < cache.getWaypoints().size()) { - final cgWaypoint waypoint = cache.getWaypoints().get(index); + case CONTEXT_MENU_WAYPOINT_EDIT: { + final cgWaypoint waypoint = cache.getWaypoint(index); + if (waypoint != null) { Intent editIntent = new Intent(this, cgeowaypointadd.class); editIntent.putExtra("waypoint", waypoint.getId()); startActivity(editIntent); refreshOnResume = true; } break; + } case CONTEXT_MENU_WAYPOINT_DUPLICATE: if (cache.duplicateWaypoint(index)) { app.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); @@ -510,14 +496,14 @@ public class CacheDetailActivity extends AbstractActivity { case CONTEXT_MENU_WAYPOINT_DEFAULT_NAVIGATION: { final cgWaypoint waypoint = cache.getWaypoint(index); if (waypoint != null) { - NavigationAppFactory.startDefaultNavigationApplication(geolocation, this, null, waypoint, null); + NavigationAppFactory.startDefaultNavigationApplication(app.currentGeo(), this, null, waypoint, null); } } break; case CONTEXT_MENU_WAYPOINT_NAVIGATE: { final cgWaypoint waypoint = cache.getWaypoint(contextMenuWPIndex); if (waypoint != null) { - NavigationAppFactory.showNavigationMenu(geolocation, this, null, waypoint, null); + NavigationAppFactory.showNavigationMenu(app.currentGeo(), this, null, waypoint, null); } } break; @@ -565,50 +551,48 @@ public class CacheDetailActivity extends AbstractActivity { public boolean onOptionsItemSelected(MenuItem item) { final int menuItem = item.getItemId(); - // no menu selected, but a new sub menu shown - if (menuItem == 0) { - return false; - } - - if (menuItem == MENU_DEFAULT_NAVIGATION) { - startDefaultNavigation(); - return true; - } else if (menuItem == MENU_LOG_VISIT) { - refreshOnResume = true; - cache.logVisit(this); - return true; - } else if (menuItem == MENU_BROWSER) { - cache.openInBrowser(this); - return true; - } else if (menuItem == MENU_CACHES_AROUND) { - cachesAround(); - return true; - } else if (menuItem == MENU_CALENDAR) { - addToCalendarWithIntent(); - return true; - } else if (menuItem == MENU_SHARE) { - if (cache != null) { - cache.shareCache(this, res); + switch(menuItem) { + case 0: + // no menu selected, but a new sub menu shown + return false; + case MENU_DEFAULT_NAVIGATION: + startDefaultNavigation(); return true; - } - return false; + case MENU_LOG_VISIT: + refreshOnResume = true; + cache.logVisit(this); + return true; + case MENU_BROWSER: + cache.openInBrowser(this); + return true; + case MENU_CACHES_AROUND: + cgeocaches.startActivityCachesAround(this, cache.getCoords()); + return true; + case MENU_CALENDAR: + addToCalendarWithIntent(); + return true; + case MENU_SHARE: + if (cache != null) { + cache.shareCache(this, res); + return true; + } + return false; } - if (NavigationAppFactory.onMenuItemSelected(item, geolocation, this, cache, null, null)) { + if (NavigationAppFactory.onMenuItemSelected(item, app.currentGeo(), this, cache, null, null)) { return true; } if (GeneralAppsFactory.onMenuItemSelected(item, this, cache)) { return true; } - int logType = menuItem - MENU_LOG_VISIT_OFFLINE; - cache.logOffline(this, LogType.getById(logType)); + cache.logOffline(this, LogType.getById(menuItem - MENU_LOG_VISIT_OFFLINE)); return true; } 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) { @@ -706,12 +690,9 @@ public class CacheDetailActivity extends AbstractActivity { progress.dismiss(); } - private class LocationUpdater implements UpdateLocationCallback { + private class LocationUpdater extends GeoObserver { @Override - public void updateLocation(cgGeo geo) { - if (geo == null) { - return; - } + public void updateLocation(final IGeoData geo) { if (cacheDistanceView == null) { return; } @@ -719,13 +700,13 @@ public class CacheDetailActivity extends AbstractActivity { try { StringBuilder dist = new StringBuilder(); - if (geo.coordsNow != null && cache != null && cache.getCoords() != null) { - dist.append(HumanDistance.getHumanDistance(geo.coordsNow.distanceTo(cache.getCoords()))); + if (geo.getCoords() != null && cache != null && cache.getCoords() != null) { + dist.append(HumanDistance.getHumanDistance(geo.getCoords().distanceTo(cache.getCoords()))); } if (cache != null && cache.getElevation() != null) { - if (geo.altitudeNow != null) { - double diff = (cache.getElevation() - geo.altitudeNow); + if (geo.getAltitude() != 0.0) { + double diff = cache.getElevation() - geo.getAltitude(); if (diff >= 0) { dist.append(" ↗"); } else if (diff < 0) { @@ -744,7 +725,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."); } } } @@ -774,25 +755,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. + * + * @param context + * The application's environment. + * @param action + * The Intent action to check for availability. + * @param uri + * The Intent URI to check for availability. * - * Also finishes this activity. + * @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( @@ -833,49 +832,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<cgCoord> getCoordinates() { - List<cgCoord> coordinates = new ArrayList<cgCoord>(); - - // cache - try { - final cgCoord coords = new cgCoord(); - coords.setCoordType("cache"); - if (StringUtils.isNotBlank(cache.getName())) { - coords.setName(cache.getName()); - } else { - coords.setName(cache.getGeocode().toUpperCase()); - } - coords.setCoords(cache.getCoords()); - coordinates.add(coords); - } catch (Exception e) { - Log.e(Settings.tag, "CacheDetailActivity.getCoordinates (cache)", e); - } - - // waypoints - try { - if (cache.hasWaypoints()) { - for (cgWaypoint waypoint : cache.getWaypoints()) { - if (null != waypoint.getCoords()) { - final cgCoord coords = new cgCoord(); - coords.setCoordType("waypoint"); - coords.setName(waypoint.getName()); - coords.setCoords(waypoint.getCoords()); - coordinates.add(coords); - } - } - } - } catch (Exception e) { - Log.e(Settings.tag, "CacheDetailActivity.getCoordinates (waypoint)", e); - } - - return coordinates; - } - - /** * Tries to navigate to the {@link cgCache} of this activity. */ private void startDefaultNavigation() { @@ -885,7 +841,7 @@ public class CacheDetailActivity extends AbstractActivity { } //TODO: previously this used also the search argument "search". check if still needed - NavigationAppFactory.startDefaultNavigationApplication(geolocation, this, cache, null, null); + NavigationAppFactory.startDefaultNavigationApplication(app.currentGeo(), this, cache, null, null); } /** @@ -898,7 +854,7 @@ public class CacheDetailActivity extends AbstractActivity { } //TODO: previously this used also the search argument "search". check if still needed - NavigationAppFactory.startDefaultNavigationApplication2(geolocation, this, cache, null, null); + NavigationAppFactory.startDefaultNavigationApplication2(app.currentGeo(), this, cache, null, null); } /** @@ -916,7 +872,7 @@ public class CacheDetailActivity extends AbstractActivity { } private void showNavigationMenu() { - NavigationAppFactory.showNavigationMenu(geolocation, this, cache, null, null); + NavigationAppFactory.showNavigationMenu(app.currentGeo(), this, cache, null, null); } /** @@ -969,7 +925,7 @@ public class CacheDetailActivity extends AbstractActivity { res.getString(R.string.user_menu_open_browser) }; - AlertDialog.Builder builder = new AlertDialog.Builder(CacheDetailActivity.this); + AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(res.getString(R.string.user_menu_title) + " " + name); builder.setItems(items, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { @@ -1063,7 +1019,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; @@ -1102,7 +1058,7 @@ public class CacheDetailActivity extends AbstractActivity { } // show number of waypoints directly in waypoint title if (page == Page.WAYPOINTS) { - int waypointCount = (cache.hasWaypoints() ? cache.getWaypoints().size() : 0); + final int waypointCount = cache.getWaypoints().size(); return res.getQuantityString(R.plurals.waypoints, waypointCount, waypointCount); } return res.getString(page.titleStringId); @@ -1182,7 +1138,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) { @@ -1200,7 +1156,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) { @@ -1230,7 +1186,7 @@ public class CacheDetailActivity extends AbstractActivity { } private ViewGroup createAttributeIconsLayout(int parentWidth) { - LinearLayout rows = new LinearLayout(CacheDetailActivity.this); + final LinearLayout rows = new LinearLayout(CacheDetailActivity.this); rows.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); rows.setOrientation(LinearLayout.VERTICAL); @@ -1239,13 +1195,7 @@ public class CacheDetailActivity extends AbstractActivity { noAttributeIconsFound = true; - final String packageName = cgeoapplication.getInstance().getBaseContext().getPackageName(); for (String attributeName : cache.getAttributes()) { - boolean strikethru = attributeName.endsWith("_no"); - // cut off _yes / _no - if (attributeName.endsWith("_no") || attributeName.endsWith("_yes")) { - attributeName = attributeName.substring(0, attributeName.lastIndexOf('_')); - } // check if another attribute icon fits in this row attributeRow.measure(0, 0); int rowWidth = attributeRow.getMeasuredWidth(); @@ -1257,12 +1207,11 @@ public class CacheDetailActivity extends AbstractActivity { rows.addView(attributeRow); } - // dynamically search icon of the attribute - Drawable d = null; - int id = res.getIdentifier("attribute_" + attributeName, "drawable", packageName); - if (id > 0) { + final boolean strikethru = !CacheAttribute.isEnabled(attributeName); + final CacheAttribute attrib = CacheAttribute.getByGcRawName(CacheAttribute.trimAttributeName(attributeName)); + if (attrib != CacheAttribute.UNKNOWN) { noAttributeIconsFound = false; - d = res.getDrawable(id); + Drawable d = res.getDrawable(attrib.drawableId); iv.setImageDrawable(d); // strike through? if (strikethru) { @@ -1274,7 +1223,7 @@ public class CacheDetailActivity extends AbstractActivity { fl.addView(strikethruImage); } } else { - d = res.getDrawable(R.drawable.attribute_icon_not_found); + Drawable d = res.getDrawable(R.drawable.attribute_icon_not_found); iv.setImageDrawable(d); } @@ -1295,25 +1244,22 @@ public class CacheDetailActivity extends AbstractActivity { private ViewGroup createAttributeDescriptionsLayout() { final LinearLayout descriptions = (LinearLayout) getLayoutInflater().inflate( R.layout.attribute_descriptions, null); - TextView attribView = (TextView) descriptions.getChildAt(0); + final TextView attribView = (TextView) descriptions.getChildAt(0); - StringBuilder buffer = new StringBuilder(); - final String packageName = cgeoapplication.getInstance().getBaseContext().getPackageName(); + final StringBuilder buffer = new StringBuilder(); final List<String> attributes = cache.getAttributes(); - for (String attribute : attributes) { - // dynamically search for a translation of the attribute - int id = res.getIdentifier("attribute_" + attribute, "string", packageName); - if (id > 0) { - String translated = res.getString(id); - if (StringUtils.isNotBlank(translated)) { - attribute = translated; - } + for (String attributeName : attributes) { + final boolean enabled = CacheAttribute.isEnabled(attributeName); + // search for a translation of the attribute + CacheAttribute attrib = CacheAttribute.getByGcRawName(CacheAttribute.trimAttributeName(attributeName)); + if (attrib != CacheAttribute.UNKNOWN) { + attributeName = attrib.getL10n(enabled); } if (buffer.length() > 0) { buffer.append('\n'); } - buffer.append(attribute); + buffer.append(attributeName); } if (noAttributeIconsFound) { @@ -1482,7 +1428,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; } @@ -1548,10 +1494,6 @@ public class CacheDetailActivity extends AbstractActivity { } } - if (geolocation != null) { - locationUpdater.updateLocation(geolocation); - } - return view; } @@ -1581,20 +1523,11 @@ 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; - - try { - cache = search.getFirstCacheFromResult(LoadFlags.LOAD_ALL_DB_ONLY); // reload cache details - } catch (Exception e) { - showToast(res.getString(R.string.err_store_failed)); - - Log.e(Settings.tag, "CacheDetailActivity.storeCacheHandler: " + e.toString()); - } - - CacheDetailActivity.this.notifyDataSetChanged(); + CacheDetailActivity.this.notifyDataSetChanged(); // reload cache details } } @@ -1608,20 +1541,11 @@ 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; - - try { - cache = search.getFirstCacheFromResult(LoadFlags.LOAD_ALL_DB_ONLY); // reload cache details - } catch (Exception e) { - showToast(res.getString(R.string.err_refresh_failed)); - - Log.e(Settings.tag, "CacheDetailActivity.refreshCacheHandler: " + e.toString()); - } - - CacheDetailActivity.this.notifyDataSetChanged(); + CacheDetailActivity.this.notifyDataSetChanged(); // reload cache details } } @@ -1701,8 +1625,7 @@ public class CacheDetailActivity extends AbstractActivity { @Override public void run() { - app.removeCache(cache.getGeocode(), EnumSet.of(RemoveFlag.REMOVE_CACHE)); - search = cgBase.searchByGeocode(cache.getGeocode(), null, 0, true, handler); + cache.refresh(CacheDetailActivity.this, cache.getListId(), handler); handler.sendEmptyMessage(0); } @@ -1732,7 +1655,7 @@ public class CacheDetailActivity extends AbstractActivity { @Override public void run() { - cgBase.dropCache(cache, handler); + cache.drop(handler); } } @@ -1788,7 +1711,7 @@ public class CacheDetailActivity extends AbstractActivity { @Override public void run() { - handler.sendEmptyMessage(cgBase.addToWatchlist(cache)); + handler.sendEmptyMessage(GCParser.addToWatchlist(cache)); } } @@ -1802,7 +1725,7 @@ public class CacheDetailActivity extends AbstractActivity { @Override public void run() { - handler.sendEmptyMessage(cgBase.removeFromWatchlist(cache)); + handler.sendEmptyMessage(GCParser.removeFromWatchlist(cache)); } } @@ -1856,7 +1779,7 @@ public class CacheDetailActivity extends AbstractActivity { if (cache.getListId() >= StoredList.STANDARD_LIST_ID) { long diff = (System.currentTimeMillis() / (60 * 1000)) - (cache.getDetailedUpdate() / (60 * 1000)); // minutes - String ago = ""; + String ago; if (diff < 15) { ago = res.getString(R.string.cache_offline_time_mins_few); } else if (diff < 50) { @@ -1889,9 +1812,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); @@ -1902,15 +1823,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 @@ -2109,7 +2030,7 @@ public class CacheDetailActivity extends AbstractActivity { // if description has HTML table, add a note at the end of the long description if (unknownTagsHandler.isTableDetected() && descriptionView == view.findViewById(R.id.longdesc)) { final int startPos = description.length(); - ((Editable) description).append("\n\n" + res.getString(R.string.cache_description_table_note)); + ((Editable) description).append("\n\n").append(res.getString(R.string.cache_description_table_note)); ((Editable) description).setSpan(new StyleSpan(Typeface.ITALIC), startPos, description.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); publishProgress(); } @@ -2234,7 +2155,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(); @@ -2250,10 +2171,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); @@ -2283,10 +2204,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()); } @@ -2300,7 +2221,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 { @@ -2391,92 +2312,88 @@ public class CacheDetailActivity extends AbstractActivity { view = (ScrollView) getLayoutInflater().inflate(R.layout.cacheview_waypoints, null); - LinearLayout waypoints = (LinearLayout) view.findViewById(R.id.waypoints); + final LinearLayout waypoints = (LinearLayout) view.findViewById(R.id.waypoints); - if (cache.hasWaypoints()) { - LinearLayout waypointView; + // sort waypoints: PP, Sx, FI, OWN + final List<cgWaypoint> sortedWaypoints = new ArrayList<cgWaypoint>(cache.getWaypoints()); + Collections.sort(sortedWaypoints); - // sort waypoints: PP, Sx, FI, OWN - List<cgWaypoint> sortedWaypoints = new ArrayList<cgWaypoint>(cache.getWaypoints()); - Collections.sort(sortedWaypoints); + for (final cgWaypoint wpt : sortedWaypoints) { + final LinearLayout waypointView = (LinearLayout) getLayoutInflater().inflate(R.layout.waypoint_item, null); - for (final cgWaypoint wpt : sortedWaypoints) { - waypointView = (LinearLayout) getLayoutInflater().inflate(R.layout.waypoint_item, null); + // coordinates + if (null != wpt.getCoords()) { + final TextView coordinatesView = (TextView) waypointView.findViewById(R.id.coordinates); + coordinatesView.setText(wpt.getCoords().toString()); + coordinatesView.setVisibility(View.VISIBLE); + } - // coordinates - if (null != wpt.getCoords()) { - final TextView coordinatesView = (TextView) waypointView.findViewById(R.id.coordinates); - coordinatesView.setText(wpt.getCoords().toString()); - coordinatesView.setVisibility(View.VISIBLE); + // info + final List<String> infoTextList = new ArrayList<String>(3); + if (WaypointType.ALL_TYPES_EXCEPT_OWN.contains(wpt.getWaypointType())) { + infoTextList.add(wpt.getWaypointType().getL10n()); + } + if (cgWaypoint.PREFIX_OWN.equalsIgnoreCase(wpt.getPrefix())) { + infoTextList.add(res.getString(R.string.waypoint_custom)); + } else { + if (StringUtils.isNotBlank(wpt.getPrefix())) { + infoTextList.add(wpt.getPrefix()); } - - // info - final List<String> infoTextList = new ArrayList<String>(3); - if (WaypointType.ALL_TYPES_EXCEPT_OWN.containsKey(wpt.getWaypointType())) { - infoTextList.add(wpt.getWaypointType().getL10n()); + if (StringUtils.isNotBlank(wpt.getLookup())) { + infoTextList.add(wpt.getLookup()); } - if (cgWaypoint.PREFIX_OWN.equalsIgnoreCase(wpt.getPrefix())) { - infoTextList.add(res.getString(R.string.waypoint_custom)); - } else { - if (StringUtils.isNotBlank(wpt.getPrefix())) { - infoTextList.add(wpt.getPrefix()); - } - if (StringUtils.isNotBlank(wpt.getLookup())) { - infoTextList.add(wpt.getLookup()); - } + } + if (CollectionUtils.isNotEmpty(infoTextList)) { + final TextView infoView = (TextView) waypointView.findViewById(R.id.info); + infoView.setText(StringUtils.join(infoTextList, Formatter.SEPARATOR)); + infoView.setVisibility(View.VISIBLE); + } + + // title + final TextView nameView = (TextView) waypointView.findViewById(R.id.name); + if (StringUtils.isNotBlank(wpt.getName())) { + nameView.setText(StringEscapeUtils.unescapeHtml4(wpt.getName())); + } else if (null != wpt.getCoords()) { + nameView.setText(wpt.getCoords().toString()); + } else { + nameView.setText(res.getString(R.string.waypoint)); + } + wpt.setIcon(res, nameView); + + // note + if (StringUtils.isNotBlank(wpt.getNote())) { + final TextView noteView = (TextView) waypointView.findViewById(R.id.note); + noteView.setVisibility(View.VISIBLE); + if (BaseUtils.containsHtml(wpt.getNote())) { + noteView.setText(Html.fromHtml(wpt.getNote()), TextView.BufferType.SPANNABLE); } - if (CollectionUtils.isNotEmpty(infoTextList)) { - final TextView infoView = (TextView) waypointView.findViewById(R.id.info); - infoView.setText(StringUtils.join(infoTextList, Formatter.SEPARATOR)); - infoView.setVisibility(View.VISIBLE); + else { + noteView.setText(wpt.getNote()); } + } - // title - TextView nameView = (TextView) waypointView.findViewById(R.id.name); - if (StringUtils.isNotBlank(wpt.getName())) { - nameView.setText(StringEscapeUtils.unescapeHtml4(wpt.getName())); - } else if (null != wpt.getCoords()) { - nameView.setText(wpt.getCoords().toString()); - } else { - nameView.setText(res.getString(R.string.waypoint)); + final View wpNavView = waypointView.findViewById(R.id.wpDefaultNavigation); + wpNavView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + NavigationAppFactory.startDefaultNavigationApplication(app.currentGeo(), CacheDetailActivity.this, null, wpt, null); } - wpt.setIcon(res, nameView); - - // note - if (StringUtils.isNotBlank(wpt.getNote())) { - final TextView noteView = (TextView) waypointView.findViewById(R.id.note); - noteView.setVisibility(View.VISIBLE); - if (BaseUtils.containsHtml(wpt.getNote())) { - noteView.setText(Html.fromHtml(wpt.getNote()), TextView.BufferType.SPANNABLE); - } - else { - noteView.setText(wpt.getNote()); - } + }); + wpNavView.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + NavigationAppFactory.startDefaultNavigationApplication2(app.currentGeo(), CacheDetailActivity.this, null, wpt, null); + return true; } + }); - View wpNavView = waypointView.findViewById(R.id.wpDefaultNavigation); - wpNavView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - NavigationAppFactory.startDefaultNavigationApplication(geolocation, CacheDetailActivity.this, null, wpt, null); - } - }); - wpNavView.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - NavigationAppFactory.startDefaultNavigationApplication2(geolocation, CacheDetailActivity.this, null, wpt, null); - return true; - } - }); - - registerForContextMenu(waypointView); - waypointView.setOnClickListener(new WaypointInfoClickListener()); + registerForContextMenu(waypointView); + waypointView.setOnClickListener(new WaypointInfoClickListener()); - waypoints.addView(waypointView); - } + waypoints.addView(waypointView); } - Button addWaypoint = (Button) view.findViewById(R.id.add_waypoint); + final Button addWaypoint = (Button) view.findViewById(R.id.add_waypoint); addWaypoint.setClickable(true); addWaypoint.setOnClickListener(new AddWaypointClickListener()); @@ -2485,16 +2402,9 @@ public class CacheDetailActivity extends AbstractActivity { private class AddWaypointClickListener implements View.OnClickListener { - public void onClick(View view) { - Intent addWptIntent = new Intent(CacheDetailActivity.this, cgeowaypointadd.class); - - addWptIntent.putExtra("geocode", cache.getGeocode()); - int wpCount = 0; - if (cache.hasWaypoints()) { - wpCount = cache.getWaypoints().size(); - } - addWptIntent.putExtra("count", wpCount); - + public void onClick(final View view) { + final Intent addWptIntent = new Intent(CacheDetailActivity.this, cgeowaypointadd.class); + addWptIntent.putExtra("geocode", cache.getGeocode()).putExtra("count", cache.getWaypoints().size()); startActivity(addWptIntent); refreshOnResume = true; } @@ -2550,4 +2460,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/GeoDataProvider.java b/main/src/cgeo/geocaching/GeoDataProvider.java new file mode 100644 index 0000000..58b0696 --- /dev/null +++ b/main/src/cgeo/geocaching/GeoDataProvider.java @@ -0,0 +1,305 @@ +package cgeo.geocaching; + +import cgeo.geocaching.enumerations.LocationProviderType; +import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.go4cache.Go4Cache; +import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.MemorySubject; + +import android.content.Context; +import android.location.GpsSatellite; +import android.location.GpsStatus; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.os.Bundle; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** + * Provide information about the user location. This class should be instantiated only once per application. + */ +class GeoDataProvider extends MemorySubject<IGeoData> { + + private static final String LAST_LOCATION_PSEUDO_PROVIDER = "last"; + private final LocationManager geoManager; + private final GpsStatus.Listener gpsStatusListener = new GpsStatusListener(); + private final LocationData gpsLocation = new LocationData(); + private final LocationData netLocation = new LocationData(); + private final Listener networkListener = new Listener(LocationManager.NETWORK_PROVIDER, netLocation); + private final Listener gpsListener = new Listener(LocationManager.GPS_PROVIDER, gpsLocation); + private final Unregisterer unregisterer = new Unregisterer(); + public boolean gpsEnabled = false; + public int satellitesVisible = 0; + public int satellitesFixed = 0; + + private static class LocationData { + public Location location; + public long timestamp = 0; + + public void update(final Location location) { + this.location = location; + timestamp = System.currentTimeMillis(); + } + + public boolean isRecent() { + return isValid() && System.currentTimeMillis() < timestamp + 30000; + } + + public boolean isValid() { + return location != null; + } + } + + private static class GeoData extends Location implements IGeoData { + public boolean gpsEnabled = false; + public int satellitesVisible = 0; + public int satellitesFixed = 0; + + GeoData(final Location location, final boolean gpsEnabled, final int satellitesVisible, final int satellitesFixed) { + super(location); + this.gpsEnabled = gpsEnabled; + this.satellitesVisible = satellitesVisible; + this.satellitesFixed = satellitesFixed; + } + + @Override + public Location getLocation() { + return this; + } + + private static LocationProviderType getLocationProviderType(final String provider) { + if (provider.equals(LocationManager.GPS_PROVIDER)) { + return LocationProviderType.GPS; + } + if (provider.equals(LocationManager.NETWORK_PROVIDER)) { + return LocationProviderType.NETWORK; + } + return LocationProviderType.LAST; + } + + @Override + public LocationProviderType getLocationProvider() { + return getLocationProviderType(getProvider()); + } + + @Override + public Geopoint getCoords() { + return new Geopoint(this); + } + + @Override + public boolean getGpsEnabled() { + return gpsEnabled; + } + + @Override + public int getSatellitesVisible() { + return satellitesVisible; + } + + @Override + public int getSatellitesFixed() { + return satellitesFixed; + } + } + + private class Unregisterer extends Thread { + + private boolean unregisterRequested = false; + private final ArrayBlockingQueue<Boolean> queue = new ArrayBlockingQueue<Boolean>(1); + + public void cancelUnregister() { + try { + queue.put(false); + } catch (final InterruptedException e) { + // Do nothing + } + } + + public void lateUnregister() { + try { + queue.put(true); + } catch (final InterruptedException e) { + // Do nothing + } + } + + @Override + public void run() { + try { + while (true) { + if (unregisterRequested) { + final Boolean element = queue.poll(2500, TimeUnit.MILLISECONDS); + if (element == null) { + // Timeout + unregisterListeners(); + unregisterRequested = false; + } else { + unregisterRequested = element; + } + } else { + unregisterRequested = queue.take(); + } + } + } catch (final InterruptedException e) { + // Do nothing + } + } + + } + + /** + * Build a new geo data provider object. + * <p/> + * There is no need to instantiate more than one such object in an application, as observers can be added + * at will. + * + * @param context the context used to retrieve the system services + */ + GeoDataProvider(final Context context) { + geoManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + unregisterer.start(); + // Start with an empty GeoData just in case someone queries it before we get + // a chance to get any information. + notifyObservers(new GeoData(new Location(LAST_LOCATION_PSEUDO_PROVIDER), false, 0, 0)); + } + + private void registerListeners() { + geoManager.addGpsStatusListener(gpsStatusListener); + + for (final Listener listener : new Listener[] { networkListener, gpsListener }) { + try { + geoManager.requestLocationUpdates(listener.locationProvider, 0, 0, listener); + } catch (final Exception e) { + Log.w("There is no location provider " + listener.locationProvider); + } + } + } + + private synchronized void unregisterListeners() { + // This method must be synchronized because it will be called asynchronously from the Unregisterer thread. + // We check that no observers have been re-added to prevent a race condition. + if (sizeObservers() == 0) { + geoManager.removeUpdates(networkListener); + geoManager.removeUpdates(gpsListener); + geoManager.removeGpsStatusListener(gpsStatusListener); + } + } + + @Override + protected void onFirstObserver() { + unregisterer.cancelUnregister(); + registerListeners(); + } + + @Override + protected void onLastObserver() { + unregisterer.lateUnregister(); + } + + private class Listener implements LocationListener { + private final String locationProvider; + private final LocationData locationData; + + Listener(final String locationProvider, final LocationData locationData) { + this.locationProvider = locationProvider; + this.locationData = locationData; + } + + @Override + public void onStatusChanged(final String provider, final int status, final Bundle extras) { + // nothing + } + + @Override + public void onProviderDisabled(final String provider) { + // nothing + } + + @Override + public void onProviderEnabled(final String provider) { + // nothing + } + + @Override + public void onLocationChanged(final Location location) { + locationData.update(location); + selectBest(); + } + } + + private final class GpsStatusListener implements GpsStatus.Listener { + + @Override + public void onGpsStatusChanged(final int event) { + boolean changed = false; + switch (event) { + case GpsStatus.GPS_EVENT_SATELLITE_STATUS: { + final GpsStatus status = geoManager.getGpsStatus(null); + int visible = 0; + int fixed = 0; + for (final GpsSatellite satellite : status.getSatellites()) { + if (satellite.usedInFix()) { + fixed++; + } + visible++; + } + if (visible != satellitesVisible || fixed != satellitesFixed) { + satellitesVisible = visible; + satellitesFixed = fixed; + changed = true; + } + break; + } + case GpsStatus.GPS_EVENT_STARTED: + if (!gpsEnabled) { + gpsEnabled = true; + changed = true; + } + break; + case GpsStatus.GPS_EVENT_STOPPED: + if (gpsEnabled) { + gpsEnabled = false; + satellitesFixed = 0; + satellitesVisible = 0; + changed = true; + } + break; + } + + if (changed) { + selectBest(); + } + } + } + + private LocationData best() { + if (gpsLocation.isRecent() || !netLocation.isValid()) { + return gpsLocation.isValid() ? gpsLocation : null; + } + if (!gpsLocation.isValid()) { + return netLocation; + } + return gpsLocation.timestamp > netLocation.timestamp ? gpsLocation : netLocation; + } + + private void selectBest() { + assign(best()); + } + + private void assign(final LocationData locationData) { + if (locationData == null) { + return; + } + + // We do not necessarily get signalled when satellites go to 0/0. + final int visible = gpsLocation.isRecent() ? satellitesVisible : 0; + final IGeoData current = new GeoData(locationData.location, gpsEnabled, visible, satellitesFixed); + notifyObservers(current); + + Go4Cache.signalCoordinates(current.getCoords()); + } + +} diff --git a/main/src/cgeo/geocaching/GeoObserver.java b/main/src/cgeo/geocaching/GeoObserver.java new file mode 100644 index 0000000..8d5475f --- /dev/null +++ b/main/src/cgeo/geocaching/GeoObserver.java @@ -0,0 +1,13 @@ +package cgeo.geocaching; + +import cgeo.geocaching.utils.IObserver; + +public abstract class GeoObserver implements IObserver<IGeoData> { + + abstract protected void updateLocation(final IGeoData geo); + + @Override + public void update(final IGeoData geo) { + updateLocation(geo); + } +} 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/IGeoData.java b/main/src/cgeo/geocaching/IGeoData.java new file mode 100644 index 0000000..9696b27 --- /dev/null +++ b/main/src/cgeo/geocaching/IGeoData.java @@ -0,0 +1,21 @@ +package cgeo.geocaching; + +import cgeo.geocaching.enumerations.LocationProviderType; +import cgeo.geocaching.geopoint.Geopoint; + +import android.location.Location; + +public interface IGeoData { + + public Location getLocation(); + public LocationProviderType getLocationProvider(); + public Geopoint getCoords(); + public double getAltitude(); + public float getBearing(); + public float getSpeed(); + public float getAccuracy(); + public boolean getGpsEnabled(); + public int getSatellitesVisible(); + public int getSatellitesFixed(); + +} diff --git a/main/src/cgeo/geocaching/IWaypoint.java b/main/src/cgeo/geocaching/IWaypoint.java index 870fb12..ad12d48 100644 --- a/main/src/cgeo/geocaching/IWaypoint.java +++ b/main/src/cgeo/geocaching/IWaypoint.java @@ -4,18 +4,17 @@ 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/LiveMapInfo.java b/main/src/cgeo/geocaching/LiveMapInfo.java index 3d6d110..822fbf6 100644 --- a/main/src/cgeo/geocaching/LiveMapInfo.java +++ b/main/src/cgeo/geocaching/LiveMapInfo.java @@ -9,8 +9,6 @@ import android.widget.CheckBox; public class LiveMapInfo extends AbstractActivity { - private int showCount; - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -18,7 +16,7 @@ public class LiveMapInfo extends AbstractActivity { setTheme(R.style.transparent); setContentView(R.layout.livemapinfo); - showCount = Settings.getLiveMapHintShowCount(); + final int showCount = Settings.getLiveMapHintShowCount(); if (showCount > 2) { final CheckBox cb = (CheckBox) findViewById(R.id.live_map_hint_hide); diff --git a/main/src/cgeo/geocaching/LogEntry.java b/main/src/cgeo/geocaching/LogEntry.java new file mode 100644 index 0000000..9864f89 --- /dev/null +++ b/main/src/cgeo/geocaching/LogEntry.java @@ -0,0 +1,86 @@ +package cgeo.geocaching; + +import cgeo.geocaching.enumerations.LogType; + +import org.apache.commons.collections.CollectionUtils; + +import java.util.ArrayList; +import java.util.Calendar; +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 + + public LogEntry(final Calendar date, final LogType type, final String text) { + this(Settings.getUsername(), date.getTimeInMillis(), type, text); + } + + public LogEntry(final long dateInMilliSeconds, final LogType type, final String text) { + this(Settings.getUsername(), dateInMilliSeconds, type, text); + } + + public LogEntry(final String author, long dateInMilliSeconds, final LogType type, final String text) { + this.author = author; + this.date = dateInMilliSeconds; + this.type = type; + this.log = text; + } + + @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 bac9c23..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; @@ -22,10 +22,10 @@ import java.util.Set; public class SearchResult implements Parcelable { final private Set<String> geocodes; - public StatusCode error = null; + private StatusCode error = null; private String url = ""; public String[] viewstates = null; - public int totalCnt = 0; + private int totalCnt = 0; final public static Parcelable.Creator<SearchResult> CREATOR = new Parcelable.Creator<SearchResult>() { public SearchResult createFromParcel(Parcel in) { @@ -47,19 +47,24 @@ public class SearchResult implements Parcelable { this.error = searchResult.error; this.url = searchResult.url; this.viewstates = searchResult.viewstates; - this.totalCnt = searchResult.totalCnt; + this.setTotal(searchResult.getTotal()); } else { this.geocodes = new HashSet<String>(); } } - public SearchResult(final Set<String> geocodes) { + public SearchResult(final Set<String> geocodes, final int total) { if (geocodes == null) { this.geocodes = new HashSet<String>(); } else { this.geocodes = new HashSet<String>(geocodes.size()); this.geocodes.addAll(geocodes); } + this.setTotal(total); + } + + public SearchResult(final Set<String> geocodes) { + this(geocodes, geocodes == null ? 0 : geocodes.size()); } public SearchResult(final Parcel in) { @@ -73,7 +78,7 @@ public class SearchResult implements Parcelable { viewstates = new String[length]; in.readStringArray(viewstates); } - totalCnt = in.readInt(); + setTotal(in.readInt()); } @Override @@ -87,7 +92,7 @@ public class SearchResult implements Parcelable { out.writeInt(viewstates.length); out.writeStringArray(viewstates); } - out.writeInt(totalCnt); + out.writeInt(getTotal()); } @Override @@ -124,7 +129,7 @@ public class SearchResult implements Parcelable { } public void setViewstates(String[] viewstates) { - if (cgBase.isEmpty(viewstates)) { + if (Login.isEmpty(viewstates)) { return; } @@ -135,6 +140,10 @@ public class SearchResult implements Parcelable { return totalCnt; } + public void setTotal(int totalCnt) { + this.totalCnt = totalCnt; + } + /** * @param excludeDisabled * @param excludeMine @@ -192,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 f2ec497..3b36b23 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; @@ -79,11 +81,12 @@ public final class Settings { private static final String KEY_DEFAULT_NAVIGATION_TOOL = "defaultNavigationTool"; private static final String KEY_DEFAULT_NAVIGATION_TOOL_2 = "defaultNavigationTool2"; private static final String KEY_LIVE_MAP_STRATEGY = "livemapstrategy"; + 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"); @@ -101,24 +104,22 @@ public final class Settings { static coordInputFormatEnum fromInt(int id) { final coordInputFormatEnum[] values = coordInputFormatEnum.values(); - if (id >= 0 && id < values.length) { - return values[id]; - } else { + if (id < 0 || id >= values.length) { return Min; } + return values[id]; } } - // 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; + 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; @@ -126,6 +127,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(); @@ -161,11 +233,7 @@ public final class Settings { } public static String getUsername() { - if (null == username) { - return sharedPrefs.getString(KEY_USERNAME, null); - } else { - return username; - } + return username != null ? username : sharedPrefs.getString(KEY_USERNAME, null); } public static boolean setLogin(final String username, final String password) { @@ -311,15 +379,13 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_MAP_LIVE, live ? 1 : 0); + edit.putBoolean(KEY_MAP_LIVE, live); } }); } public static int getLastList() { - final int listId = sharedPrefs.getInt(KEY_LAST_USED_LIST, StoredList.STANDARD_LIST_ID); - - return listId; + return sharedPrefs.getInt(KEY_LAST_USED_LIST, StoredList.STANDARD_LIST_ID); } public static void saveLastList(final int listId) { @@ -356,26 +422,16 @@ public final class Settings { } public static boolean setMapFile(final String mapFile) { - final boolean commitResult = editSharedSettings(new PrefRunnable() { - + return editSharedSettings(new PrefRunnable() { @Override public void edit(Editor edit) { edit.putString(KEY_MAPFILE, mapFile); } }); - - 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() { @@ -417,7 +473,7 @@ public final class Settings { } public static boolean getLoadDirImg() { - return isPremiumMember() ? false : sharedPrefs.getBoolean(KEY_LOAD_DIRECTION_IMG, true); + return !isPremiumMember() && sharedPrefs.getBoolean(KEY_LOAD_DIRECTION_IMG, true); } public static void setGcCustomDate(final String format) { @@ -439,7 +495,7 @@ public final class Settings { } public static boolean isExcludeMyCaches() { - return 0 != sharedPrefs.getInt(KEY_EXCLUDE_OWN, 0); + return sharedPrefs.getBoolean(KEY_EXCLUDE_OWN, false); } /** @@ -459,7 +515,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); } }); } @@ -479,7 +535,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) { @@ -487,13 +543,13 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_SHOW_ADDRESS, showAddress ? 1 : 0); + edit.putBoolean(KEY_SHOW_ADDRESS, showAddress); } }); } public static boolean isShowCaptcha() { - return isPremiumMember() ? false : sharedPrefs.getBoolean(KEY_SHOW_CAPTCHA, false); + return !isPremiumMember() && sharedPrefs.getBoolean(KEY_SHOW_CAPTCHA, false); } public static void setShowCaptcha(final boolean showCaptcha) { @@ -507,7 +563,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) { @@ -515,13 +571,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) { @@ -529,13 +585,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, 0); + return sharedPrefs.getBoolean(KEY_USE_OFFLINEWPMAPS, false); } public static void setStoreOfflineWpMaps(final boolean offlineMaps) { @@ -543,7 +599,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); } }); } @@ -563,7 +619,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) { @@ -571,13 +627,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) { @@ -585,7 +641,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); } }); } @@ -637,7 +693,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) { @@ -645,13 +701,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) { @@ -659,7 +715,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_PUBLICLOC, publicLocation ? 1 : 0); + edit.putBoolean(KEY_PUBLICLOC, publicLocation); } }); } @@ -693,7 +749,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) { @@ -701,17 +757,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) { @@ -719,7 +775,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); } }); } @@ -782,7 +838,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) { @@ -790,13 +846,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() { @@ -804,13 +860,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) { @@ -818,7 +874,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_SKIN, lightSkin ? 1 : 0); + edit.putBoolean(KEY_SKIN, lightSkin); } }); } @@ -860,6 +916,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); } @@ -875,7 +937,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) { @@ -883,7 +945,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); } }); } @@ -1017,8 +1079,23 @@ public final class Settings { }); } + + public static boolean isDebug() { + return Log.isDebug(); + } + + public static void setDebug(final boolean debug) { + editSharedSettings(new PrefRunnable() { + + @Override public void edit(Editor edit) { + edit.putBoolean(KEY_DEBUG, 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) { @@ -1026,7 +1103,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); } }); } @@ -1044,4 +1121,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 e7c975c..2e5f423 100644 --- a/main/src/cgeo/geocaching/StaticMapsActivity.java +++ b/main/src/cgeo/geocaching/StaticMapsActivity.java @@ -2,6 +2,7 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.enumerations.LoadFlags; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; @@ -13,7 +14,6 @@ import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; @@ -37,26 +37,20 @@ public class StaticMapsActivity extends AbstractActivity { @Override public void handleMessage(Message msg) { + if (waitDialog != null) { + waitDialog.dismiss(); + } try { if (CollectionUtils.isEmpty(maps)) { - if (waitDialog != null) { - waitDialog.dismiss(); - } - if ((waypoint_id != null && Settings.isStoreOfflineWpMaps()) || (waypoint_id == null && Settings.isStoreOfflineMaps())) { - AlertDialog.Builder builder = new AlertDialog.Builder(StaticMapsActivity.this); + final AlertDialog.Builder builder = new AlertDialog.Builder(StaticMapsActivity.this); builder.setMessage(R.string.err_detail_ask_store_map_static).setPositiveButton(android.R.string.yes, dialogClickListener) .setNegativeButton(android.R.string.no, dialogClickListener).show(); } else { showToast(res.getString(R.string.err_detail_not_load_map_static)); finish(); } - return; } else { - if (waitDialog != null) { - waitDialog.dismiss(); - } - if (inflater == null) { inflater = getLayoutInflater(); } @@ -66,7 +60,7 @@ public class StaticMapsActivity extends AbstractActivity { } smapsView.removeAllViews(); - for (Bitmap image : maps) { + for (final Bitmap image : maps) { if (image != null) { final ImageView map = (ImageView) inflater.inflate(R.layout.map_static_item, null); map.setImageBitmap(image); @@ -75,10 +69,7 @@ public class StaticMapsActivity extends AbstractActivity { } } } catch (Exception e) { - if (waitDialog != null) { - waitDialog.dismiss(); - } - Log.e(Settings.tag, "StaticMapsActivity.loadMapsHandler: " + e.toString()); + Log.e("StaticMapsActivity.loadMapsHandler: " + e.toString()); } } }; @@ -160,7 +151,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 +170,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 fcb8ed9..9fbf429 100644 --- a/main/src/cgeo/geocaching/StaticMapsProvider.java +++ b/main/src/cgeo/geocaching/StaticMapsProvider.java @@ -1,10 +1,11 @@ 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; import org.apache.commons.lang3.StringUtils; @@ -12,7 +13,6 @@ import org.apache.http.HttpResponse; import android.app.Activity; import android.content.Context; -import android.util.Log; import android.view.Display; import android.view.WindowManager; @@ -30,28 +30,43 @@ 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) { - 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); - downloadMap(cache, 14, "roadmap", markerUrl, prefix, 4, latlonMap, edge, waypoints); - 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 downloadDifferentZooms(final String geocode, String markerUrl, String prefix, String latlonMap, int edge, final Parameters waypoints) { + downloadMap(geocode, 20, "satellite", markerUrl, prefix, 1, latlonMap, edge, waypoints); + downloadMap(geocode, 18, "satellite", markerUrl, prefix, 2, latlonMap, edge, waypoints); + downloadMap(geocode, 16, "roadmap", markerUrl, prefix, 3, latlonMap, edge, waypoints); + downloadMap(geocode, 14, "roadmap", markerUrl, prefix, 4, latlonMap, edge, waypoints); + downloadMap(geocode, 11, "roadmap", markerUrl, prefix, 5, latlonMap, edge, waypoints); + } + + private static void downloadMap(String geocode, 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) { - if (LocalStorage.saveEntityToFile(httpResponse, file)) { - // Delete image if it has no contents - final long fileSize = file.length(); - if (fileSize < MIN_MAP_IMAGE_BYTES) { - file.delete(); + if (httpResponse.getStatusLine().getStatusCode() == 200) { + final File file = getMapFile(geocode, prefix, level, true); + if (LocalStorage.saveEntityToFile(httpResponse, file)) { + // Delete image if it has no contents + final long fileSize = file.length(); + if (fileSize < MIN_MAP_IMAGE_BYTES) { + file.delete(); + } } + } else { + Log.d("StaticMapsProvider.downloadMap: httpResponseCode = " + httpResponse.getStatusLine().getStatusCode()); } + } else { + Log.e("StaticMapsProvider.downloadMap: httpResponse is null"); } } @@ -79,24 +94,24 @@ public class StaticMapsProvider { // download static map for current waypoints if (Settings.isStoreOfflineWpMaps() && CollectionUtils.isNotEmpty(cache.getWaypoints())) { for (cgWaypoint waypoint : cache.getWaypoints()) { - storeWaypointStaticMap(cache, edge, waypoint, false); + storeWaypointStaticMap(cache.getGeocode(), edge, waypoint, false); } } } public static void storeWaypointStaticMap(cgCache cache, Activity activity, cgWaypoint waypoint, boolean waitForResult) { int edge = StaticMapsProvider.guessMinDisplaySide(activity); - storeWaypointStaticMap(cache, edge, waypoint, waitForResult); + storeWaypointStaticMap(cache.getGeocode(), edge, waypoint, waitForResult); } - private static void storeWaypointStaticMap(cgCache cache, int edge, cgWaypoint waypoint, final boolean waitForResult) { + private static void storeWaypointStaticMap(final String geocode, int edge, cgWaypoint waypoint, final boolean waitForResult) { if (waypoint.getCoords() == null) { return; } 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(geocode, wpMarkerUrl, "wp" + waypoint.getId() + "_", wpLatlonMap, edge, null, waitForResult); } public static void storeCacheStaticMap(cgCache cache, Activity activity, final boolean waitForResult) { @@ -104,30 +119,25 @@ public class StaticMapsProvider { storeCacheStaticMap(cache, edge, waitForResult); } - private static void storeCacheStaticMap(cgCache cache, int edge, final boolean waitForResult) { + private static void storeCacheStaticMap(final cgCache cache, final int edge, final boolean waitForResult) { final String latlonMap = cache.getCoords().format(Format.LAT_LON_DECDEGREE_COMMA); - final StringBuilder waypoints = new StringBuilder(); - 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 Parameters waypoints = new Parameters(); + for (final cgWaypoint waypoint : cache.getWaypoints()) { + if (waypoint.getCoords() == null) { + continue; } + 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.getGeocode(), cacheMarkerUrl, "", latlonMap, edge, waypoints, waitForResult); } private static int guessMinDisplaySide(Display display) { final int maxWidth = display.getWidth() - 25; final int maxHeight = display.getHeight() - 25; - int edge = 0; + int edge; if (maxWidth > maxHeight) { edge = maxWidth; } else { @@ -140,22 +150,22 @@ public class StaticMapsProvider { return guessMinDisplaySide(((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()); } - private static void downloadMaps(final cgCache cache, final String markerUrl, final String prefix, final String latlonMap, final int edge, - final String waypoints, boolean waitForResult) { + private static void downloadMaps(final String geocode, final String markerUrl, final String prefix, final String latlonMap, final int edge, + final Parameters waypoints, boolean waitForResult) { if (waitForResult) { - downloadDifferentZooms(cache, markerUrl, prefix, latlonMap, edge, waypoints); + downloadDifferentZooms(geocode, 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); + downloadDifferentZooms(geocode, markerUrl, prefix, latlonMap, edge, waypoints); } }; 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 +178,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 +193,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..eaf677d 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 >= cgData.customListIdOffset) { + 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/UpdateLocationCallback.java b/main/src/cgeo/geocaching/UpdateLocationCallback.java deleted file mode 100644 index f0334a1..0000000 --- a/main/src/cgeo/geocaching/UpdateLocationCallback.java +++ /dev/null @@ -1,5 +0,0 @@ -package cgeo.geocaching; - -public interface UpdateLocationCallback { - public void updateLocation(cgGeo geo); -} diff --git a/main/src/cgeo/geocaching/VisitCacheActivity.java b/main/src/cgeo/geocaching/VisitCacheActivity.java index f0acd97..72e70e9 100644 --- a/main/src/cgeo/geocaching/VisitCacheActivity.java +++ b/main/src/cgeo/geocaching/VisitCacheActivity.java @@ -1,18 +1,20 @@ 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; 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; @@ -26,7 +28,6 @@ import android.content.res.Configuration; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.Menu; @@ -64,12 +65,11 @@ 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; private Button postButton = null; - private Button saveButton = null; private Button clearButton = null; private CheckBox tweetCheck = null; private LinearLayout tweetBox = null; @@ -88,16 +88,13 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D showToast(res.getString(R.string.info_log_type_changed)); } - if (cgBase.isEmpty(viewstates) && attempts < 2) { - final LoadDataThread thread; - thread = new LoadDataThread(); - thread.start(); - - return; - } else if (cgBase.isEmpty(viewstates) && attempts >= 2) { - showToast(res.getString(R.string.err_log_load_data)); - showProgress(false); - + if (Login.isEmpty(viewstates)) { + if (attempts < 2) { + new LoadDataThread().start(); + } else { + showToast(res.getString(R.string.err_log_load_data)); + showProgress(false); + } return; } @@ -114,7 +111,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); @@ -295,7 +292,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D @Override public boolean onCreateOptionsMenu(Menu menu) { - SubMenu menuLog = null; + SubMenu menuLog; menuLog = menu.addSubMenu(0, 0, 0, res.getString(R.string.log_add)).setIcon(android.R.drawable.ic_menu_add); for (LogTemplate template : LogTemplateProvider.getTemplates()) { @@ -336,7 +333,9 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D if (id == MENU_SIGNATURE) { insertIntoLog(LogTemplateProvider.applyTemplates(Settings.getSignature(), false), true); return true; - } else if (id >= 10 && id <= 19) { + } + + if (id >= 10 && id <= 19) { rating = (id - 9) / 2.0; if (rating < 1) { rating = 0; @@ -344,12 +343,13 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D updatePostButtonText(); return true; } + final LogTemplate template = LogTemplateProvider.getTemplate(id); if (template != null) { - final String newText = template.getValue(false); - insertIntoLog(newText, true); + insertIntoLog(template.getValue(false), true); return true; } + return false; } @@ -370,7 +370,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 +382,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); } @@ -400,9 +400,10 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D if (group == R.id.type) { setType(LogType.getById(id)); - return true; - } else if (group == R.id.changebutton) { + } + + if (group == R.id.changebutton) { try { final LogTypeTrackable logType = LogTypeTrackable.findById(id); if (logType != null) { @@ -419,14 +420,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 +443,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()); } } @@ -471,11 +472,11 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D tweetBox = (LinearLayout) findViewById(R.id.tweet_box); tweetCheck = (CheckBox) findViewById(R.id.tweet); clearButton = (Button) findViewById(R.id.clear); - saveButton = (Button) findViewById(R.id.save); + final Button saveButton = (Button) findViewById(R.id.save); 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 +508,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 +523,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 +546,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 +610,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); @@ -633,7 +634,6 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D } if (!Settings.isLogin()) { // allow offline logging showToast(res.getString(R.string.err_login)); - return; } } @@ -656,19 +656,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,34 +695,21 @@ 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(); - logNow.author = Settings.getUsername(); - logNow.date = date.getTimeInMillis(); - logNow.type = typeSelected; - logNow.log = log; - - if (cache != null) { - cache.prependLog(logNow); - } - app.addLog(geocode, logNow); + final LogEntry logNow = new LogEntry(date, typeSelected, log); + + cache.prependLog(logNow); + // app.saveLogs(cache); if (typeSelected == LogType.LOG_FOUND_IT) { - app.markFound(geocode); - if (cache != null) { - cache.setFound(true); - } + cache.setFound(true); } - if (cache != null) { - app.saveCache(cache, EnumSet.of(SaveFlag.SAVE_CACHE)); - } else { - app.removeCache(geocode, EnumSet.of(RemoveFlag.REMOVE_CACHE)); - } + app.saveCache(cache, EnumSet.of(SaveFlag.SAVE_CACHE)); } if (status == StatusCode.NO_ERROR) { @@ -741,7 +728,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 +752,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/ActivityMixin.java b/main/src/cgeo/geocaching/activity/ActivityMixin.java index 0e0041a..9b1bd2a 100644 --- a/main/src/cgeo/geocaching/activity/ActivityMixin.java +++ b/main/src/cgeo/geocaching/activity/ActivityMixin.java @@ -40,7 +40,7 @@ public final class ActivityMixin { fromActivity.finish(); } - public final static void goManual(final Context context, final String helpTopic) { + public static void goManual(final Context context, final String helpTopic) { if (StringUtils.isBlank(helpTopic)) { return; } @@ -55,7 +55,7 @@ public final class ActivityMixin { } } - public final static void setTitle(final Activity activity, final String text) { + public static void setTitle(final Activity activity, final String text) { if (StringUtils.isBlank(text)) { return; } @@ -66,7 +66,7 @@ public final class ActivityMixin { } } - public final static void showProgress(final Activity activity, final boolean show) { + public static void showProgress(final Activity activity, final boolean show) { if (activity == null) { return; } @@ -79,7 +79,7 @@ public final class ActivityMixin { } } - public final static void setTheme(final Activity activity) { + public static void setTheme(final Activity activity) { if (Settings.isLightSkin()) { activity.setTheme(R.style.light); } else { @@ -87,7 +87,7 @@ public final class ActivityMixin { } } - public final static void showToast(final Activity activity, final String text) { + public static void showToast(final Activity activity, final String text) { if (StringUtils.isNotBlank(text)) { Toast toast = Toast.makeText(activity, text, Toast.LENGTH_LONG); @@ -96,7 +96,7 @@ public final class ActivityMixin { } } - public final static void showShortToast(final Activity activity, final String text) { + public static void showShortToast(final Activity activity, final String text) { if (StringUtils.isNotBlank(text)) { Toast toast = Toast.makeText(activity, text, Toast.LENGTH_SHORT); @@ -105,7 +105,7 @@ public final class ActivityMixin { } } - public static final void helpDialog(final Activity activity, final String title, final String message, final Drawable icon) { + public static void helpDialog(final Activity activity, final String title, final String message, final Drawable icon) { if (StringUtils.isBlank(message)) { return; } 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/activity/Progress.java b/main/src/cgeo/geocaching/activity/Progress.java index 70f829d..dbe4700 100644 --- a/main/src/cgeo/geocaching/activity/Progress.java +++ b/main/src/cgeo/geocaching/activity/Progress.java @@ -13,6 +13,7 @@ public class Progress { private ProgressDialog dialog; private int progress = 0; + private int progressDivider = 1; public synchronized void dismiss() { if (dialog != null && dialog.isShowing()) { @@ -65,16 +66,19 @@ public class Progress { public synchronized void setMaxProgressAndReset(final int max) { if (dialog != null && dialog.isShowing()) { - dialog.setMax(max); + final int modMax = max / this.progressDivider; + dialog.setMax(modMax); dialog.setProgress(0); } + this.progress = 0; } public synchronized void setProgress(final int progress) { + final int modProgress = progress / this.progressDivider; if (dialog != null && dialog.isShowing()) { - dialog.setProgress(progress); + dialog.setProgress(modProgress); } - this.progress = progress; + this.progress = modProgress; } public synchronized int getProgress() { @@ -83,4 +87,8 @@ public class Progress { } return this.progress; } + + public synchronized void setProgressDivider(final int progressDivider) { + this.progressDivider = progressDivider; + } } diff --git a/main/src/cgeo/geocaching/apps/AbstractApp.java b/main/src/cgeo/geocaching/apps/AbstractApp.java index 1161a05..f79afe0 100644 --- a/main/src/cgeo/geocaching/apps/AbstractApp.java +++ b/main/src/cgeo/geocaching/apps/AbstractApp.java @@ -33,8 +33,7 @@ public abstract class AbstractApp implements App { try { // This can throw an exception where the exception type is only defined on API Level > 3 // therefore surround with try-catch - final Intent intent = packageManager.getLaunchIntentForPackage(packageName); - return intent; + return packageManager.getLaunchIntentForPackage(packageName); } catch (Exception e) { return null; } diff --git a/main/src/cgeo/geocaching/apps/AbstractLocusApp.java b/main/src/cgeo/geocaching/apps/AbstractLocusApp.java index 46105cd..6a239a6 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; @@ -37,6 +36,10 @@ public abstract class AbstractLocusApp extends AbstractApp { super(getString(R.string.caches_map_locus), INTENT); } + protected AbstractLocusApp(final String text, final String intent) { + super(text, intent); + } + @Override public boolean isInstalled(Context context) { return LocusUtils.isLocusAvailable(context); @@ -52,7 +55,7 @@ public abstract class AbstractLocusApp extends AbstractApp { * @param activity * @author koem */ - protected static boolean showInLocus(final List<? extends Object> objectsToShow, final boolean withCacheWaypoints, + protected static boolean showInLocus(final List<?> objectsToShow, final boolean withCacheWaypoints, final boolean export, final Activity activity) { if (objectsToShow == null || objectsToShow.isEmpty()) { return false; @@ -78,13 +81,13 @@ public abstract class AbstractLocusApp extends AbstractApp { } if (pd.getPoints().size() <= 1000) { - DisplayData.sendData(activity, pd, false); + DisplayData.sendData(activity, pd, export); } else { final ArrayList<PointsData> data = new ArrayList<PointsData>(); data.add(pd); DisplayData.sendDataCursor(activity, data, "content://" + LocusDataStorageProvider.class.getCanonicalName().toLowerCase(), - false); + export); } return true; @@ -108,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()); @@ -124,7 +127,7 @@ public abstract class AbstractLocusApp extends AbstractApp { pg.name = cache.getName(); pg.placedBy = cache.getOwner(); if (cache.getHiddenDate() != null) { - pg.hidden = ISO8601DATE.format(Long.valueOf(cache.getHiddenDate().getTime())); + pg.hidden = ISO8601DATE.format(cache.getHiddenDate().getTime()); } int locusId = toLocusType(cache.getType()); if (locusId != NO_LOCUS_ID) { @@ -187,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 a845108..49db025 100644 --- a/main/src/cgeo/geocaching/apps/cache/GeneralAppsFactory.java +++ b/main/src/cgeo/geocaching/apps/cache/GeneralAppsFactory.java @@ -1,13 +1,12 @@ package cgeo.geocaching.apps.cache; -import cgeo.geocaching.Settings; import cgeo.geocaching.cgCache; import cgeo.geocaching.apps.AbstractAppFactory; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.ArrayUtils; import android.app.Activity; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; @@ -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/AbstractPointNavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java index bf7ebb1..16b641e 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java @@ -1,7 +1,7 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.IGeoData; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.geopoint.Geopoint; @@ -24,7 +24,7 @@ abstract class AbstractPointNavigationApp extends AbstractNavigationApp { } @Override - public final boolean invoke(cgGeo geo, Activity activity, cgCache cache, cgWaypoint waypoint, Geopoint coords) { + public final boolean invoke(IGeoData geo, Activity activity, cgCache cache, cgWaypoint waypoint, Geopoint coords) { if (cache == null && waypoint == null && coords == null) { return false; } @@ -46,13 +46,24 @@ abstract class AbstractPointNavigationApp extends AbstractNavigationApp { protected abstract void navigate(Activity activity, Geopoint point); - private static Geopoint getCoordinates(cgCache cache, cgWaypoint waypoint, Geopoint coords) { + /** + * Return the first of the cache coordinates, the waypoint coordinates or the extra coordinates. <code>null</code> + * entities are skipped. + * + * @param cache a cache + * @param waypoint a waypoint + * @param coords extra coordinates + * @return the first non-null coordinates, or null if none are set + */ + private static Geopoint getCoordinates(final cgCache cache, final cgWaypoint waypoint, final Geopoint coords) { if (cache != null && cache.getCoords() != null) { return cache.getCoords(); } - else if (waypoint != null && waypoint.getCoords() != null) { + + if (waypoint != null && waypoint.getCoords() != null) { return waypoint.getCoords(); } + return coords; } }
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java b/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java index 3d804d9..720b85a 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java @@ -1,8 +1,8 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.cgeonavigate; import cgeo.geocaching.geopoint.Geopoint; @@ -22,7 +22,7 @@ class CompassApp extends AbstractNavigationApp { } @Override - public boolean invoke(cgGeo geo, Activity activity, cgCache cache, + public boolean invoke(IGeoData geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint coords) { if (cache != null && cache.getGeocode() != null) { diff --git a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java index 649823a..24aa693 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java @@ -1,15 +1,14 @@ 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; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.net.Uri; -import android.util.Log; class GoogleMapsApp extends AbstractPointNavigationApp { @@ -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 f94a623..fb72157 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java @@ -1,18 +1,18 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; import cgeo.geocaching.Settings; +import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; -import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.utils.Log; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.net.Uri; -import android.util.Log; class GoogleNavigationApp extends AbstractNavigationApp { @@ -26,7 +26,7 @@ class GoogleNavigationApp extends AbstractNavigationApp { } @Override - public boolean invoke(final cgGeo geo, final Activity activity, final cgCache cache, final cgWaypoint waypoint, final Geopoint coords) { + public boolean invoke(final IGeoData geo, final Activity activity, final cgCache cache, final cgWaypoint waypoint, final Geopoint coords) { if (activity == null) { return false; } @@ -50,8 +50,8 @@ class GoogleNavigationApp extends AbstractNavigationApp { return true; } - private static boolean navigateToCoordinates(cgGeo geo, Activity activity, final Geopoint coords) { - final Geopoint coordsNow = geo == null ? null : geo.coordsNow; + private static boolean navigateToCoordinates(IGeoData geo, Activity activity, final Geopoint coords) { + final Geopoint coordsNow = geo == null ? null : geo.getCoords(); // Google Navigation if (Settings.isUseGoogleNavigation()) { @@ -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/InternalMap.java b/main/src/cgeo/geocaching/apps/cache/navi/InternalMap.java index 44f151e..2f05459 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/InternalMap.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/InternalMap.java @@ -1,8 +1,8 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.enumerations.WaypointType; import cgeo.geocaching.geopoint.Geopoint; @@ -18,7 +18,7 @@ class InternalMap extends AbstractNavigationApp { } @Override - public boolean invoke(cgGeo geo, Activity activity, cgCache cache, + public boolean invoke(IGeoData geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint coords) { if (cache != null) { CGeoMap.startActivityGeoCode(activity, cache.getGeocode()); diff --git a/main/src/cgeo/geocaching/apps/cache/navi/LocusApp.java b/main/src/cgeo/geocaching/apps/cache/navi/LocusApp.java index 260d933..60e3315 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/LocusApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/LocusApp.java @@ -1,9 +1,9 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.IGeoData; +import cgeo.geocaching.apps.AbstractLocusApp; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; -import cgeo.geocaching.apps.AbstractLocusApp; import cgeo.geocaching.geopoint.Geopoint; import android.app.Activity; @@ -20,7 +20,7 @@ class LocusApp extends AbstractLocusApp implements NavigationApp { * @author koem */ @Override - public boolean invoke(cgGeo geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint coords) { + public boolean invoke(IGeoData geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint coords) { final ArrayList<Object> points = new ArrayList<Object>(); @@ -34,7 +34,7 @@ class LocusApp extends AbstractLocusApp implements NavigationApp { points.add(waypoint); } - return showInLocus(points, true, activity); + return showInLocus(points, true, false, activity); } } diff --git a/main/src/cgeo/geocaching/apps/cache/navi/NavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/NavigationApp.java index 119d27b..62629de 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/NavigationApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/NavigationApp.java @@ -1,15 +1,15 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.IGeoData; +import cgeo.geocaching.apps.App; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; -import cgeo.geocaching.apps.App; import cgeo.geocaching.geopoint.Geopoint; import android.app.Activity; public interface NavigationApp extends App { - public boolean invoke(final cgGeo geo, final Activity activity, + public boolean invoke(final IGeoData geo, final Activity activity, final cgCache cache, final cgWaypoint waypoint, final Geopoint coords); } diff --git a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java index e2a1fc1..6f179ab 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java @@ -1,28 +1,24 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; -import cgeo.geocaching.SearchResult; import cgeo.geocaching.Settings; import cgeo.geocaching.StaticMapsProvider; +import cgeo.geocaching.apps.AbstractAppFactory; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.cgeoapplication; -import cgeo.geocaching.apps.AbstractAppFactory; import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; -import android.util.Log; 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 +62,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(); + } } /** @@ -73,7 +79,7 @@ public final class NavigationAppFactory extends AbstractAppFactory { * A dialog is created for tool selection and the selected tool is started afterwards. * <p /> * Delegates to - * {@link #showNavigationMenu(cgGeo, Activity, cgCache, SearchResult, cgWaypoint, Geopoint, boolean, boolean)} with + * {@link #showNavigationMenu(IGeoData, Activity, cgCache, cgWaypoint, Geopoint, boolean, boolean)} with * <code>showInternalMap = true</code> and <code>showDefaultNavigation = false</code> * * @param geo @@ -82,7 +88,7 @@ public final class NavigationAppFactory extends AbstractAppFactory { * @param waypoint * @param destination */ - public static void showNavigationMenu(final cgGeo geo, final Activity activity, + public static void showNavigationMenu(final IGeoData geo, final Activity activity, final cgCache cache, final cgWaypoint waypoint, final Geopoint destination) { showNavigationMenu(geo, activity, cache, waypoint, destination, true, false); } @@ -104,9 +110,9 @@ public final class NavigationAppFactory extends AbstractAppFactory { * @param showDefaultNavigation * should be <code>false</code> by default * - * @see #showNavigationMenu(cgGeo, Activity, cgCache, cgWaypoint, Geopoint) + * @see #showNavigationMenu(IGeoData, Activity, cgCache, cgWaypoint, Geopoint) */ - public static void showNavigationMenu(final cgGeo geo, final Activity activity, + public static void showNavigationMenu(final IGeoData geo, final Activity activity, final cgCache cache, final cgWaypoint waypoint, final Geopoint destination, final boolean showInternalMap, final boolean showDefaultNavigation) { final AlertDialog.Builder builder = new AlertDialog.Builder(activity); @@ -127,24 +133,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) { @@ -196,10 +187,10 @@ public final class NavigationAppFactory extends AbstractAppFactory { /** * Adds the installed navigation tools to the given menu. - * Use {@link #onMenuItemSelected(MenuItem, cgGeo, Activity, cgCache, SearchResult, cgWaypoint, Geopoint)} on + * Use {@link #onMenuItemSelected(MenuItem, IGeoData, Activity, cgCache, cgWaypoint, Geopoint)} on * selection event to start the selected navigation tool. * - * <b>Only use this way if {@link #showNavigationMenu(cgGeo, Activity, cgCache, SearchResult, cgWaypoint, Geopoint)} + * <b>Only use this way if {@link #showNavigationMenu(IGeoData, Activity, cgCache, cgWaypoint, Geopoint)} * is not suitable for the given usecase.</b> * * @param menu @@ -211,11 +202,11 @@ public final class NavigationAppFactory extends AbstractAppFactory { /** * Adds the installed navigation tools to the given menu. - * Use {@link #onMenuItemSelected(MenuItem, cgGeo, Activity, cgCache, cgWaypoint, Geopoint)} on + * Use {@link #onMenuItemSelected(MenuItem, IGeoData, Activity, cgCache, cgWaypoint, Geopoint)} on * selection event to start the selected navigation tool. * * <b>Only use this way if - * {@link #showNavigationMenu(cgGeo, Activity, cgCache, cgWaypoint, Geopoint, boolean, boolean)} is + * {@link #showNavigationMenu(IGeoData, Activity, cgCache, cgWaypoint, Geopoint, boolean, boolean)} is * not suitable for the given usecase.</b> * * @param menu @@ -247,7 +238,7 @@ public final class NavigationAppFactory extends AbstractAppFactory { * @return */ public static boolean onMenuItemSelected(final MenuItem item, - final cgGeo geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint destination) { + final IGeoData geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint destination) { if (cache == null && waypoint == null && destination == null) { return false; } @@ -257,7 +248,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; @@ -279,11 +270,10 @@ public final class NavigationAppFactory extends AbstractAppFactory { * @param geo * @param activity * @param cache - * @param search * @param waypoint * @param destination */ - public static void startDefaultNavigationApplication(final cgGeo geo, Activity activity, cgCache cache, + public static void startDefaultNavigationApplication(final IGeoData geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint destination) { final NavigationApp app = getDefaultNavigationApplication(activity); @@ -291,22 +281,21 @@ 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 - * @param search * @param waypoint * @param destination */ - public static void startDefaultNavigationApplication2(final cgGeo geo, Activity activity, cgCache cache, + public static void startDefaultNavigationApplication2(final IGeoData geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint destination) { final NavigationApp app = getDefaultNavigationApplication2(activity); @@ -314,14 +303,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 +330,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/cache/navi/RMapsApp.java b/main/src/cgeo/geocaching/apps/cache/navi/RMapsApp.java index a87e61b..9af90ac 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/RMapsApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/RMapsApp.java @@ -1,8 +1,8 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter.Format; @@ -21,7 +21,7 @@ class RMapsApp extends AbstractNavigationApp { } @Override - public boolean invoke(cgGeo geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint coords) { + public boolean invoke(IGeoData geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint coords) { try { final ArrayList<String> locations = new ArrayList<String>(); if (cache != null && cache.getCoords() != null) { diff --git a/main/src/cgeo/geocaching/apps/cache/navi/StaticMapApp.java b/main/src/cgeo/geocaching/apps/cache/navi/StaticMapApp.java index a0eb5a1..d8b66c2 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/StaticMapApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/StaticMapApp.java @@ -1,11 +1,12 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.IGeoData; +import cgeo.geocaching.ILogable; import cgeo.geocaching.R; import cgeo.geocaching.StaticMapsActivity; +import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; -import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.geopoint.Geopoint; import android.app.Activity; @@ -24,26 +25,21 @@ class StaticMapApp extends AbstractNavigationApp { } @Override - public boolean invoke(cgGeo geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint coords) { - - String geocode = null; - if (cache != null && cache.getListId() != 0) { - geocode = cache.getGeocode().toUpperCase(); - } - if (waypoint != null) { - geocode = waypoint.getGeocode().toUpperCase(); - } + public boolean invoke(IGeoData geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint coords) { + final ILogable logable = cache != null && cache.getListId() != 0 ? cache : waypoint; + final String geocode = logable.getGeocode().toUpperCase(); if (geocode == null) { ActivityMixin.showToast(activity, getString(R.string.err_detail_no_map_static)); return true; - } else { - final Intent intent = new Intent(activity, StaticMapsActivity.class); - intent.putExtra("geocode", geocode); - if (waypoint != null) { - intent.putExtra("waypoint", waypoint.getId()); - } - activity.startActivity(intent); - return true; } + + final Intent intent = new Intent(activity, StaticMapsActivity.class); + intent.putExtra("geocode", geocode); + if (waypoint != null) { + intent.putExtra("waypoint", waypoint.getId()); + } + activity.startActivity(intent); + + return true; } } diff --git a/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java b/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java index 621aea4..45ebaff 100644 --- a/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java +++ b/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java @@ -1,9 +1,9 @@ package cgeo.geocaching.apps.cachelist; +import cgeo.geocaching.IGeoData; import cgeo.geocaching.SearchResult; -import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.apps.App; +import cgeo.geocaching.cgCache; import android.app.Activity; @@ -11,7 +11,7 @@ import java.util.List; interface CacheListApp extends App { - boolean invoke(final cgGeo geo, final List<cgCache> caches, + boolean invoke(final IGeoData geo, final List<cgCache> caches, final Activity activity, final SearchResult search); } diff --git a/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java b/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java index fd19353..fef9d2d 100644 --- a/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java +++ b/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java @@ -1,18 +1,15 @@ package cgeo.geocaching.apps.cachelist; +import cgeo.geocaching.IGeoData; 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; import cgeo.geocaching.apps.AbstractAppFactory; - -import org.apache.commons.lang3.ArrayUtils; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.utils.Log; import android.app.Activity; import android.content.res.Resources; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.SubMenu; @@ -21,15 +18,12 @@ import java.util.ArrayList; import java.util.List; public final class CacheListAppFactory extends AbstractAppFactory { - private static CacheListApp[] apps = new CacheListApp[] {}; - - private static CacheListApp[] getMultiPointNavigationApps() { - if (ArrayUtils.isEmpty(apps)) { - apps = new CacheListApp[] { - new InternalCacheListMap(), - new LocusCacheListApp() }; - } - return apps; + private static class LazyHolder { + public static final CacheListApp[] apps = { + new InternalCacheListMap(), + new LocusCacheListApp(false), + new LocusCacheListApp(true) + }; } /** @@ -38,41 +32,41 @@ public final class CacheListAppFactory extends AbstractAppFactory { * @param res * @return the added menu item (also for a sub menu, then the menu item in the parent menu is returned) */ - public static MenuItem addMenuItems(Menu menu, - Activity activity, Resources res) { - List<CacheListApp> activeApps = new ArrayList<CacheListApp>(); - for (CacheListApp app : getMultiPointNavigationApps()) { + public static MenuItem addMenuItems(final Menu menu, final Activity activity, final Resources res) { + final List<CacheListApp> activeApps = new ArrayList<CacheListApp>(LazyHolder.apps.length); + for (final CacheListApp app : LazyHolder.apps) { if (app.isInstalled(activity)) { activeApps.add(app); } } // use a new sub menu, if more than one app is available - if (activeApps.size() > 1) { - SubMenu subMenu = menu.addSubMenu(0, 101, 0, - res.getString(R.string.caches_on_map)).setIcon( - android.R.drawable.ic_menu_mapmode); - for (CacheListApp app : activeApps) { - subMenu.add(0, app.getId(), 0, app.getName()); - } - return subMenu.getItem(); - } else if (activeApps.size() == 1) { - return menu.add(0, activeApps.get(0).getId(), 0, - activeApps.get(0).getName()).setIcon(android.R.drawable.ic_menu_mapmode); + switch (activeApps.size()) { + case 0: + return null; + case 1: + return menu.add(0, activeApps.get(0).getId(), 0, + activeApps.get(0).getName()).setIcon(android.R.drawable.ic_menu_mapmode); + default: + final SubMenu subMenu = menu.addSubMenu(0, 101, 0, + res.getString(R.string.caches_on_map)).setIcon(android.R.drawable.ic_menu_mapmode); + for (final CacheListApp app : activeApps) { + subMenu.add(0, app.getId(), 0, app.getName()); + } + return subMenu.getItem(); } - return null; } public static boolean onMenuItemSelected(final MenuItem item, - final cgGeo geo, final List<cgCache> caches, final IAbstractActivity activity, + final IGeoData geo, final List<cgCache> caches, final IAbstractActivity activity, final SearchResult search) { - CacheListApp app = (CacheListApp) getAppFromMenuItem(item, apps); + final CacheListApp app = (CacheListApp) getAppFromMenuItem(item, LazyHolder.apps); if (app != null) { try { boolean result = app.invoke(geo, caches, (Activity) activity, search); 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/apps/cachelist/InternalCacheListMap.java b/main/src/cgeo/geocaching/apps/cachelist/InternalCacheListMap.java index 5eaefc9..f450bbc 100644 --- a/main/src/cgeo/geocaching/apps/cachelist/InternalCacheListMap.java +++ b/main/src/cgeo/geocaching/apps/cachelist/InternalCacheListMap.java @@ -1,10 +1,10 @@ package cgeo.geocaching.apps.cachelist; +import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; import cgeo.geocaching.SearchResult; -import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.apps.AbstractApp; +import cgeo.geocaching.cgCache; import cgeo.geocaching.maps.CGeoMap; import android.app.Activity; @@ -24,7 +24,7 @@ class InternalCacheListMap extends AbstractApp implements CacheListApp { } @Override - public boolean invoke(cgGeo geo, List<cgCache> caches, Activity activity, final SearchResult search) { + public boolean invoke(IGeoData geo, List<cgCache> caches, Activity activity, final SearchResult search) { CGeoMap.startActivitySearch(activity, search, null); return true; } diff --git a/main/src/cgeo/geocaching/apps/cachelist/LocusCacheListApp.java b/main/src/cgeo/geocaching/apps/cachelist/LocusCacheListApp.java index 0c5455c..b7557c3 100644 --- a/main/src/cgeo/geocaching/apps/cachelist/LocusCacheListApp.java +++ b/main/src/cgeo/geocaching/apps/cachelist/LocusCacheListApp.java @@ -1,18 +1,27 @@ package cgeo.geocaching.apps.cachelist; +import cgeo.geocaching.IGeoData; +import cgeo.geocaching.R; import cgeo.geocaching.SearchResult; -import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.apps.AbstractLocusApp; +import cgeo.geocaching.cgCache; import org.apache.commons.collections.CollectionUtils; import android.app.Activity; +import android.content.Intent; import java.util.List; class LocusCacheListApp extends AbstractLocusApp implements CacheListApp { + private boolean export; + + public LocusCacheListApp(boolean export) { + super(getString(export ? R.string.caches_map_locus_export : R.string.caches_map_locus), Intent.ACTION_VIEW); + this.export = export; + } + /** * show caches in Locus * @@ -20,12 +29,12 @@ class LocusCacheListApp extends AbstractLocusApp implements CacheListApp { * @author koem */ @Override - public boolean invoke(cgGeo geo, List<cgCache> cacheList, Activity activity, final SearchResult search) { + public boolean invoke(IGeoData geo, List<cgCache> cacheList, Activity activity, final SearchResult search) { if (CollectionUtils.isEmpty(cacheList)) { return false; } - showInLocus(cacheList, false, activity); + showInLocus(cacheList, false, export, activity); return true; } 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 b7f49e1..a426614 100644 --- a/main/src/cgeo/geocaching/cgCache.java +++ b/main/src/cgeo/geocaching/cgCache.java @@ -9,13 +9,15 @@ 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; import org.apache.commons.collections.CollectionUtils; @@ -26,8 +28,9 @@ 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 android.util.Log; import java.util.ArrayList; import java.util.Calendar; @@ -43,7 +46,7 @@ import java.util.regex.Pattern; /** * Internal c:geo representation of a "cache" */ -public class cgCache implements ICache { +public class cgCache implements ICache, IWaypoint { private long updated = 0; private long detailedUpdate = 0; @@ -88,7 +91,7 @@ public class cgCache implements ICache { 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 +103,7 @@ public class cgCache implements ICache { private String nameForSorting; private final EnumSet<StorageLocation> storageLocation = EnumSet.of(StorageLocation.HEAP); private boolean finalDefined = false; - private int zoomlevel = Tile.ZOOMLEVEL_MAX; + private int zoomlevel = Tile.ZOOMLEVEL_MAX + 1; private static final Pattern NUMBER_PATTERN = Pattern.compile("\\d+"); @@ -295,7 +298,7 @@ public class cgCache implements ICache { /** * Compare two caches quickly. For map and list fields only the references are compared ! * - * @param other + * @param other the other cache to compare this one to * @return true if both caches have the same content */ private boolean isEqualTo(final cgCache other) { @@ -309,7 +312,7 @@ public class cgCache implements ICache { premiumMembersOnly == other.premiumMembersOnly && difficulty == other.difficulty && terrain == other.terrain && - (coords != null ? coords.isEqualTo(other.coords) : null == other.coords) && + (coords != null ? coords.equals(other.coords) : null == other.coords) && reliableLatLon == other.reliableLatLon && disabled == other.disabled && archived == other.archived && @@ -366,50 +369,33 @@ public class cgCache implements ICache { cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); - if (hidden.compareTo(cal.getTime()) < 0) { - return false; - } - return true; + return hidden.compareTo(cal.getTime()) >= 0; } /** - * checks if a page contains the guid of a cache + * Checks if a page contains the guid of a cache * - * @param cache - * the cache to look for * @param page - * the page to search in - * - * @return true: page contains guid of cache, false: otherwise + * the page to search in, may be null + * @return true if the page contains the guid of the cache, false otherwise */ - boolean isGuidContainedInPage(final String page) { - if (StringUtils.isBlank(page)) { - return false; - } - // check if the guid of the cache is anywhere in the page - if (StringUtils.isBlank(guid)) { - return false; - } - 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"); - return true; - } else { - Log.i(Settings.tag, "cgCache.isGuidContainedInPage: guid '" + guid + "' not found"); + public boolean isGuidContainedInPage(final String page) { + if (StringUtils.isBlank(page) || StringUtils.isBlank(guid)) { return false; } + final Boolean found = Pattern.compile(guid, Pattern.CASE_INSENSITIVE).matcher(page).find(); + Log.i("cgCache.isGuidContainedInPage: guid '" + guid + "' " + (found ? "" : "not ") + "found"); + return found; } 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) { + public void logVisit(final IAbstractActivity fromActivity) { if (StringUtils.isBlank(cacheId)) { fromActivity.showToast(((Activity) fromActivity).getResources().getString(R.string.err_cannot_log_visit)); - return true; + return; } Intent logVisitIntent = new Intent((Activity) fromActivity, VisitCacheActivity.class); logVisitIntent.putExtra(VisitCacheActivity.EXTRAS_ID, cacheId); @@ -417,18 +403,12 @@ public class cgCache implements ICache { logVisitIntent.putExtra(VisitCacheActivity.EXTRAS_FOUND, found); ((Activity) fromActivity).startActivity(logVisitIntent); - - return true; } - public boolean logOffline(final IAbstractActivity fromActivity, final LogType logType) { - String log = ""; - if (StringUtils.isNotBlank(Settings.getSignature()) - && Settings.isAutoInsertSignature()) { - log = LogTemplateProvider.applyTemplates(Settings.getSignature(), true); - } - logOffline(fromActivity, log, Calendar.getInstance(), logType); - return true; + public void logOffline(final IAbstractActivity fromActivity, final LogType logType) { + final boolean mustIncludeSignature = StringUtils.isNotBlank(Settings.getSignature()) && Settings.isAutoInsertSignature(); + final String initial = mustIncludeSignature ? LogTemplateProvider.applyTemplates(Settings.getSignature(), true) : ""; + logOffline(fromActivity, initial, Calendar.getInstance(), logType); } void logOffline(final IAbstractActivity fromActivity, final String log, Calendar date, final LogType logType) { @@ -523,16 +503,6 @@ public class cgCache implements ICache { } @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; } @@ -938,14 +908,10 @@ public class cgCache implements ICache { } } - if (saveToDatabase) { - return cgeoapplication.getInstance().saveWaypoints(geocode, waypoints, false); - } - - return false; + return saveToDatabase && cgeoapplication.getInstance().saveWaypoints(this); } - public List<cgLog> getLogs() { + public List<LogEntry> getLogs() { return getLogs(true); } @@ -954,15 +920,15 @@ public class cgCache implements ICache { * 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); } @@ -974,7 +940,7 @@ public class cgCache implements ICache { * @param logs * the log entries */ - public void setLogs(List<cgLog> logs) { + public void setLogs(List<LogEntry> logs) { this.logs = logs; } @@ -1133,8 +1099,8 @@ public class cgCache implements ICache { * @param storageLocation * the storageLocation to set */ - public void addStorageLocation(StorageLocation sl) { - this.storageLocation.add(sl); + public void addStorageLocation(final StorageLocation storageLocation) { + this.storageLocation.add(storageLocation); } /** @@ -1167,11 +1133,7 @@ public class cgCache implements ICache { resetFinalDefined(); } - if (saveToDatabase) { - return cgeoapplication.getInstance().saveOwnWaypoint(waypoint.getId(), geocode, waypoint); - } - - return false; + return saveToDatabase && cgeoapplication.getInstance().saveOwnWaypoint(waypoint.getId(), geocode, waypoint); } public boolean hasWaypoints() { @@ -1209,30 +1171,23 @@ public class cgCache implements ICache { } /** - * @param index - * @return <code>true</code>, if the waypoint was duplicated + * Duplicate a waypoint. + * + * @param index the waypoint to duplicate + * @return <code>true</code> if the waypoint was duplicated, <code>false</code> otherwise (invalid index) */ - public boolean duplicateWaypoint(int index) { - if (!isValidWaypointIndex(index)) { + public boolean duplicateWaypoint(final int index) { + final cgWaypoint original = getWaypoint(index); + if (original == null) { return false; } - final cgWaypoint copy = new cgWaypoint(waypoints.get(index)); + final cgWaypoint copy = new cgWaypoint(original); copy.setUserDefined(); copy.setName(cgeoapplication.getInstance().getString(R.string.waypoint_copy_of) + " " + copy.getName()); waypoints.add(index + 1, copy); return cgeoapplication.getInstance().saveOwnWaypoint(-1, geocode, copy); } - private boolean isValidWaypointIndex(int index) { - if (!hasWaypoints()) { - return false; - } - if (index < 0 || index >= waypoints.size()) { - return false; - } - return true; - } - /** * delete a user defined waypoint * @@ -1240,11 +1195,11 @@ public class cgCache implements ICache { * of the waypoint in cache's waypoint list * @return <code>true</code>, if the waypoint was deleted */ - public boolean deleteWaypoint(int index) { - if (!isValidWaypointIndex(index)) { + public boolean deleteWaypoint(final int index) { + final cgWaypoint waypoint = getWaypoint(index); + if (waypoint == null) { return false; } - final cgWaypoint waypoint = waypoints.get(index); if (waypoint.isUserDefined()) { waypoints.remove(index); cgeoapplication.getInstance().deleteWaypoint(waypoint.getId()); @@ -1265,17 +1220,13 @@ public class cgCache implements ICache { * to be removed from cache * @return <code>true</code>, if the waypoint was deleted */ - public boolean deleteWaypoint(cgWaypoint waypoint) { + public boolean deleteWaypoint(final cgWaypoint waypoint) { if (waypoint.getId() <= 0) { return false; } final int index = getWaypointIndex(waypoint); - if (index >= 0) { - return deleteWaypoint(index); - } - - return false; + return index >= 0 && deleteWaypoint(index); } /** @@ -1283,38 +1234,36 @@ public class cgCache implements ICache { * * @param waypoint * to find index for - * @return index in <code>waypoints</code> if found, else -1 + * @return index in <code>waypoints</code> if found, -1 otherwise */ - private int getWaypointIndex(cgWaypoint waypoint) { - int index = 0; - - for (cgWaypoint wp : waypoints) { - if (wp.getId() == waypoint.getId()) { + private int getWaypointIndex(final cgWaypoint waypoint) { + final int id = waypoint.getId(); + for (int index = 0; index < waypoints.size(); index++) { + if (waypoints.get(index).getId() == id) { return index; } - index++; } - return -1; } /** - * @param index - * @return waypoint or <code>null</code> + * Retrieve a given waypoint. + * + * @param index the index of the waypoint + * @return waypoint or <code>null</code> if index is out of range */ - public cgWaypoint getWaypoint(int index) { - if (!isValidWaypointIndex(index)) { - return null; - } - return waypoints.get(index); + public cgWaypoint getWaypoint(final int index) { + return waypoints != null && index >= 0 && index < waypoints.size() ? waypoints.get(index) : null; } /** - * @param index + * Lookup a waypoint by its id. + * + * @param id the id of the waypoint to look for * @return waypoint or <code>null</code> */ - public cgWaypoint getWaypointById(int id) { - for (cgWaypoint waypoint : waypoints) { + public cgWaypoint getWaypointById(final int id) { + for (final cgWaypoint waypoint : waypoints) { if (waypoint.getId() == id) { return waypoint; } @@ -1333,16 +1282,16 @@ public class cgCache implements ICache { Matcher matcher = coordPattern.matcher(note); while (matcher.find()) { try { - final Geopoint point = GeopointParser.parse(note.substring(matcher.start())); + final Geopoint point = new Geopoint(note.substring(matcher.start())); // coords must have non zero latitude and longitude and at least one part shall have fractional degrees - if (point != null && point.getLatitudeE6() != 0 && point.getLongitudeE6() != 0 && ((point.getLatitudeE6() % 1000) != 0 || (point.getLongitudeE6() % 1000) != 0)) { + if (point.getLatitudeE6() != 0 && point.getLongitudeE6() != 0 && ((point.getLatitudeE6() % 1000) != 0 || (point.getLongitudeE6() % 1000) != 0)) { final String name = cgeoapplication.getInstance().getString(R.string.cache_personal_note) + " " + count; final cgWaypoint waypoint = new cgWaypoint(name, WaypointType.WAYPOINT, false); waypoint.setCoords(point); addWaypoint(waypoint, false); count++; } - } catch (GeopointParser.ParseException e) { + } catch (Geopoint.ParseException e) { // ignore } @@ -1350,7 +1299,7 @@ public class cgCache implements ICache { matcher = coordPattern.matcher(note); } } catch (Exception e) { - Log.e(Settings.tag, "cgCache.parseWaypointsFromNote: " + e.toString()); + Log.e("cgCache.parseWaypointsFromNote: " + e.toString()); } } @@ -1365,16 +1314,16 @@ public class cgCache implements ICache { 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); } @@ -1403,20 +1352,198 @@ public class cgCache implements ICache { 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); } public void store(Activity activity, CancellableHandler handler) { final int listId = Math.max(getListId(), StoredList.STANDARD_LIST_ID); - cgBase.storeCache(activity, this, null, listId, handler); - } - - public int getZoomlevel() { - return this.zoomlevel; + storeCache(activity, this, null, listId, false, handler); } public void setZoomlevel(int zoomlevel) { this.zoomlevel = zoomlevel; } + + @Override + public int getId() { + return 0; + } + + @Override + public WaypointType getWaypointType() { + return null; + } + + @Override + public String getCoordType() { + return "cache"; + } + + public void drop(Handler handler) { + try { + cgeoapplication.getInstance().markDropped(Collections.singletonList(this)); + 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/cgCoord.java b/main/src/cgeo/geocaching/cgCoord.java deleted file mode 100644 index 236b8f5..0000000 --- a/main/src/cgeo/geocaching/cgCoord.java +++ /dev/null @@ -1,168 +0,0 @@ -package cgeo.geocaching; - -import cgeo.geocaching.enumerations.CacheSize; -import cgeo.geocaching.enumerations.CacheType; -import cgeo.geocaching.enumerations.WaypointType; -import cgeo.geocaching.geopoint.Geopoint; - -public class cgCoord implements IBasicCache, IWaypoint { - - private int id = 0; // only valid if constructed with a waypoint - private WaypointType waypointType = null; // only valid if constructed with a waypoint - private String guid = null; // only valid if constructed with a cache - private CacheType cacheType = null; // only valid if constructed with a cache - private String geocode = ""; - private String coordType = "cache"; // used values: { cache, waypoint } - private String typeSpec = CacheType.TRADITIONAL.id; - private String name = ""; - private boolean found = false; - private boolean disabled = false; - private Geopoint coords = new Geopoint(0, 0); - private float difficulty = 0; - private float terrain = 0; - private CacheSize size = CacheSize.UNKNOWN; - - public cgCoord() { - } - - public cgCoord(cgCache cache) { - guid = cache.getGuid(); - disabled = cache.isDisabled(); - found = cache.isFound(); - geocode = cache.getGeocode(); - coords = cache.getCoords(); - name = cache.getName(); - coordType = "cache"; - typeSpec = cache.getType().id; - difficulty = cache.getDifficulty(); - terrain = cache.getTerrain(); - size = cache.getSize(); - cacheType = cache.getType(); - } - - public cgCoord(cgWaypoint waypoint) { - id = waypoint.getId(); - disabled = false; - found = false; - geocode = waypoint.getGeocode(); - coords = waypoint.getCoords(); - name = waypoint.getName(); - coordType = "waypoint"; - typeSpec = waypoint.getWaypointType() != null ? waypoint.getWaypointType().id : null; - waypointType = waypoint.getWaypointType(); - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - @Override - public String getGeocode() { - return geocode; - } - - public void setGeocode(String geocode) { - this.geocode = geocode; - } - - public String getCoordType() { - return coordType; - } - - public void setCoordType(String type) { - this.coordType = type; - } - - public String getTypeSpec() { - return typeSpec; - } - - public void setTypeSpec(String typeSpec) { - this.typeSpec = typeSpec; - } - - @Override - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public boolean isFound() { - return found; - } - - public void setFound(boolean found) { - this.found = found; - } - - @Override - public boolean isDisabled() { - return disabled; - } - - public void setDisabled(boolean disabled) { - this.disabled = disabled; - } - - public Geopoint getCoords() { - return coords; - } - - public void setCoords(Geopoint coords) { - this.coords = coords; - } - - @Override - public float getDifficulty() { - return difficulty; - } - - public void setDifficulty(float difficulty) { - this.difficulty = difficulty; - } - - @Override - public float getTerrain() { - return terrain; - } - - public void setTerrain(float terrain) { - this.terrain = terrain; - } - - @Override - public CacheSize getSize() { - return size; - } - - public void setSize(CacheSize size) { - this.size = size; - } - - public void setGuid(String guid) { - this.guid = guid; - } - - @Override - public String getGuid() { - return guid; - } - - @Override - public WaypointType getWaypointType() { - return waypointType; - } - - @Override - public CacheType getType() { - return cacheType; - } -} diff --git a/main/src/cgeo/geocaching/cgData.java b/main/src/cgeo/geocaching/cgData.java index 3f48b07..fd90a02 100644 --- a/main/src/cgeo/geocaching/cgData.java +++ b/main/src/cgeo/geocaching/cgData.java @@ -10,6 +10,8 @@ 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; import org.apache.commons.collections.MapUtils; @@ -24,7 +26,6 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDoneException; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteStatement; -import android.util.Log; import java.io.File; import java.util.ArrayList; @@ -57,6 +58,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; @@ -68,11 +71,11 @@ public class cgData { private Context context = null; private CacheCache cacheCache = null; private String path = null; - private cgDbHelper dbHelper = null; + private DbHelper dbHelper = null; private SQLiteDatabase databaseRO = null; private SQLiteDatabase databaseRW = null; private static final int dbVersion = 62; - private static final int customListIdOffset = 10; + public static final int customListIdOffset = 10; private static final String dbName = "data"; private static final String dbTableCaches = "cg_caches"; private static final String dbTableLists = "cg_lists"; @@ -260,28 +263,28 @@ public class cgData { if (databaseRW == null || !databaseRW.isOpen()) { try { if (dbHelper == null) { - dbHelper = new cgDbHelper(context); + dbHelper = new DbHelper(context); } 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()); } } if (databaseRO == null || !databaseRO.isOpen()) { try { if (dbHelper == null) { - dbHelper = new cgDbHelper(context); + dbHelper = new DbHelper(context); } databaseRO = dbHelper.getReadableDatabase(); @@ -290,16 +293,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 +327,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 +341,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 +362,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; } @@ -368,27 +371,23 @@ public class cgData { final boolean backupDone = LocalStorage.copy(new File(path), target); init(); - if (backupDone) { - Log.i(Settings.tag, "Database was copied to " + target); - return target.getPath(); - } else { - Log.e(Settings.tag, "Database could not be copied to " + target); + if (!backupDone) { + Log.e("Database could not be copied to " + target); return null; } + + Log.i("Database was copied to " + target); + return target.getPath(); } public static File isRestoreFile() { final File fileSourceFile = backupFile(); - if (fileSourceFile.exists()) { - return fileSourceFile; - } else { - return null; - } + return fileSourceFile.exists() ? fileSourceFile : null; } 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,17 +397,17 @@ 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; } - private static class cgDbHelper extends SQLiteOpenHelper { + private static class DbHelper extends SQLiteOpenHelper { - cgDbHelper(Context context) { + DbHelper(Context context) { super(context, dbName, null, dbVersion); } @@ -451,7 +450,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 +463,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 +483,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 +493,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 +502,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 +514,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 +529,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 +617,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 +631,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 +639,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 +647,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 +658,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 +669,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 +702,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); } } @@ -1017,7 +751,7 @@ public class cgData { "100"); if (cursor != null) { - int index = 0; + int index; if (cursor.getCount() > 0) { cursor.moveToFirst(); @@ -1032,7 +766,7 @@ public class cgData { } } } catch (Exception e) { - Log.e(Settings.tag, "cgData.allDetailedThere: " + e.toString()); + Log.e("cgData.allDetailedThere: " + e.toString()); } if (cursor != null) { @@ -1078,7 +812,7 @@ public class cgData { } if (cursor != null) { - int index = 0; + int index; cnt = cursor.getCount(); if (cnt > 0) { @@ -1093,7 +827,7 @@ public class cgData { } } } catch (Exception e) { - Log.e(Settings.tag, "cgData.isThere: " + e.toString()); + Log.e("cgData.isThere: " + e.toString()); } if (cursor != null) { @@ -1129,7 +863,7 @@ public class cgData { public boolean isOffline(String geocode, String guid) { init(); - Cursor cursor = null; + Cursor cursor; long listId = StoredList.TEMPORARY_LIST_ID; try { @@ -1159,7 +893,7 @@ public class cgData { if (cursor != null) { final int cnt = cursor.getCount(); - int index = 0; + int index; if (cnt > 0) { cursor.moveToFirst(); @@ -1171,7 +905,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 +926,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 +947,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 +988,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(); @@ -1308,55 +1042,20 @@ public class cgData { values.put("coordsChanged", cache.hasUserModifiedCoords() ? 1 : 0); values.put("finalDefined", cache.hasFinalDefined() ? 1 : 0); - boolean statusOk = true; - - if (cache.hasAttributes()) { - if (!saveAttributes(cache.getGeocode(), cache.getAttributes())) { - statusOk = false; - } - } - - if (cache.hasWaypoints()) { - if (!saveWaypoints(cache.getGeocode(), cache.getWaypoints(), true)) { - statusOk = false; - } - } - - if (cache.getSpoilers() != null) { - if (!saveSpoilers(cache.getGeocode(), cache.getSpoilers())) { - statusOk = false; - } - } - - if (CollectionUtils.isNotEmpty(cache.getLogs())) { - if (!saveLogs(cache.getGeocode(), cache.getLogs())) { - statusOk = false; - } - } - - if (MapUtils.isNotEmpty(cache.getLogCounts())) { - if (!saveLogCount(cache.getGeocode(), cache.getLogCounts())) { - statusOk = false; - } - } - - if (cache.getInventory() != null) { - if (!saveInventory(cache.getGeocode(), cache.getInventory())) { - statusOk = false; - } - } - - if (!statusOk) { - cache.setDetailed(false); - cache.setDetailedUpdate(0L); - } - + boolean result = false; init(); //try to update record else insert fresh.. - boolean result = false; databaseRW.beginTransaction(); + try { + saveAttributesWithoutTransaction(cache); + saveWaypointsWithoutTransaction(cache); + saveSpoilersWithoutTransaction(cache); + saveLogsWithoutTransaction(cache.getGeocode(), cache.getLogs()); + saveLogCountsWithoutTransaction(cache); + saveInventoryWithoutTransaction(cache.getGeocode(), cache.getInventory()); + int rows = databaseRW.update(dbTableCaches, values, "geocode = ?", new String[] { cache.getGeocode() }); if (rows == 0) { // cache is not in the DB, insert it @@ -1370,129 +1069,102 @@ public class cgData { databaseRW.endTransaction(); } - values = null; return result; } - public boolean saveAttributes(String geocode, List<String> attributes) { - if (StringUtils.isBlank(geocode) || attributes == null) { - return false; - } + private void saveAttributesWithoutTransaction(final cgCache cache) { + String geocode = cache.getGeocode(); + databaseRW.delete(dbTableAttributes, "geocode = ?", new String[] { geocode }); - init(); + final List<String> attributes = cache.getAttributes(); + if (CollectionUtils.isNotEmpty(attributes)) { - databaseRW.beginTransaction(); - try { - databaseRW.delete(dbTableAttributes, "geocode = ?", new String[] { geocode }); - - if (!attributes.isEmpty()) { - - InsertHelper helper = new InsertHelper(databaseRW, dbTableAttributes); - long timeStamp = System.currentTimeMillis(); + InsertHelper helper = new InsertHelper(databaseRW, dbTableAttributes); + long timeStamp = System.currentTimeMillis(); - for (String attribute : attributes) { - helper.prepareForInsert(); + for (String attribute : attributes) { + helper.prepareForInsert(); - helper.bind(ATTRIBUTES_GEOCODE, geocode); - helper.bind(ATTRIBUTES_UPDATED, timeStamp); - helper.bind(ATTRIBUTES_ATTRIBUTE, attribute); + helper.bind(ATTRIBUTES_GEOCODE, geocode); + helper.bind(ATTRIBUTES_UPDATED, timeStamp); + helper.bind(ATTRIBUTES_ATTRIBUTE, attribute); - helper.execute(); - } - helper.close(); + helper.execute(); } - databaseRW.setTransactionSuccessful(); - } finally { - databaseRW.endTransaction(); + helper.close(); } - - return true; } /** * 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) { - if (StringUtils.isBlank(geocode) || waypoints == null) { - return false; - } - + public boolean saveWaypoints(final cgCache cache) { + boolean result = false; init(); - - Log.d(Settings.tag, "cgData.saveWaypoints(drop=" + drop + ")"); - - boolean ok = false; databaseRW.beginTransaction(); - try { - if (drop) { - databaseRW.delete(dbTableWaypoints, "geocode = ? and type <> ? and own = 0", new String[] { geocode, "own" }); - } - - if (!waypoints.isEmpty()) { - ContentValues values = new ContentValues(); - long timeStamp = System.currentTimeMillis(); - for (cgWaypoint oneWaypoint : waypoints) { - if (oneWaypoint.isUserDefined()) { - continue; - } - - values.clear(); - values.put("geocode", geocode); - values.put("updated", timeStamp); - values.put("type", oneWaypoint.getWaypointType() != null ? oneWaypoint.getWaypointType().id : null); - values.put("prefix", oneWaypoint.getPrefix()); - values.put("lookup", oneWaypoint.getLookup()); - values.put("name", oneWaypoint.getName()); - values.put("latlon", oneWaypoint.getLatlon()); - putCoords(values, oneWaypoint.getCoords()); - values.put("note", oneWaypoint.getNote()); - values.put("own", oneWaypoint.isUserDefined() ? 1 : 0); - - final long rowId = databaseRW.insert(dbTableWaypoints, null, values); - oneWaypoint.setId((int) rowId); - } - } + try { + saveWaypointsWithoutTransaction(cache); databaseRW.setTransactionSuccessful(); - ok = true; + result = true; + } catch (Exception e) { + Log.e("saveWaypoints", e); } finally { databaseRW.endTransaction(); } + return result; + } - return ok; + private void saveWaypointsWithoutTransaction(final cgCache cache) { + String geocode = cache.getGeocode(); + databaseRW.delete(dbTableWaypoints, "geocode = ? and type <> ? and own = 0", new String[] { geocode, "own" }); + + List<cgWaypoint> waypoints = cache.getWaypoints(); + if (CollectionUtils.isNotEmpty(waypoints)) { + ContentValues values = new ContentValues(); + long timeStamp = System.currentTimeMillis(); + for (cgWaypoint oneWaypoint : waypoints) { + if (oneWaypoint.isUserDefined()) { + continue; + } + + values.clear(); + values.put("geocode", geocode); + values.put("updated", timeStamp); + values.put("type", oneWaypoint.getWaypointType() != null ? oneWaypoint.getWaypointType().id : null); + values.put("prefix", oneWaypoint.getPrefix()); + values.put("lookup", oneWaypoint.getLookup()); + values.put("name", oneWaypoint.getName()); + values.put("latlon", oneWaypoint.getLatlon()); + putCoords(values, oneWaypoint.getCoords()); + values.put("note", oneWaypoint.getNote()); + values.put("own", oneWaypoint.isUserDefined() ? 1 : 0); + + final long rowId = databaseRW.insert(dbTableWaypoints, null, values); + oneWaypoint.setId((int) rowId); + } + } } /** @@ -1555,11 +1227,7 @@ public class cgData { ok = true; } else { final int rows = databaseRW.update(dbTableWaypoints, values, "_id = " + id, null); - if (rows > 0) { - ok = true; - } else { - ok = false; - } + ok = rows > 0; } databaseRW.setTransactionSuccessful(); } finally { @@ -1576,121 +1244,72 @@ public class cgData { init(); - int deleted = databaseRW.delete(dbTableWaypoints, "_id = " + id, null); - - if (deleted > 0) { - return true; - } - - return false; + return databaseRW.delete(dbTableWaypoints, "_id = " + id, null) > 0; } - public boolean saveSpoilers(String geocode, List<cgImage> spoilers) { - if (StringUtils.isBlank(geocode) || spoilers == null) { - return false; - } - - init(); - - databaseRW.beginTransaction(); - try { - databaseRW.delete(dbTableSpoilers, "geocode = ?", new String[] { geocode }); + private void saveSpoilersWithoutTransaction(final cgCache cache) { + String geocode = cache.getGeocode(); + databaseRW.delete(dbTableSpoilers, "geocode = ?", new String[] { geocode }); - if (!spoilers.isEmpty()) { - ContentValues values = new ContentValues(); - long timeStamp = System.currentTimeMillis(); - for (cgImage oneSpoiler : spoilers) { - values.clear(); - values.put("geocode", geocode); - values.put("updated", timeStamp); - values.put("url", oneSpoiler.getUrl()); - values.put("title", oneSpoiler.getTitle()); - values.put("description", oneSpoiler.getDescription()); + List<cgImage> spoilers = cache.getSpoilers(); + if (CollectionUtils.isNotEmpty(spoilers)) { + ContentValues values = new ContentValues(); + long timeStamp = System.currentTimeMillis(); + for (cgImage spoiler : spoilers) { + values.clear(); + values.put("geocode", geocode); + values.put("updated", timeStamp); + values.put("url", spoiler.getUrl()); + values.put("title", spoiler.getTitle()); + values.put("description", spoiler.getDescription()); - databaseRW.insert(dbTableSpoilers, null, values); - } + databaseRW.insert(dbTableSpoilers, null, values); } - databaseRW.setTransactionSuccessful(); - } finally { - databaseRW.endTransaction(); } - - return true; } - public boolean saveLogs(String geocode, List<cgLog> logs) { - return saveLogs(geocode, logs, true); - } + private void saveLogsWithoutTransaction(final String geocode, final List<LogEntry> logs) { + // TODO delete logimages referring these logs + databaseRW.delete(dbTableLogs, "geocode = ?", new String[] { geocode }); - public boolean saveLogs(String geocode, List<cgLog> logs, boolean drop) { - if (StringUtils.isBlank(geocode) || logs == null) { - return false; - } - - init(); - - databaseRW.beginTransaction(); - try { - if (drop) { - // TODO delete logimages referring these logs - databaseRW.delete(dbTableLogs, "geocode = ?", new String[] { geocode }); - } - - if (!logs.isEmpty()) { - InsertHelper helper = new InsertHelper(databaseRW, dbTableLogs); - long timeStamp = System.currentTimeMillis(); - for (cgLog log : logs) { - helper.prepareForInsert(); - - helper.bind(LOGS_GEOCODE, geocode); - helper.bind(LOGS_UPDATED, timeStamp); - helper.bind(LOGS_TYPE, log.type.id); - helper.bind(LOGS_AUTHOR, log.author); - helper.bind(LOGS_LOG, log.log); - helper.bind(LOGS_DATE, log.date); - helper.bind(LOGS_FOUND, log.found); - helper.bind(LOGS_FRIEND, log.friend); - - long log_id = helper.execute(); - - if (CollectionUtils.isNotEmpty(log.logImages)) { - ContentValues values = new ContentValues(); - for (cgImage img : log.logImages) { - values.clear(); - values.put("log_id", log_id); - values.put("title", img.getTitle()); - values.put("url", img.getUrl()); - databaseRW.insert(dbTableLogImages, null, values); - } + if (CollectionUtils.isNotEmpty(logs)) { + InsertHelper helper = new InsertHelper(databaseRW, dbTableLogs); + long timeStamp = System.currentTimeMillis(); + for (LogEntry log : logs) { + helper.prepareForInsert(); + + helper.bind(LOGS_GEOCODE, geocode); + helper.bind(LOGS_UPDATED, timeStamp); + helper.bind(LOGS_TYPE, log.type.id); + helper.bind(LOGS_AUTHOR, log.author); + helper.bind(LOGS_LOG, log.log); + helper.bind(LOGS_DATE, log.date); + helper.bind(LOGS_FOUND, log.found); + helper.bind(LOGS_FRIEND, log.friend); + + long log_id = helper.execute(); + + if (log.hasLogImages()) { + ContentValues values = new ContentValues(); + for (cgImage img : log.getLogImages()) { + values.clear(); + values.put("log_id", log_id); + values.put("title", img.getTitle()); + values.put("url", img.getUrl()); + databaseRW.insert(dbTableLogImages, null, values); } } - helper.close(); } - databaseRW.setTransactionSuccessful(); - } finally { - databaseRW.endTransaction(); + helper.close(); } - - return true; - } - - public boolean saveLogCount(String geocode, Map<LogType, Integer> logCounts) { - return saveLogCount(geocode, logCounts, true); } - public boolean saveLogCount(String geocode, Map<LogType, Integer> logCounts, boolean drop) { - if (StringUtils.isBlank(geocode) || MapUtils.isEmpty(logCounts)) { - return false; - } - - init(); - - databaseRW.beginTransaction(); - try { - if (drop) { - databaseRW.delete(dbTableLogCount, "geocode = ?", new String[] { geocode }); - } + private void saveLogCountsWithoutTransaction(final cgCache cache) { + String geocode = cache.getGeocode(); + databaseRW.delete(dbTableLogCount, "geocode = ?", new String[] { geocode }); + Map<LogType, Integer> logCounts = cache.getLogCounts(); + if (MapUtils.isNotEmpty(logCounts)) { ContentValues values = new ContentValues(); Set<Entry<LogType, Integer>> logCountsItems = logCounts.entrySet(); @@ -1704,6 +1323,15 @@ public class cgData { databaseRW.insert(dbTableLogCount, null, values); } + } + } + + public boolean saveTrackable(final cgTrackable trackable) { + init(); + + databaseRW.beginTransaction(); + try { + saveInventoryWithoutTransaction(null, Collections.singletonList(trackable)); databaseRW.setTransactionSuccessful(); } finally { databaseRW.endTransaction(); @@ -1712,81 +1340,46 @@ public class cgData { return true; } - public boolean saveInventory(String geocode, List<cgTrackable> trackables) { - if (trackables == null) { - return false; + private void saveInventoryWithoutTransaction(final String geocode, final List<cgTrackable> trackables) { + if (geocode != null) { + databaseRW.delete(dbTableTrackables, "geocode = ?", new String[] { geocode }); } - init(); - - databaseRW.beginTransaction(); - try { - if (geocode != null) { - databaseRW.delete(dbTableTrackables, "geocode = ?", new String[] { geocode }); - } - - if (!trackables.isEmpty()) { - ContentValues values = new ContentValues(); - long timeStamp = System.currentTimeMillis(); - for (cgTrackable oneTrackable : trackables) { - values.clear(); - if (geocode != null) { - values.put("geocode", geocode); - } - values.put("updated", timeStamp); - values.put("tbcode", oneTrackable.getGeocode()); - values.put("guid", oneTrackable.getGuid()); - values.put("title", oneTrackable.getName()); - values.put("owner", oneTrackable.getOwner()); - if (oneTrackable.getReleased() != null) { - values.put("released", oneTrackable.getReleased().getTime()); - } else { - values.put("released", 0L); - } - values.put("goal", oneTrackable.getGoal()); - values.put("description", oneTrackable.getDetails()); + if (CollectionUtils.isNotEmpty(trackables)) { + ContentValues values = new ContentValues(); + long timeStamp = System.currentTimeMillis(); + for (cgTrackable trackable : trackables) { + values.clear(); + if (geocode != null) { + values.put("geocode", geocode); + } + values.put("updated", timeStamp); + values.put("tbcode", trackable.getGeocode()); + values.put("guid", trackable.getGuid()); + values.put("title", trackable.getName()); + values.put("owner", trackable.getOwner()); + if (trackable.getReleased() != null) { + values.put("released", trackable.getReleased().getTime()); + } else { + values.put("released", 0L); + } + values.put("goal", trackable.getGoal()); + values.put("description", trackable.getDetails()); - databaseRW.insert(dbTableTrackables, null, values); + databaseRW.insert(dbTableTrackables, null, values); - saveLogs(oneTrackable.getGeocode(), oneTrackable.getLogs()); - } + saveLogsWithoutTransaction(trackable.getGeocode(), trackable.getLogs()); } - databaseRW.setTransactionSuccessful(); - } finally { - databaseRW.endTransaction(); } - - 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); } /** @@ -1837,12 +1430,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()); } } @@ -1857,7 +1448,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; } @@ -1866,150 +1457,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(')'); + if (!cursor.moveToFirst()) { + return Collections.emptySet(); } - 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 (loadFlags.contains(LoadFlag.LOAD_ATTRIBUTES)) { - cache.setAttributes(loadAttributes(cache.getGeocode())); - } + final Set<cgCache> caches = new HashSet<cgCache>(); + do { + //Extracted Method = LOADDBMINIMAL + cgCache cache = cgData.createCacheFromDatabaseContent(cursor); - 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_ATTRIBUTES)) { + cache.setAttributes(loadAttributes(cache.getGeocode())); + } - 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_WAYPOINTS)) { + final List<cgWaypoint> waypoints = loadWaypoints(cache.getGeocode()); + if (CollectionUtils.isNotEmpty(waypoints)) { + cache.setWaypoints(waypoints, false); + } + } - 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_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_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_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_OFFLINE_LOG)) { - cache.setLogOffline(hasLogOffline(cache.getGeocode())); + 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.addStorageLocation(StorageLocation.DATABASE); - cacheCache.putCacheInCache(cache); + cache.getInventory().addAll(inventory); + } + } - caches.add(cache); - } while (cursor.moveToNext()); + if (loadFlags.contains(LoadFlag.LOAD_OFFLINE_LOG)) { + cache.setLogOffline(hasLogOffline(cache.getGeocode())); } - } - } catch (Exception e) { - Log.e(Settings.tag, "cgData.getCaches: " + e.toString()); - } + cache.addStorageLocation(StorageLocation.DATABASE); + cacheCache.putCacheInCache(cache); - if (cursor != null) { + caches.add(cache); + } while (cursor.moveToNext()); + return caches; + } finally { cursor.close(); } + } - return caches; + /** + * Builds a where for a viewport with the size enhanced by 50%. + * + * @param dbTable + * @param viewport + * @return + */ + + private static String buildCoordinateWhere(final String dbTable, final Viewport viewport) { + return viewport.resize(1.5).sqlWhere(dbTable); } /** @@ -2128,7 +1676,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; } @@ -2179,7 +1727,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, @@ -2187,7 +1735,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(); @@ -2213,7 +1761,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, @@ -2256,7 +1804,7 @@ public class cgData { return waypoint; } - public List<cgImage> loadSpoilers(String geocode) { + private List<cgImage> loadSpoilers(String geocode) { if (StringUtils.isBlank(geocode)) { return null; } @@ -2301,7 +1849,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, @@ -2313,7 +1861,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(); @@ -2323,10 +1871,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. @@ -2353,7 +1898,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(); } @@ -2361,14 +1906,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 " @@ -2376,7 +1921,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"); @@ -2389,24 +1934,20 @@ 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( + cursor.getString(indexAuthor), + cursor.getLong(indexDate), + LogType.getById(cursor.getInt(indexType)), + cursor.getString(indexLog)); log.id = cursor.getInt(indexLogsId); - log.type = LogType.getById(cursor.getInt(indexType)); - log.author = cursor.getString(indexAuthor); - log.log = cursor.getString(indexLog); - log.date = cursor.getLong(indexDate); log.found = cursor.getInt(indexFound); - log.friend = cursor.getInt(indexFriend) == 1 ? true : false; + log.friend = cursor.getInt(indexFriend) == 1; logs.add(log); } 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)); } } } @@ -2457,7 +1998,7 @@ public class cgData { return logCounts; } - public List<cgTrackable> loadInventory(String geocode) { + private List<cgTrackable> loadInventory(String geocode) { if (StringUtils.isBlank(geocode)) { return null; } @@ -2530,11 +2071,14 @@ public class cgData { trackable.setGuid(cursor.getString(cursor.getColumnIndex("guid"))); trackable.setName(cursor.getString(cursor.getColumnIndex("title"))); trackable.setOwner(cursor.getString(cursor.getColumnIndex("owner"))); - String releasedPre = cursor.getString(cursor.getColumnIndex("released")); - if (releasedPre != null && Long.getLong(releasedPre) != null) { - trackable.setReleased(new Date(Long.getLong(releasedPre))); - } else { - trackable.setReleased(null); + String released = cursor.getString(cursor.getColumnIndex("released")); + if (released != null) { + try { + long releaseMilliSeconds = Long.parseLong(released); + trackable.setReleased(new Date(releaseMilliSeconds)); + } catch (NumberFormatException e) { + Log.e("createTrackableFromDatabaseContent", e); + } } trackable.setGoal(cursor.getString(cursor.getColumnIndex("goal"))); trackable.setDetails(cursor.getString(cursor.getColumnIndex("description"))); @@ -2543,22 +2087,22 @@ public class cgData { } /** - * Number of caches stored. The number is shown on the starting activitiy of c:geo + * Number of caches stored. The number is shown on the starting activity of c:geo * * @param detailedOnly * @param cacheType * @param list * @return */ - public int getAllStoredCachesCount(final boolean detailedOnly, final CacheType cacheType, final Integer list) { + public int getAllStoredCachesCount(final boolean detailedOnly, final CacheType cacheType, final int list) { if (cacheType == null) { throw new IllegalArgumentException("cacheType must not be null"); } init(); - String listSql = null; - String listSqlW = null; - if (list == null) { + String listSql; + String listSqlW; + if (list == 0) { listSql = " where reason >= 1"; listSqlW = " and reason >= 1"; } else if (list >= 1) { @@ -2570,7 +2114,7 @@ public class cgData { int count = 0; try { - String sql = "select count(_id) from " + dbTableCaches; // this default is not used, but we like to have variables initialized + String sql; // this default is not used, but we like to have variables initialized if (!detailedOnly) { if (cacheType == CacheType.ALL) { sql = "select count(_id) from " + dbTableCaches + listSql; @@ -2588,7 +2132,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; @@ -2604,16 +2148,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"); } @@ -2637,7 +2188,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" }, @@ -2647,22 +2200,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; @@ -2712,58 +2272,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) { @@ -2778,7 +2326,7 @@ public class cgData { } try { - Cursor cursor = databaseRO.query( + final Cursor cursor = databaseRO.query( dbTableCaches, new String[] { "geocode" }, where.toString(), @@ -2788,110 +2336,21 @@ 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; } - public boolean markFound(String geocode) { - if (StringUtils.isBlank(geocode)) { - return false; - } - - init(); - - boolean result = false; - databaseRW.beginTransaction(); - try { - ContentValues values = new ContentValues(); - values.put("found", 1); - int rows = databaseRW.update(dbTableCaches, values, "geocode = ?", new String[] { geocode }); - if (rows > 0) { - // update CacheCache - cgCache cache = cacheCache.getCacheFromCache(geocode); - if (cache != null) { - cache.setFound(true); - cacheCache.putCacheInCache(cache); - } - result = true; - } - databaseRW.setTransactionSuccessful(); - } finally { - databaseRW.endTransaction(); - } - - return result; - } - /** delete caches from the DB store 3 days or more before */ public void clean() { clean(false); @@ -2906,9 +2365,9 @@ public class cgData { public void clean(boolean more) { init(); - Log.d(Settings.tag, "Database clean: started"); + Log.d("Database clean: started"); - Cursor cursor = null; + Cursor cursor; Set<String> geocodes = new HashSet<String>(); try { @@ -2951,7 +2410,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); } @@ -2959,13 +2418,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"); } /** @@ -2981,7 +2440,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); } } @@ -3078,20 +2537,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, @@ -3106,11 +2565,11 @@ public class cgData { if (cursor != null && cursor.getCount() > 0) { cursor.moveToFirst(); - log = new cgLog(); + log = new LogEntry( + cursor.getLong(cursor.getColumnIndex("date")), + LogType.getById(cursor.getInt(cursor.getColumnIndex("type"))), + cursor.getString(cursor.getColumnIndex("log"))); log.id = cursor.getInt(cursor.getColumnIndex("_id")); - log.type = LogType.getById(cursor.getInt(cursor.getColumnIndex("type"))); - log.log = cursor.getString(cursor.getColumnIndex("log")); - log.date = cursor.getLong(cursor.getColumnIndex("date")); } if (cursor != null) { @@ -3160,7 +2619,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; @@ -3203,7 +2662,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; } @@ -3282,11 +2741,7 @@ public class cgData { databaseRW.endTransaction(); } - if (id < 0) { - return -1; - } else { - return (id + customListIdOffset); - } + return id >= 0 ? id + customListIdOffset : -1; } /** @@ -3347,40 +2802,33 @@ public class cgData { return status; } - public void moveToList(String geocode, int listId) { - if (StringUtils.isBlank(geocode)) { + public void moveToList(final List<cgCache> caches, final int listId) { + if (caches.isEmpty()) { return; } - init(); - ContentValues values = new ContentValues(); + final ContentValues values = new ContentValues(); values.put("reason", listId); + databaseRW.beginTransaction(); try { - databaseRW.update(dbTableCaches, values, "geocode = ?", new String[] { geocode }); + for (cgCache cache : caches) { + databaseRW.update(dbTableCaches, values, "geocode = ?", new String[] { cache.getGeocode() }); + cache.setListId(listId); + } databaseRW.setTransactionSuccessful(); } finally { databaseRW.endTransaction(); } - - // update CacheCache - cgCache cache = cacheCache.getCacheFromCache(geocode); - if (cache != null) { - cache.setListId(listId); - cacheCache.putCacheInCache(cache); - } } public synchronized boolean status() { - if (databaseRO == null || databaseRW == null || !initialized) { - return false; - } + return databaseRO != null && databaseRW != null && initialized; - return true; } - public boolean removeSearchedDestination(cgDestination destination) { + public boolean removeSearchedDestination(Destination destination) { boolean success = true; if (destination == null) { success = false; @@ -3392,7 +2840,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(); @@ -3429,7 +2877,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; @@ -3451,7 +2899,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) { @@ -3470,7 +2918,51 @@ 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 Set<cgWaypoint> loadWaypoints(final Viewport viewport, boolean excludeMine, boolean excludeDisabled) { + final StringBuilder where = new StringBuilder(buildCoordinateWhere(dbTableWaypoints, viewport)); + if (excludeMine) { + where.append(" and ").append(dbTableCaches).append(".own == 0 and ").append(dbTableCaches).append(".found == 0"); + } + if (excludeDisabled) { + where.append(" and ").append(dbTableCaches).append(".disabled == 0"); + } + init(); + + final StringBuilder query = new StringBuilder("SELECT "); + for (int i = 0; i < WAYPOINT_COLUMNS.length; i++) { + query.append(i > 0 ? ", " : "").append(dbTableWaypoints).append('.').append(WAYPOINT_COLUMNS[i]).append(' '); + } + query.append(" FROM ").append(dbTableWaypoints).append(", ").append(dbTableCaches).append(" WHERE ").append(dbTableWaypoints).append("._id == ").append(dbTableCaches).append("._id and ").append(where); + + final Cursor cursor = databaseRO.rawQuery(query.toString(), null); + try { + if (!cursor.moveToFirst()) { + return Collections.emptySet(); + } + + final Set<cgWaypoint> waypoints = new HashSet<cgWaypoint>(); + do { + waypoints.add(createWaypointFromDatabaseContent(cursor)); + } while (cursor.moveToNext()); + return waypoints; + } finally { + cursor.close(); + } } } 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 deleted file mode 100644 index dcad1ba..0000000 --- a/main/src/cgeo/geocaching/cgGeo.java +++ /dev/null @@ -1,252 +0,0 @@ -package cgeo.geocaching; - -import cgeo.geocaching.enumerations.LocationProviderType; -import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.go4cache.Go4Cache; - -import android.content.Context; -import android.location.GpsSatellite; -import android.location.GpsStatus; -import android.location.Location; -import android.location.LocationListener; -import android.location.LocationManager; -import android.os.Bundle; -import android.util.Log; - -import java.util.Iterator; - -public class cgGeo { - - private static final String LAST_LOCATION_PSEUDO_PROVIDER = "last"; - private final LocationManager geoManager = (LocationManager) cgeoapplication.getInstance().getSystemService(Context.LOCATION_SERVICE); - private UpdateLocationCallback updateLocationCallback = null; - private final AbstractLocationListener networkListener = new NetworkLocationListener(); - private final AbstractLocationListener gpsListener = new GpsLocationListener(); - private final GpsStatusListener gpsStatusListener = new GpsStatusListener(); - private Location locGps = null; - private Location locNet = null; - private long locGpsLast = 0L; - public Location location = null; - public LocationProviderType locationProvider = LocationProviderType.LAST; - public Geopoint coordsNow = null; - public Double altitudeNow = null; - public float bearingNow = 0; - public float speedNow = 0; - public float accuracyNow = -1f; - public int satellitesVisible = 0; - public int satellitesFixed = 0; - - public cgGeo() { - restoreLastLocation(); - - geoManager.addGpsStatusListener(gpsStatusListener); - - for (AbstractLocationListener listener : new AbstractLocationListener[] { networkListener, gpsListener }) { - try { - geoManager.requestLocationUpdates(listener.locationProvider, 0, 0, listener); - } catch (Exception e) { - Log.w(Settings.tag, "There is no location provider " + listener.locationProvider); - } - } - } - - public void closeGeo() { - geoManager.removeUpdates(networkListener); - geoManager.removeUpdates(gpsListener); - geoManager.removeGpsStatusListener(gpsStatusListener); - } - - public void replaceUpdate(UpdateLocationCallback callback) { - updateLocationCallback = callback; - fireLocationCallback(); - } - - private void fireLocationCallback() { - if (updateLocationCallback != null) { - updateLocationCallback.updateLocation(this); - } - } - - private static abstract class AbstractLocationListener implements LocationListener { - private final String locationProvider; - - protected AbstractLocationListener(String provider) { - this.locationProvider = provider; - } - - @Override - public void onStatusChanged(String provider, int status, Bundle extras) { - // nothing - } - - @Override - public void onProviderDisabled(String provider) { - // nothing - } - - @Override - public void onProviderEnabled(String provider) { - // nothing - } - } - - private final class GpsLocationListener extends AbstractLocationListener { - - public GpsLocationListener() { - super(LocationManager.GPS_PROVIDER); - } - - @Override - public void onLocationChanged(Location location) { - locGps = location; - locGpsLast = System.currentTimeMillis(); - selectBest(location.getProvider()); - } - } - - private final class NetworkLocationListener extends AbstractLocationListener { - - protected NetworkLocationListener() { - super(LocationManager.NETWORK_PROVIDER); - } - - @Override - public void onLocationChanged(Location location) { - locNet = location; - selectBest(location.getProvider()); - } - - } - - private final class GpsStatusListener implements GpsStatus.Listener { - - @Override - public void onGpsStatusChanged(int event) { - if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS) { - final GpsStatus status = geoManager.getGpsStatus(null); - final Iterator<GpsSatellite> statusIterator = status.getSatellites().iterator(); - - int satellites = 0; - int fixed = 0; - - while (statusIterator.hasNext()) { - GpsSatellite sat = statusIterator.next(); - if (sat.usedInFix()) { - fixed++; - } - satellites++; - } - - boolean changed = false; - if (satellites != satellitesVisible) { - satellitesVisible = satellites; - changed = true; - } - if (fixed != satellitesFixed) { - satellitesFixed = fixed; - changed = true; - } - - if (changed) { - selectBest(null); - } - } - } - } - - private void selectBest(final String signallingProvider) { - if (locNet != null && locGps == null) { // we have only NET - assign(locNet); - } - else if ((locNet == null && locGps != null) // we have only GPS - || (satellitesFixed > 0) // GPS seems to be fixed - || (signallingProvider != null && signallingProvider.equals(LocationManager.GPS_PROVIDER)) // we have new location from GPS - || locGpsLast > (System.currentTimeMillis() - 30 * 1000) // GPS was working in last 30 seconds - ) { - assign(locGps); - } - else { - assign(locNet); // nothing else, using NET - } - } - - private void assignLastLocation(final Geopoint coords) { - if (coords == null) { - return; - } - - locationProvider = LocationProviderType.LAST; - coordsNow = coords; - altitudeNow = null; - bearingNow = 0f; - speedNow = 0f; - accuracyNow = 999f; - - fireLocationCallback(); - } - - private void assign(final Location loc) { - if (loc == null) { - locationProvider = LocationProviderType.LAST; - return; - } - - location = loc; - - final String provider = location.getProvider(); - if (provider.equals(LocationManager.GPS_PROVIDER)) { - locationProvider = LocationProviderType.GPS; - } else if (provider.equals(LocationManager.NETWORK_PROVIDER)) { - locationProvider = LocationProviderType.NETWORK; - } else if (provider.equalsIgnoreCase(LAST_LOCATION_PSEUDO_PROVIDER)) { - locationProvider = LocationProviderType.LAST; - } - - coordsNow = new Geopoint(location.getLatitude(), location.getLongitude()); - cgeoapplication.getInstance().setLastCoords(coordsNow); - - if (location.hasAltitude() && locationProvider != LocationProviderType.LAST) { - altitudeNow = location.getAltitude() + Settings.getAltCorrection(); - } else { - altitudeNow = null; - } - if (location.hasBearing() && locationProvider != LocationProviderType.LAST) { - bearingNow = location.getBearing(); - } else { - bearingNow = 0f; - } - if (location.hasSpeed() && locationProvider != LocationProviderType.LAST) { - speedNow = location.getSpeed(); - } else { - speedNow = 0f; - } - if (location.hasAccuracy() && locationProvider != LocationProviderType.LAST) { - accuracyNow = location.getAccuracy(); - } else { - accuracyNow = 999f; - } - - fireLocationCallback(); - - if (locationProvider == LocationProviderType.GPS || locationProvider == LocationProviderType.NETWORK) { - Go4Cache.signalCoordinates(coordsNow); - } - } - - private void restoreLastLocation() { - // restore from last location (stored by app) - assignLastLocation(cgeoapplication.getInstance().getLastCoords()); - - // restore from last location (stored by device sensors) - for (String provider : new String[] { LocationManager.GPS_PROVIDER, LocationManager.NETWORK_PROVIDER }) { - final Location lastLocation = geoManager.getLastKnownLocation(provider); - if (lastLocation != null) { - lastLocation.setProvider(LAST_LOCATION_PSEUDO_PROVIDER); - assign(lastLocation); - - Log.i(Settings.tag, "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 8e8dffd..6d38ea1 100644 --- a/main/src/cgeo/geocaching/cgSearchHandler.java +++ b/main/src/cgeo/geocaching/cgSearchHandler.java @@ -1,5 +1,7 @@ package cgeo.geocaching; +import cgeo.geocaching.utils.Log; + import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; @@ -8,7 +10,6 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.EditText; @@ -98,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 3daddc5..ff73a66 100644 --- a/main/src/cgeo/geocaching/cgSearchThread.java +++ b/main/src/cgeo/geocaching/cgSearchThread.java @@ -1,7 +1,8 @@ package cgeo.geocaching; +import cgeo.geocaching.utils.Log; + import android.os.Handler; -import android.util.Log; abstract public class cgSearchThread extends Thread { private Handler recaptchaHandler = null; @@ -22,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 b5fc215..ff84833 100644 --- a/main/src/cgeo/geocaching/cgTrackable.java +++ b/main/src/cgeo/geocaching/cgTrackable.java @@ -1,9 +1,10 @@ package cgeo.geocaching; +import cgeo.geocaching.utils.Log; + import org.apache.commons.lang3.StringUtils; import android.text.Html; -import android.util.Log; import java.util.ArrayList; import java.util.Date; @@ -16,7 +17,6 @@ public class cgTrackable implements ILogable { static final public int SPOTTED_UNKNOWN = 3; static final public int SPOTTED_OWNER = 4; - private String error = ""; private String guid = ""; private String geocode = ""; private String iconUrl = ""; @@ -33,7 +33,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() { @@ -43,17 +43,13 @@ 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; } } return "http://coord.info/" + geocode.toUpperCase(); } - public String getError() { - return error; - } - public String getGuid() { return guid; } @@ -187,11 +183,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; } @@ -209,10 +205,7 @@ public class cgTrackable implements ILogable { } public boolean isLoggable() { - if (StringUtils.startsWithIgnoreCase(geocode, "GK")) { - return false; - } - return true; + return !StringUtils.startsWithIgnoreCase(geocode, "GK"); } public String getTrackingcode() { 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 b13c141..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(); @@ -244,4 +232,9 @@ public class cgWaypoint implements IWaypoint, Comparable<cgWaypoint> { public boolean isFinalWithCoords() { return WaypointType.FINAL == waypointType && null != coords; } + + @Override + public String getCoordType() { + return "waypoint"; + } }
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/cgeo.java b/main/src/cgeo/geocaching/cgeo.java index 7367d82..019d217 100644 --- a/main/src/cgeo/geocaching/cgeo.java +++ b/main/src/cgeo/geocaching/cgeo.java @@ -2,18 +2,16 @@ 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.IObserver; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -25,6 +23,7 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.location.Address; @@ -32,7 +31,6 @@ import android.location.Geocoder; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; @@ -60,8 +58,6 @@ public class cgeo extends AbstractActivity { public static final int SEARCH_REQUEST_CODE = 2; private int version = 0; - private cgGeo geo = null; - private UpdateLocationCallback geoUpdate = null; private TextView filterTitle = null; private boolean cleanupRunning = false; private int countBubbleCnt = 0; @@ -70,6 +66,8 @@ public class cgeo extends AbstractActivity { private boolean addressObtaining = false; private boolean initialized = false; + final private UpdateLocation locationUpdater = new UpdateLocation(); + private Handler updateUserInfoHandler = new Handler() { @Override @@ -115,9 +113,7 @@ public class cgeo extends AbstractActivity { addText.append(address.getAdminArea()); } - if (geo != null) { - addCoords = geo.coordsNow; - } + addCoords = app.currentGeo().getCoords(); TextView navLocation = (TextView) findViewById(R.id.nav_location); navLocation.setText(addText.toString()); @@ -130,6 +126,44 @@ public class cgeo extends AbstractActivity { } }; + private class SatellitesHandler extends Handler implements IObserver<IGeoData> { + + private boolean gpsEnabled = false; + private int satellitesFixed = 0; + private int satellitesVisible = 0; + + @Override + public void handleMessage(final Message msg) { + final IGeoData data = (IGeoData) msg.obj; + if (data.getGpsEnabled() == gpsEnabled && + data.getSatellitesFixed() == satellitesFixed && + data.getSatellitesVisible() == satellitesVisible) { + return; + } + gpsEnabled = data.getGpsEnabled(); + satellitesFixed = data.getSatellitesFixed(); + satellitesVisible = data.getSatellitesVisible(); + + final TextView navSatellites = (TextView) findViewById(R.id.nav_satellites); + if (gpsEnabled) { + if (satellitesFixed > 0) { + navSatellites.setText(res.getString(R.string.loc_sat) + ": " + satellitesFixed + '/' + satellitesVisible); + } else if (satellitesVisible >= 0) { + navSatellites.setText(res.getString(R.string.loc_sat) + ": 0/" + satellitesVisible); + } + } else { + navSatellites.setText(res.getString(R.string.loc_gps_disabled)); + } + } + + @Override + public void update(final IGeoData data) { + obtainMessage(0, data).sendToTarget(); + } + } + + private SatellitesHandler satellitesHandler = new SatellitesHandler(); + private Handler firstLoginHandler = new Handler() { @Override @@ -141,7 +175,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()); } } }; @@ -156,29 +190,22 @@ public class cgeo extends AbstractActivity { app.setAction(null); - app.cleanGeo(); app.cleanDir(); setContentView(R.layout.main); setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); // type to search try { - PackageManager manager = this.getPackageManager(); - PackageInfo info = manager.getPackageInfo(this.getPackageName(), 0); - + final PackageInfo info = getPackageManager().getPackageInfo(this.getPackageName(), 0); version = info.versionCode; - - Log.i(Settings.tag, "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("Starting " + info.packageName + " " + info.versionCode + " a.k.a " + info.versionName + "…"); + } catch (final NameNotFoundException e) { + Log.i("No info."); } try { if (!Settings.isHelpShown()) { - RelativeLayout helper = (RelativeLayout) findViewById(R.id.helper); + final RelativeLayout helper = (RelativeLayout) findViewById(R.id.helper); if (helper != null) { helper.setVisibility(View.VISIBLE); helper.setClickable(true); @@ -209,9 +236,9 @@ public class cgeo extends AbstractActivity { @Override public void onResume() { super.onResume(); - + app.addGeoObserver(locationUpdater); + app.addGeoObserver(satellitesHandler); updateUserInfoHandler.sendEmptyMessage(-1); - init(); } @@ -220,32 +247,20 @@ public class cgeo extends AbstractActivity { initialized = false; app.showLoginToast = true; - if (geo != null) { - geo = app.removeGeo(); - } - super.onDestroy(); } @Override public void onStop() { initialized = false; - - if (geo != null) { - geo = app.removeGeo(); - } - super.onStop(); } @Override public void onPause() { initialized = false; - - if (geo != null) { - geo = app.removeGeo(); - } - + app.deleteGeoObserver(locationUpdater); + app.deleteGeoObserver(satellitesHandler); super.onPause(); } @@ -345,11 +360,8 @@ public class cgeo extends AbstractActivity { // context menu for offline button if (v.getId() == R.id.search_offline) { - List<StoredList> cacheLists = app.getLists(); - int listCount = cacheLists.size(); menu.setHeaderTitle(res.getString(R.string.list_title)); - for (int i = 0; i < listCount; i++) { - StoredList list = cacheLists.get(i); + for (final StoredList list : app.getLists()) { menu.add(Menu.NONE, MENU_OPEN_LIST + list.id, Menu.NONE, list.getTitleAndCount()); } return; @@ -398,23 +410,22 @@ public class cgeo extends AbstractActivity { } @Override - public boolean onContextItemSelected(MenuItem item) { + public boolean onContextItemSelected(final MenuItem item) { final int id = item.getItemId(); + if (id < 0) { + return false; + } if (id == 0) { Settings.setCacheType(CacheType.ALL); setFilterTitle(); - - return true; } else if (id > MENU_OPEN_LIST) { - int listId = id - MENU_OPEN_LIST; - Settings.saveLastList(listId); + Settings.saveLastList(id - MENU_OPEN_LIST); cgeocaches.startActivityOffline(this); - return true; - } else if (id > 0) { + } else { final String itemTitle = item.getTitle().toString(); CacheType cacheType = CacheType.ALL; - for (CacheType ct : CacheType.values()) { + for (final CacheType ct : CacheType.values()) { if (ct.getL10n().equalsIgnoreCase(itemTitle)) { cacheType = ct; break; @@ -422,11 +433,9 @@ public class cgeo extends AbstractActivity { } Settings.setCacheType(cacheType); setFilterTitle(); - - return true; } - return false; + return true; } private void setFilterTitle() { @@ -452,40 +461,12 @@ 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) { (new firstLogin()).start(); } - if (geo == null) { - geoUpdate = new UpdateLocation(); - geo = app.startGeo(geoUpdate); - } - final View findOnMap = findViewById(R.id.map); findOnMap.setClickable(true); findOnMap.setOnClickListener(new OnClickListener() { @@ -565,22 +546,16 @@ public class cgeo extends AbstractActivity { .show(); } - private class UpdateLocation implements UpdateLocationCallback { - - private final View nearestView = findViewById(R.id.nearest); - private final TextView navType = (TextView) findViewById(R.id.nav_type); - private final TextView navAccuracy = (TextView) findViewById(R.id.nav_accuracy); - private final TextView navSatellites = (TextView) findViewById(R.id.nav_satellites); - private final TextView navLocation = (TextView) findViewById(R.id.nav_location); + private class UpdateLocation extends GeoObserver { @Override - public void updateLocation(cgGeo geo) { - if (geo == null) { - return; - } - + public void updateLocation(final IGeoData geo) { + final View nearestView = findViewById(R.id.nearest); + final TextView navType = (TextView) findViewById(R.id.nav_type); + final TextView navAccuracy = (TextView) findViewById(R.id.nav_accuracy); + final TextView navLocation = (TextView) findViewById(R.id.nav_location); try { - if (geo.coordsNow != null) { + if (geo.getCoords() != null) { if (!nearestView.isClickable()) { nearestView.setFocusable(true); nearestView.setClickable(true); @@ -592,23 +567,14 @@ public class cgeo extends AbstractActivity { nearestView.setBackgroundResource(R.drawable.main_nearby); } - String satellites = null; - if (geo.satellitesFixed > 0) { - satellites = res.getString(R.string.loc_sat) + ": " + geo.satellitesFixed + "/" + geo.satellitesVisible; - } else if (geo.satellitesVisible >= 0) { - satellites = res.getString(R.string.loc_sat) + ": 0/" + geo.satellitesVisible; - } else { - satellites = ""; - } - navSatellites.setText(satellites); - navType.setText(res.getString(geo.locationProvider.resourceId)); + navType.setText(res.getString(geo.getLocationProvider().resourceId)); - if (geo.accuracyNow >= 0) { - int speed = Math.round(geo.speedNow) * 60 * 60 / 1000; + if (geo.getAccuracy() >= 0) { + int speed = Math.round(geo.getSpeed()) * 60 * 60 / 1000; if (Settings.isUseMetricUnits()) { - navAccuracy.setText("±" + Math.round(geo.accuracyNow) + " m" + Formatter.SEPARATOR + speed + " km/h"); + navAccuracy.setText("±" + Math.round(geo.getAccuracy()) + " m" + Formatter.SEPARATOR + speed + " km/h"); } else { - navAccuracy.setText("±" + Math.round(geo.accuracyNow * IConversion.METERS_TO_FEET) + " ft" + Formatter.SEPARATOR + speed / IConversion.MILES_TO_KILOMETER + " mph"); + navAccuracy.setText("±" + Math.round(geo.getAccuracy() * IConversion.METERS_TO_FEET) + " ft" + Formatter.SEPARATOR + speed / IConversion.MILES_TO_KILOMETER + " mph"); } } else { navAccuracy.setText(null); @@ -618,15 +584,15 @@ public class cgeo extends AbstractActivity { if (addCoords == null) { navLocation.setText(res.getString(R.string.loc_no_addr)); } - if (addCoords == null || (geo.coordsNow.distanceTo(addCoords) > 0.5 && !addressObtaining)) { + if (addCoords == null || (geo.getCoords().distanceTo(addCoords) > 0.5 && !addressObtaining)) { (new ObtainAddressThread()).start(); } } else { - if (geo.altitudeNow != null) { - final String humanAlt = HumanDistance.getHumanDistance(geo.altitudeNow.floatValue() / 1000); - navLocation.setText(geo.coordsNow + " | " + humanAlt); + if (geo.getAltitude() != 0.0) { + final String humanAlt = HumanDistance.getHumanDistance((float) geo.getAltitude() / 1000); + navLocation.setText(geo.getCoords() + " | " + humanAlt); } else { - navLocation.setText(geo.coordsNow.toString()); + navLocation.setText(geo.getCoords().toString()); } } } else { @@ -641,7 +607,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."); } } } @@ -660,12 +626,12 @@ public class cgeo extends AbstractActivity { * unused here but needed since this method is referenced from XML layout */ public void cgeoFindNearest(View v) { - if (geo == null || geo.coordsNow == null) { + if (app.currentGeo().getCoords() == null) { return; } findViewById(R.id.nearest).setPressed(true); - cgeocaches.startActivityNearest(this, geo.coordsNow); + cgeocaches.startActivityNearest(this, app.currentGeo().getCoords()); } /** @@ -704,6 +670,14 @@ public class cgeo extends AbstractActivity { findViewById(R.id.filter_button).performClick(); } + /** + * @param v + * unused here but needed since this method is referenced from XML layout + */ + public void cgeoNavSettings(View v) { + startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS)); + } + private class CountBubbleUpdateThread extends Thread { private Handler countBubbleHandler = new Handler() { private TextView countBubble = null; @@ -723,7 +697,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()); } } }; @@ -748,7 +722,7 @@ public class cgeo extends AbstractActivity { } } - countBubbleCnt = app.getAllStoredCachesCount(true, CacheType.ALL, null); + countBubbleCnt = app.getAllStoredCachesCount(true, CacheType.ALL); countBubbleHandler.sendEmptyMessage(0); } @@ -767,7 +741,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; } @@ -805,9 +779,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); } } } @@ -821,9 +793,6 @@ public class cgeo extends AbstractActivity { @Override public void run() { - if (geo == null) { - return; - } if (addressObtaining) { return; } @@ -831,10 +800,10 @@ public class cgeo extends AbstractActivity { try { final Geocoder geocoder = new Geocoder(cgeo.this, Locale.getDefault()); - - addresses = geocoder.getFromLocation(geo.coordsNow.getLatitude(), geo.coordsNow.getLongitude(), 1); + final Geopoint coords = app.currentGeo().getCoords(); + addresses = geocoder.getFromLocation(coords.getLatitude(), coords.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 1fc6605..f112539 100644 --- a/main/src/cgeo/geocaching/cgeoabout.java +++ b/main/src/cgeo/geocaching/cgeoabout.java @@ -1,14 +1,13 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.utils.Log; import android.content.Intent; import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.text.method.LinkMovementMethod; -import android.util.Log; import android.view.View; import android.widget.TextView; @@ -27,17 +26,13 @@ public class cgeoabout extends AbstractActivity { private void init() { try { - PackageManager manager = this.getPackageManager(); - PackageInfo info = manager.getPackageInfo(this.getPackageName(), 0); + final PackageInfo info = getPackageManager().getPackageInfo(this.getPackageName(), 0); setTitle(res.getString(R.string.about) + " (ver. " + info.versionName + ")"); - - manager = null; - ((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 db0088c..4fac391 100644 --- a/main/src/cgeo/geocaching/cgeoadvsearch.java +++ b/main/src/cgeo/geocaching/cgeoadvsearch.java @@ -4,9 +4,10 @@ import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.connector.gc.GCConstants; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter; -import cgeo.geocaching.geopoint.GeopointParser; import cgeo.geocaching.utils.BaseUtils; import cgeo.geocaching.utils.EditUtils; +import cgeo.geocaching.utils.IObserver; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; @@ -14,7 +15,6 @@ import android.app.SearchManager; import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -24,16 +24,13 @@ import android.widget.AutoCompleteTextView; import android.widget.Button; import android.widget.EditText; -public class cgeoadvsearch extends AbstractActivity { +public class cgeoadvsearch extends AbstractActivity implements IObserver<IGeoData> { public static final String EXTRAS_KEYWORDSEARCH = "keywordsearch"; private static final int MENU_SEARCH_OWN_CACHES = 1; - private cgGeo geo = null; - private UpdateLocationCallback geoUpdate = new update(); private EditText latEdit = null; private EditText lonEdit = null; - private String[] geocodesInCache = null; public cgeoadvsearch() { super("c:geo-search"); @@ -80,34 +77,13 @@ public class cgeoadvsearch extends AbstractActivity { @Override public void onResume() { super.onResume(); - + app.addGeoObserver(this); init(); } @Override - public void onDestroy() { - if (geo != null) { - geo = app.removeGeo(); - } - - super.onDestroy(); - } - - @Override - public void onStop() { - if (geo != null) { - geo = app.removeGeo(); - } - - super.onStop(); - } - - @Override public void onPause() { - if (geo != null) { - geo = app.removeGeo(); - } - + app.deleteGeoObserver(this); super.onPause(); } @@ -121,32 +97,25 @@ public class cgeoadvsearch extends AbstractActivity { * @return true if a search was performed, else false */ private boolean instantSearch(final String query, final boolean keywordSearch) { - try { - String result = BaseUtils.getMatch(query, GCConstants.PATTERN_GC_CODE, true, 0, "", false); - if (StringUtils.isNotBlank(result)) { - final Intent cachesIntent = new Intent(this, CacheDetailActivity.class); - cachesIntent.putExtra("geocode", result.toUpperCase()); - startActivity(cachesIntent); + final String geocode = BaseUtils.getMatch(query, GCConstants.PATTERN_GC_CODE, true, 0, "", false); + if (StringUtils.isNotBlank(geocode)) { + final Intent cachesIntent = new Intent(this, CacheDetailActivity.class); + cachesIntent.putExtra("geocode", geocode.toUpperCase()); + startActivity(cachesIntent); + return true; + } - return true; - } else { - result = BaseUtils.getMatch(query, GCConstants.PATTERN_TB_CODE, true, 0, "", false); - if (StringUtils.isNotBlank(result)) { - final Intent trackablesIntent = new Intent(this, cgeotrackable.class); - trackablesIntent.putExtra("geocode", result.toUpperCase()); - startActivity(trackablesIntent); - - return true; - } else if (keywordSearch) { // keyword fallback, if desired by caller - cgeocaches.startActivityKeyword(this, query.trim()); - return true; - } else { - return false; - } + final String trackable = BaseUtils.getMatch(query, GCConstants.PATTERN_TB_CODE, true, 0, "", false); + if (StringUtils.isNotBlank(trackable)) { + final Intent trackablesIntent = new Intent(this, cgeotrackable.class); + trackablesIntent.putExtra("geocode", trackable.toUpperCase()); + startActivity(trackablesIntent); + return true; + } - } - } catch (Exception e) { - Log.w(Settings.tag, "cgeoadvsearch.instantSearch: " + e.toString()); + if (keywordSearch) { // keyword fallback, if desired by caller + cgeocaches.startActivityKeyword(this, query.trim()); + return true; } return false; @@ -155,10 +124,6 @@ public class cgeoadvsearch extends AbstractActivity { private void init() { Settings.getLogin(); - if (geo == null) { - geo = app.startGeo(geoUpdate); - } - ((Button) findViewById(R.id.buttonLatitude)).setOnClickListener(new findByCoordsAction()); ((Button) findViewById(R.id.buttonLongitude)).setOnClickListener(new findByCoordsAction()); @@ -184,7 +149,7 @@ public class cgeoadvsearch extends AbstractActivity { findByGeocodeFn(); } }); - geocodesInCache = app.geocodesInCache(); + final String[] geocodesInCache = app.geocodesInCache(); if (geocodesInCache != null) { final ArrayAdapter<String> geocodesAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, geocodesInCache); geocodeEdit.setAdapter(geocodesAdapter); @@ -246,33 +211,26 @@ public class cgeoadvsearch extends AbstractActivity { displayTrackable.setOnClickListener(new findTrackableListener()); } - private class update implements UpdateLocationCallback { - - @Override - public void updateLocation(cgGeo geo) { - if (geo == null) { - return; + @Override + public void update(final IGeoData geo) { + try { + if (latEdit == null) { + latEdit = (EditText) findViewById(R.id.latitude); + } + if (lonEdit == null) { + lonEdit = (EditText) findViewById(R.id.longitude); } - try { - if (latEdit == null) { - latEdit = (EditText) findViewById(R.id.latitude); - } - if (lonEdit == null) { - lonEdit = (EditText) findViewById(R.id.longitude); + if (geo.getCoords() != null) { + if (latEdit != null) { + latEdit.setHint(geo.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE_RAW)); } - - if (geo.coordsNow != null) { - if (latEdit != null) { - latEdit.setHint(geo.coordsNow.format(GeopointFormatter.Format.LAT_DECMINUTE_RAW)); - } - if (lonEdit != null) { - lonEdit.setHint(geo.coordsNow.format(GeopointFormatter.Format.LON_DECMINUTE_RAW)); - } + if (lonEdit != null) { + lonEdit.setHint(geo.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE_RAW)); } - } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); } + } catch (Exception e) { + Log.w("Failed to update location."); } } @@ -280,7 +238,7 @@ public class cgeoadvsearch extends AbstractActivity { @Override public void onClick(View arg0) { - cgeocoords coordsDialog = new cgeocoords(cgeoadvsearch.this, null, null, geo); + cgeocoords coordsDialog = new cgeocoords(cgeoadvsearch.this, null, null, app.currentGeo()); coordsDialog.setCancelable(true); coordsDialog.setOnCoordinateUpdate(new cgeocoords.CoordinateUpdate() { @Override @@ -307,14 +265,15 @@ public class cgeoadvsearch extends AbstractActivity { final String lonText = lonView.getText().toString(); if (StringUtils.isEmpty(latText) || StringUtils.isEmpty(lonText)) { - if (geo.coordsNow != null) { - latView.setText(geo.coordsNow.format(GeopointFormatter.Format.LAT_DECMINUTE)); - lonView.setText(geo.coordsNow.format(GeopointFormatter.Format.LON_DECMINUTE)); + final IGeoData geo = app.currentGeo(); + if (geo.getCoords() != null) { + latView.setText(geo.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE)); + lonView.setText(geo.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE)); } } else { try { - cgeocaches.startActivityCoordinates(this, GeopointParser.parseLatitude(latText), GeopointParser.parseLongitude(lonText)); - } catch (GeopointParser.ParseException e) { + cgeocaches.startActivityCoordinates(this, new Geopoint(latText, lonText)); + } catch (Geopoint.ParseException e) { showToast(res.getString(e.resource)); } } diff --git a/main/src/cgeo/geocaching/cgeoapplication.java b/main/src/cgeo/geocaching/cgeoapplication.java index e2b39d8..d0ee5c3 100644 --- a/main/src/cgeo/geocaching/cgeoapplication.java +++ b/main/src/cgeo/geocaching/cgeoapplication.java @@ -7,6 +7,9 @@ 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.IObserver; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; @@ -17,13 +20,11 @@ import android.content.Context; import android.content.res.Resources; import android.os.Handler; import android.os.Message; -import android.util.Log; import java.io.File; -import java.util.ArrayList; +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; @@ -33,9 +34,7 @@ public class cgeoapplication extends Application { private cgData storage = null; private String action = null; - private Geopoint lastCoords = null; - private cgGeo geo = null; - private boolean geoInUse = false; + private volatile GeoDataProvider geo; private cgDirection dir = null; private boolean dirInUse = false; public boolean firstRun = true; // c:geo is just launched @@ -54,16 +53,15 @@ 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(); if (storage != null) { @@ -114,73 +112,45 @@ public class cgeoapplication extends Application { restoreThread.start(); } - public void cleanGeo() { - if (geo != null) { - geo.closeGeo(); - geo = null; - } - } - - public void cleanDir() { - if (dir != null) { - dir.closeDir(); - dir = null; - } + public void addGeoObserver(final IObserver<? super IGeoData> observer) { + currentGeoObject().addObserver(observer); } - public boolean storageStatus() { - return storage.status(); + public void deleteGeoObserver(final IObserver<? super IGeoData> observer) { + currentGeoObject().deleteObserver(observer); } - public cgGeo startGeo(UpdateLocationCallback geoUpdate) { + private GeoDataProvider currentGeoObject() { if (geo == null) { - geo = new cgGeo(); - Log.i(Settings.tag, "Location service started"); + synchronized(this) { + if (geo == null) { + geo = new GeoDataProvider(this); + } + } } - - geo.replaceUpdate(geoUpdate); - geoInUse = true; - return geo; } - public float getSpeedFromGeo() { - return geo != null ? geo.speedNow : 0f; + public IGeoData currentGeo() { + return currentGeoObject().getMemory(); } - public cgGeo removeGeo() { - if (geo != null) { - geo.replaceUpdate(null); + public void cleanDir() { + if (dir != null) { + dir.closeDir(); + dir = null; } - geoInUse = false; - - (new removeGeoThread()).start(); - - return null; } - private class removeGeoThread extends Thread { - - @Override - public void run() { - try { - sleep(2500); - } catch (Exception e) { - // nothing - } - - if (!geoInUse && geo != null) { - cleanGeo(); - Log.i(Settings.tag, "Location service stopped"); - } - } + public boolean storageStatus() { + return storage.status(); } public cgDirection startDir(Context context, UpdateDirectionCallback dirUpdate) { 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 +182,7 @@ public class cgeoapplication extends Application { if (!dirInUse && dir != null) { cleanDir(); - Log.i(Settings.tag, "Direction service stopped"); + Log.i("Direction service stopped"); } } } @@ -264,10 +234,7 @@ public class cgeoapplication extends Application { return null; } - cgTrackable trackable = null; - trackable = storage.loadTrackable(geocode); - - return trackable; + return storage.loadTrackable(geocode); } /** {@link cgData#allDetailedThere()} */ @@ -275,56 +242,53 @@ 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); } /** {@link cgData#loadBatchOfStoredGeocodes(boolean, Geopoint, CacheType, int)} */ public SearchResult getBatchOfStoredCaches(final boolean detailedOnly, final Geopoint coords, final CacheType cacheType, final int listId) { final Set<String> geocodes = storage.loadBatchOfStoredGeocodes(detailedOnly, coords, cacheType, listId); - final SearchResult search = new SearchResult(geocodes); - search.totalCnt = getAllStoredCachesCount(true, cacheType, listId); - return search; + return new SearchResult(geocodes, getAllStoredCachesCount(true, cacheType, listId)); } /** {@link cgData#loadHistoryOfSearchedLocations()} */ - public List<cgDestination> getHistoryOfSearchedLocations() { + public List<Destination> getHistoryOfSearchedLocations() { return storage.loadHistoryOfSearchedLocations(); } public SearchResult getHistoryOfCaches(final boolean detailedOnly, final CacheType cacheType) { final Set<String> geocodes = storage.loadBatchOfHistoricGeocodes(detailedOnly, cacheType); - final SearchResult search = new SearchResult(geocodes); - - search.totalCnt = getAllHistoricCachesCount(); - return search; + 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(Viewport, 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(Viewport, CacheType)} */ + public SearchResult getStoredInViewport(final Viewport viewport, final CacheType cacheType) { + final Set<String> geocodes = storage.loadStoredInViewport(viewport, cacheType); return new SearchResult(geocodes); } - /** {@link cgData#getAllStoredCachesCount(boolean, CacheType, Integer)} */ + /** {@link cgData#getAllStoredCachesCount(boolean, CacheType, int)} */ + public int getAllStoredCachesCount(final boolean detailedOnly, final CacheType cacheType) { + return storage.getAllStoredCachesCount(detailedOnly, cacheType, 0); + } + + /** {@link cgData#getAllStoredCachesCount(boolean, CacheType, int)} */ public int getAllStoredCachesCount(final boolean detailedOnly, final CacheType cacheType, final Integer list) { return storage.getAllStoredCachesCount(detailedOnly, cacheType, list); } @@ -335,18 +299,13 @@ public class cgeoapplication extends Application { } /** {@link cgData#moveToList(String, int)} */ - public void markStored(String geocode, int listId) { - storage.moveToList(geocode, listId); + public void markStored(List<cgCache> caches, int listId) { + storage.moveToList(caches, listId); } /** {@link cgData#moveToList(String, int)} */ - public void markDropped(String geocode) { - storage.moveToList(geocode, StoredList.TEMPORARY_LIST_ID); - } - - /** {@link cgData#markFound(String)} */ - public boolean markFound(String geocode) { - return storage.markFound(geocode); + public void markDropped(List<cgCache> caches) { + storage.moveToList(caches, StoredList.TEMPORARY_LIST_ID); } /** {@link cgData#clearSearchedDestinations()} */ @@ -354,14 +313,14 @@ 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)} */ - public boolean saveWaypoints(String geocode, List<cgWaypoint> waypoints, boolean drop) { - return storage.saveWaypoints(geocode, waypoints, drop); + public boolean saveWaypoints(final cgCache cache) { + return storage.saveWaypoints(cache); } public boolean saveOwnWaypoint(int id, String geocode, cgWaypoint waypoint) { @@ -378,10 +337,7 @@ public class cgeoapplication extends Application { } public boolean saveTrackable(cgTrackable trackable) { - final List<cgTrackable> list = new ArrayList<cgTrackable>(); - list.add(trackable); - - return storage.saveInventory("---", list); + return storage.saveTrackable(trackable); } /** {@link cgData#dropList(int)} **/ @@ -389,21 +345,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); @@ -428,35 +374,13 @@ public class cgeoapplication extends Application { return StringUtils.defaultString(action); } - public boolean addLog(String geocode, cgLog log) { - if (StringUtils.isBlank(geocode)) { - return false; - } - if (log == null) { - return false; - } - - List<cgLog> list = new ArrayList<cgLog>(); - list.add(log); - - return storage.saveLogs(geocode, list, false); - } - - public void setLastCoords(final Geopoint coords) { - lastCoords = coords; - } - - public Geopoint getLastCoords() { - return lastCoords; - } - /** {@link cgData#saveLogOffline(String, Date, LogType, String)} */ public boolean saveLogOffline(String geocode, Date date, LogType logtype, String log) { return storage.saveLogOffline(geocode, date, logtype, log); } /** {@link cgData#loadLogOffline(String)} */ - public cgLog loadLogOffline(String geocode) { + public LogEntry loadLogOffline(String geocode) { return storage.loadLogOffline(geocode); } @@ -500,14 +424,14 @@ 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); } /** {@link cgData#moveToList(String, int)} */ - public void moveToList(String geocode, int listId) { - storage.moveToList(geocode, listId); + public void moveToList(List<cgCache> caches, int listId) { + storage.moveToList(caches, listId); } /** {@link cgData#getCacheDescription(String)} */ @@ -525,11 +449,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); @@ -545,4 +464,8 @@ public class cgeoapplication extends Application { storage.removeCaches(geocodes, removeFlags); } + public Set<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 21ecb5e..db44e16 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; @@ -39,6 +37,8 @@ import cgeo.geocaching.sorting.TerrainComparator; import cgeo.geocaching.sorting.VisitComparator; import cgeo.geocaching.sorting.VoteComparator; import cgeo.geocaching.ui.CacheListAdapter; +import cgeo.geocaching.utils.IObserver; +import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.RunnableWithArgument; import org.apache.commons.collections.CollectionUtils; @@ -50,13 +50,10 @@ import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; 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.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.KeyEvent; @@ -66,31 +63,22 @@ 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.List; import java.util.Map; import java.util.Set; -public class cgeocaches extends AbstractListActivity { +public class cgeocaches extends AbstractListActivity implements IObserver<IGeoData> { 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,21 +98,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; private static final int MENU_SORT_FINDS = 62; @@ -132,12 +114,12 @@ 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_RESTART_GEO_AND_DIR = -2; private static final int MSG_CANCEL = -99; private String action = null; @@ -155,9 +137,7 @@ public class cgeocaches extends AbstractListActivity { private TextView listFooterText = null; private Progress progress = new Progress(); private Float northHeading = 0f; - private cgGeo geo = null; private cgDirection dir = null; - private UpdateLocationCallback geoUpdate = new UpdateLocation(); private UpdateDirectionCallback dirUpdate = new UpdateDirection(); private String title = ""; private int detailTotal = 0; @@ -165,11 +145,8 @@ public class cgeocaches extends AbstractListActivity { private long detailProgressTime = 0L; 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() { @@ -177,7 +154,7 @@ public class cgeocaches extends AbstractListActivity { public void handleMessage(Message msg) { try { if (search != null) { - setTitle(title + " [" + search.getCount() + "]"); + setTitle(title + " [" + search.getCount() + ']'); cacheList.clear(); final Set<cgCache> caches = search.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB); @@ -206,14 +183,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"))); } }); @@ -221,7 +198,7 @@ public class cgeocaches extends AbstractListActivity { AlertDialog alert = dialog.create(); alert.show(); } else if (app != null && search != null && search.getError() != null) { - showToast(res.getString(R.string.err_download_fail) + " " + search.getError().getErrorString(res) + "."); + showToast(res.getString(R.string.err_download_fail) + ' ' + search.getError().getErrorString(res) + '.'); hideLoading(); showProgress(false); @@ -230,13 +207,14 @@ public class cgeocaches extends AbstractListActivity { return; } - if (geo != null && geo.coordsNow != null) { - adapter.setActualCoordinates(geo.coordsNow); + final Geopoint coordsNow = app.currentGeo().getCoords(); + if (coordsNow != null) { + adapter.setActualCoordinates(coordsNow); adapter.setActualHeading(northHeading); } } 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 +227,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) { @@ -297,13 +275,14 @@ public class cgeocaches extends AbstractListActivity { return; } - if (geo != null && geo.coordsNow != null) { - adapter.setActualCoordinates(geo.coordsNow); + final Geopoint coordsNow = app.currentGeo().getCoords(); + if (coordsNow != null) { + adapter.setActualCoordinates(coordsNow); adapter.setActualHeading(northHeading); } } 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(); @@ -342,6 +321,8 @@ public class cgeocaches extends AbstractListActivity { if (threadDetails != null) { threadDetails.kill(); } + } else if (msg.what == MSG_RESTART_GEO_AND_DIR) { + startGeoAndDir(); } else { if (cacheList != null && search != null) { final Set<cgCache> cacheListTmp = search.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB); @@ -353,8 +334,9 @@ public class cgeocaches extends AbstractListActivity { } } - if (geo != null && geo.coordsNow != null) { - adapter.setActualCoordinates(geo.coordsNow); + final Geopoint coordsNow = app.currentGeo().getCoords(); + if (coordsNow != null) { + adapter.setActualCoordinates(coordsNow); adapter.setActualHeading(northHeading); } @@ -383,12 +365,10 @@ public class cgeocaches extends AbstractListActivity { refreshCurrentList(); } else if (msg.what == -2) { progress.dismiss(); - startGeoAndDir(); showToast(res.getString(R.string.sendToCgeo_download_fail)); finish(); } else if (msg.what == -3) { progress.dismiss(); - startGeoAndDir(); showToast(res.getString(R.string.sendToCgeo_no_registration)); finish(); } else if (msg.what == MSG_CANCEL) { @@ -410,7 +390,6 @@ public class cgeocaches extends AbstractListActivity { Collections.sort(cacheList, gcComparator); } - startGeoAndDir(); progress.dismiss(); } } @@ -419,11 +398,7 @@ public class cgeocaches extends AbstractListActivity { @Override public void handleMessage(Message msg) { - if (msg.what == MSG_CANCEL) { - if (threadR != null) { - threadR.kill(); - } - } else { + if (msg.what != MSG_CANCEL) { if (adapter != null) { adapter.setSelectMode(false, true); } @@ -469,39 +444,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 @@ -526,6 +468,13 @@ public class cgeocaches extends AbstractListActivity { super.onCreate(savedInstanceState); // init + if (CollectionUtils.isNotEmpty(cacheList)) { + setMoreCaches(); + } + + setTitle(title); + setAdapter(); + app.setAction(action); setTheme(); @@ -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,12 +495,10 @@ 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); } } - init(); - Thread threadPure; cgSearchThread thread; @@ -666,7 +613,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(); @@ -696,27 +643,18 @@ public class cgeocaches extends AbstractListActivity { } @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - - init(); - } - - @Override public void onResume() { super.onResume(); init(); - if (adapter != null && geo != null && geo.coordsNow != null) { - adapter.setActualCoordinates(geo.coordsNow); - adapter.setActualHeading(northHeading); - } - if (adapter != null) { adapter.setSelectMode(false, true); - if (geo != null && geo.coordsNow != null) { - adapter.forceSort(geo.coordsNow); + final Geopoint coordsNow = app.currentGeo().getCoords(); + if (coordsNow != null) { + adapter.setActualCoordinates(coordsNow); + adapter.setActualHeading(northHeading); + adapter.forceSort(coordsNow); } } @@ -726,8 +664,8 @@ 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); - if (newSearch != null && newSearch.totalCnt != search.totalCnt) { + SearchResult newSearch = cgeoapplication.getInstance().getBatchOfStoredCaches(true, coords, cacheType, listId); + if (newSearch != null && newSearch.getTotal() != search.getTotal()) { refreshCurrentList(); } } @@ -739,15 +677,11 @@ public class cgeocaches extends AbstractListActivity { adapter = null; } - removeGeoAndDir(); - super.onDestroy(); } @Override public void onStop() { - removeGeoAndDir(); - super.onStop(); } @@ -760,17 +694,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)); @@ -795,7 +719,7 @@ public class cgeocaches extends AbstractListActivity { Collections.sort(sortedLabels); for (String label : sortedLabels) { Integer id = comparators.get(label); - subMenuSort.add(1, id.intValue(), 0, label).setCheckable(true).setChecked(id.intValue() == MENU_SORT_DISTANCE); + subMenuSort.add(1, id, 0, label).setCheckable(true).setChecked(id == MENU_SORT_DISTANCE); } subMenuSort.setGroupCheckable(1, true, true); @@ -808,21 +732,19 @@ 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) - { - 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 - subMenuImport.add(1, MENU_IMPORT_GPX, 0, res.getString(R.string.gpx_import_title)).setCheckable(false).setChecked(false); - subMenuImport.add(1, MENU_IMPORT_WEB, 0, res.getString(R.string.web_import_title)).setCheckable(false).setChecked(false); + + //TODO: add submenu/AlertDialog and use R.string.gpx_import_title + subMenu.add(0, MENU_IMPORT_GPX, 0, res.getString(R.string.gpx_import_title)); + if (Settings.getWebDeviceCode() != null) { + subMenu.add(0, MENU_IMPORT_WEB, 0, res.getString(R.string.web_import_title)); } + + subMenu.add(0, MENU_EXPORT, 0, res.getString(R.string.export)); // export caches } 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,40 +781,27 @@ 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 int[] hideIfEmptyList = new int[] { MENU_SWITCH_SELECT_MODE, - SUBMENU_MANAGE_OFFLINE, SUBMENU_MANAGE_HISTORY, SUBMENU_SHOW_MAP, SUBMENU_SORT, - MENU_REFRESH_STORED }; + MENU_REFRESH_STORED, + MENU_DROP_CACHES, + MENU_DROP_CACHES_AND_LIST, + MENU_MOVE_TO_LIST, + MENU_EXPORT, + MENU_REMOVE_FROM_HISTORY + }; boolean menuVisible = cacheList.size() > 0; for (int itemId : hideIfEmptyList) { @@ -922,42 +831,31 @@ public class cgeocaches extends AbstractListActivity { } item = menu.findItem(MENU_MOVE_TO_LIST); if (item != null) { - 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; - } - } + item.setVisible(multipleLists && cacheList.size() > 0); } + 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 +883,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 +942,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(); @@ -1083,24 +974,7 @@ public class cgeocaches extends AbstractListActivity { return true; } - 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(); + return CacheListAppFactory.onMenuItemSelected(item, app.currentGeo(), cacheList, this, search); } private void setComparator(MenuItem item, @@ -1123,7 +997,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,41 +1027,33 @@ 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) { + List<cgCache> selected; + final boolean moveAll = adapter.getChecked() == 0; + if (moveAll) { + selected = new ArrayList<cgCache>(cacheList); + } else { + selected = adapter.getCheckedCaches(); + } + app.moveToList(selected, 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 public boolean onContextItemSelected(MenuItem item) { - final int id = item.getItemId(); ContextMenu.ContextMenuInfo info = item.getMenuInfo(); // restore menu info for sub menu items, see @@ -1201,69 +1067,62 @@ 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) { - final cgCache cache = getCacheFromAdapter(adapterInfo); - NavigationAppFactory.startDefaultNavigationApplication(geo, this, cache, null, null); - return true; - } else if (id == MENU_NAVIGATION) { - final cgCache cache = getCacheFromAdapter(adapterInfo); - NavigationAppFactory.showNavigationMenu(geo, this, cache, null, null); - return true; - } else if (id == MENU_LOG_VISIT) { - return getCacheFromAdapter(adapterInfo).logVisit(this); - } else if (id == MENU_CACHE_DETAILS) { - final Intent cachesIntent = new Intent(this, CacheDetailActivity.class); - final cgCache cache = getCacheFromAdapter(adapterInfo); - cachesIntent.putExtra("geocode", cache.getGeocode().toUpperCase()); - cachesIntent.putExtra("name", cache.getName()); - startActivity(cachesIntent); + final cgCache cache = adapterInfo != null ? getCacheFromAdapter(adapterInfo) : null; - return true; - } else if (id == MENU_DROP_CACHE) { - cgBase.dropCache(getCacheFromAdapter(adapterInfo), new Handler() { - @Override - public void handleMessage(Message msg) { - refreshCurrentList(); - } - }); - 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()); - } + final int id = item.getItemId(); + switch (id) { + case MENU_DEFAULT_NAVIGATION: + NavigationAppFactory.startDefaultNavigationApplication(app.currentGeo(), this, cache, null, null); + break; + case MENU_NAVIGATION: + NavigationAppFactory.showNavigationMenu(app.currentGeo(), this, cache, null, null); + break; + case MENU_LOG_VISIT: + cache.logVisit(this); + break; + case MENU_CACHE_DETAILS: + final Intent cachesIntent = new Intent(this, CacheDetailActivity.class); + cachesIntent.putExtra("geocode", cache.getGeocode().toUpperCase()); + cachesIntent.putExtra("name", cache.getName()); + startActivity(cachesIntent); + break; + case MENU_DROP_CACHE: + cache.drop(new Handler() { + @Override + public void handleMessage(Message msg) { + refreshCurrentList(); + } + }); + break; + case MENU_MOVE_TO_LIST: + 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; - app.moveToList(geocode, newListId); - adapter.resetChecks(); - refreshCurrentList(); + @Override + public void run(Integer newListId) { + app.moveToList(Collections.singletonList(cache), newListId); + adapter.resetChecks(); + refreshCurrentList(); + } + }); + break; + case MENU_STORE_CACHE: + //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); + break; + default: + // we must remember the menu info for the sub menu, there is a bug + // in Android: + // https://code.google.com/p/android/issues/detail?id=7139 + lastMenuInfo = info; + if (cache != null) { + // create a search for a single cache (as if in details view) + cache.logOffline(this, LogType.getById(id - MENU_LOG_VISIT_OFFLINE)); } - }); - builder.create().show(); - return true; } - // we must remember the menu info for the sub menu, there is a bug - // in Android: - // https://code.google.com/p/android/issues/detail?id=7139 - lastMenuInfo = info; - - if (adapterInfo != null) { - // create a search for a single cache (as if in details view) - final cgCache cache = getCacheFromAdapter(adapterInfo); - - int logType = id - MENU_LOG_VISIT_OFFLINE; - cache.logOffline(this, LogType.getById(logType)); - } return true; } @@ -1336,9 +1195,8 @@ public class cgeocaches extends AbstractListActivity { } adapter.reFilter(); - if (geo != null) { - adapter.setActualCoordinates(geo.coordsNow); - } + adapter.setActualCoordinates(app.currentGeo().getCoords()); + if (dir != null) { adapter.setActualHeading(dir.directionNow); } @@ -1388,38 +1246,22 @@ public class cgeocaches extends AbstractListActivity { private void init() { startGeoAndDir(); - if (CollectionUtils.isNotEmpty(cacheList)) { - setMoreCaches(); - } - - setTitle(title); - setAdapter(); - - if (geo != null) { - geoUpdate.updateLocation(geo); - } if (dir != null) { dirUpdate.updateDirection(dir); } } - // sensor & geolocation manager + // Sensor & geolocation manager. This must be called from the UI thread as it may + // cause the system listeners to start if nobody else required them before. private void startGeoAndDir() { - if (geo == null) { - geo = app.startGeo(geoUpdate); - } + app.addGeoObserver(this); if (Settings.isLiveList() && Settings.isUseCompass() && dir == null) { dir = app.startDir(this, dirUpdate); } } private void removeGeoAndDir() { - if (dir != null) { - dir = app.removeDir(); - } - if (geo != null) { - geo = app.removeGeo(); - } + app.deleteGeoObserver(this); } private void importGpx() { @@ -1463,8 +1305,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 +1327,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 +1348,17 @@ 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 = adapter.getCheckedCaches(); + } 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() { @@ -1574,38 +1404,30 @@ public class cgeocaches extends AbstractListActivity { public void dropSelected() { progress.show(this, null, res.getString(R.string.caches_drop_progress), true, dropDetailsHandler.obtainMessage(MSG_CANCEL)); - - threadR = new DropDetailsThread(dropDetailsHandler); - threadR.start(); + new DropDetailsThread(dropDetailsHandler).start(); } - private class UpdateLocation implements UpdateLocationCallback { + @Override + public void update(final IGeoData geo) { + if (adapter == null) { + return; + } - @Override - public void updateLocation(cgGeo geo) { - if (geo == null) { - return; - } - if (adapter == null) { - return; + try { + if (cacheList != null && geo.getCoords() != null) { + adapter.setActualCoordinates(geo.getCoords()); } - try { - if (cacheList != null && geo.coordsNow != null) { - adapter.setActualCoordinates(geo.coordsNow); + if (!Settings.isUseCompass() || geo.getSpeed() > 5) { // use GPS when speed is higher than 18 km/h + if (!Settings.isUseCompass()) { + adapter.setActualHeading(geo.getBearing()); } - - if (!Settings.isUseCompass() || geo.speedNow > 5) { // use GPS when speed is higher than 18 km/h - if (!Settings.isUseCompass()) { - adapter.setActualHeading(geo.bearingNow); - } - if (northHeading != null) { - adapter.setActualHeading(northHeading); - } + if (northHeading != null) { + adapter.setActualHeading(northHeading); } - } catch (Exception e) { - Log.w(Settings.tag, "Failed to UpdateLocation location."); } + } catch (Exception e) { + Log.w("Failed to UpdateLocation location."); } } @@ -1621,7 +1443,7 @@ public class cgeocaches extends AbstractListActivity { } northHeading = dir.directionNow; - if (northHeading != null && adapter != null && (geo == null || geo.speedNow <= 5)) { // use compass when speed is lower than 18 km/h) { + if (northHeading != null && adapter != null && (app.currentGeo().getSpeed() <= 5)) { // use compass when speed is lower than 18 km/h) { adapter.setActualHeading(northHeading); } } @@ -1641,7 +1463,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 +1493,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()); } @@ -1692,13 +1514,12 @@ public class cgeocaches extends AbstractListActivity { showToast(res.getString(R.string.warn_no_coordinates)); finish(); - return; } } @Override public void run() { - search = cgBase.searchByCoords(this, coords, cacheType, Settings.isShowCaptcha()); + search = GCParser.searchByCoords(this, coords, cacheType, Settings.isShowCaptcha()); handler.sendMessage(Message.obtain()); } @@ -1719,13 +1540,12 @@ public class cgeocaches extends AbstractListActivity { showToast(res.getString(R.string.warn_no_keyword)); finish(); - return; } } @Override public void run() { - search = cgBase.searchByKeyword(this, keyword, cacheType, Settings.isShowCaptcha()); + search = GCParser.searchByKeyword(this, keyword, cacheType, Settings.isShowCaptcha()); handler.sendMessage(Message.obtain()); } } @@ -1745,13 +1565,12 @@ public class cgeocaches extends AbstractListActivity { showToast(res.getString(R.string.warn_no_username)); finish(); - return; } } @Override public void run() { - search = cgBase.searchByUsername(this, username, cacheType, Settings.isShowCaptcha()); + search = GCParser.searchByUsername(this, username, cacheType, Settings.isShowCaptcha()); handler.sendMessage(Message.obtain()); } } @@ -1771,20 +1590,12 @@ public class cgeocaches extends AbstractListActivity { showToast(res.getString(R.string.warn_no_username)); finish(); - return; } } @Override public void run() { - Map<String, String> params = new HashMap<String, String>(); - params.put("username", username); - if (cacheType != null) { - 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 +1640,7 @@ public class cgeocaches extends AbstractListActivity { try { if (needToStop) { - Log.i(Settings.tag, "Stopped storing process."); + Log.i("Stopped storing process."); break; } @@ -1840,32 +1651,33 @@ 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.storeCache(cgeocaches.this, cache, null, 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(); } cacheListTemp.clear(); + handler.sendEmptyMessage(MSG_RESTART_GEO_AND_DIR); handler.sendEmptyMessage(MSG_DONE); } } @@ -1904,21 +1716,18 @@ 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); if (response.length() > 2) { - - String GCcode = response; - delay = 1; - handler.sendMessage(handler.obtainMessage(1, GCcode)); + handler.sendMessage(handler.obtainMessage(1, response)); yield(); - cgBase.storeCache(cgeocaches.this, null, GCcode, listIdLFW, null); + cgCache.storeCache(cgeocaches.this, null, response, listIdLFW, false, null); - handler.sendMessage(handler.obtainMessage(2, GCcode)); + handler.sendMessage(handler.obtainMessage(2, response)); yield(); } else if ("RG".equals(response)) { //Server returned RG (registration) and this device no longer registered. @@ -1949,58 +1758,42 @@ 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()); } } handler.sendEmptyMessage(ret); + + startGeoAndDir(); } } private class DropDetailsThread extends Thread { final private Handler handler; - private volatile boolean needToStop = false; - private int checked = 0; + private List<cgCache> selected = new ArrayList<cgCache>(); public DropDetailsThread(Handler handlerIn) { setPriority(Thread.MIN_PRIORITY); handler = handlerIn; - if (adapter != null) { - checked = adapter.getChecked(); + int checked = adapter.getChecked(); + if (checked == 0) { + selected = new ArrayList<cgCache>(cacheList); + } + else { + selected = adapter.getCheckedCaches(); } - } - - public void kill() { - needToStop = true; } @Override public void run() { removeGeoAndDir(); - - final List<cgCache> cacheListTemp = new ArrayList<cgCache>(cacheList); - for (cgCache cache : cacheListTemp) { - if (checked > 0 && !cache.isStatusChecked()) { - continue; - } - - try { - if (needToStop) { - Log.i(Settings.tag, "Stopped dropping process."); - break; - } - - app.markDropped(cache.getGeocode()); - } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.DropDetailsThread: " + e.toString()); - } - } - cacheListTemp.clear(); - + app.markDropped(selected); handler.sendEmptyMessage(MSG_DONE); + + startGeoAndDir(); } } @@ -2036,7 +1829,7 @@ public class cgeocaches extends AbstractListActivity { try { if (needToStop) { - Log.i(Settings.tag, "Stopped removing process."); + Log.i("Stopped removing process."); break; } @@ -2047,128 +1840,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()); } } @@ -2193,7 +1865,7 @@ public class cgeocaches extends AbstractListActivity { private void hideLoading() { final ListView list = getListView(); - final RelativeLayout loading = (RelativeLayout) findViewById(R.id.loading); + final View loading = findViewById(R.id.loading); if (list.getVisibility() == View.GONE) { list.setVisibility(View.VISIBLE); @@ -2209,41 +1881,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); } }); - builder.create().show(); } public void switchListById(int id) { @@ -2287,72 +1931,17 @@ public class cgeocaches extends AbstractListActivity { @Override public void run() { - int checked = adapter.getChecked(); - if (checked > 0) { - final List<cgCache> cacheListTemp = new ArrayList<cgCache>(cacheList); - for (cgCache cache : cacheListTemp) { - if (cache.isStatusChecked()) { - app.moveToList(cache.getGeocode(), listId); - } - } - } - + final List<cgCache> caches = adapter.getCheckedCaches(); + app.moveToList(caches, listId); handler.sendEmptyMessage(listId); } } - 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 +2050,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 +2117,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 +2127,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..0ad2e81 100644 --- a/main/src/cgeo/geocaching/cgeocoords.java +++ b/main/src/cgeo/geocaching/cgeocoords.java @@ -5,12 +5,11 @@ import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.compatibility.Compatibility; import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.geopoint.Geopoint.DDD; -import cgeo.geocaching.geopoint.Geopoint.DMM; -import cgeo.geocaching.geopoint.Geopoint.DMS; -import cgeo.geocaching.geopoint.Geopoint.Direction; import cgeo.geocaching.geopoint.GeopointFormatter; -import cgeo.geocaching.geopoint.GeopointParser.ParseException; +import cgeo.geocaching.geopoint.direction.DDD; +import cgeo.geocaching.geopoint.direction.DMM; +import cgeo.geocaching.geopoint.direction.DMS; +import cgeo.geocaching.geopoint.direction.Direction; import org.apache.commons.lang3.StringUtils; @@ -32,7 +31,7 @@ import android.widget.TextView; public class cgeocoords extends Dialog { final private AbstractActivity context; - final private cgGeo geo; + final private IGeoData geo; final private cgCache cache; private Geopoint gp; @@ -43,13 +42,11 @@ public class cgeocoords extends Dialog { private TextView tLatSep1, tLatSep2, tLatSep3; private TextView tLonSep1, tLonSep2, tLonSep3; - private Spinner spinner; - private CoordinateUpdate cuListener; private coordInputFormatEnum currentFormat = null; - public cgeocoords(final AbstractActivity context, final cgCache cache, final Geopoint gp, final cgGeo geo) { + public cgeocoords(final AbstractActivity context, final cgCache cache, final Geopoint gp, final IGeoData geo) { super(context); this.context = context; this.geo = geo; @@ -57,8 +54,8 @@ public class cgeocoords extends Dialog { if (gp != null) { this.gp = gp; - } else if (geo != null && geo.coordsNow != null) { - this.gp = geo.coordsNow; + } else if (geo != null && geo.getCoords() != null) { + this.gp = geo.getCoords(); } else { this.gp = new Geopoint(0.0, 0.0); } @@ -84,7 +81,7 @@ public class cgeocoords extends Dialog { } }); - spinner = (Spinner) findViewById(R.id.spinnerCoordinateFormats); + final Spinner spinner = (Spinner) findViewById(R.id.spinnerCoordinateFormats); final ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(context, R.array.waypoint_coordinate_formats, @@ -352,7 +349,7 @@ public class cgeocoords extends Dialog { if (currentFormat == coordInputFormatEnum.Plain) { try { gp = new Geopoint(eLat.getText().toString(), eLon.getText().toString()); - } catch (ParseException e) { + } catch (Geopoint.ParseException e) { if (signalError) { context.showToast(context.getResources().getString(R.string.err_parse_lat_lon)); } @@ -416,10 +413,10 @@ public class cgeocoords extends Dialog { // Start new format with an acceptable value: either the current one // entered by the user, else our current coordinates, else (0,0). if (!calc(false)) { - if (geo != null && geo.coordsNow != null) { - gp = geo.coordsNow; + if (geo != null && geo.getCoords() != null) { + gp = geo.getCoords(); } else { - gp = new Geopoint(0, 0); + gp = new Geopoint(0.0, 0.0); } } } @@ -439,12 +436,12 @@ public class cgeocoords extends Dialog { @Override public void onClick(View v) { - if (geo == null || geo.coordsNow == null) { + if (geo == null || geo.getCoords() == null) { context.showToast(context.getResources().getString(R.string.err_point_unknown_position)); return; } - gp = geo.coordsNow; + gp = geo.getCoords(); updateGUI(); } } diff --git a/main/src/cgeo/geocaching/cgeoimages.java b/main/src/cgeo/geocaching/cgeoimages.java index 79c0e24..7145d59 100644 --- a/main/src/cgeo/geocaching/cgeoimages.java +++ b/main/src/cgeo/geocaching/cgeoimages.java @@ -3,6 +3,7 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.files.LocalStorage; import cgeo.geocaching.network.HtmlImage; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -18,7 +19,7 @@ import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.text.Html; -import android.util.Log; +import android.util.SparseArray; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; @@ -34,7 +35,6 @@ import java.io.FileOutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; public class cgeoimages extends AbstractActivity { @@ -51,7 +51,7 @@ public class cgeoimages extends AbstractActivity { private LinearLayout imagesView = null; private int count = 0; private int countDone = 0; - private final HashMap<Integer, cgImage> images = new HashMap<Integer, cgImage>(); + private final SparseArray<cgImage> images = new SparseArray<cgImage>(); private BitmapDrawable currentDrawable; private cgImage currentImage; @@ -60,14 +60,14 @@ public class cgeoimages extends AbstractActivity { private void loadImages(final List<cgImage> images, final int progressMessage, final boolean offline) { count = images.size(); - progressDialog = new ProgressDialog(cgeoimages.this); + progressDialog = new ProgressDialog(this); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setMessage(res.getString(progressMessage)); progressDialog.setCancelable(true); progressDialog.setMax(count); progressDialog.show(); - LinearLayout rowView = null; + LinearLayout rowView; for (final cgImage img : images) { rowView = (LinearLayout) inflater.inflate(R.layout.cache_image_item, null); @@ -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 a8e660a..0aeed10 100644 --- a/main/src/cgeo/geocaching/cgeoinit.java +++ b/main/src/cgeo/geocaching/cgeoinit.java @@ -4,13 +4,16 @@ 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; @@ -19,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; @@ -26,7 +30,6 @@ import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; @@ -45,7 +48,6 @@ import android.widget.TextView; import java.io.File; import java.util.Collection; import java.util.List; -import java.util.concurrent.atomic.AtomicReference; public class cgeoinit extends AbstractActivity { @@ -73,7 +75,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 +103,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()) { @@ -173,7 +175,7 @@ public class cgeoinit extends AbstractActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == 0) { - boolean status = false; + boolean status; ((EditText) findViewById(R.id.username)).setText(""); ((EditText) findViewById(R.id.password)).setText(""); @@ -669,6 +671,17 @@ public class cgeoinit extends AbstractActivity { refreshBackupLabel(); + // Debug settings + final CheckBox debugButton = (CheckBox) findViewById(R.id.debug); + debugButton.setChecked(Settings.isDebug()); + debugButton.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + Settings.setDebug(!Settings.isDebug()); + debugButton.setChecked(Settings.isDebug()); + } + }); } private void initMapfileEdittext(boolean setFocus) { @@ -685,42 +698,34 @@ public class cgeoinit extends AbstractActivity { */ public void backup(View view) { // avoid overwriting an existing backup with an empty database (can happen directly after reinstalling the app) - if (app.getAllStoredCachesCount(true, CacheType.ALL, null) == 0) { + if (app.getAllStoredCachesCount(true, CacheType.ALL) == 0) { helpDialog(res.getString(R.string.init_backup), res.getString(R.string.init_backup_unnecessary)); return; } - final AtomicReference<String> fileRef = new AtomicReference<String>(null); final ProgressDialog dialog = ProgressDialog.show(this, res.getString(R.string.init_backup), res.getString(R.string.init_backup_running), true, false); - Thread backupThread = new Thread() { - final Handler handler = new Handler() { - @Override - public void handleMessage(Message msg) { - dialog.dismiss(); - final String file = fileRef.get(); - if (file != null) { - helpDialog(res.getString(R.string.init_backup_backup), res.getString(R.string.init_backup_success) + "\n" + file); - } else { - helpDialog(res.getString(R.string.init_backup_backup), res.getString(R.string.init_backup_failed)); - } - refreshBackupLabel(); - } - }; - + new Thread() { @Override public void run() { - fileRef.set(app.backupDatabase()); - handler.sendMessage(handler.obtainMessage()); + final String backupFileName = app.backupDatabase(); + runOnUiThread(new Runnable() { + @Override + public void run() { + dialog.dismiss(); + helpDialog(res.getString(R.string.init_backup_backup), + backupFileName != null ? res.getString(R.string.init_backup_success) + "\n" + backupFileName : res.getString(R.string.init_backup_failed)); + refreshBackupLabel(); + } + }); } - }; - backupThread.start(); + }.start(); } private void refreshBackupLabel() { 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)); } @@ -810,7 +815,7 @@ public class cgeoinit extends AbstractActivity { loginDialog.setCancelable(false); Settings.setLogin(username, password); - Network.clearCookies(); + Cookies.clearCookies(); (new Thread() { @@ -852,7 +857,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) { @@ -861,7 +866,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); @@ -881,9 +886,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 01a9e74..9e903b6 100644 --- a/main/src/cgeo/geocaching/cgeonavigate.java +++ b/main/src/cgeo/geocaching/cgeonavigate.java @@ -6,16 +6,16 @@ import cgeo.geocaching.geopoint.HumanDistance; import cgeo.geocaching.geopoint.IConversion; import cgeo.geocaching.maps.CGeoMap; import cgeo.geocaching.ui.CompassView; +import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.IObserver; +import cgeo.geocaching.utils.PeriodicHandler; import org.apache.commons.lang3.StringUtils; import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.os.Handler; -import android.os.Message; import android.os.PowerManager; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.SubMenu; @@ -25,19 +25,16 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -public class cgeonavigate extends AbstractActivity { +public class cgeonavigate extends AbstractActivity implements IObserver<IGeoData> { - 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<cgCoord> coordinates = new ArrayList<cgCoord>(); + private static final List<IWaypoint> coordinates = new ArrayList<IWaypoint>(); private static final int MENU_MAP = 0; private static final int MENU_SWITCH_COMPASS_GPS = 1; private PowerManager pm = null; - private cgGeo geo = null; private cgDirection dir = null; - private UpdateLocationCallback geoUpdate = new update(); private UpdateDirectionCallback dirUpdate = new UpdateDirection(); private Geopoint dstCoords = null; private float cacheHeading = 0; @@ -51,19 +48,15 @@ public class cgeonavigate extends AbstractActivity { private TextView distanceView = null; private TextView headingView = null; private CompassView compassView = null; - private updaterThread updater = null; - private Handler updaterHandler = new Handler() { + private PeriodicHandler updaterHandler = new PeriodicHandler(20) { @Override - public void handleMessage(Message msg) { - try { - if (compassView != null && northHeading != null) { - compassView.updateNorth(northHeading, cacheHeading); - } - } catch (Exception e) { - Log.e(Settings.tag, "cgeonavigate.updaterHandler: " + e.toString()); + public void act() { + if (compassView != null && northHeading != null) { + compassView.updateNorth(northHeading, cacheHeading); } } + }; private String geocode; @@ -80,9 +73,6 @@ public class cgeonavigate extends AbstractActivity { setTitle(res.getString(R.string.compass_title)); // sensor & geolocation manager - if (geo == null) { - geo = app.startGeo(geoUpdate); - } if (Settings.isUseCompass() && dir == null) { dir = app.startDir(this, dirUpdate); } @@ -93,7 +83,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)) { @@ -116,19 +106,18 @@ public class cgeonavigate extends AbstractActivity { setTitle(); setDestCoords(); - if (geo != null) { - geoUpdate.updateLocation(geo); - } if (dir != null) { dirUpdate.updateDirection(dir); } // get textviews once compassView = (CompassView) findViewById(R.id.rose); + } - // start updater thread - updater = new updaterThread(updaterHandler); - updater.start(); + @Override + public void onStart() { + super.onStart(); + updaterHandler.start(); } @Override @@ -138,9 +127,7 @@ public class cgeonavigate extends AbstractActivity { setGo4CacheAction(); // sensor & geolocation manager - if (geo == null) { - geo = app.startGeo(geoUpdate); - } + app.addGeoObserver(this); if (Settings.isUseCompass() && dir == null) { dir = app.startDir(this, dirUpdate); } @@ -149,12 +136,6 @@ public class cgeonavigate extends AbstractActivity { if (pm == null) { pm = (PowerManager) getSystemService(Context.POWER_SERVICE); } - - // updater thread - if (updater == null) { - updater = new updaterThread(updaterHandler); - updater.start(); - } } private void setGo4CacheAction() { @@ -167,21 +148,18 @@ public class cgeonavigate extends AbstractActivity { @Override public void onStop() { - if (geo != null) { - geo = app.removeGeo(); - } if (dir != null) { dir = app.removeDir(); } + updaterHandler.stop(); + super.onStop(); } @Override public void onPause() { - if (geo != null) { - geo = app.removeGeo(); - } + app.deleteGeoObserver(this); if (dir != null) { dir = app.removeDir(); } @@ -191,9 +169,6 @@ public class cgeonavigate extends AbstractActivity { @Override public void onDestroy() { - if (geo != null) { - geo = app.removeGeo(); - } if (dir != null) { dir = app.removeDir(); } @@ -205,42 +180,27 @@ public class cgeonavigate extends AbstractActivity { } @Override - public boolean onCreateOptionsMenu(Menu menu) { - if (Settings.isUseCompass()) { - menu.add(0, MENU_SWITCH_COMPASS_GPS, 0, res.getString(R.string.use_gps)).setIcon(android.R.drawable.ic_menu_compass); - } else { - menu.add(0, MENU_SWITCH_COMPASS_GPS, 0, res.getString(R.string.use_compass)).setIcon(android.R.drawable.ic_menu_compass); - } + public boolean onCreateOptionsMenu(final Menu menu) { + menu.add(0, MENU_SWITCH_COMPASS_GPS, 0, res.getString(Settings.isUseCompass() ? R.string.use_gps : R.string.use_compass)).setIcon(android.R.drawable.ic_menu_compass); menu.add(0, MENU_MAP, 0, res.getString(R.string.caches_on_map)).setIcon(android.R.drawable.ic_menu_mapmode); menu.add(0, 2, 0, res.getString(R.string.destination_set)).setIcon(android.R.drawable.ic_menu_edit); if (coordinates.size() > 1) { - SubMenu subMenu = menu.addSubMenu(0, 3, 0, res.getString(R.string.destination_select)).setIcon(android.R.drawable.ic_menu_myplaces); - + final SubMenu subMenu = menu.addSubMenu(0, 3, 0, res.getString(R.string.destination_select)).setIcon(android.R.drawable.ic_menu_myplaces); int cnt = 4; - for (cgCoord coordinate : coordinates) { + for (final IWaypoint coordinate : coordinates) { subMenu.add(0, cnt, 0, coordinate.getName() + " (" + coordinate.getCoordType() + ")"); cnt++; } - - return true; } else { menu.add(0, 3, 0, res.getString(R.string.destination_select)).setIcon(android.R.drawable.ic_menu_myplaces).setEnabled(false); - - return true; } + return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); - - MenuItem item = menu.findItem(MENU_SWITCH_COMPASS_GPS); - if (Settings.isUseCompass()) { - item.setTitle(res.getString(R.string.use_gps)); - } else { - item.setTitle(res.getString(R.string.use_compass)); - } - + menu.findItem(MENU_SWITCH_COMPASS_GPS).setTitle(res.getString(Settings.isUseCompass() ? R.string.use_gps : R.string.use_compass)); return true; } @@ -270,15 +230,15 @@ public class cgeonavigate extends AbstractActivity { finish(); return true; } else if (id > 3 && coordinates.get(id - 4) != null) { - cgCoord coordinate = coordinates.get(id - 4); + final IWaypoint coordinate = coordinates.get(id - 4); title = coordinate.getName(); dstCoords = coordinate.getCoords(); setTitle(); setDestCoords(); - updateDistanceInfo(); + updateDistanceInfo(app.currentGeo()); - Log.d(Settings.tag, "destination set: " + title + " (" + dstCoords + ")"); + Log.d("destination set: " + title + " (" + dstCoords + ")"); return true; } @@ -301,25 +261,8 @@ 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) { + private void updateDistanceInfo(final IGeoData geo) { + if (geo.getCoords() == null || dstCoords == null) { return; } @@ -330,69 +273,62 @@ public class cgeonavigate extends AbstractActivity { headingView = (TextView) findViewById(R.id.heading); } - cacheHeading = geo.coordsNow.bearingTo(dstCoords); - distanceView.setText(HumanDistance.getHumanDistance(geo.coordsNow.distanceTo(dstCoords))); + cacheHeading = geo.getCoords().bearingTo(dstCoords); + distanceView.setText(HumanDistance.getHumanDistance(geo.getCoords().distanceTo(dstCoords))); headingView.setText(Math.round(cacheHeading) + "°"); } - private class update implements UpdateLocationCallback { - - @Override - public void updateLocation(cgGeo geo) { - if (geo == null) { - return; + @Override + public void update(final IGeoData geo) { + try { + if (navType == null || navLocation == null || navAccuracy == null) { + navType = (TextView) findViewById(R.id.nav_type); + navAccuracy = (TextView) findViewById(R.id.nav_accuracy); + navSatellites = (TextView) findViewById(R.id.nav_satellites); + navLocation = (TextView) findViewById(R.id.nav_location); } - try { - if (navType == null || navLocation == null || navAccuracy == null) { - navType = (TextView) findViewById(R.id.nav_type); - navAccuracy = (TextView) findViewById(R.id.nav_accuracy); - navSatellites = (TextView) findViewById(R.id.nav_satellites); - navLocation = (TextView) findViewById(R.id.nav_location); + if (geo.getCoords() != null) { + String satellites; + if (geo.getSatellitesFixed() > 0) { + satellites = res.getString(R.string.loc_sat) + ": " + geo.getSatellitesFixed() + "/" + geo.getSatellitesVisible(); + } else if (geo.getSatellitesVisible() >= 0) { + satellites = res.getString(R.string.loc_sat) + ": 0/" + geo.getSatellitesVisible(); + } else { + satellites = ""; } + navSatellites.setText(satellites); + navType.setText(res.getString(geo.getLocationProvider().resourceId)); - if (geo.coordsNow != null) { - String satellites = null; - if (geo.satellitesFixed > 0) { - satellites = res.getString(R.string.loc_sat) + ": " + geo.satellitesFixed + "/" + geo.satellitesVisible; - } else if (geo.satellitesVisible >= 0) { - satellites = res.getString(R.string.loc_sat) + ": 0/" + geo.satellitesVisible; + if (geo.getAccuracy() >= 0) { + if (Settings.isUseMetricUnits()) { + navAccuracy.setText("±" + Math.round(geo.getAccuracy()) + " m"); } else { - satellites = ""; + navAccuracy.setText("±" + Math.round(geo.getAccuracy() * IConversion.METERS_TO_FEET) + " ft"); } - navSatellites.setText(satellites); - navType.setText(res.getString(geo.locationProvider.resourceId)); - - if (geo.accuracyNow >= 0) { - if (Settings.isUseMetricUnits()) { - navAccuracy.setText("±" + Math.round(geo.accuracyNow) + " m"); - } else { - navAccuracy.setText("±" + Math.round(geo.accuracyNow * IConversion.METERS_TO_FEET) + " ft"); - } - } else { - navAccuracy.setText(null); - } - - if (geo.altitudeNow != null) { - final String humanAlt = HumanDistance.getHumanDistance(geo.altitudeNow.floatValue() / 1000); - navLocation.setText(geo.coordsNow + " | " + humanAlt); - } else { - navLocation.setText(geo.coordsNow.toString()); - } - - updateDistanceInfo(); } else { - navType.setText(null); navAccuracy.setText(null); - navLocation.setText(res.getString(R.string.loc_trying)); } - if (!Settings.isUseCompass() || geo.speedNow > 5) { // use GPS when speed is higher than 18 km/h - northHeading = geo.bearingNow; + if (geo.getAltitude() != 0.0f) { + final String humanAlt = HumanDistance.getHumanDistance((float) geo.getAltitude() / 1000); + navLocation.setText(geo.getCoords() + " | " + humanAlt); + } else { + navLocation.setText(geo.getCoords().toString()); } - } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); + + updateDistanceInfo(geo); + } else { + navType.setText(null); + navAccuracy.setText(null); + navLocation.setText(res.getString(R.string.loc_trying)); + } + + if (!Settings.isUseCompass() || geo.getSpeed() > 5) { // use GPS when speed is higher than 18 km/h + northHeading = geo.getBearing(); } + } catch (Exception e) { + Log.w("Failed to LocationUpdater location."); } } @@ -404,45 +340,20 @@ public class cgeonavigate extends AbstractActivity { return; } - if (geo == null || geo.speedNow <= 5) { // use compass when speed is lower than 18 km/h + if (app.currentGeo().getSpeed() <= 5) { // use compass when speed is lower than 18 km/h northHeading = dir.directionNow; } } } - private static class updaterThread extends Thread { - - private Handler handler = null; - - public updaterThread(Handler handlerIn) { - handler = handlerIn; - } - - @Override - public void run() { - while (!Thread.currentThread().isInterrupted()) { - if (handler != null) { - handler.sendMessage(Message.obtain()); - } - - try { - Thread.sleep(20); - } catch (Exception e) { - Thread.currentThread().interrupt(); - } - } - } - } - - public static void startActivity(final Context context, final String geocode, final String displayedName, final Geopoint coords, final Collection<cgCoord> coordinatesWithType) { + public static void startActivity(final Context context, final String geocode, final String displayedName, final Geopoint coords, final Collection<IWaypoint> coordinatesWithType) { coordinates.clear(); if (coordinatesWithType != null) { // avoid possible NPE coordinates.addAll(coordinatesWithType); } 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 890f396..e85b27d 100644 --- a/main/src/cgeo/geocaching/cgeopoint.java +++ b/main/src/cgeo/geocaching/cgeopoint.java @@ -5,7 +5,9 @@ import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; 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 cgeo.geocaching.utils.IObserver; import org.apache.commons.lang3.StringUtils; @@ -13,7 +15,6 @@ import android.app.Activity; import android.content.Context; import android.content.res.Configuration; import android.os.Bundle; -import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; @@ -34,24 +35,24 @@ import android.widget.TextView; import java.util.List; -public class cgeopoint extends AbstractActivity { +public class cgeopoint extends AbstractActivity implements IObserver<IGeoData> { private static final int MENU_DEFAULT_NAVIGATION = 2; private static final int MENU_NAVIGATE = 0; 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; } @@ -84,12 +85,10 @@ public class cgeopoint extends AbstractActivity { } } - private cgGeo geo = null; - private UpdateLocationCallback geoUpdate = new update(); 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 +136,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()); } } }); @@ -146,7 +145,7 @@ public class cgeopoint extends AbstractActivity { historyListView.setOnCreateContextMenuListener(new OnCreateContextMenuListener() { @Override public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { + ContextMenuInfo menuInfo) { menu.add(Menu.NONE, CONTEXT_MENU_NAVIGATE, Menu.NONE, res.getString(R.string.cache_menu_navigate)); menu.add(Menu.NONE, CONTEXT_MENU_EDIT_WAYPOINT, Menu.NONE, R.string.waypoint_edit); menu.add(Menu.NONE, CONTEXT_MENU_DELETE_WAYPOINT, Menu.NONE, R.string.waypoint_delete); @@ -163,21 +162,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(app.currentGeo(), 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 +204,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(); @@ -224,42 +223,27 @@ public class cgeopoint extends AbstractActivity { @Override public void onResume() { super.onResume(); - + app.addGeoObserver(this); init(); } @Override public void onDestroy() { - if (geo != null) { - geo = app.removeGeo(); - } - super.onDestroy(); } @Override public void onStop() { - if (geo != null) { - geo = app.removeGeo(); - } - super.onStop(); } @Override public void onPause() { - if (geo != null) { - geo = app.removeGeo(); - } - + app.deleteGeoObserver(this); super.onPause(); } private void init() { - if (geo == null) { - geo = app.startGeo(geoUpdate); - } - latButton = (Button) findViewById(R.id.buttonLatitude); lonButton = (Button) findViewById(R.id.buttonLongitude); @@ -305,7 +289,7 @@ public class cgeopoint extends AbstractActivity { if (latButton.getText().length() > 0 && lonButton.getText().length() > 0) { gp = new Geopoint(latButton.getText().toString() + " " + lonButton.getText().toString()); } - cgeocoords coordsDialog = new cgeocoords(cgeopoint.this, null, gp, geo); + cgeocoords coordsDialog = new cgeocoords(cgeopoint.this, null, gp, app.currentGeo()); coordsDialog.setCancelable(true); coordsDialog.setOnCoordinateUpdate(new cgeocoords.CoordinateUpdate() { @Override @@ -382,8 +366,7 @@ public class cgeopoint extends AbstractActivity { final Geopoint coords = getDestination(); - if (coords != null) - { + if (coords != null) { addToHistory(coords); } @@ -401,7 +384,7 @@ public class cgeopoint extends AbstractActivity { return true; case MENU_NAVIGATE: - NavigationAppFactory.showNavigationMenu(geo, this, null, null, coords); + NavigationAppFactory.showNavigationMenu(app.currentGeo(), this, null, null, coords); return true; default: return false; @@ -410,12 +393,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 +406,7 @@ public class cgeopoint extends AbstractActivity { } } - private void removeFromHistory(cgDestination destination) { + private void removeFromHistory(Destination destination) { if (getHistoryOfSearchedLocations().contains(destination)) { getHistoryOfSearchedLocations().remove(destination); @@ -472,7 +452,7 @@ public class cgeopoint extends AbstractActivity { return; } - NavigationAppFactory.startDefaultNavigationApplication(geo, this, null, null, geopoint); + NavigationAppFactory.startDefaultNavigationApplication(app.currentGeo(), this, null, null, geopoint); } private void cachesAround() { @@ -483,46 +463,40 @@ public class cgeopoint extends AbstractActivity { return; } - cgeocaches.startActivityCoordinates(this, coords.getLatitude(), coords.getLongitude()); + cgeocaches.startActivityCoordinates(this, coords); finish(); } - private class update implements UpdateLocationCallback { - - @Override - public void updateLocation(cgGeo geo) { - if (geo == null) { - return; - } - - try { - 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."); - } + @Override + public void update(final IGeoData geo) { + try { + latButton.setHint(geo.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE_RAW)); + lonButton.setHint(geo.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE_RAW)); + } catch (final Exception e) { + Log.w("Failed to update location."); } } private class currentListener implements View.OnClickListener { public void onClick(View arg0) { - if (geo == null || geo.coordsNow == null) { + final Geopoint coords = app.currentGeo().getCoords(); + if (coords == null) { showToast(res.getString(R.string.err_point_unknown_position)); return; } - latButton.setText(geo.coordsNow.format(GeopointFormatter.Format.LAT_DECMINUTE)); - lonButton.setText(geo.coordsNow.format(GeopointFormatter.Format.LON_DECMINUTE)); + latButton.setText(coords.format(GeopointFormatter.Format.LAT_DECMINUTE)); + lonButton.setText(coords.format(GeopointFormatter.Format.LON_DECMINUTE)); changed = false; } } private Geopoint getDestination() { - Geopoint result = null; - Geopoint coords = null; + Geopoint result; + Geopoint coords; String bearingText = ((EditText) findViewById(R.id.bearing)).getText().toString(); // combine distance from EditText and distanceUnit saved from Spinner @@ -538,23 +512,23 @@ public class cgeopoint extends AbstractActivity { if (StringUtils.isNotBlank(latText) && StringUtils.isNotBlank(lonText)) { try { - coords = GeopointParser.parse(latText, lonText); - } catch (GeopointParser.ParseException e) { + coords = new Geopoint(latText, lonText); + } catch (Geopoint.ParseException e) { showToast(res.getString(e.resource)); return null; } } else { - if (geo == null || geo.coordsNow == null) { + if (app.currentGeo().getCoords() == null) { showToast(res.getString(R.string.err_point_curr_position_unavailable)); return null; } - coords = geo.coordsNow; + coords = app.currentGeo().getCoords(); } if (StringUtils.isNotBlank(bearingText) && StringUtils.isNotBlank(distanceText)) { // bearing & distance - double bearing = 0; + double bearing; try { bearing = Double.parseDouble(bearingText); } catch (NumberFormatException e) { diff --git a/main/src/cgeo/geocaching/cgeopopup.java b/main/src/cgeo/geocaching/cgeopopup.java index afc7df6..dc98928 100644 --- a/main/src/cgeo/geocaching/cgeopopup.java +++ b/main/src/cgeo/geocaching/cgeopopup.java @@ -11,20 +11,23 @@ import cgeo.geocaching.gcvote.GCVote; import cgeo.geocaching.gcvote.GCVoteRating; import cgeo.geocaching.geopoint.HumanDistance; import cgeo.geocaching.utils.CancellableHandler; +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.graphics.Rect; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; +import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; @@ -42,8 +45,7 @@ public class cgeopopup extends AbstractActivity { private LayoutInflater inflater = null; private String geocode = null; private cgCache cache = null; - private cgGeo geo = null; - private UpdateLocationCallback geoUpdate = new update(); + private GeoObserver geoUpdate = new UpdateLocation(); private ProgressDialog storeDialog = null; private ProgressDialog dropDialog = null; private TextView cacheDistance = null; @@ -74,7 +76,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 +99,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) { @@ -145,6 +147,19 @@ public class cgeopopup extends AbstractActivity { } @Override + public boolean onTouchEvent(final MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP) { + final Rect r = new Rect(0, 0, 0, 0); + getWindow().getDecorView().getHitRect(r); + if (!r.contains((int) event.getX(), (int) event.getY())) { + finish(); + return true; + } + } + return super.onTouchEvent(event); + } + + @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, 2, 0, NavigationAppFactory.getDefaultNavigationApplication(this).getName()).setIcon(android.R.drawable.ic_menu_compass); // default navigation tool menu.add(0, 3, 0, res.getString(R.string.cache_menu_navigate)).setIcon(android.R.drawable.ic_menu_mapmode); @@ -182,34 +197,31 @@ public class cgeopopup extends AbstractActivity { public boolean onOptionsItemSelected(MenuItem item) { final int menuItem = item.getItemId(); - if (menuItem == 2) { - navigateTo(); - return true; - } else if (menuItem == 3) { - NavigationAppFactory.showNavigationMenu(geo, this, cache, null, null); - return true; - } else if (menuItem == 5) { - cachesAround(); - return true; - } else if (menuItem == MENU_LOG_VISIT) { - cache.logVisit(this); - finish(); - return true; - } else if (menuItem == 7) { - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/seek/cache_details.aspx?wp=" + cache.getGeocode()))); - return true; + switch (menuItem) { + case 2: + navigateTo(); + break; + case 3: + NavigationAppFactory.showNavigationMenu(app.currentGeo(), this, cache, null, null); + break; + case 5: + cachesAround(); + break; + case MENU_LOG_VISIT: + cache.logVisit(this); + finish(); + break; + case 7: + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/seek/cache_details.aspx?wp=" + cache.getGeocode()))); + break; + default: + cache.logOffline(this, LogType.getById(menuItem - MENU_LOG_VISIT_OFFLINE)); } - int logType = menuItem - MENU_LOG_VISIT_OFFLINE; - cache.logOffline(this, LogType.getById(logType)); return true; } private void init() { - if (geo == null) { - geo = app.startGeo(geoUpdate); - } - app.setAction(geocode); cache = app.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB); @@ -278,7 +290,7 @@ public class cgeopopup extends AbstractActivity { itemName.setText(res.getString(R.string.cache_status)); - StringBuilder state = new StringBuilder(); + final StringBuilder state = new StringBuilder(); if (cache.isFound()) { if (state.length() > 0) { state.append(", "); @@ -306,8 +318,6 @@ public class cgeopopup extends AbstractActivity { itemValue.setText(state.toString()); detailsList.addView(itemLayout); - - state = null; } // distance @@ -403,7 +413,6 @@ public class cgeopopup extends AbstractActivity { startActivity(cachesIntent); finish(); - return; } }); @@ -417,7 +426,7 @@ public class cgeopopup extends AbstractActivity { if (cache.getListId() > 0) { long diff = (System.currentTimeMillis() / (60 * 1000)) - (cache.getDetailedUpdate() / (60 * 1000)); // minutes - String ago = ""; + String ago; if (diff < 15) { ago = res.getString(R.string.cache_offline_time_mins_few); } else if (diff < 50) { @@ -452,11 +461,7 @@ public class cgeopopup extends AbstractActivity { offlineStore.setOnClickListener(new storeCache()); } } catch (Exception e) { - Log.e(Settings.tag, "cgeopopup.init: " + e.toString()); - } - - if (geo != null) { - geoUpdate.updateLocation(geo); + Log.e("cgeopopup.init: " + e.toString()); } } @@ -470,52 +475,37 @@ public class cgeopopup extends AbstractActivity { @Override public void onResume() { super.onResume(); - + app.addGeoObserver(geoUpdate); init(); } @Override public void onDestroy() { - if (geo != null) { - geo = app.removeGeo(); - } - super.onDestroy(); } @Override public void onStop() { - if (geo != null) { - geo = app.removeGeo(); - } - super.onStop(); } @Override public void onPause() { - if (geo != null) { - geo = app.removeGeo(); - } - + app.deleteGeoObserver(geoUpdate); super.onPause(); } - private class update implements UpdateLocationCallback { + private class UpdateLocation extends GeoObserver { @Override - public void updateLocation(cgGeo geo) { - if (geo == null) { - return; - } - + protected void updateLocation(final IGeoData geo) { try { - if (geo.coordsNow != null && cache != null && cache.getCoords() != null) { - cacheDistance.setText(HumanDistance.getHumanDistance(geo.coordsNow.distanceTo(cache.getCoords()))); + if (geo.getCoords() != null && cache != null && cache.getCoords() != null) { + cacheDistance.setText(HumanDistance.getHumanDistance(geo.getCoords().distanceTo(cache.getCoords()))); cacheDistance.bringToFront(); } } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); + Log.w("Failed to UpdateLocation location."); } } } @@ -526,7 +516,7 @@ public class cgeopopup extends AbstractActivity { return; } - NavigationAppFactory.startDefaultNavigationApplication(geo, this, cache, null, null); + NavigationAppFactory.startDefaultNavigationApplication(app.currentGeo(), this, cache, null, null); } private void cachesAround() { @@ -595,7 +585,7 @@ public class cgeopopup extends AbstractActivity { @Override public void run() { - cgBase.dropCache(cache, handler); + cache.drop(handler); } } @@ -636,7 +626,7 @@ public class cgeopopup extends AbstractActivity { showToast(res.getString(R.string.cache_coordinates_no)); return; } - NavigationAppFactory.startDefaultNavigationApplication(geo, this, cache, null, null); + NavigationAppFactory.startDefaultNavigationApplication(app.currentGeo(), this, cache, null, null); finish(); } @@ -648,7 +638,7 @@ public class cgeopopup extends AbstractActivity { showToast(res.getString(R.string.cache_coordinates_no)); return; } - NavigationAppFactory.startDefaultNavigationApplication2(geo, this, cache, null, null); + NavigationAppFactory.startDefaultNavigationApplication2(app.currentGeo(), this, cache, null, null); finish(); } @@ -657,4 +647,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 e5af4d3..5a3ed7b 100644 --- a/main/src/cgeo/geocaching/cgeotouch.java +++ b/main/src/cgeo/geocaching/cgeotouch.java @@ -1,13 +1,16 @@ 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; @@ -17,7 +20,6 @@ import android.content.res.Configuration; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; @@ -34,7 +36,6 @@ import java.util.Calendar; import java.util.List; public class cgeotouch extends AbstractActivity implements DateDialog.DateDialogParent { - private cgTrackable trackable = null; private List<LogType> logTypes = new ArrayList<LogType>(); private ProgressDialog waitDialog = null; private String guid = null; @@ -58,33 +59,28 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog private Handler loadDataHandler = new Handler() { @Override - public void handleMessage(Message msg) { - if (MSG_UPDATE_TYPE == msg.what) { + public void handleMessage(final Message msg) { + if (msg.what == MSG_UPDATE_TYPE) { setType((LogType) msg.obj); showToast(res.getString(R.string.info_log_type_changed)); } else { - if (cgBase.isEmpty(viewstates) && attempts < 2) { - showToast(res.getString(R.string.err_log_load_data_again)); + if (Login.isEmpty(viewstates)) { + if (attempts < 2) { + showToast(res.getString(R.string.err_log_load_data_again)); + new loadData(guid).start(); + } else { + showToast(res.getString(R.string.err_log_load_data)); + showProgress(false); + } + } else { + gettingViewstate = false; // we're done, user can post log - loadData thread; - thread = new loadData(guid); - thread.start(); + final Button buttonPost = (Button) findViewById(R.id.post); + buttonPost.setEnabled(true); + buttonPost.setOnClickListener(new postListener()); - return; - } else if (cgBase.isEmpty(viewstates) && attempts >= 2) { - showToast(res.getString(R.string.err_log_load_data)); showProgress(false); - - return; } - - gettingViewstate = false; // we're done, user can post log - - Button buttonPost = (Button) findViewById(R.id.post); - buttonPost.setEnabled(true); - buttonPost.setOnClickListener(new postListener()); - - showProgress(false); } } }; @@ -129,7 +125,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog } } - trackable = app.getTrackableByGeocode("logging trackable"); + final cgTrackable trackable = app.getTrackableByGeocode("logging trackable"); if (StringUtils.isNotBlank(trackable.getName())) { setTitle(res.getString(R.string.trackable_touch) + trackable.getName()); @@ -139,7 +135,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog app.setAction("logging trackable"); - if (trackable == null || guid == null) { + if (guid == null) { showToast(res.getString(R.string.err_tb_forgot_saw)); finish(); @@ -192,10 +188,10 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); - EditText text = null; - String textContent = null; - String dateString = null; - String timeString = null; + EditText text; + String textContent; + String dateString; + String timeString; String addText = ""; if ((id >= 0x1 && id <= 0x7)) { @@ -203,8 +199,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 +283,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 +295,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 +315,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) { @@ -372,7 +368,6 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog showToast(res.getString(R.string.err_tb_forgot_saw)); finish(); - return; } } @@ -392,11 +387,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 +403,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 +437,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 +447,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 1d5b5db..2a0a017 100644 --- a/main/src/cgeo/geocaching/cgeotrackable.java +++ b/main/src/cgeo/geocaching/cgeotrackable.java @@ -1,10 +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; @@ -16,7 +18,6 @@ import android.os.Handler; import android.os.Message; import android.text.Html; import android.text.method.LinkMovementMethod; -import android.util.Log; import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.Menu; @@ -48,13 +49,6 @@ public class cgeotrackable extends AbstractActivity { @Override public void handleMessage(Message msg) { - if (trackable != null && StringUtils.isNotBlank(trackable.getError())) { - showToast(res.getString(R.string.err_tb_details_download) + " " + trackable.getError() + "."); - - finish(); - return; - } - if (trackable == null) { if (waitDialog != null) { waitDialog.dismiss(); @@ -94,7 +88,7 @@ public class cgeotrackable extends AbstractActivity { addDetail(R.string.trackable_name, StringUtils.isNotBlank(trackable.getName()) ? Html.fromHtml(trackable.getName()).toString() : res.getString(R.string.trackable_unknown)); // trackable type - String tbType = null; + String tbType; if (StringUtils.isNotBlank(trackable.getType())) { tbType = Html.fromHtml(trackable.getType()).toString(); } else { @@ -117,7 +111,7 @@ public class cgeotrackable extends AbstractActivity { trackable.getSpottedType() == cgTrackable.SPOTTED_UNKNOWN || trackable.getSpottedType() == cgTrackable.SPOTTED_OWNER ) { - String text = null; + String text; if (trackable.getSpottedType() == cgTrackable.SPOTTED_CACHE) { text = res.getString(R.string.trackable_spotted_in_cache) + " " + Html.fromHtml(trackable.getSpottedName()).toString(); @@ -155,7 +149,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 @@ -213,7 +207,7 @@ public class cgeotrackable extends AbstractActivity { @Override public void run() { - BitmapDrawable image = null; + BitmapDrawable image; try { HtmlImage imgGetter = new HtmlImage(cgeotrackable.this, geocode, true, 0, false); @@ -221,7 +215,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 +223,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(); @@ -356,21 +350,20 @@ public class cgeotrackable extends AbstractActivity { } @Override - public boolean onContextItemSelected(MenuItem item) { - final int id = item.getItemId(); - - if (id == 1) { - cgeocaches.startActivityOwner(this, contextMenuUser); - return true; - } else if (id == 2) { - cgeocaches.startActivityUserName(this, contextMenuUser); - return true; - } else if (id == 3) { - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?u=" + URLEncoder.encode(contextMenuUser)))); - - return true; + public boolean onContextItemSelected(final MenuItem item) { + switch (item.getItemId()) { + case 1: + cgeocaches.startActivityOwner(this, contextMenuUser); + return true; + case 2: + cgeocaches.startActivityUserName(this, contextMenuUser); + return true; + case 3: + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?u=" + URLEncoder.encode(contextMenuUser)))); + return true; + default: + return false; } - return false; } @Override @@ -418,7 +411,6 @@ public class cgeotrackable extends AbstractActivity { stop(); finish(); - return; } } @@ -428,7 +420,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 +434,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,24 +452,21 @@ 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()); } }); } TextView logView = (TextView) rowView.findViewById(R.id.log); logView.setMovementMethod(LinkMovementMethod.getInstance()); - logView.setText(Html.fromHtml(log.log, new HtmlImage(cgeotrackable.this, null, false, StoredList.TEMPORARY_LIST_ID, false), null), TextView.BufferType.SPANNABLE); + logView.setText(Html.fromHtml(log.log, new HtmlImage(this, null, false, StoredList.TEMPORARY_LIST_ID, false), null), TextView.BufferType.SPANNABLE); // 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 +476,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 +514,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); } } } @@ -565,7 +554,7 @@ public class cgeotrackable extends AbstractActivity { return; } - BitmapDrawable image = null; + BitmapDrawable image; try { HtmlImage imgGetter = new HtmlImage(cgeotrackable.this, trackable.getGeocode(), false, 0, false); @@ -573,7 +562,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 453308e..e8aa770 100644 --- a/main/src/cgeo/geocaching/cgeowaypoint.java +++ b/main/src/cgeo/geocaching/cgeowaypoint.java @@ -4,16 +4,18 @@ import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; +import cgeo.geocaching.utils.IObserver; +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; import android.os.Message; import android.text.Html; -import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; @@ -26,7 +28,7 @@ import android.widget.TextView; import java.util.EnumSet; -public class cgeowaypoint extends AbstractActivity { +public class cgeowaypoint extends AbstractActivity implements IObserver<IGeoData> { private static final int MENU_ID_NAVIGATION = 0; private static final int MENU_ID_CACHES_AROUND = 5; @@ -35,83 +37,67 @@ public class cgeowaypoint extends AbstractActivity { private cgWaypoint waypoint = null; private int id = -1; private ProgressDialog waitDialog = null; - private cgGeo geo = null; - private UpdateLocationCallback geoUpdate = new update(); private Handler loadWaypointHandler = new Handler() { @Override public void handleMessage(Message msg) { - try { - if (waypoint == null) { - if (waitDialog != null) { - waitDialog.dismiss(); - waitDialog = null; - } + if (waitDialog != null) { + waitDialog.dismiss(); + waitDialog = null; + } - showToast(res.getString(R.string.err_waypoint_load_failed)); + if (waypoint == null) { + showToast(res.getString(R.string.err_waypoint_load_failed)); + finish(); + return; + } - finish(); - return; - } else { - final TextView identification = (TextView) findViewById(R.id.identification); - final TextView coords = (TextView) findViewById(R.id.coordinates); - final ImageView defaultNavigation = (ImageView) findViewById(R.id.defaultNavigation); - final View separator = findViewById(R.id.separator); + final TextView identification = (TextView) findViewById(R.id.identification); + final TextView coords = (TextView) findViewById(R.id.coordinates); + final ImageView defaultNavigation = (ImageView) findViewById(R.id.defaultNavigation); + final View separator = findViewById(R.id.separator); - final View headline = findViewById(R.id.headline); - registerNavigationMenu(headline); + final View headline = findViewById(R.id.headline); + registerNavigationMenu(headline); - if (StringUtils.isNotBlank(waypoint.getName())) { - setTitle(Html.fromHtml(waypoint.getName()).toString()); - } else { - setTitle(res.getString(R.string.waypoint_title)); - } + if (StringUtils.isNotBlank(waypoint.getName())) { + setTitle(Html.fromHtml(waypoint.getName()).toString()); + } else { + setTitle(res.getString(R.string.waypoint_title)); + } - if (!waypoint.getPrefix().equalsIgnoreCase("OWN")) { - identification.setText(waypoint.getPrefix() + "/" + waypoint.getLookup()); - } else { - identification.setText(res.getString(R.string.waypoint_custom)); - } - registerNavigationMenu(identification); - waypoint.setIcon(res, identification); - - if (waypoint.getCoords() != null) { - coords.setText(Html.fromHtml(waypoint.getCoords().toString()), TextView.BufferType.SPANNABLE); - defaultNavigation.setVisibility(View.VISIBLE); - separator.setVisibility(View.VISIBLE); - } else { - coords.setText(res.getString(R.string.waypoint_unknown_coordinates)); - defaultNavigation.setVisibility(View.GONE); - separator.setVisibility(View.GONE); - } - registerNavigationMenu(coords); + if (!waypoint.getPrefix().equalsIgnoreCase("OWN")) { + identification.setText(waypoint.getPrefix() + "/" + waypoint.getLookup()); + } else { + identification.setText(res.getString(R.string.waypoint_custom)); + } + registerNavigationMenu(identification); + waypoint.setIcon(res, identification); - if (StringUtils.isNotBlank(waypoint.getNote())) { - final TextView note = (TextView) findViewById(R.id.note); - note.setText(Html.fromHtml(waypoint.getNote()), TextView.BufferType.SPANNABLE); - registerNavigationMenu(note); - } + if (waypoint.getCoords() != null) { + coords.setText(Html.fromHtml(waypoint.getCoords().toString()), TextView.BufferType.SPANNABLE); + defaultNavigation.setVisibility(View.VISIBLE); + separator.setVisibility(View.VISIBLE); + } else { + coords.setText(res.getString(R.string.waypoint_unknown_coordinates)); + defaultNavigation.setVisibility(View.GONE); + separator.setVisibility(View.GONE); + } + registerNavigationMenu(coords); - Button buttonEdit = (Button) findViewById(R.id.edit); - buttonEdit.setOnClickListener(new editWaypointListener()); + if (StringUtils.isNotBlank(waypoint.getNote())) { + final TextView note = (TextView) findViewById(R.id.note); + note.setText(Html.fromHtml(waypoint.getNote()), TextView.BufferType.SPANNABLE); + registerNavigationMenu(note); + } - Button buttonDelete = (Button) findViewById(R.id.delete); - if (waypoint.isUserDefined()) { - buttonDelete.setOnClickListener(new deleteWaypointListener()); - buttonDelete.setVisibility(View.VISIBLE); - } + final Button buttonEdit = (Button) findViewById(R.id.edit); + buttonEdit.setOnClickListener(new editWaypointListener()); - if (waitDialog != null) { - waitDialog.dismiss(); - waitDialog = null; - } - } - } catch (Exception e) { - if (waitDialog != null) { - waitDialog.dismiss(); - waitDialog = null; - } - Log.e(Settings.tag, "cgeowaypoint.loadWaypointHandler: " + e.toString()); + if (waypoint.isUserDefined()) { + final Button buttonDelete = (Button) findViewById(R.id.delete); + buttonDelete.setOnClickListener(new deleteWaypointListener()); + buttonDelete.setVisibility(View.VISIBLE); } } @@ -155,10 +141,6 @@ public class cgeowaypoint extends AbstractActivity { return; } - if (geo == null) { - geo = app.startGeo(geoUpdate); - } - waitDialog = ProgressDialog.show(this, null, res.getString(R.string.waypoint_loading), true); waitDialog.setCancelable(true); @@ -178,10 +160,7 @@ public class cgeowaypoint extends AbstractActivity { public void onResume() { super.onResume(); - - if (geo == null) { - geo = app.startGeo(geoUpdate); - } + app.addGeoObserver(this); if (waitDialog == null) { waitDialog = ProgressDialog.show(this, null, res.getString(R.string.waypoint_loading), true); @@ -193,28 +172,17 @@ public class cgeowaypoint extends AbstractActivity { @Override public void onDestroy() { - if (geo != null) { - geo = app.removeGeo(); - } - super.onDestroy(); } @Override public void onStop() { - if (geo != null) { - geo = app.removeGeo(); - } - super.onStop(); } @Override public void onPause() { - if (geo != null) { - geo = app.removeGeo(); - } - + app.deleteGeoObserver(this); super.onPause(); } @@ -249,21 +217,22 @@ public class cgeowaypoint extends AbstractActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { - final int menuItem = item.getItemId(); - if (menuItem == MENU_ID_DEFAULT_NAVIGATION) { - goDefaultNavigation(null); - return true; - } else if (menuItem == MENU_ID_CACHES_AROUND) { - cachesAround(); - return true; - } else if (menuItem == MENU_ID_OPEN_GEOCACHE) { - goToGeocache(); - return true; - } else if (menuItem == MENU_ID_NAVIGATION) { - NavigationAppFactory.showNavigationMenu(geo, this, null, waypoint, null); - return true; + switch (item.getItemId()) { + case MENU_ID_DEFAULT_NAVIGATION: + goDefaultNavigation(null); + return true; + case MENU_ID_CACHES_AROUND: + cachesAround(); + return true; + case MENU_ID_OPEN_GEOCACHE: + goToGeocache(); + return true; + case MENU_ID_NAVIGATION: + NavigationAppFactory.showNavigationMenu(app.currentGeo(), this, null, waypoint, null); + return true; + default: + return false; } - return false; } private void cachesAround() { @@ -295,17 +264,14 @@ 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()); } } } - private static class update implements UpdateLocationCallback { - - @Override - public void updateLocation(cgGeo geo) { - // nothing - } + @Override + public void update(final IGeoData geo) { + // nothing } private class editWaypointListener implements View.OnClickListener { @@ -328,7 +294,6 @@ public class cgeowaypoint extends AbstractActivity { StaticMapsProvider.removeWpStaticMaps(id, geocode); finish(); - return; } else { showToast(res.getString(R.string.err_waypoint_delete_failed)); } @@ -344,7 +309,7 @@ public class cgeowaypoint extends AbstractActivity { return; } - NavigationAppFactory.startDefaultNavigationApplication(geo, this, null, waypoint, null); + NavigationAppFactory.startDefaultNavigationApplication(app.currentGeo(), this, null, waypoint, null); } /** @@ -355,7 +320,7 @@ public class cgeowaypoint extends AbstractActivity { return; } - NavigationAppFactory.startDefaultNavigationApplication2(geo, this, null, waypoint, null); + NavigationAppFactory.startDefaultNavigationApplication2(app.currentGeo(), this, null, waypoint, null); } private boolean navigationPossible() { @@ -381,6 +346,12 @@ public class cgeowaypoint extends AbstractActivity { if (handled) { return true; } - return NavigationAppFactory.onMenuItemSelected(item, geo, this, null, waypoint, null); + return NavigationAppFactory.onMenuItemSelected(item, app.currentGeo(), 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 9c00241..9c02eef 100644 --- a/main/src/cgeo/geocaching/cgeowaypointadd.java +++ b/main/src/cgeo/geocaching/cgeowaypointadd.java @@ -8,7 +8,9 @@ import cgeo.geocaching.enumerations.WaypointType; 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.IObserver; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; @@ -17,7 +19,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.text.Html; -import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; @@ -31,12 +32,10 @@ import java.util.ArrayList; import java.util.EnumSet; import java.util.List; -public class cgeowaypointadd extends AbstractActivity { +public class cgeowaypointadd extends AbstractActivity implements IObserver<IGeoData> { private String geocode = null; private int id = -1; - private cgGeo geo = null; - private UpdateLocationCallback geoUpdate = new update(); private ProgressDialog waitDialog = null; private cgWaypoint waypoint = null; private Geopoint gpTemp = null; @@ -72,7 +71,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 +85,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(); @@ -99,10 +103,6 @@ public class cgeowaypointadd extends AbstractActivity { setContentView(R.layout.waypoint_new); setTitle("waypoint"); - if (geo == null) { - geo = app.startGeo(geoUpdate); - } - // get parameters Bundle extras = getIntent().getExtras(); if (extras != null) { @@ -136,7 +136,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); @@ -162,10 +165,7 @@ public class cgeowaypointadd extends AbstractActivity { public void onResume() { super.onResume(); - - if (geo == null) { - geo = app.startGeo(geoUpdate); - } + app.addGeoObserver(this); if (id > 0) { if (waitDialog == null) { @@ -179,28 +179,17 @@ public class cgeowaypointadd extends AbstractActivity { @Override public void onDestroy() { - if (geo != null) { - geo = app.removeGeo(); - } - super.onDestroy(); } @Override public void onStop() { - if (geo != null) { - geo = app.removeGeo(); - } - super.onStop(); } @Override public void onPause() { - if (geo != null) { - geo = app.removeGeo(); - } - + app.deleteGeoObserver(this); super.onPause(); } @@ -208,7 +197,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); @@ -241,23 +230,20 @@ public class cgeowaypointadd extends AbstractActivity { distanceUnitSelector.setOnItemSelectedListener(new changeDistanceUnit(this)); } - private class update implements UpdateLocationCallback { - - @Override - public void updateLocation(cgGeo geo) { - Log.d(Settings.tag, "cgeowaypointadd.updateLocation called"); - if (geo == null || geo.coordsNow == null) { - return; - } + @Override + public void update(final IGeoData geo) { + Log.d("cgeowaypointadd.updateLocation called"); + if (geo.getCoords() == null) { + return; + } - try { - Button bLat = (Button) findViewById(R.id.buttonLatitude); - Button bLon = (Button) findViewById(R.id.buttonLongitude); - 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."); - } + try { + Button bLat = (Button) findViewById(R.id.buttonLatitude); + Button bLon = (Button) findViewById(R.id.buttonLongitude); + bLat.setHint(geo.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE_RAW)); + bLon.setHint(geo.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE_RAW)); + } catch (Exception e) { + Log.w("Failed to update location."); } } @@ -270,7 +256,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()); } } } @@ -285,7 +271,7 @@ public class cgeowaypointadd extends AbstractActivity { gp = gpTemp; } cgCache cache = app.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS); - cgeocoords coordsDialog = new cgeocoords(cgeowaypointadd.this, cache, gp, geo); + cgeocoords coordsDialog = new cgeocoords(cgeowaypointadd.this, cache, gp, app.currentGeo()); coordsDialog.setCancelable(true); coordsDialog.setOnCoordinateUpdate(new cgeocoords.CoordinateUpdate() { @Override @@ -361,31 +347,27 @@ public class cgeowaypointadd extends AbstractActivity { return; } - double latitude; - double longitude; + Geopoint coords; if (StringUtils.isNotBlank(latText) && StringUtils.isNotBlank(lonText)) { try { - latitude = GeopointParser.parseLatitude(latText); - longitude = GeopointParser.parseLongitude(lonText); - } catch (GeopointParser.ParseException e) { + coords = new Geopoint(latText, lonText); + } catch (Geopoint.ParseException e) { showToast(res.getString(e.resource)); return; } } else { - if (geo == null || geo.coordsNow == null) { + final IGeoData geo = app.currentGeo(); + if (geo.getCoords() == null) { showToast(res.getString(R.string.err_point_curr_position_unavailable)); return; } - - latitude = geo.coordsNow.getLatitude(); - longitude = geo.coordsNow.getLongitude(); + coords = geo.getCoords(); } - Geopoint coords = null; if (StringUtils.isNotBlank(bearingText) && StringUtils.isNotBlank(distanceText)) { // bearing & distance - double bearing = 0; + double bearing; try { bearing = Double.parseDouble(bearingText); } catch (NumberFormatException e) { @@ -401,9 +383,7 @@ public class cgeowaypointadd extends AbstractActivity { return; } - coords = new Geopoint(latitude, longitude).project(bearing, distance); - } else { - coords = new Geopoint(latitude, longitude); + coords = coords.project(bearing, distance); } String name = ((EditText) findViewById(R.id.name)).getText().toString().trim(); @@ -429,7 +409,6 @@ public class cgeowaypointadd extends AbstractActivity { StaticMapsProvider.storeWaypointStaticMap(cache, cgeowaypointadd.this, waypoint, false); } finish(); - return; } else { showToast(res.getString(R.string.err_waypoint_add_failed)); } diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java index 6d01e55..0fc9624 100644 --- a/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java +++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java @@ -1,10 +1,9 @@ package cgeo.geocaching.compatibility; -import cgeo.geocaching.Settings; +import cgeo.geocaching.utils.Log; import android.app.Activity; import android.app.backup.BackupManager; -import android.util.Log; import android.view.Display; public class AndroidLevel8 implements AndroidLevel8Interface { @@ -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 344ff6a..6086604 100644 --- a/main/src/cgeo/geocaching/compatibility/Compatibility.java +++ b/main/src/cgeo/geocaching/compatibility/Compatibility.java @@ -1,7 +1,9 @@ package cgeo.geocaching.compatibility; -import cgeo.geocaching.Settings; import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.utils.Log; + +import org.apache.commons.lang3.reflect.MethodUtils; import android.app.Activity; import android.content.Intent; @@ -9,13 +11,10 @@ import android.content.res.Configuration; import android.net.Uri; import android.os.Build; import android.text.InputType; -import android.util.Log; import android.view.Display; import android.view.Surface; import android.widget.EditText; -import java.lang.reflect.Method; - public final class Compatibility { private final static int sdkVersion = Integer.parseInt(Build.VERSION.SDK); @@ -25,16 +24,7 @@ public final class Compatibility { private final static AndroidLevel8Interface level8; private final static AndroidLevel11Interface level11; - private static Method overridePendingTransitionMethod = null; - static { - if (isLevel5) { - try { - overridePendingTransitionMethod = Activity.class.getMethod("overridePendingTransition", Integer.TYPE, Integer.TYPE); - } catch (Exception e) { - Log.e(Settings.tag, "cannot get overridePendingTransition", e); - } - } if (isLevel8) { level8 = new AndroidLevel8(); } @@ -63,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() @@ -102,9 +92,9 @@ public final class Compatibility { private static void overridePendingTransition(final Activity activity, int enterAnim, int exitAnim) { try { - overridePendingTransitionMethod.invoke(activity, enterAnim, exitAnim); + 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/OXConnector.java b/main/src/cgeo/geocaching/connector/OXConnector.java index 755dbaa..cfde92f 100644 --- a/main/src/cgeo/geocaching/connector/OXConnector.java +++ b/main/src/cgeo/geocaching/connector/OXConnector.java @@ -32,4 +32,10 @@ public class OXConnector extends AbstractConnector { return "www.opencaching.com"; } + @Override + public String getLicenseText(cgCache cache) { + // NOT TO BE TRANSLATED + return "<a href=\"" + getCacheUrl(cache) + "\">" + getName() + "</a> data licensed under the Creative Commons BY-SA 3.0 License"; + } + } diff --git a/main/src/cgeo/geocaching/connector/gc/GCBase.java b/main/src/cgeo/geocaching/connector/gc/GCBase.java index 7c56583..d7f6241 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCBase.java +++ b/main/src/cgeo/geocaching/connector/gc/GCBase.java @@ -1,8 +1,8 @@ package cgeo.geocaching.connector.gc; +import cgeo.geocaching.ICoordinates; 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 +13,12 @@ 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; import org.apache.commons.lang3.StringUtils; @@ -27,10 +28,10 @@ import org.json.JSONException; import org.json.JSONObject; import android.graphics.Bitmap; -import android.util.Log; 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 +53,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 * @@ -64,7 +68,7 @@ public class GCBase { public static SearchResult searchByViewport(final Viewport viewport, final String[] tokens) { Strategy strategy = Settings.getLiveMapStrategy(); if (strategy == Strategy.AUTO) { - float speedNow = cgeoapplication.getInstance().getSpeedFromGeo(); + float speedNow = cgeoapplication.getInstance().currentGeo().getSpeed(); strategy = speedNow >= 8 ? Strategy.FAST : Strategy.DETAILED; // 8 m/s = 30 km/h } // return searchByViewport(viewport, tokens, strategy); @@ -73,7 +77,7 @@ public class GCBase { { SearchResult result = searchByViewport(viewport, tokens, strategy); String text = Formatter.SEPARATOR + strategy.getL10n() + Formatter.SEPARATOR; - int speed = (int) cgeoapplication.getInstance().getSpeedFromGeo(); + int speed = (int) cgeoapplication.getInstance().currentGeo().getSpeed(); if (Settings.isUseMetricUnits()) { text += speed + " km/h"; } else { @@ -84,6 +88,17 @@ public class GCBase { } } + public static void removeFromTileCache(final ICoordinates point) { + if (point != null) { + Collection<Tile> tiles = new ArrayList<Tile>(tileCache.values()); + for (Tile tile : tiles) { + if (tile.containsPoint(point)) { + 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 +113,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 +125,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()); + final 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 +213,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 +298,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 +306,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 +358,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 +369,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 = StringUtils.defaultString(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 1c57508..b461cc2 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java +++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java @@ -3,21 +3,18 @@ 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; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import android.util.Log; - 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,39 +100,37 @@ 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 { search.addGeocode(geocode); } - search.error = StatusCode.NO_ERROR; + search.setError(StatusCode.NO_ERROR); return search; } - Log.e(Settings.tag, "cgeoBase.searchByGeocode: No data from server"); - search.error = StatusCode.COMMUNICATION_ERROR; + 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; } - final SearchResult search = searchResult.filterSearchResults(false, false, Settings.getCacheType()); - - return search; + return searchResult.filterSearchResults(false, false, Settings.getCacheType()); } @Override diff --git a/main/src/cgeo/geocaching/cgBase.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java index 0d39608..e0cb70f 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,13 +24,12 @@ 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; import cgeo.geocaching.utils.BaseUtils; import cgeo.geocaching.utils.CancellableHandler; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.ArrayUtils; @@ -35,101 +39,35 @@ 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 android.util.Log; import java.net.URLDecoder; 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; } final List<String> cids = new ArrayList<String>(); - final List<String> guids = new ArrayList<String>(); String recaptchaChallenge = null; String recaptchaText = null; String page = pageContent; @@ -144,7 +82,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 +101,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 +110,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; } @@ -195,8 +133,6 @@ public class cgBase { while (matcherGuidAndDisabled.find()) { if (matcherGuidAndDisabled.groupCount() > 0) { - guids.add(matcherGuidAndDisabled.group(1)); - cache.setGuid(matcherGuidAndDisabled.group(1)); if (matcherGuidAndDisabled.group(4) != null) { cache.setName(Html.fromHtml(matcherGuidAndDisabled.group(4).trim()).toString()); @@ -215,7 +151,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())) { @@ -247,15 +183,11 @@ public class cgBase { if (StringUtils.isNotBlank(inventoryPre)) { final Matcher matcherTbsInside = GCConstants.PATTERN_SEARCH_TRACKABLESINSIDE.matcher(inventoryPre); while (matcherTbsInside.find()) { - if (matcherTbsInside.groupCount() == 2 && matcherTbsInside.group(2) != null) { - final String inventoryItem = matcherTbsInside.group(2).toLowerCase(); - if (inventoryItem.equals("premium member only cache")) { - continue; - } else { - if (cache.getInventoryItems() <= 0) { - cache.setInventoryItems(1); - } - } + if (matcherTbsInside.groupCount() == 2 && + matcherTbsInside.group(2) != null && + !matcherTbsInside.group(2).equalsIgnoreCase("premium member only cache") && + cache.getInventoryItems() <= 0) { + cache.setInventoryItems(1); } } } @@ -276,14 +208,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) { @@ -300,10 +232,10 @@ public class cgBase { try { String result = BaseUtils.getMatch(page, GCConstants.PATTERN_SEARCH_TOTALCOUNT, false, 1, null, true); if (null != result) { - searchResult.totalCnt = Integer.parseInt(result); + 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 +247,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,9 +277,9 @@ 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.error = StatusCode.UNAPPROVED_LICENSE; + searchResult.setError(StatusCode.UNAPPROVED_LICENSE); return searchResult; } @@ -356,7 +288,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()); } } @@ -384,6 +316,9 @@ public class cgBase { if (CancellableHandler.isCancelled(handler)) { return null; } + // 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) + CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_render); // save full detailed caches cgeoapplication.getInstance().saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); } @@ -391,33 +326,33 @@ 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; } final SearchResult searchResult = new SearchResult(); if (page.contains("Cache is Unpublished") || page.contains("you cannot view this cache listing until it has been published")) { - searchResult.error = StatusCode.UNPUBLISHED_CACHE; + searchResult.setError(StatusCode.UNPUBLISHED_CACHE); return searchResult; } if (page.contains("Sorry, the owner of this listing has made it viewable to Premium Members only.")) { - searchResult.error = StatusCode.PREMIUM_ONLY; + searchResult.setError(StatusCode.PREMIUM_ONLY); return searchResult; } if (page.contains("has chosen to make this cache listing visible to Premium Members only.")) { - searchResult.error = StatusCode.PREMIUM_ONLY; + searchResult.setError(StatusCode.PREMIUM_ONLY); return searchResult; } final String cacheName = Html.fromHtml(BaseUtils.getMatch(page, GCConstants.PATTERN_NAME, true, "")).toString(); if ("An Error Has Occurred".equalsIgnoreCase(cacheName)) { - searchResult.error = StatusCode.UNKNOWN_ERROR; + searchResult.setError(StatusCode.UNKNOWN_ERROR); return searchResult; } @@ -454,7 +389,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; } @@ -462,7 +397,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; } @@ -499,7 +434,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 @@ -525,7 +460,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()); } } @@ -542,7 +477,7 @@ public class cgBase { } } - checkFields(cache); + cache.checkFields(); // cache personal note cache.setPersonalNote(BaseUtils.getMatch(page, GCConstants.PATTERN_PERSONALNOTE, true, cache.getPersonalNote())); @@ -579,7 +514,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 @@ -589,7 +524,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); @@ -616,7 +551,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 @@ -650,7 +585,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 @@ -675,7 +610,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 @@ -683,8 +618,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); @@ -693,16 +627,15 @@ public class cgBase { } // waypoints - int wpBegin = 0; - int wpEnd = 0; + int wpBegin; + int wpEnd; wpBegin = page.indexOf("<table class=\"Table\" id=\"ctl00_ContentBody_Waypoints\">"); if (wpBegin != -1) { // parse waypoints 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); @@ -729,7 +662,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); @@ -769,7 +702,7 @@ public class cgBase { // last check for necessary cache conditions if (StringUtils.isBlank(cache.getGeocode())) { - searchResult.error = StatusCode.UNKNOWN_ERROR; + searchResult.setError(StatusCode.UNKNOWN_ERROR); return searchResult; } @@ -777,485 +710,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; @@ -1265,12 +719,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; } @@ -1282,33 +736,25 @@ public class cgBase { "__EVENTARGUMENT", ""); Login.putViewstates(params, viewstates); - String page = Network.getResponseData(Network.postRequest(uri, params)); + final String page = Login.postRequestLogged(uri, params); if (!Login.getLoginStatus(page)) { - final StatusCode loginState = Login.login(); - 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."); - } else { - search.setError(loginState); - Log.e(Settings.tag, "cgeoBase.searchByNextPage: Can not log in geocaching"); - return search; - } + Log.e("cgeoBase.postLogTrackable: 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; } // save to application - search.setError(searchResult.error); + search.setError(searchResult.getError()); search.setViewstates(searchResult.viewstates); for (String geocode : searchResult.getGeocodes()) { search.addGeocode(geocode); @@ -1316,30 +762,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; } /** @@ -1357,16 +798,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; } @@ -1384,7 +825,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; } @@ -1394,7 +835,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; } @@ -1403,7 +844,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); @@ -1411,7 +852,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; } @@ -1421,7 +862,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; } @@ -1437,16 +878,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; } @@ -1455,14 +896,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; } @@ -1485,9 +926,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( @@ -1506,7 +947,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); @@ -1519,20 +960,10 @@ public class cgBase { } final String uri = new Uri.Builder().scheme("http").authority("www.geocaching.com").path("/seek/log.aspx").encodedQuery("ID=" + cacheid).build().toString(); - String page = Network.getResponseData(Network.postRequest(uri, params)); + String page = Login.postRequestLogged(uri, params); if (!Login.getLoginStatus(page)) { - final StatusCode loginState = Login.login(); - 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 + ")"); - return loginState; - } - } - - if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.postLog: No data from server"); - return StatusCode.NO_DATA_FROM_SERVER; + Log.e("cgeoBase.postLogTrackable: Can not log in geocaching"); + return StatusCode.NOT_LOGGED_IN; } // maintenance, archived needs to be confirmed @@ -1543,8 +974,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; } @@ -1559,8 +990,8 @@ public class cgBase { if (trackables != null && !trackables.isEmpty()) { // we have some trackables to proceed final StringBuilder hdnSelected = new StringBuilder(); - for (cgTrackableLog tb : trackables) { - String ctl = null; + for (TrackableLog tb : trackables) { + String ctl; final String action = Integer.toString(tb.id) + tb.action.action; if (tb.ctl < 10) { @@ -1583,14 +1014,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); @@ -1604,26 +1035,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 @@ -1649,34 +1080,24 @@ public class cgBase { "ctl00$ContentBody$uxVistOtherListingGC", ""); final String uri = new Uri.Builder().scheme("http").authority("www.geocaching.com").path("/track/log.aspx").encodedQuery("wid=" + tbid).build().toString(); - String page = Network.getResponseData(Network.postRequest(uri, params)); + final String page = Login.postRequestLogged(uri, params); if (!Login.getLoginStatus(page)) { - final StatusCode loginState = Login.login(); - 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 + ")"); - return loginState; - } - } - - if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.postLogTrackable: No data from server"); - return StatusCode.NO_DATA_FROM_SERVER; + Log.e("cgeoBase.postLogTrackable: Can not log in geocaching"); + return StatusCode.NOT_LOGGED_IN; } try { 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; } @@ -1689,19 +1110,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, null); 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 } @@ -1715,10 +1136,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, null); 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 } @@ -1732,273 +1153,424 @@ 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()); - public static void storeCache(Activity activity, cgCache origCache, String geocode, int listId, CancellableHandler handler) { + // 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 { - cgCache cache; - // get cache details, they may not yet be complete - if (origCache != null) { - // only reload the cache, if it was already stored or has not all 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, null); - cache = search.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB); - } else { - cache = origCache; - } - } else if (StringUtils.isNotBlank(geocode)) { - final SearchResult search = searchByGeocode(geocode, null, listId, false, null); - 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 + final String distance = BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_DISTANCE, false, null); + if (null != distance) { + trackable.setDistance(DistanceParser.parseDistance(distance, Settings.isUseMetricUnits())); + } - // 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()) { + long date = 0; + try { + date = Login.parseGcCustomDate(matcherLogs.group(2)).getTime(); + } catch (ParseException e) { + } - // store map previews - StaticMapsProvider.downloadMaps(cache, activity); + final LogEntry logDone = new LogEntry( + Html.fromHtml(matcherLogs.group(3)).toString().trim(), + date, + LogType.getByIconName(matcherLogs.group(1)), + matcherLogs.group(7).trim()); - if (CancellableHandler.isCancelled(handler)) { - return; - } + if (matcherLogs.group(4) != null && matcherLogs.group(6) != null) { + logDone.cacheGuid = matcherLogs.group(4); + logDone.cacheName = matcherLogs.group(6); + } - cache.setListId(listId); - cgeoapplication.getInstance().saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); + // 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); + } - if (handler != null) { - handler.sendMessage(Message.obtain()); + 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()); + } + + // 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; + + 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); + + // 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); + + long date = 0; + try { + date = Login.parseGcCustomDate(entry.getString("Visited")).getTime(); + } catch (ParseException e) { + Log.e("GCParser.loadLogsFromDetails: failed to parse log date."); + } + + final LogEntry logDone = new LogEntry( + entry.getString("UserName"), + date, + LogType.getByIconName(logIconName), + entry.getString("LogText")); + logDone.found = entry.getInt("GeocacheFindCount"); + logDone.friend = friends; + + 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, ctl); - /** - * 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/connector/gc/IconDecoder.java b/main/src/cgeo/geocaching/connector/gc/IconDecoder.java index 43ca2ce..74e78cc 100644 --- a/main/src/cgeo/geocaching/connector/gc/IconDecoder.java +++ b/main/src/cgeo/geocaching/connector/gc/IconDecoder.java @@ -153,12 +153,10 @@ public abstract class IconDecoder { } if ((bitmap.getPixel(x + POSX_FOUND, y + POSY_FOUND) & 0x00FFFFFF) == COLOR_FOUND) { cache.setFound(true); - return; } } catch (IllegalArgumentException e) { // intentionally left blank } - return; } } diff --git a/main/src/cgeo/geocaching/network/Login.java b/main/src/cgeo/geocaching/connector/gc/Login.java index be80a19..28b2c6a 100644 --- a/main/src/cgeo/geocaching/network/Login.java +++ b/main/src/cgeo/geocaching/connector/gc/Login.java @@ -1,11 +1,15 @@ -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; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; @@ -14,7 +18,6 @@ import org.apache.http.HttpResponse; import android.content.Context; import android.graphics.drawable.BitmapDrawable; -import android.util.Log; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -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 + " (" + getActualMemberStatus() + ')'); + Log.i("Already logged in Geocaching.com as " + login.left + " (" + Settings.getMemberStatus() + ')'); 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); @@ -107,38 +106,38 @@ public abstract class Login { loginResponse = Network.postRequest("https://www.geocaching.com/login/default.aspx", params); loginData = Network.getResponseData(loginResponse); - if (StringUtils.isNotBlank(loginData)) { - if (Login.getLoginStatus(loginData)) { - Log.i(Settings.tag, "Successfully logged in Geocaching.com as " + login.left + " (" + getActualMemberStatus() + ')'); - - Login.switchToEnglish(loginData); - Settings.setCookieStore(Network.dumpCookieStore()); - - return StatusCode.NO_ERROR; // logged in - } else { - if (loginData.contains("Your username/password combination does not match.")) { - Log.i(Settings.tag, "Failed to log in Geocaching.com as " + login.left + " because of wrong username/password"); - return StatusCode.WRONG_LOGIN_DATA; // wrong login - } else { - Log.i(Settings.tag, "Failed to log in Geocaching.com as " + login.left + " for some unknown reason"); - return StatusCode.UNKNOWN_ERROR; // can't login - } - } - } else { - Log.e(Settings.tag, "cgeoBase.login: Failed to retrieve login page (2nd)"); + if (StringUtils.isBlank(loginData)) { + 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 } + + if (Login.getLoginStatus(loginData)) { + Log.i("Successfully logged in Geocaching.com as " + login.left + " (" + Settings.getMemberStatus() + ')'); + + Login.switchToEnglish(loginData); + Settings.setCookieStore(Cookies.dumpCookieStore()); + + return StatusCode.NO_ERROR; // logged in + } + + if (loginData.contains("Your username/password combination does not match.")) { + Log.i("Failed to log in Geocaching.com as " + login.left + " because of wrong username/password"); + return StatusCode.WRONG_LOGIN_DATA; // wrong login + } + + Log.i("Failed to log in Geocaching.com as " + login.left + " for some unknown reason"); + return StatusCode.UNKNOWN_ERROR; // can't login } 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,21 +182,18 @@ 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("[,.]", ""))); + Settings.setMemberStatus(BaseUtils.getMatch(page, GCConstants.PATTERN_MEMBER_STATUS, true, null)); return true; } @@ -213,28 +201,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"); + if (previousPage != null && previousPage.contains(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 +226,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 +245,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 +257,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 +299,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 +335,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 +353,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 +391,47 @@ 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, final Parameters params) { + HttpResponse response = Network.postRequest(uri, params); + String data = Network.getResponseData(response); + + if (!getLoginStatus(data)) { + if (login() == StatusCode.NO_ERROR) { + response = Network.postRequest(uri, params); + data = Network.getResponseData(response); + } else { + Log.i("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 + * @return + */ + public static String getRequestLogged(final String uri, final Parameters params) { + final String data = Network.getResponseData(Network.getRequest(uri, params)); + + if (getLoginStatus(data)) { + return data; + } + + if (login() == StatusCode.NO_ERROR) { + return Network.getResponseData(Network.getRequest(uri, params)); + } - return getViewstates(Network.getResponseData(response)); + Log.w("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 8613787..692f28b 100644 --- a/main/src/cgeo/geocaching/connector/gc/Tile.java +++ b/main/src/cgeo/geocaching/connector/gc/Tile.java @@ -1,15 +1,16 @@ package cgeo.geocaching.connector.gc; -import cgeo.geocaching.Settings; +import cgeo.geocaching.ICoordinates; 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; -import android.util.Log; import java.io.IOException; @@ -45,22 +46,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() { @@ -141,7 +136,7 @@ public class Tile { Tile tileRight = new Tile(right, zoom); if (tileLeft.tileX == tileRight.tileX) { - zoom = zoom + 1; + zoom += 1; } return Math.min(zoom, ZOOMLEVEL_MAX); @@ -161,7 +156,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())) @@ -173,7 +168,7 @@ public class Tile { Tile tileTop = new Tile(top, zoom); if (Math.abs(tileBottom.tileY - tileTop.tileY) > 1) { - zoom = zoom - 1; + zoom -= 1; } return Math.min(zoom, ZOOMLEVEL_MAX); @@ -213,26 +208,22 @@ 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(final ICoordinates point) { + return viewPort.contains(point); + } } diff --git a/main/src/cgeo/geocaching/connector/opencaching/ApiOpenCachingConnector.java b/main/src/cgeo/geocaching/connector/opencaching/ApiOpenCachingConnector.java index 8ed6acd..e4f382b 100644 --- a/main/src/cgeo/geocaching/connector/opencaching/ApiOpenCachingConnector.java +++ b/main/src/cgeo/geocaching/connector/opencaching/ApiOpenCachingConnector.java @@ -40,8 +40,6 @@ public class ApiOpenCachingConnector extends OpenCachingConnector { } final SearchResult searchResult = new SearchResult(); searchResult.addCache(cache); - - final SearchResult search = searchResult.filterSearchResults(false, false, Settings.getCacheType()); - return search; + return searchResult.filterSearchResults(false, false, Settings.getCacheType()); } } diff --git a/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java b/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java index 9c3ab4a..165e277 100644 --- a/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java +++ b/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java @@ -1,19 +1,20 @@ package cgeo.geocaching.connector.opencaching; -import cgeo.geocaching.Settings; +import cgeo.geocaching.LogEntry; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgImage; -import cgeo.geocaching.cgLog; +import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.IConnector; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; +import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter; -import cgeo.geocaching.geopoint.GeopointParser; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import org.json.JSONArray; @@ -22,12 +23,12 @@ import org.json.JSONObject; import android.net.Uri; import android.text.Html; -import android.util.Log; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; +import java.util.EnumSet; import java.util.List; import java.util.Locale; @@ -75,13 +76,7 @@ final public class OkapiClient { return null; } - final cgCache cache = parseCache(data); - - long time = new Date().getTime(); - cache.setUpdated(time); - cache.setDetailedUpdate(time); - - return cache; + return parseCache(data); } public static List<cgCache> getCachesAround(final Geopoint center, IConnector connector) { @@ -117,7 +112,7 @@ final public class OkapiClient { return caches; } } catch (JSONException e) { - Log.e(Settings.tag, "OkapiClient.parseCaches", e); + Log.e("OkapiClient.parseCaches", e); } return null; } @@ -177,8 +172,14 @@ final public class OkapiClient { cache.setLogs(parseLogs(response.getJSONArray(CACHE_LATEST_LOGS))); cache.setHidden(parseDate(response.getString(CACHE_HIDDEN))); + cache.setUpdated(System.currentTimeMillis()); + cache.setDetailedUpdate(cache.getUpdated()); + cache.setDetailed(true); + + // 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; } @@ -200,22 +201,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(); - 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)); + LogEntry log = new LogEntry( + parseUser(logResponse.getJSONObject(LOG_USER)), + parseDate(logResponse.getString(LOG_DATE)).getTime(), + parseLogType(logResponse.getString(LOG_TYPE)), + logResponse.getString(LOG_COMMENT).trim()); 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; @@ -225,7 +226,7 @@ final public class OkapiClient { if ("Found it".equalsIgnoreCase(logType)) { return LogType.LOG_FOUND_IT; } - else if ("Didn't find it".equalsIgnoreCase(logType)) { + if ("Didn't find it".equalsIgnoreCase(logType)) { return LogType.LOG_DIDNT_FIND_IT; } return LogType.LOG_NOTE; @@ -237,7 +238,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; } @@ -246,7 +247,7 @@ final public class OkapiClient { final String latitude = StringUtils.substringBefore(location, "|"); final String longitude = StringUtils.substringAfter(location, "|"); // FIXME: the next line should be a setter at cgCache - cache.setCoords(GeopointParser.parse(latitude, longitude)); + cache.setCoords(new Geopoint(latitude, longitude)); } private static CacheSize getCacheSize(final JSONObject response) { @@ -257,7 +258,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: @@ -279,11 +280,14 @@ final public class OkapiClient { private static CacheType getCacheType(final String cacheType) { if (cacheType.equalsIgnoreCase("Traditional")) { return CacheType.TRADITIONAL; - } else if (cacheType.equalsIgnoreCase("Multi")) { + } + if (cacheType.equalsIgnoreCase("Multi")) { return CacheType.MULTI; - } else if (cacheType.equalsIgnoreCase("Quiz")) { + } + if (cacheType.equalsIgnoreCase("Quiz")) { return CacheType.MYSTERY; - } else if (cacheType.equalsIgnoreCase("Virtual")) { + } + if (cacheType.equalsIgnoreCase("Virtual")) { return CacheType.VIRTUAL; } return CacheType.UNKNOWN; diff --git a/main/src/cgeo/geocaching/enumerations/CacheAttribute.java b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java new file mode 100644 index 0000000..4a502fb --- /dev/null +++ b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java @@ -0,0 +1,140 @@ +package cgeo.geocaching.enumerations; + +import cgeo.geocaching.R; +import cgeo.geocaching.cgeoapplication; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + + +public enum CacheAttribute { + UNKNOWN(0, "", R.drawable.attribute__strikethru, 0, 0), + DOGS(1, "dogs", R.drawable.attribute_dogs, R.string.attribute_dogs_yes, R.string.attribute_dogs_no), + FEE(2, "fee", R.drawable.attribute_fee, R.string.attribute_fee_yes, R.string.attribute_fee_no), + RAPPELLING(3, "rappelling", R.drawable.attribute_rappelling, R.string.attribute_rappelling_yes, R.string.attribute_rappelling_no), + BOAT(4, "boat", R.drawable.attribute_boat, R.string.attribute_boat_yes, R.string.attribute_boat_no), + SCUBA(5, "scuba", R.drawable.attribute_scuba, R.string.attribute_scuba_yes, R.string.attribute_scuba_no), + KIDS(6, "kids", R.drawable.attribute_kids, R.string.attribute_kids_yes, R.string.attribute_kids_no), + ONEHOUR(7, "onehour", R.drawable.attribute_onehour, R.string.attribute_onehour_yes, R.string.attribute_onehour_no), + SCENIC(8, "scenic", R.drawable.attribute_scenic, R.string.attribute_scenic_yes, R.string.attribute_scenic_no), + HIKING(9, "hiking", R.drawable.attribute_hiking, R.string.attribute_hiking_yes, R.string.attribute_hiking_no), + CLIMBING(10, "climbing", R.drawable.attribute_climbing, R.string.attribute_climbing_yes, R.string.attribute_climbing_no), + WADING(11, "wading", R.drawable.attribute_wading, R.string.attribute_wading_yes, R.string.attribute_wading_no), + SWIMMING(12, "swimming", R.drawable.attribute_swimming, R.string.attribute_swimming_yes, R.string.attribute_swimming_no), + AVAILABLE(13, "available", R.drawable.attribute_available, R.string.attribute_available_yes, R.string.attribute_available_no), + NIGHT(14, "night", R.drawable.attribute_night, R.string.attribute_night_yes, R.string.attribute_night_no), + WINTER(15, "winter", R.drawable.attribute_winter, R.string.attribute_winter_yes, R.string.attribute_winter_no), + POISONOAK(17, "poisonoak", R.drawable.attribute_poisonoak, R.string.attribute_poisonoak_yes, R.string.attribute_poisonoak_no), + DANGEROUSANIMALS(18, "dangerousanimals", R.drawable.attribute_dangerousanimals, R.string.attribute_dangerousanimals_yes, R.string.attribute_dangerousanimals_no), + TICKS(19, "ticks", R.drawable.attribute_ticks, R.string.attribute_ticks_yes, R.string.attribute_ticks_no), + MINE(29, "mine", R.drawable.attribute_mine, R.string.attribute_mine_yes, R.string.attribute_mine_no), + CLIFF(21, "cliff", R.drawable.attribute_cliff, R.string.attribute_cliff_yes, R.string.attribute_cliff_no), + HUNTING(22, "hunting", R.drawable.attribute_hunting, R.string.attribute_hunting_yes, R.string.attribute_hunting_no), + DANGER(23, "danger", R.drawable.attribute_danger, R.string.attribute_danger_yes, R.string.attribute_danger_no), + WHEELCHAIR(24, "wheelchair", R.drawable.attribute_wheelchair, R.string.attribute_wheelchair_yes, R.string.attribute_wheelchair_no), + PARKING(25, "parking", R.drawable.attribute_parking, R.string.attribute_parking_yes, R.string.attribute_parking_no), + PUBLIC(26, "public", R.drawable.attribute_public, R.string.attribute_public_yes, R.string.attribute_public_no), + WATER(27, "water", R.drawable.attribute_water, R.string.attribute_water_yes, R.string.attribute_water_no), + RESTROOMS(28, "restrooms", R.drawable.attribute_restrooms, R.string.attribute_restrooms_yes, R.string.attribute_restrooms_no), + PHONE(29, "phone", R.drawable.attribute_phone, R.string.attribute_phone_yes, R.string.attribute_phone_no), + PICNIC(30, "picnic", R.drawable.attribute_picnic, R.string.attribute_picnic_yes, R.string.attribute_picnic_no), + CAMPING(31, "camping", R.drawable.attribute_camping, R.string.attribute_camping_yes, R.string.attribute_camping_no), + BICYCLES(32, "bicycles", R.drawable.attribute_bicycles, R.string.attribute_bicycles_yes, R.string.attribute_bicycles_no), + MOTORCYCLES(33, "motorcycles", R.drawable.attribute_motorcycles, R.string.attribute_motorcycles_yes, R.string.attribute_motorcycles_no), + QUADS(34, "quads", R.drawable.attribute_quads, R.string.attribute_quads_yes, R.string.attribute_quads_no), + JEEPS(35, "jeeps", R.drawable.attribute_jeeps, R.string.attribute_jeeps_yes, R.string.attribute_jeeps_no), + SNOWMOBILES(36, "snowmobiles", R.drawable.attribute_snowmobiles, R.string.attribute_snowmobiles_yes, R.string.attribute_snowmobiles_no), + HORSES(37, "horses", R.drawable.attribute_horses, R.string.attribute_horses_yes, R.string.attribute_horses_no), + CAMPFIRES(38, "campfires", R.drawable.attribute_campfires, R.string.attribute_campfires_yes, R.string.attribute_campfires_no), + THORN(39, "thorn", R.drawable.attribute_thorn, R.string.attribute_thorn_yes, R.string.attribute_thorn_no), + STEALTH(40, "stealth", R.drawable.attribute_stealth, R.string.attribute_stealth_yes, R.string.attribute_stealth_no), + STROLLER(41, "stroller", R.drawable.attribute_stroller, R.string.attribute_stroller_yes, R.string.attribute_stroller_no), + FIRSTAID(42, "firstaid", R.drawable.attribute_firstaid, R.string.attribute_firstaid_yes, R.string.attribute_firstaid_no), + COW(43, "cow", R.drawable.attribute_cow, R.string.attribute_cow_yes, R.string.attribute_cow_no), + FLASHLIGHT(44, "flashlight", R.drawable.attribute_flashlight, R.string.attribute_flashlight_yes, R.string.attribute_flashlight_no), + LANDF(45, "landf", R.drawable.attribute_landf, R.string.attribute_landf_yes, R.string.attribute_landf_no), + RV(46, "rv", R.drawable.attribute_rv, R.string.attribute_rv_yes, R.string.attribute_rv_no), + FIELD_PUZZLE(47, "field_puzzle", R.drawable.attribute_field_puzzle, R.string.attribute_field_puzzle_yes, R.string.attribute_field_puzzle_no), + UV(48, "uv", R.drawable.attribute_uv, R.string.attribute_uv_yes, R.string.attribute_uv_no), + SNOWSHOES(49, "snowshoes", R.drawable.attribute_snowshoes, R.string.attribute_snowshoes_yes, R.string.attribute_snowshoes_no), + SKIIS(50, "skiis", R.drawable.attribute_skiis, R.string.attribute_skiis_yes, R.string.attribute_skiis_no), + SPECIAL_TOOLS(51, "s_tool", R.drawable.attribute_s_tool, R.string.attribute_s_tool_yes, R.string.attribute_s_tool_no), + NIGHTCACHE(52, "nightcache", R.drawable.attribute_nightcache, R.string.attribute_nightcache_yes, R.string.attribute_nightcache_no), + PARKNGRAB(53, "parkngrab", R.drawable.attribute_parkngrab, R.string.attribute_parkngrab_yes, R.string.attribute_parkngrab_no), + ABANDONED_BUILDING(54, "abandonedbuilding", R.drawable.attribute_abandonedbuilding, R.string.attribute_abandonedbuilding_yes, R.string.attribute_abandonedbuilding_no), + HIKE_SHORT(55, "hike_short", R.drawable.attribute_hike_short, R.string.attribute_hike_short_yes, R.string.attribute_hike_short_no), + HIKE_MED(56, "hike_med", R.drawable.attribute_hike_med, R.string.attribute_hike_med_yes, R.string.attribute_hike_med_no), + HIKE_LONG(57, "hike_long", R.drawable.attribute_hike_long, R.string.attribute_hike_long_yes, R.string.attribute_hike_long_no), + FUEL(58, "fuel", R.drawable.attribute_fuel, R.string.attribute_fuel_yes, R.string.attribute_fuel_no), + FOOD(59, "food", R.drawable.attribute_food, R.string.attribute_food_yes, R.string.attribute_food_no), + WIRELESS_BEACON(60, "wirelessbeacon", R.drawable.attribute_wirelessbeacon, R.string.attribute_wirelessbeacon_yes, R.string.attribute_wirelessbeacon_no), + PARTNERSHIP(61, "partnership", R.drawable.attribute_partnership, R.string.attribute_partnership_yes, R.string.attribute_partnership_no), + SEASONAL(62, "seasonal", R.drawable.attribute_seasonal, R.string.attribute_seasonal_yes, R.string.attribute_seasonal_no), + TOURIST_OK(63, "touristok", R.drawable.attribute_touristok, R.string.attribute_touristok_yes, R.string.attribute_touristok_no), + TREECLIMBING(64, "treeclimbing", R.drawable.attribute_treeclimbing, R.string.attribute_treeclimbing_yes, R.string.attribute_treeclimbing_no), + FRONTYARD(65, "frontyard", R.drawable.attribute_frontyard, R.string.attribute_frontyard_yes, R.string.attribute_frontyard_no), + TEAMWORK(66, "teamwork", R.drawable.attribute_teamwork, R.string.attribute_teamwork_yes, R.string.attribute_teamwork_no); + + private static final String INTERNAL_PRE = "attribute_"; + private static final String INTERNAL_YES = "_yes"; + private static final String INTERNAL_NO = "_no"; + + public final int id; + public final String gcRawName; + public final int drawableId; + public final int stringIdYes; + public final int stringIdNo; + + private CacheAttribute(final int id, final String gcRawName, final int drawableId, final int stringIdYes, final int stringIdNo) { + this.id = id; + this.gcRawName = gcRawName; + this.drawableId = drawableId; + this.stringIdYes = stringIdYes; + this.stringIdNo = stringIdNo; + } + + public String getL10n(final boolean enabled) { + return cgeoapplication.getInstance().getResources().getString(enabled ? stringIdYes : stringIdNo); + } + + 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(); + } + + public static boolean isEnabled(final String attributeName) { + return !StringUtils.endsWithIgnoreCase(attributeName, INTERNAL_NO); + } +} diff --git a/main/src/cgeo/geocaching/enumerations/CacheSize.java b/main/src/cgeo/geocaching/enumerations/CacheSize.java index 9b0a559..6fffcdb 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; @@ -43,7 +41,7 @@ public enum CacheSize { FIND_BY_ID = Collections.unmodifiableMap(mapping); } - public final static CacheSize getById(final String id) { + public static CacheSize getById(final String id) { if (id == null) { return UNKNOWN; } @@ -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..9667911 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; } @@ -62,16 +60,16 @@ public enum CacheType { FIND_BY_PATTERN = Collections.unmodifiableMap(mappingPattern); } - public final static CacheType getById(final String id) { - final CacheType result = id != null ? CacheType.FIND_BY_ID.get(id.toLowerCase().trim()) : null; + public static CacheType getById(final String id) { + final CacheType result = (id != null) ? CacheType.FIND_BY_ID.get(id.toLowerCase().trim()) : null; if (result == null) { return UNKNOWN; } return result; } - public final static CacheType getByPattern(final String pattern) { - final CacheType result = pattern != null ? CacheType.FIND_BY_PATTERN.get(pattern.toLowerCase().trim()) : null; + public static CacheType getByPattern(final String pattern) { + 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..5cc7efc 100644 --- a/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java +++ b/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java @@ -28,16 +28,14 @@ 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) { + public static Strategy getById(final int id) { for (Strategy strategy : Strategy.values()) { if (strategy.id == id) { return strategy; @@ -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..e4add78 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; @@ -68,7 +66,7 @@ public enum LogType { FIND_BY_TYPE = Collections.unmodifiableMap(mappingType); } - public final static LogType getById(final int id) { + public static LogType getById(final int id) { for (LogType logType : values()) { if (logType.id == id) { return logType; @@ -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..babc4b6 --- /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; + 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..e7579f3 --- /dev/null +++ b/main/src/cgeo/geocaching/export/GpxExport.java @@ -0,0 +1,328 @@ +package cgeo.geocaching.export; + +import cgeo.geocaching.LogEntry; +import cgeo.geocaching.R; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgWaypoint; +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.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +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"); + 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; + } + + Writer gpx = null; + + try { + exportLocation.mkdirs(); + + final SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); + exportFile = new File(exportLocation.toString() + File.separatorChar + "export_" + fileNameDateFormat.format(new Date()) + ".gpx"); + + gpx = new BufferedWriter(new FileWriter(exportFile)); + + gpx.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); + gpx.write("<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\">"); + + + 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.write("<wpt "); + gpx.write("lat=\""); + gpx.write(Double.toString(cache.getCoords().getLatitude())); + gpx.write("\" "); + gpx.write("lon=\""); + gpx.write(Double.toString(cache.getCoords().getLongitude())); + gpx.write("\">"); + + gpx.write("<time>"); + gpx.write(StringEscapeUtils.escapeXml(dateFormatZ.format(cache.getHiddenDate()))); + gpx.write("</time>"); + + gpx.write("<name>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getGeocode())); + gpx.write("</name>"); + + gpx.write("<desc>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getName())); + gpx.write("</desc>"); + + gpx.write("<sym>"); + gpx.write(cache.isFound() ? "Geocache Found" : "Geocache"); + gpx.write("</sym>"); + + gpx.write("<type>"); + gpx.write(StringEscapeUtils.escapeXml("Geocache|" + cache.getType().toString())); //TODO: Correct (english) string + gpx.write("</type>"); + + gpx.write("<groundspeak:cache "); + gpx.write("available=\""); + gpx.write(!cache.isDisabled() ? "True" : "False"); + gpx.write("\" archived=\""); + gpx.write(cache.isArchived() ? "True" : "False"); + gpx.write("\" "); + gpx.write("xmlns:groundspeak=\"http://www.groundspeak.com/cache/1/0/1\">"); + + gpx.write("<groundspeak:name>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getName())); + gpx.write("</groundspeak:name>"); + + gpx.write("<groundspeak:placed_by>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getOwner())); + gpx.write("</groundspeak:placed_by>"); + + gpx.write("<groundspeak:owner>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getOwnerReal())); + gpx.write("</groundspeak:owner>"); + + gpx.write("<groundspeak:type>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getType().toString())); //TODO: Correct (english) string + gpx.write("</groundspeak:type>"); + + gpx.write("<groundspeak:container>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getSize().toString())); //TODO: Correct (english) string + gpx.write("</groundspeak:container>"); + + if (cache.hasAttributes()) { + //TODO: Attribute conversion required: English verbose name, gpx-id + gpx.write("<groundspeak:attributes>"); + + for (String attribute : cache.getAttributes()) { + final CacheAttribute attr = CacheAttribute.getByGcRawName(CacheAttribute.trimAttributeName(attribute)); + final boolean enabled = CacheAttribute.isEnabled(attribute); + + gpx.write("<groundspeak:attribute id=\""); + gpx.write(Integer.toString(attr.id)); + gpx.write("\" inc=\""); + if (enabled) { + gpx.write('1'); + } else { + gpx.write('0'); + } + gpx.write("\">"); + gpx.write(StringEscapeUtils.escapeXml(attr.getL10n(enabled))); + gpx.write("</groundspeak:attribute>"); + } + + gpx.write("</groundspeak:attributes>"); + } + + gpx.write("<groundspeak:difficulty>"); + gpx.write(Float.toString(cache.getDifficulty())); + gpx.write("</groundspeak:difficulty>"); + + gpx.write("<groundspeak:terrain>"); + gpx.write(Float.toString(cache.getTerrain())); + gpx.write("</groundspeak:terrain>"); + + gpx.write("<groundspeak:country>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getLocation())); + gpx.write("</groundspeak:country>"); + + gpx.write("<groundspeak:state>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getLocation())); + gpx.write("</groundspeak:state>"); + + gpx.write("<groundspeak:short_description html=\""); + if (BaseUtils.containsHtml(cache.getShortDescription())) { + gpx.write("True"); + } else { + gpx.write("False"); + } + gpx.write("\">"); + gpx.write(StringEscapeUtils.escapeXml(cache.getShortDescription())); + gpx.write("</groundspeak:short_description>"); + + gpx.write("<groundspeak:long_description html=\""); + if (BaseUtils.containsHtml(cache.getDescription())) { + gpx.write("True"); + } else { + gpx.write("False"); + } + gpx.write("\">"); + gpx.write(StringEscapeUtils.escapeXml(cache.getDescription())); + gpx.write("</groundspeak:long_description>"); + + gpx.write("<groundspeak:encoded_hints>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getHint())); + gpx.write("</groundspeak:encoded_hints>"); + + gpx.write("</groundspeak:cache>"); + + if (cache.getLogs().size() > 0) { + gpx.write("<groundspeak:logs>"); + + for (LogEntry log : cache.getLogs()) { + gpx.write("<groundspeak:log id=\""); + gpx.write(Integer.toString(log.id)); + gpx.write("\">"); + + gpx.write("<groundspeak:date>"); + gpx.write(StringEscapeUtils.escapeXml(dateFormatZ.format(new Date(log.date)))); + gpx.write("</groundspeak:date>"); + + gpx.write("<groundspeak:type>"); + gpx.write(StringEscapeUtils.escapeXml(log.type.type)); + gpx.write("</groundspeak:type>"); + + gpx.write("<groundspeak:finder id=\"\">"); + gpx.write(StringEscapeUtils.escapeXml(log.author)); + gpx.write("</groundspeak:finder>"); + + gpx.write("<groundspeak:text encoded=\"False\">"); + gpx.write(StringEscapeUtils.escapeXml(log.log)); + gpx.write("</groundspeak:text>"); + + gpx.write("</groundspeak:log>"); + } + + gpx.write("</groundspeak:logs>"); + } + + gpx.write("</wpt>"); + + for (cgWaypoint wp : cache.getWaypoints()) { + gpx.write("<wpt lat=\""); + gpx.write(Double.toString(wp.getCoords().getLatitude())); + gpx.write("\" lon=\""); + gpx.write(Double.toString(wp.getCoords().getLongitude())); + gpx.write("\">"); + + gpx.write("<name>"); + gpx.write(StringEscapeUtils.escapeXml(wp.getPrefix())); + gpx.write(StringEscapeUtils.escapeXml(cache.getGeocode().substring(2))); + gpx.write("</name>"); + + gpx.write("<cmt />"); + + gpx.write("<desc>"); + gpx.write(StringEscapeUtils.escapeXml(wp.getNote())); + gpx.write("</desc>"); + + gpx.write("<sym>"); + gpx.write(StringEscapeUtils.escapeXml(wp.getWaypointType().toString())); + gpx.write("</sym>"); + + gpx.write("<type>Waypoint|"); + gpx.write(StringEscapeUtils.escapeXml(wp.getWaypointType().toString())); + gpx.write("</type>"); + + gpx.write("</wpt>"); + } + + publishProgress(i + 1); + } + + gpx.write("</gpx>"); + + gpx.close(); + } catch (Exception e) { + Log.e("GpxExport.ExportTask export", e); + + if (gpx != null) { + try { + gpx.close(); + } catch (IOException ee) { + } + } + + // delete partial gpx file on error + if (exportFile.exists()) { + exportFile.delete(); + } + + 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 cef7b89..2fa4e5d 100644 --- a/main/src/cgeo/geocaching/files/FileList.java +++ b/main/src/cgeo/geocaching/files/FileList.java @@ -1,9 +1,9 @@ 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; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.ArrayUtils; @@ -15,7 +15,6 @@ import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.widget.ArrayAdapter; import java.io.File; @@ -64,30 +63,14 @@ public abstract class FileList<T extends ArrayAdapter<File>> extends AbstractLis @Override public void handleMessage(Message msg) { - try { - if (CollectionUtils.isEmpty(files)) { - if (waitDialog != null) { - waitDialog.dismiss(); - } - - showToast(res.getString(R.string.file_list_no_files)); - - finish(); - return; - } else { - if (adapter != null) { - adapter.notifyDataSetChanged(); - } - } - - if (waitDialog != null) { - waitDialog.dismiss(); - } - } catch (Exception e) { - if (waitDialog != null) { - waitDialog.dismiss(); - } - Log.e(Settings.tag, "cgFileList.loadFilesHandler: " + e.toString()); + if (waitDialog != null) { + waitDialog.dismiss(); + } + if (CollectionUtils.isEmpty(files)) { + showToast(res.getString(R.string.file_list_no_files)); + finish(); + } else if (adapter != null) { + adapter.notifyDataSetChanged(); } } }; @@ -188,10 +171,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")); @@ -237,7 +220,6 @@ public abstract class FileList<T extends ArrayAdapter<File>> extends AbstractLis } } - return; } /** diff --git a/main/src/cgeo/geocaching/files/FileParser.java b/main/src/cgeo/geocaching/files/FileParser.java index 20e757c..090573a 100644 --- a/main/src/cgeo/geocaching/files/FileParser.java +++ b/main/src/cgeo/geocaching/files/FileParser.java @@ -52,7 +52,7 @@ public abstract class FileParser { final BufferedReader input = new BufferedReader(new InputStreamReader(progressInputStream)); try { - String line = null; + String line; while ((line = input.readLine()) != null) { buffer.append(line); showProgressMessage(progressHandler, progressInputStream.getProgress()); diff --git a/main/src/cgeo/geocaching/files/GPXImporter.java b/main/src/cgeo/geocaching/files/GPXImporter.java index 4697a62..c669dcb 100644 --- a/main/src/cgeo/geocaching/files/GPXImporter.java +++ b/main/src/cgeo/geocaching/files/GPXImporter.java @@ -11,6 +11,7 @@ import cgeo.geocaching.activity.Progress; import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.enumerations.LoadFlags.SaveFlag;
import cgeo.geocaching.utils.CancellableHandler;
+import cgeo.geocaching.utils.Log;
import org.apache.commons.lang3.StringUtils;
@@ -23,7 +24,6 @@ import android.content.res.Resources; import android.net.Uri;
import android.os.Handler;
import android.os.Message;
-import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
@@ -34,7 +34,6 @@ import java.util.Collection; import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
-import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@@ -56,8 +55,8 @@ public class GPXImporter { public static final String WAYPOINTS_FILE_SUFFIX = "-wpts";
public static final String WAYPOINTS_FILE_SUFFIX_AND_EXTENSION = WAYPOINTS_FILE_SUFFIX + GPX_FILE_EXTENSION;
- private static final List<String> GPX_MIME_TYPES = Arrays.asList(new String[] { "text/xml", "application/xml" });
- private static final List<String> ZIP_MIME_TYPES = Arrays.asList(new String[] { "application/zip", "application/x-compressed", "application/x-zip-compressed", "application/x-zip", "application/octet-stream" });
+ private static final List<String> GPX_MIME_TYPES = Arrays.asList("text/xml", "application/xml");
+ private static final List<String> ZIP_MIME_TYPES = Arrays.asList("application/zip", "application/x-compressed", "application/x-zip-compressed", "application/x-zip", "application/octet-stream");
private Progress progress = new Progress();
@@ -113,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)) {
@@ -143,25 +142,29 @@ 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()));
- importStaticMaps(search);
+ boolean finishedWithoutCancel = importStaticMaps(search);
+ // Skip last message if static maps where canceled
+ if (!finishedWithoutCancel) {
+ return;
+ }
}
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()));
}
}
@@ -186,19 +189,20 @@ public class GPXImporter { return search;
}
- private void importStaticMaps(final SearchResult importedCaches) {
+ private boolean importStaticMaps(final SearchResult importedCaches) {
final cgeoapplication app = cgeoapplication.getInstance();
- Set<cgCache> caches = importedCaches.getCachesFromSearchResult(LoadFlags.LOAD_WAYPOINTS);
int storedCacheMaps = 0;
- for (cgCache cache : caches) {
- Log.d(Settings.tag, "GPXImporter.ImportThread.importStaticMaps start downloadMaps");
+ for (String geocode : importedCaches.getGeocodes()) {
+ cgCache cache = app.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS);
+ Log.d("GPXImporter.ImportThread.importStaticMaps start downloadMaps for cache " + geocode);
StaticMapsProvider.downloadMaps(cache, app);
storedCacheMaps++;
if (progressHandler.isCancelled()) {
- return;
+ return false;
}
progressHandler.sendMessage(progressHandler.obtainMessage(0, storedCacheMaps, 0));
}
+ return true;
}
}
@@ -212,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);
@@ -249,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);
@@ -257,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);
}
@@ -278,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 {
@@ -343,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
@@ -360,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
@@ -377,6 +381,8 @@ public class GPXImporter { };
final private Handler importStepHandler = new Handler() {
+ private boolean showProgressAfterCancel = false;
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -387,9 +393,16 @@ public class GPXImporter { case IMPORT_STEP_READ_FILE:
case IMPORT_STEP_READ_WPT_FILE:
+ progress.setProgressDivider(1024);
+ progress.setMessage(res.getString(msg.arg1));
+ progress.setMaxProgressAndReset(msg.arg2);
+ break;
+
case IMPORT_STEP_STORE_CACHES:
+ progress.setProgressDivider(1);
progress.setMessage(res.getString(msg.arg1));
progress.setMaxProgressAndReset(msg.arg2);
+ showProgressAfterCancel = true;
break;
case IMPORT_STEP_STORE_STATIC_MAPS:
@@ -401,6 +414,7 @@ public class GPXImporter { case IMPORT_STEP_STATIC_MAPS_SKIPPED:
progress.dismiss();
+ progressHandler.cancel();
StringBuilder bufferSkipped = new StringBuilder(20);
bufferSkipped.append(res.getString(R.string.gpx_import_static_maps_skipped)).append(", ").append(msg.arg1).append(' ').append(res.getString(R.string.gpx_import_caches_imported));
fromActivity.helpDialog(res.getString(R.string.gpx_import_title_caches_imported), bufferSkipped.toString());
@@ -426,7 +440,10 @@ public class GPXImporter { case IMPORT_STEP_CANCELED:
StringBuilder bufferCanceled = new StringBuilder(20);
- bufferCanceled.append(res.getString(R.string.gpx_import_canceled)).append(", ").append(progress.getProgress()).append(' ').append(res.getString(R.string.gpx_import_caches_imported));
+ bufferCanceled.append(res.getString(R.string.gpx_import_canceled));
+ if (showProgressAfterCancel) {
+ bufferCanceled.append(", ").append(progress.getProgress()).append(' ').append(res.getString(R.string.gpx_import_caches_imported));
+ }
fromActivity.showShortToast(bufferCanceled.toString());
importFinished();
break;
diff --git a/main/src/cgeo/geocaching/files/GPXParser.java b/main/src/cgeo/geocaching/files/GPXParser.java index e4e4e3a..7870a16 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.LogEntry; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; import cgeo.geocaching.StoredList; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgLog; import cgeo.geocaching.cgTrackable; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.cgeoapplication; @@ -15,6 +14,7 @@ import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.WaypointType; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.utils.CancellableHandler; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import org.xml.sax.Attributes; @@ -25,7 +25,6 @@ import android.sax.EndElementListener; import android.sax.EndTextElementListener; import android.sax.RootElement; import android.sax.StartElementListener; -import android.util.Log; import android.util.Xml; import java.io.IOException; @@ -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 = null; private String type = null; private String sym = null; @@ -194,7 +193,7 @@ public abstract class GPXParser extends FileParser { return null; // id not found } // get text for string - String stringName = null; + String stringName; try { stringName = cgeoapplication.getInstance().getResources().getResourceName(stringId); } catch (NullPointerException e) { @@ -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()); } } }); @@ -437,7 +436,7 @@ public abstract class GPXParser extends FileParser { @Override public void end(String watchList) { - cache.setOnWatchlist(Boolean.valueOf(watchList.trim()).booleanValue()); + cache.setOnWatchlist(Boolean.valueOf(watchList.trim())); } }); @@ -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("", 0, LogType.LOG_UNKNOWN, ""); 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); } } @@ -821,9 +820,9 @@ public abstract class GPXParser extends FileParser { private void createNoteFromGSAKUserdata() { if (StringUtils.isBlank(cache.getPersonalNote())) { final StringBuilder buffer = new StringBuilder(); - for (int i = 0; i < userData.length; i++) { - if (StringUtils.isNotBlank(userData[i])) { - buffer.append(' ').append(userData[i]); + for (final String anUserData : userData) { + if (StringUtils.isNotBlank(anUserData)) { + buffer.append(' ').append(anUserData); } } final String note = buffer.toString().trim(); diff --git a/main/src/cgeo/geocaching/files/LocParser.java b/main/src/cgeo/geocaching/files/LocParser.java index 029d049..b17b203 100644 --- a/main/src/cgeo/geocaching/files/LocParser.java +++ b/main/src/cgeo/geocaching/files/LocParser.java @@ -1,21 +1,17 @@ package cgeo.geocaching.files; import cgeo.geocaching.SearchResult; -import cgeo.geocaching.Settings; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgCoord; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.geopoint.GeopointParser; import cgeo.geocaching.utils.CancellableHandler; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; -import android.util.Log; - import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -30,6 +26,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public final class LocParser extends FileParser { + private static final Pattern patternGeocode = Pattern .compile("name id=\"([^\"]+)\""); private static final Pattern patternLat = Pattern @@ -45,10 +42,21 @@ public final class LocParser extends FileParser { .compile("<container>([^<]+)</container>"); private static final Pattern patternName = Pattern.compile("CDATA\\[([^\\]]+)\\]"); + private static final CacheSize[] SIZES = { + CacheSize.NOT_CHOSEN, // 1 + CacheSize.MICRO, // 2 + CacheSize.REGULAR, // 3 + CacheSize.LARGE, // 4 + CacheSize.VIRTUAL, // 5 + CacheSize.OTHER, // 6 + CacheSize.UNKNOWN, // 7 + CacheSize.SMALL, // 8 + }; + private int listId; public static void parseLoc(final SearchResult searchResult, final String fileContent) { - final Map<String, cgCoord> cidCoords = parseCoordinates(fileContent); + final Map<String, cgCache> cidCoords = parseCoordinates(fileContent); // save found cache coordinates final HashSet<String> contained = new HashSet<String>(); @@ -59,12 +67,12 @@ public final class LocParser extends FileParser { } Set<cgCache> caches = cgeoapplication.getInstance().loadCaches(contained, LoadFlags.LOAD_CACHE_OR_DB); for (cgCache cache : caches) { - cgCoord coord = cidCoords.get(cache.getGeocode()); + cgCache coord = cidCoords.get(cache.getGeocode()); copyCoordToCache(coord, cache); } } - private static void copyCoordToCache(final cgCoord coord, final cgCache cache) { + private static void copyCoordToCache(final cgCache coord, final cgCache cache) { cache.setCoords(coord.getCoords()); cache.setDifficulty(coord.getDifficulty()); cache.setTerrain(coord.getTerrain()); @@ -76,9 +84,8 @@ public final class LocParser extends FileParser { } } - static Map<String, cgCoord> parseCoordinates( - final String fileContent) { - final Map<String, cgCoord> coords = new HashMap<String, cgCoord>(); + static Map<String, cgCache> parseCoordinates(final String fileContent) { + final Map<String, cgCache> coords = new HashMap<String, cgCache>(); if (StringUtils.isBlank(fileContent)) { return coords; } @@ -88,76 +95,25 @@ public final class LocParser extends FileParser { // parse coordinates for (String pointString : points) { - final cgCoord pointCoord = new cgCoord(); - - final Matcher matcherGeocode = patternGeocode.matcher(pointString); - if (matcherGeocode.find()) { - String geocode = matcherGeocode.group(1).trim().toUpperCase(); - pointCoord.setName(geocode); - pointCoord.setGeocode(geocode); - } - final Matcher matcherName = patternName.matcher(pointString); - if (matcherName.find()) { - String name = matcherName.group(1).trim(); - pointCoord.setName(StringUtils.substringBeforeLast(name, " by ").trim()); - // owner = StringUtils.substringAfterLast(" by ").trim(); - } - final Matcher matcherLat = patternLat.matcher(pointString); - final Matcher matcherLon = patternLon.matcher(pointString); - if (matcherLat.find() && matcherLon.find()) { - pointCoord.setCoords(parsePoint(matcherLat.group(1).trim(), matcherLon.group(1).trim())); - } - final Matcher matcherDifficulty = patternDifficulty.matcher(pointString); - if (matcherDifficulty.find()) { - pointCoord.setDifficulty(Float.parseFloat(matcherDifficulty.group(1).trim())); - } - final Matcher matcherTerrain = patternTerrain.matcher(pointString); - if (matcherTerrain.find()) { - pointCoord.setTerrain(Float.parseFloat(matcherTerrain.group(1).trim())); - } - final Matcher matcherContainer = patternContainer.matcher(pointString); - if (matcherContainer.find()) { - final int size = Integer.parseInt(matcherContainer.group(1) - .trim()); - - if (size == 1) { - pointCoord.setSize(CacheSize.NOT_CHOSEN); - } else if (size == 2) { - pointCoord.setSize(CacheSize.MICRO); - } else if (size == 3) { - pointCoord.setSize(CacheSize.REGULAR); - } else if (size == 4) { - pointCoord.setSize(CacheSize.LARGE); - } else if (size == 5) { - pointCoord.setSize(CacheSize.VIRTUAL); - } else if (size == 6) { - pointCoord.setSize(CacheSize.OTHER); - } else if (size == 8) { - pointCoord.setSize(CacheSize.SMALL); - } else { - pointCoord.setSize(CacheSize.UNKNOWN); - } - } - + final cgCache pointCoord = parseCache(pointString); if (StringUtils.isNotBlank(pointCoord.getGeocode())) { coords.put(pointCoord.getGeocode(), pointCoord); } } - Log.i(Settings.tag, - "Coordinates found in .loc file: " + coords.size()); + Log.i("Coordinates found in .loc file: " + coords.size()); return coords; } - private static Geopoint parsePoint(String latitude, String longitude) { + public static Geopoint parsePoint(final String latitude, final String longitude) { // the loc file contains the coordinates as plain floating point values, therefore avoid using the GeopointParser 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); + return new Geopoint(latitude, longitude); } public LocParser(int listId) { @@ -168,10 +124,10 @@ public final class LocParser extends FileParser { public Collection<cgCache> parse(InputStream stream, CancellableHandler progressHandler) throws IOException, ParserException { // TODO: progress reporting happens during reading stream only, not during parsing String streamContent = readStream(stream, progressHandler).toString(); - final Map<String, cgCoord> coords = parseCoordinates(streamContent); + final Map<String, cgCache> coords = parseCoordinates(streamContent); final List<cgCache> caches = new ArrayList<cgCache>(); - for (Entry<String, cgCoord> entry : coords.entrySet()) { - cgCoord coord = entry.getValue(); + for (Entry<String, cgCache> entry : coords.entrySet()) { + cgCache coord = entry.getValue(); if (StringUtils.isBlank(coord.getGeocode()) || StringUtils.isBlank(coord.getName())) { continue; } @@ -185,7 +141,50 @@ 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; } + + public static cgCache parseCache(final String pointString) { + final cgCache cache = new cgCache(); + final Matcher matcherGeocode = patternGeocode.matcher(pointString); + if (matcherGeocode.find()) { + final String geocode = matcherGeocode.group(1).trim().toUpperCase(); + cache.setGeocode(geocode.toUpperCase()); + } + + final Matcher matcherName = patternName.matcher(pointString); + if (matcherName.find()) { + final String name = matcherName.group(1).trim(); + cache.setName(StringUtils.substringBeforeLast(name, " by ").trim()); + } else { + cache.setName(cache.getGeocode()); + } + + final Matcher matcherLat = patternLat.matcher(pointString); + final Matcher matcherLon = patternLon.matcher(pointString); + if (matcherLat.find() && matcherLon.find()) { + cache.setCoords(parsePoint(matcherLat.group(1).trim(), matcherLon.group(1).trim())); + } + + final Matcher matcherDifficulty = patternDifficulty.matcher(pointString); + if (matcherDifficulty.find()) { + cache.setDifficulty(Float.parseFloat(matcherDifficulty.group(1).trim())); + } + + final Matcher matcherTerrain = patternTerrain.matcher(pointString); + if (matcherTerrain.find()) { + cache.setTerrain(Float.parseFloat(matcherTerrain.group(1).trim())); + } + + final Matcher matcherContainer = patternContainer.matcher(pointString); + if (matcherContainer.find()) { + final int size = Integer.parseInt(matcherContainer.group(1).trim()); + if (size >= 1 && size <= 8) { + cache.setSize(SIZES[size - 1]); + } + } + + return cache; + } } diff --git a/main/src/cgeo/geocaching/files/LocalStorage.java b/main/src/cgeo/geocaching/files/LocalStorage.java index b5fa5f6..6853c08 100644 --- a/main/src/cgeo/geocaching/files/LocalStorage.java +++ b/main/src/cgeo/geocaching/files/LocalStorage.java @@ -1,18 +1,20 @@ package cgeo.geocaching.files; -import cgeo.geocaching.Settings; import cgeo.geocaching.utils.CryptUtils; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; +import org.apache.http.Header; import org.apache.http.HttpResponse; import android.os.Environment; -import android.util.Log; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -59,12 +61,7 @@ public class LocalStorage { */ static String getExtension(final String url) { final String urlExt = StringUtils.substringAfterLast(url, "."); - if (urlExt.length() > 4) { - return ""; - } else if (urlExt.length() > 0) { - return "." + urlExt; - } - return ""; + return urlExt.length() >= 1 && urlExt.length() <= 4 ? "." + urlExt : ""; } /** @@ -143,7 +140,7 @@ public class LocalStorage { * the entity whose content will be saved * @param targetFile * the target file, which will be created if necessary - * @return true if the operation was successful, false otherwise + * @return true if the operation was successful, false otherwise, in which case the file will not exist */ public static boolean saveEntityToFile(final HttpResponse response, final File targetFile) { if (response == null) { @@ -151,16 +148,65 @@ public class LocalStorage { } try { - return saveToFile(response.getEntity().getContent(), targetFile); + final boolean saved = saveToFile(response.getEntity().getContent(), targetFile); + saveHeader("etag", saved ? response : null, targetFile); + saveHeader("last-modified", saved ? response : null, targetFile); + return saved; } catch (IOException e) { - Log.e(Settings.tag, "LocalStorage.saveEntityToFile", e); + Log.e("LocalStorage.saveEntityToFile", e); } return false; } + private static void saveHeader(final String name, final HttpResponse response, final File baseFile) { + final Header header = response != null ? response.getFirstHeader(name) : null; + final File file = filenameForHeader(baseFile, name); + if (header == null) { + file.delete(); + } else { + saveToFile(new ByteArrayInputStream(header.getValue().getBytes()), file); + } + } + + private static File filenameForHeader(final File baseFile, final String name) { + return new File(baseFile.getAbsolutePath() + "-" + name); + } + + /** + * Get the saved header value for this file. + * + * @param baseFile + * the name of the cached resource + * @param name + * the name of the header ("etag" or "last-modified") + * @return null if no value has been cached, the value otherwise + */ + public static String getSavedHeader(final File baseFile, final String name) { + try { + final File file = filenameForHeader(baseFile, name); + final FileReader f = new FileReader(file); + try { + // No header will be more than 256 bytes + final char[] value = new char[256]; + final int count = f.read(value); + return new String(value, 0, count); + } finally { + f.close(); + } + } catch (final FileNotFoundException e) { + // Do nothing, the file does not exist + } catch (final Exception e) { + Log.w("could not read saved header " + name + " for " + baseFile, e); + } + return null; + } + /** * Save an HTTP response to a file. + * <p/> + * If the response could not be saved to the file due, for example, to a network error, + * the file will not exist when this method returns. * * @param entity * the entity whose content will be saved @@ -176,16 +222,18 @@ public class LocalStorage { try { try { final FileOutputStream fos = new FileOutputStream(targetFile); - try { - return copy(inputStream, fos); - } finally { - fos.close(); + final boolean written = copy(inputStream, fos); + fos.close(); + if (!written) { + targetFile.delete(); } + return written; } finally { inputStream.close(); } } catch (IOException e) { - Log.e(Settings.tag, "LocalStorage.saveToFile", e); + Log.e("LocalStorage.saveToFile", e); + targetFile.delete(); } return false; } @@ -208,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(); @@ -225,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; } @@ -233,15 +281,16 @@ public class LocalStorage { } private static boolean copy(final InputStream input, final OutputStream output) { - byte[] buffer = new byte[4096]; + final byte[] buffer = new byte[4096]; int length; try { while ((length = input.read(buffer)) > 0) { output.write(buffer, 0, length); } - output.flush(); // FIXME: is that necessary? + // 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; } @@ -267,7 +316,7 @@ public class LocalStorage { } } } - + return path.delete(); } 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 7b8992b..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; @@ -41,16 +41,20 @@ public class AttributeFilter extends AbstractFilter { 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 { - 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]); + @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]); + } + 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..05b97e0 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 IFilter[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 fa2af0d..5a00009 100644 --- a/main/src/cgeo/geocaching/gcvote/GCVote.java +++ b/main/src/cgeo/geocaching/gcvote/GCVote.java @@ -4,19 +4,17 @@ 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 android.util.Log; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -29,7 +27,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 @@ -59,13 +57,12 @@ public final class GCVote { } final Map<String, GCVoteRating> ratings = getRating(guids, geocodes); - if (ratings != null) { - for (Entry<String, GCVoteRating> entry : ratings.entrySet()) { - return entry.getValue(); - } + + if (MapUtils.isEmpty(ratings)) { + return null; } - return null; + return ratings.values().iterator().next(); } /** @@ -96,12 +93,12 @@ 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; } - String voteData = null; + String voteData; final Matcher matcherVoteElement = patternVoteElement.matcher(page); while (matcherVoteElement.find()) { voteData = matcherVoteElement.group(1); @@ -118,7 +115,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 +132,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 +142,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 +155,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 +169,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 +180,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 +217,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 +255,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 be4a622..974c902 100644 --- a/main/src/cgeo/geocaching/geopoint/Geopoint.java +++ b/main/src/cgeo/geocaching/geopoint/Geopoint.java @@ -1,25 +1,28 @@ package cgeo.geocaching.geopoint; -import cgeo.geocaching.Settings; +import cgeo.geocaching.ICoordinates; +import cgeo.geocaching.R; import cgeo.geocaching.geopoint.GeopointFormatter.Format; +import cgeo.geocaching.geopoint.direction.DDD; +import cgeo.geocaching.geopoint.direction.DMM; +import cgeo.geocaching.geopoint.direction.DMS; +import cgeo.geocaching.geopoint.direction.Direction; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import org.json.JSONArray; import org.json.JSONObject; import android.location.Location; -import android.util.Log; - -import java.math.BigDecimal; -import java.math.RoundingMode; +import android.os.Parcel; +import android.os.Parcelable; /** * 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,29 +50,18 @@ 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 * string to parse - * @throws GeopointParser.ParseException + * @throws Geopoint.ParseException * if the string cannot be parsed - * @see GeopointParser.parse() + * @see GeopointParser#parse(String) */ public Geopoint(final String text) { - this(GeopointParser.parseLatitude(text), GeopointParser.parseLongitude(text)); + final Geopoint parsed = GeopointParser.parse(text); + this.latitude = parsed.latitude; + this.longitude = parsed.longitude; } /** @@ -79,9 +71,9 @@ public final class Geopoint * latitude string to parse * @param lonText * longitude string to parse - * @throws GeopointParser.ParseException + * @throws Geopoint.ParseException * if any argument string cannot be parsed - * @see GeopointParser.parse() + * @see GeopointParser#parse(String, String) */ public Geopoint(final String latText, final String lonText) { this(GeopointParser.parseLatitude(latText), GeopointParser.parseLongitude(lonText)); @@ -90,7 +82,7 @@ public final class Geopoint /** * Creates new Geopoint with given Location. * - * @param gp + * @param loc * the Location to clone */ public Geopoint(final Location loc) { @@ -98,6 +90,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 +117,7 @@ public final class Geopoint */ public int getLatitudeE6() { - return (int) (latitude * 1E6); + return (int) Math.round(latitude * 1E6); } /** @@ -134,7 +137,7 @@ public final class Geopoint */ public int getLongitudeE6() { - return (int) (longitude * 1E6); + return (int) Math.round(longitude * 1E6); } /** @@ -200,16 +203,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 +250,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 @@ -299,188 +307,27 @@ public final class Geopoint return dms; } - /* Constant values needed for calculation */ - private static final double D60 = 60.0d; - private static final double D1000 = 1000.0d; - private static final double D3600 = 3600.0d; - private static final BigDecimal BD_SIXTY = BigDecimal.valueOf(D60); - private static final BigDecimal BD_THOUSAND = BigDecimal.valueOf(D1000); - private static final BigDecimal BD_ONEHOUNDREDTHOUSAND = BigDecimal.valueOf(100000.0d); - - /** - * Value type for the direction. - */ - public static class Direction { - /** latitude direction, 'N' or 'S' */ - public final char latDir; - /** longitude direction, 'E' or 'W' */ - public final char lonDir; - - private Direction(final double latSigned, final double lonSigned) { - latDir = latSigned < 0 ? 'S' : 'N'; - lonDir = lonSigned < 0 ? 'W' : 'E'; - } - - protected static String addZeros(final int value, final int len) { - return StringUtils.leftPad(Integer.toString(value), len, '0'); - } - } - - /** - * Value type for the DDD.DDDDD format. - */ - public static final class DDD extends Direction { - - /** latitude degree value */ - public final int latDeg; - /** fractional part of the latitude degree value */ - public final int latDegFrac; - - public final int lonDeg; - public final int lonDegFrac; - - private DDD(final double latSigned, final double lonSigned) { - super(latSigned, lonSigned); - BigDecimal bdLat = BigDecimal.valueOf(latSigned).abs(); - latDeg = bdLat.intValue(); - BigDecimal bdLatFrac = bdLat.subtract(BigDecimal.valueOf(latDeg)).multiply(BD_ONEHOUNDREDTHOUSAND); - latDegFrac = bdLatFrac.setScale(0, RoundingMode.HALF_UP).intValue(); - - BigDecimal bdlon = BigDecimal.valueOf(lonSigned).abs(); - lonDeg = bdlon.intValue(); - BigDecimal bdLonFrac = bdlon.subtract(BigDecimal.valueOf(lonDeg)).multiply(BD_ONEHOUNDREDTHOUSAND); - lonDegFrac = bdLonFrac.setScale(0, RoundingMode.HALF_UP).intValue(); - } - - public static Geopoint createGeopoint(final String latDir, final String latDeg, final String latDegFrac, - final String lonDir, final String lonDeg, final String lonDegFrac) { - double lat = 0.0d; - double lon = 0.0d; - try { - lat = Double.parseDouble(latDeg + "." + addZeros(Integer.parseInt(latDegFrac), 5)); - lon = Double.parseDouble(lonDeg + "." + addZeros(Integer.parseInt(lonDegFrac), 5)); - } catch (NumberFormatException e) { - } - lat *= "S".equalsIgnoreCase(latDir) ? -1 : 1; - lon *= "W".equalsIgnoreCase(lonDir) ? -1 : 1; - return new Geopoint(lat, lon); - } - } - - public static final class DMM extends Direction { - - public final int latDeg; - public final double latMinRaw; - public final int latMin; - public final int latMinFrac; - - public final int lonDeg; - public final double lonMinRaw; - public final int lonMin; - public final int lonMinFrac; - - private DMM(final double latSigned, final double lonSigned) { - super(latSigned, lonSigned); - BigDecimal bdLat = BigDecimal.valueOf(latSigned).abs(); - latDeg = bdLat.intValue(); - BigDecimal bdLatMin = bdLat.subtract(BigDecimal.valueOf(latDeg)).multiply(BD_SIXTY); - // Rounding here ... - bdLatMin = bdLatMin.setScale(3, RoundingMode.HALF_UP); - latMinRaw = bdLatMin.doubleValue(); - latMin = bdLatMin.intValue(); - BigDecimal bdLatMinFrac = bdLatMin.subtract(BigDecimal.valueOf(latMin)).multiply(BD_THOUSAND); - latMinFrac = bdLatMinFrac.setScale(0, RoundingMode.HALF_UP).intValue(); - - BigDecimal bdlon = BigDecimal.valueOf(lonSigned).abs(); - lonDeg = bdlon.intValue(); - BigDecimal bdLonMin = bdlon.subtract(BigDecimal.valueOf(lonDeg)).multiply(BD_SIXTY); - // Rounding here ... - bdLonMin = bdLonMin.setScale(3, RoundingMode.HALF_UP); - lonMinRaw = bdLonMin.doubleValue(); - lonMin = bdLonMin.intValue(); - BigDecimal bdLonMinFrac = bdLonMin.subtract(BigDecimal.valueOf(lonMin)).multiply(BD_THOUSAND); - lonMinFrac = bdLonMinFrac.setScale(0, RoundingMode.HALF_UP).intValue(); - } - - public static Geopoint createGeopoint(final String latDir, final String latDeg, final String latMin, final String latMinFrac, - final String lonDir, final String lonDeg, final String lonMin, final String lonMinFrac) { - double lat = 0.0d; - double lon = 0.0d; - try { - lat = Double.parseDouble(latDeg) + Double.parseDouble(latMin + "." + addZeros(Integer.parseInt(latMinFrac), 3)) / D60; - lon = Double.parseDouble(lonDeg) + Double.parseDouble(lonMin + "." + addZeros(Integer.parseInt(lonMinFrac), 3)) / D60; - } catch (NumberFormatException e) { - } - lat *= "S".equalsIgnoreCase(latDir) ? -1 : 1; - lon *= "W".equalsIgnoreCase(lonDir) ? -1 : 1; - return new Geopoint(lat, lon); - } - } - - public static final class DMS extends Direction { - - public final int latDeg; - public final int latMin; - public final double latSecRaw; - public final int latSec; - public final int latSecFrac; - - public final int lonDeg; - public final int lonMin; - public final double lonSecRaw; - public final int lonSec; - public final int lonSecFrac; - - private DMS(final double latSigned, final double lonSigned) { - super(latSigned, lonSigned); - BigDecimal bdLat = BigDecimal.valueOf(latSigned).abs(); - latDeg = bdLat.intValue(); - BigDecimal bdLatMin = bdLat.subtract(BigDecimal.valueOf(latDeg)).multiply(BD_SIXTY); - latMin = bdLatMin.intValue(); - BigDecimal bdLatSec = bdLatMin.subtract(BigDecimal.valueOf(latMin)).multiply(BD_SIXTY); - // Rounding here ... - bdLatSec = bdLatSec.setScale(3, RoundingMode.HALF_UP); - latSecRaw = bdLatSec.doubleValue(); - latSec = bdLatSec.intValue(); - BigDecimal bdLatSecFrac = bdLatSec.subtract(BigDecimal.valueOf(latSec)).multiply(BD_THOUSAND); - latSecFrac = bdLatSecFrac.setScale(0, RoundingMode.HALF_UP).intValue(); - - BigDecimal bdlon = BigDecimal.valueOf(lonSigned).abs(); - lonDeg = bdlon.intValue(); - BigDecimal bdLonMin = bdlon.subtract(BigDecimal.valueOf(lonDeg)).multiply(BD_SIXTY); - lonMin = bdLonMin.intValue(); - BigDecimal bdLonSec = bdLonMin.subtract(BigDecimal.valueOf(lonMin)).multiply(BD_SIXTY); - // Rounding here ... - bdLonSec = bdLonSec.setScale(3, RoundingMode.HALF_UP); - lonSecRaw = bdLonSec.doubleValue(); - lonSec = bdLonSec.intValue(); - BigDecimal bdLonSecFrac = bdLonSec.subtract(BigDecimal.valueOf(lonSec)).multiply(BD_THOUSAND); - lonSecFrac = bdLonSecFrac.setScale(0, RoundingMode.HALF_UP).intValue(); - } + abstract public static class GeopointException + extends RuntimeException + { + private static final long serialVersionUID = 1L; - public static Geopoint createGeopoint(final String latDir, final String latDeg, final String latMin, final String latSec, final String latSecFrac, - final String lonDir, final String lonDeg, final String lonMin, final String lonSec, final String lonSecFrac) { - double lat = 0.0d; - double lon = 0.0d; - try { - lat = Double.parseDouble(latDeg) + Double.parseDouble(latMin) / D60 + Double.parseDouble(latSec + "." + addZeros(Integer.parseInt(latSecFrac), 3)) / D3600; - lon = Double.parseDouble(lonDeg) + Double.parseDouble(lonMin) / D60 + Double.parseDouble(lonSec + "." + addZeros(Integer.parseInt(lonSecFrac), 3)) / D3600; - } catch (NumberFormatException e) { - } - lat *= "S".equalsIgnoreCase(latDir) ? -1 : 1; - lon *= "W".equalsIgnoreCase(lonDir) ? -1 : 1; - return new Geopoint(lat, lon); + public GeopointException(String msg) + { + super(msg); } } - abstract public static class GeopointException - extends RuntimeException + public static class ParseException + extends GeopointException { private static final long serialVersionUID = 1L; + public final int resource; - public GeopointException(String msg) + public ParseException(final String msg, final GeopointParser.LatLon faulty) { super(msg); + resource = faulty == GeopointParser.LatLon.LAT ? R.string.err_parse_lat : R.string.err_parse_lon; } } @@ -506,10 +353,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/GeopointFormatter.java b/main/src/cgeo/geocaching/geopoint/GeopointFormatter.java index d0baee9..43f83a3 100644 --- a/main/src/cgeo/geocaching/geopoint/GeopointFormatter.java +++ b/main/src/cgeo/geocaching/geopoint/GeopointFormatter.java @@ -1,7 +1,7 @@ package cgeo.geocaching.geopoint; -import cgeo.geocaching.geopoint.Geopoint.DMM; -import cgeo.geocaching.geopoint.Geopoint.DMS; +import cgeo.geocaching.geopoint.direction.DMM; +import cgeo.geocaching.geopoint.direction.DMS; import java.util.Locale; diff --git a/main/src/cgeo/geocaching/geopoint/GeopointParser.java b/main/src/cgeo/geocaching/geopoint/GeopointParser.java index ad5d6ba..7604b9d 100644 --- a/main/src/cgeo/geocaching/geopoint/GeopointParser.java +++ b/main/src/cgeo/geocaching/geopoint/GeopointParser.java @@ -1,7 +1,5 @@ package cgeo.geocaching.geopoint; -import cgeo.geocaching.R; -import cgeo.geocaching.geopoint.Geopoint.GeopointException; import org.apache.commons.lang3.StringUtils; @@ -11,8 +9,7 @@ import java.util.regex.Pattern; /** * Parse coordinates. */ -public class GeopointParser -{ +class GeopointParser { private static class ResultWrapper { final double result; final int matcherPos; @@ -29,7 +26,7 @@ public class GeopointParser private static final Pattern patternLat = Pattern.compile("\\b([NS])\\s*(\\d+)°?(?:\\s*(\\d+)(?:[.,](\\d+)|'?\\s*(\\d+(?:[.,]\\d+)?)(?:''|\")?)?)?", Pattern.CASE_INSENSITIVE); private static final Pattern patternLon = Pattern.compile("\\b([WE])\\s*(\\d+)°?(?:\\s*(\\d+)(?:[.,](\\d+)|'?\\s*(\\d+(?:[.,]\\d+)?)(?:''|\")?)?)?", Pattern.CASE_INSENSITIVE); - private enum LatLon + enum LatLon { LAT, LON @@ -52,7 +49,7 @@ public class GeopointParser * @param text * the string to parse * @return an Geopoint with parsed latitude and longitude - * @throws ParseException + * @throws Geopoint.ParseException * if lat or lon could not be parsed */ public static Geopoint parse(final String text) @@ -63,7 +60,7 @@ public class GeopointParser final ResultWrapper longitudeWrapper = parseHelper(text.substring(latitudeWrapper.matcherPos + latitudeWrapper.matcherLength), LatLon.LON); if (longitudeWrapper.matcherPos - (latitudeWrapper.matcherPos + latitudeWrapper.matcherLength) >= 10) { - throw new ParseException("Distance between latitude and longitude text is to large.", LatLon.LON); + throw new Geopoint.ParseException("Distance between latitude and longitude text is to large.", LatLon.LON); } final double lon = longitudeWrapper.result; @@ -89,7 +86,7 @@ public class GeopointParser * @param longitude * the longitude string to parse * @return an Geopoint with parsed latitude and longitude - * @throws ParseException + * @throws Geopoint.ParseException * if lat or lon could not be parsed */ public static Geopoint parse(final String latitude, final String longitude) @@ -129,32 +126,31 @@ public class GeopointParser return new ResultWrapper(sign * (degree + minutes / 60.0 + seconds / 3600.0), matcher.start(), matcher.group().length()); - } else { + } - // Nothing found with "N 52...", try to match string as decimaldegree - try { - final String[] items = StringUtils.split(text.trim()); - if (items.length > 0) { - final int index = (latlon == LatLon.LON ? items.length - 1 : 0); - final int pos = (latlon == LatLon.LON ? text.lastIndexOf(items[index]) : text.indexOf(items[index])); - return new ResultWrapper(Double.parseDouble(items[index]), pos, items[index].length()); - } - } catch (NumberFormatException e) { - // The right exception will be raised below. + // Nothing found with "N 52...", try to match string as decimaldegree + try { + final String[] items = StringUtils.split(text.trim()); + if (items.length > 0) { + final int index = (latlon == LatLon.LON ? items.length - 1 : 0); + final int pos = (latlon == LatLon.LON ? text.lastIndexOf(items[index]) : text.indexOf(items[index])); + return new ResultWrapper(Double.parseDouble(items[index]), pos, items[index].length()); } + } catch (NumberFormatException e) { + // The right exception will be raised below. } - throw new ParseException("Could not parse coordinates as " + latlon + ": \"" + text + "\"", latlon); + throw new Geopoint.ParseException("Could not parse coordinates as " + latlon + ": \"" + text + "\"", latlon); } /** * Parses latitude out of a given string. * - * @see parse() + * @see #parse(String) * @param text * the string to be parsed * @return the latitude as decimal degree - * @throws ParseException + * @throws Geopoint.ParseException * if latitude could not be parsed */ public static double parseLatitude(final String text) @@ -165,28 +161,15 @@ public class GeopointParser /** * Parses longitude out of a given string. * - * @see parse() + * @see #parse(String) * @param text * the string to be parsed * @return the longitude as decimal degree - * @throws ParseException + * @throws Geopoint.ParseException * if longitude could not be parsed */ public static double parseLongitude(final String text) { return parseHelper(text, LatLon.LON).result; } - - public static class ParseException - extends GeopointException - { - private static final long serialVersionUID = 1L; - public final int resource; - - public ParseException(final String msg, final LatLon faulty) - { - super(msg); - resource = faulty == LatLon.LAT ? R.string.err_parse_lat : R.string.err_parse_lon; - } - } } diff --git a/main/src/cgeo/geocaching/geopoint/HumanDistance.java b/main/src/cgeo/geocaching/geopoint/HumanDistance.java index 278bb7b..25d1bb7 100644 --- a/main/src/cgeo/geocaching/geopoint/HumanDistance.java +++ b/main/src/cgeo/geocaching/geopoint/HumanDistance.java @@ -2,41 +2,48 @@ package cgeo.geocaching.geopoint; import cgeo.geocaching.Settings; +import org.apache.commons.lang3.tuple.ImmutablePair; + public class HumanDistance { - public static String getHumanDistance(final Float distanceKilometers) { - if (distanceKilometers == null) { - return "?"; - } + public static ImmutablePair<Double, String> scaleUnit(final double distanceKilometers) { + double distance; + String units; if (Settings.isUseMetricUnits()) { - if (distanceKilometers > 100) { - return String.format("%d", Math.round(distanceKilometers)) + " km"; - } else if (distanceKilometers > 10) { - return String.format("%.1f", Double.valueOf(Math.round(distanceKilometers * 10.0) / 10.0)) + " km"; - } else if (distanceKilometers > 1) { - return String.format("%.2f", Double.valueOf(Math.round(distanceKilometers * 100.0) / 100.0)) + " km"; - } else if (distanceKilometers > 0.1) { - return String.format("%d", Math.round(distanceKilometers * 1000.0)) + " m"; - } else if (distanceKilometers > 0.01) { - return String.format("%.1f", Double.valueOf(Math.round(distanceKilometers * 1000.0 * 10.0) / 10.0)) + " m"; + if (distanceKilometers >= 1) { + distance = distanceKilometers; + units = "km"; } else { - return String.format("%.2f", Double.valueOf(Math.round(distanceKilometers * 1000.0 * 100.0) / 100.0)) + " m"; + distance = distanceKilometers * 1000; + units = "m"; } } else { - final float miles = distanceKilometers / IConversion.MILES_TO_KILOMETER; - if (distanceKilometers > 100) { - return String.format("%d", Math.round(miles)) + " mi"; - } else if (distanceKilometers > 0.5) { - return String.format("%.1f", Double.valueOf(Math.round(miles * 10.0) / 10.0)) + " mi"; - } else if (distanceKilometers > 0.1) { - return String.format("%.2f", Double.valueOf(Math.round(miles * 100.0) / 100.0)) + " mi"; - } else if (distanceKilometers > 0.05) { - return String.format("%d", Math.round(miles * 5280.0)) + " ft"; - } else if (distanceKilometers > 0.01) { - return String.format("%.1f", Double.valueOf(Math.round(miles * 5280 * 10.0) / 10.0)) + " ft"; + distance = distanceKilometers / IConversion.MILES_TO_KILOMETER; + if (distance >= 0.1) { + units = "mi"; } else { - return String.format("%.2f", Double.valueOf(Math.round(miles * 5280 * 100.0) / 100.0)) + " ft"; + distance *= 5280; + units = "ft"; } } + return new ImmutablePair<Double, String>(distance, units); + } + + public static String getHumanDistance(final Float distanceKilometers) { + if (distanceKilometers == null) { + return "?"; + } + + final ImmutablePair<Double, String> scaled = scaleUnit(distanceKilometers); + String formatString; + if (scaled.left >= 100) { + formatString = "%.0f"; + } else if (scaled.left >= 10) { + formatString = "%.1f"; + } else { + formatString = "%.2f"; + } + + return String.format(formatString + " %s", scaled.left, scaled.right); } } diff --git a/main/src/cgeo/geocaching/geopoint/Viewport.java b/main/src/cgeo/geocaching/geopoint/Viewport.java index 4d46970..1eeadce 100644 --- a/main/src/cgeo/geocaching/geopoint/Viewport.java +++ b/main/src/cgeo/geocaching/geopoint/Viewport.java @@ -1,8 +1,11 @@ package cgeo.geocaching.geopoint; -import cgeo.geocaching.Settings; +import cgeo.geocaching.ICoordinates; + +import java.util.Locale; +import java.util.Set; + -import android.util.Log; public class Viewport { @@ -10,19 +13,25 @@ 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 double getLatitudeMin() { @@ -45,78 +54,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). + * Return the "where" part of the string appropriate for a SQL query. * - * expects coordinates in E6 format + * @param dbTable + * the database table to use as prefix, or null if no prefix is required + * @return the string without the "where" keyword + */ + 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()); + } + + /** + * Return a widened or shrunk viewport. * - * @param centerLat1 - * @param centerLon1 - * @param centerLat2 - * @param centerLon2 - * @param spanLat1 - * @param spanLon1 - * @param spanLat2 - * @param spanLon2 - * @return + * @param factor + * multiplicative factor for the latitude and longitude span (> 1 to widen, < 1 to shrink) + * @return a widened or shrunk viewport */ - 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 Viewport resize(final double factor) { + return new Viewport(getCenter(), getLatitudeSpan() * factor, getLongitudeSpan() * factor); + } - final int right1 = centerLat1 + (spanLat1 / 2); - final int right2 = centerLat2 + (spanLat2 / 2); - if (right2 >= right1) { - 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; + } - final int top1 = centerLon1 + (spanLon1 / 2); - final int top2 = centerLon2 + (spanLon2 / 2); - if (top2 >= top1) { - return false; - } + 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) { + if (point != null && point.getCoords() != null) { + if (viewport == null) { + viewport = new Viewport(point, point); + } else { + viewport = viewport.expand(point); + } } + } + 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/geopoint/direction/DDD.java b/main/src/cgeo/geocaching/geopoint/direction/DDD.java new file mode 100644 index 0000000..939d6ca --- /dev/null +++ b/main/src/cgeo/geocaching/geopoint/direction/DDD.java @@ -0,0 +1,47 @@ +package cgeo.geocaching.geopoint.direction; + +import cgeo.geocaching.geopoint.Geopoint; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * Value type for the DDD.DDDDD format. + */ +public final class DDD extends Direction { + + /** latitude degree value */ + public final int latDeg; + /** fractional part of the latitude degree value */ + public final int latDegFrac; + + public final int lonDeg; + public final int lonDegFrac; + + public DDD(final double latSigned, final double lonSigned) { + super(latSigned, lonSigned); + BigDecimal bdLat = BigDecimal.valueOf(latSigned).abs(); + latDeg = bdLat.intValue(); + BigDecimal bdLatFrac = bdLat.subtract(BigDecimal.valueOf(latDeg)).multiply(BD_ONEHOUNDREDTHOUSAND); + latDegFrac = bdLatFrac.setScale(0, RoundingMode.HALF_UP).intValue(); + + BigDecimal bdlon = BigDecimal.valueOf(lonSigned).abs(); + lonDeg = bdlon.intValue(); + BigDecimal bdLonFrac = bdlon.subtract(BigDecimal.valueOf(lonDeg)).multiply(BD_ONEHOUNDREDTHOUSAND); + lonDegFrac = bdLonFrac.setScale(0, RoundingMode.HALF_UP).intValue(); + } + + public static Geopoint createGeopoint(final String latDir, final String latDeg, final String latDegFrac, + final String lonDir, final String lonDeg, final String lonDegFrac) { + double lat = 0.0d; + double lon = 0.0d; + try { + lat = Double.parseDouble(latDeg + "." + addZeros(Integer.parseInt(latDegFrac), 5)); + lon = Double.parseDouble(lonDeg + "." + addZeros(Integer.parseInt(lonDegFrac), 5)); + } catch (NumberFormatException e) { + } + lat *= "S".equalsIgnoreCase(latDir) ? -1 : 1; + lon *= "W".equalsIgnoreCase(lonDir) ? -1 : 1; + return new Geopoint(lat, lon); + } +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/geopoint/direction/DMM.java b/main/src/cgeo/geocaching/geopoint/direction/DMM.java new file mode 100644 index 0000000..7426f28 --- /dev/null +++ b/main/src/cgeo/geocaching/geopoint/direction/DMM.java @@ -0,0 +1,56 @@ +package cgeo.geocaching.geopoint.direction; + +import cgeo.geocaching.geopoint.Geopoint; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +public final class DMM extends Direction { + + public final int latDeg; + public final double latMinRaw; + public final int latMin; + public final int latMinFrac; + + public final int lonDeg; + public final double lonMinRaw; + public final int lonMin; + public final int lonMinFrac; + + public DMM(final double latSigned, final double lonSigned) { + super(latSigned, lonSigned); + BigDecimal bdLat = BigDecimal.valueOf(latSigned).abs(); + latDeg = bdLat.intValue(); + BigDecimal bdLatMin = bdLat.subtract(BigDecimal.valueOf(latDeg)).multiply(BD_SIXTY); + // Rounding here ... + bdLatMin = bdLatMin.setScale(3, RoundingMode.HALF_UP); + latMinRaw = bdLatMin.doubleValue(); + latMin = bdLatMin.intValue(); + BigDecimal bdLatMinFrac = bdLatMin.subtract(BigDecimal.valueOf(latMin)).multiply(BD_THOUSAND); + latMinFrac = bdLatMinFrac.setScale(0, RoundingMode.HALF_UP).intValue(); + + BigDecimal bdlon = BigDecimal.valueOf(lonSigned).abs(); + lonDeg = bdlon.intValue(); + BigDecimal bdLonMin = bdlon.subtract(BigDecimal.valueOf(lonDeg)).multiply(BD_SIXTY); + // Rounding here ... + bdLonMin = bdLonMin.setScale(3, RoundingMode.HALF_UP); + lonMinRaw = bdLonMin.doubleValue(); + lonMin = bdLonMin.intValue(); + BigDecimal bdLonMinFrac = bdLonMin.subtract(BigDecimal.valueOf(lonMin)).multiply(BD_THOUSAND); + lonMinFrac = bdLonMinFrac.setScale(0, RoundingMode.HALF_UP).intValue(); + } + + public static Geopoint createGeopoint(final String latDir, final String latDeg, final String latMin, final String latMinFrac, + final String lonDir, final String lonDeg, final String lonMin, final String lonMinFrac) { + double lat = 0.0d; + double lon = 0.0d; + try { + lat = Double.parseDouble(latDeg) + Double.parseDouble(latMin + "." + addZeros(Integer.parseInt(latMinFrac), 3)) / D60; + lon = Double.parseDouble(lonDeg) + Double.parseDouble(lonMin + "." + addZeros(Integer.parseInt(lonMinFrac), 3)) / D60; + } catch (NumberFormatException e) { + } + lat *= "S".equalsIgnoreCase(latDir) ? -1 : 1; + lon *= "W".equalsIgnoreCase(lonDir) ? -1 : 1; + return new Geopoint(lat, lon); + } +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/geopoint/direction/DMS.java b/main/src/cgeo/geocaching/geopoint/direction/DMS.java new file mode 100644 index 0000000..34a9a3d --- /dev/null +++ b/main/src/cgeo/geocaching/geopoint/direction/DMS.java @@ -0,0 +1,62 @@ +package cgeo.geocaching.geopoint.direction; + +import cgeo.geocaching.geopoint.Geopoint; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +public final class DMS extends Direction { + + public final int latDeg; + public final int latMin; + public final double latSecRaw; + public final int latSec; + public final int latSecFrac; + + public final int lonDeg; + public final int lonMin; + public final double lonSecRaw; + public final int lonSec; + public final int lonSecFrac; + + public DMS(final double latSigned, final double lonSigned) { + super(latSigned, lonSigned); + BigDecimal bdLat = BigDecimal.valueOf(latSigned).abs(); + latDeg = bdLat.intValue(); + BigDecimal bdLatMin = bdLat.subtract(BigDecimal.valueOf(latDeg)).multiply(BD_SIXTY); + latMin = bdLatMin.intValue(); + BigDecimal bdLatSec = bdLatMin.subtract(BigDecimal.valueOf(latMin)).multiply(BD_SIXTY); + // Rounding here ... + bdLatSec = bdLatSec.setScale(3, RoundingMode.HALF_UP); + latSecRaw = bdLatSec.doubleValue(); + latSec = bdLatSec.intValue(); + BigDecimal bdLatSecFrac = bdLatSec.subtract(BigDecimal.valueOf(latSec)).multiply(BD_THOUSAND); + latSecFrac = bdLatSecFrac.setScale(0, RoundingMode.HALF_UP).intValue(); + + BigDecimal bdlon = BigDecimal.valueOf(lonSigned).abs(); + lonDeg = bdlon.intValue(); + BigDecimal bdLonMin = bdlon.subtract(BigDecimal.valueOf(lonDeg)).multiply(BD_SIXTY); + lonMin = bdLonMin.intValue(); + BigDecimal bdLonSec = bdLonMin.subtract(BigDecimal.valueOf(lonMin)).multiply(BD_SIXTY); + // Rounding here ... + bdLonSec = bdLonSec.setScale(3, RoundingMode.HALF_UP); + lonSecRaw = bdLonSec.doubleValue(); + lonSec = bdLonSec.intValue(); + BigDecimal bdLonSecFrac = bdLonSec.subtract(BigDecimal.valueOf(lonSec)).multiply(BD_THOUSAND); + lonSecFrac = bdLonSecFrac.setScale(0, RoundingMode.HALF_UP).intValue(); + } + + public static Geopoint createGeopoint(final String latDir, final String latDeg, final String latMin, final String latSec, final String latSecFrac, + final String lonDir, final String lonDeg, final String lonMin, final String lonSec, final String lonSecFrac) { + double lat = 0.0d; + double lon = 0.0d; + try { + lat = Double.parseDouble(latDeg) + Double.parseDouble(latMin) / D60 + Double.parseDouble(latSec + "." + addZeros(Integer.parseInt(latSecFrac), 3)) / D3600; + lon = Double.parseDouble(lonDeg) + Double.parseDouble(lonMin) / D60 + Double.parseDouble(lonSec + "." + addZeros(Integer.parseInt(lonSecFrac), 3)) / D3600; + } catch (NumberFormatException e) { + } + lat *= "S".equalsIgnoreCase(latDir) ? -1 : 1; + lon *= "W".equalsIgnoreCase(lonDir) ? -1 : 1; + return new Geopoint(lat, lon); + } +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/geopoint/direction/Direction.java b/main/src/cgeo/geocaching/geopoint/direction/Direction.java new file mode 100644 index 0000000..ad91516 --- /dev/null +++ b/main/src/cgeo/geocaching/geopoint/direction/Direction.java @@ -0,0 +1,29 @@ +package cgeo.geocaching.geopoint.direction; + +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; + +public class Direction { + /* Constant values needed for calculation */ + static final double D60 = 60.0d; + private static final double D1000 = 1000.0d; + static final double D3600 = 3600.0d; + static final BigDecimal BD_SIXTY = BigDecimal.valueOf(D60); + static final BigDecimal BD_THOUSAND = BigDecimal.valueOf(D1000); + static final BigDecimal BD_ONEHOUNDREDTHOUSAND = BigDecimal.valueOf(100000.0d); + + /** latitude direction, 'N' or 'S' */ + public final char latDir; + /** longitude direction, 'E' or 'W' */ + public final char lonDir; + + public Direction(final double latSigned, final double lonSigned) { + latDir = latSigned < 0 ? 'S' : 'N'; + lonDir = lonSigned < 0 ? 'W' : 'E'; + } + + protected static String addZeros(final int value, final int len) { + return StringUtils.leftPad(Integer.toString(value), len, '0'); + } +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/go4cache/Go4Cache.java b/main/src/cgeo/geocaching/go4cache/Go4Cache.java index fb53c27..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; @@ -9,13 +8,15 @@ import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.utils.CryptUtils; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import android.util.Log; +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/go4cache/Go4CacheUser.java b/main/src/cgeo/geocaching/go4cache/Go4CacheUser.java index 606d8f3..08fd02e 100644 --- a/main/src/cgeo/geocaching/go4cache/Go4CacheUser.java +++ b/main/src/cgeo/geocaching/go4cache/Go4CacheUser.java @@ -44,14 +44,16 @@ public class Go4CacheUser { } public int getIconId() { - if (null == client) { + if (client == null) { return -1; } if (client.equalsIgnoreCase("c:geo")) { return R.drawable.client_cgeo; - } else if (client.equalsIgnoreCase("preCaching")) { + } + if (client.equalsIgnoreCase("preCaching")) { return R.drawable.client_precaching; - } else if (client.equalsIgnoreCase("Handy Geocaching")) { + } + if (client.equalsIgnoreCase("Handy Geocaching")) { return R.drawable.client_handygeocaching; } return -1; diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java index a1f703d..18815af 100644 --- a/main/src/cgeo/geocaching/maps/CGeoMap.java +++ b/main/src/cgeo/geocaching/maps/CGeoMap.java @@ -1,23 +1,23 @@ package cgeo.geocaching.maps; +import cgeo.geocaching.GeoObserver; +import cgeo.geocaching.IGeoData; +import cgeo.geocaching.IWaypoint; import cgeo.geocaching.LiveMapInfo; import cgeo.geocaching.R; import cgeo.geocaching.SearchResult; import cgeo.geocaching.Settings; import cgeo.geocaching.StoredList; import cgeo.geocaching.UpdateDirectionCallback; -import cgeo.geocaching.UpdateLocationCallback; -import cgeo.geocaching.cgBase; +import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgCoord; import cgeo.geocaching.cgDirection; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.cgeoapplication; 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,9 @@ import cgeo.geocaching.maps.interfaces.MapProvider; import cgeo.geocaching.maps.interfaces.MapViewImpl; import cgeo.geocaching.maps.interfaces.OnMapDragListener; import cgeo.geocaching.maps.interfaces.OtherCachersOverlayItemImpl; -import cgeo.geocaching.network.Login; import cgeo.geocaching.utils.CancellableHandler; -import cgeo.geocaching.utils.LRUList; +import cgeo.geocaching.utils.LeastRecentlyUsedSet; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -54,7 +54,7 @@ import android.graphics.drawable.LayerDrawable; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.util.Log; +import android.util.SparseArray; import android.view.Menu; import android.view.MenuItem; import android.view.SubMenu; @@ -67,10 +67,8 @@ import android.widget.TextView; import android.widget.ViewSwitcher.ViewFactory; import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; @@ -95,8 +93,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"; @@ -116,6 +113,7 @@ 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; @@ -123,9 +121,8 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private MapViewImpl mapView = null; private MapControllerImpl mapController = null; private cgeoapplication app = null; - private cgGeo geo = null; private cgDirection dir = null; - private UpdateLocationCallback geoUpdate = new UpdateLoc(); + final private GeoObserver geoUpdate = new UpdateLoc(); private UpdateDirectionCallback dirUpdate = new UpdateDir(); private SearchResult searchIntent = null; private String geocodeIntent = null; @@ -138,14 +135,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; @@ -170,10 +161,12 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private static final int[][] INSET_USERMODIFIEDCOORDS = { { 21, 28, 0, 0 }, { 19, 25, 0, 0 } }; // bottom right, 12x12 / 26x26 private static final int[][] INSET_PERSONALNOTE = { { 0, 28, 21, 0 }, { 0, 25, 19, 0 } }; // bottom left, 12x12 / 26x26 - private static Map<Integer, LayerDrawable> overlaysCache = new HashMap<Integer, LayerDrawable>(); + private static SparseArray<LayerDrawable> overlaysCache = new SparseArray<LayerDrawable>(); private int cachesCnt = 0; /** List of caches in the viewport */ - private final LRUList<cgCache> caches = new LRUList<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; @@ -289,9 +282,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto waitDialog.setOnCancelListener(null); } - if (geo == null) { - geo = app.startGeo(geoUpdate); - } if (Settings.isUseCompass() && dir == null) { dir = app.startDir(activity, dirUpdate); } @@ -304,9 +294,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto loadDetailsThread.stopIt(); } - if (geo == null) { - geo = app.startGeo(geoUpdate); - } if (Settings.isUseCompass() && dir == null) { dir = app.startDir(activity, dirUpdate); } @@ -337,19 +324,15 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } 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++; } } @@ -361,6 +344,7 @@ 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 @@ -373,34 +357,29 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto app = (cgeoapplication) activity.getApplication(); mapProvider = Settings.getMapProvider(); - // Restore previously saved map source if any - if (savedInstanceState != null) { - currentSourceId = savedInstanceState.getInt(BUNDLE_MAP_SOURCE, Settings.getMapSource()); - } else { - currentSourceId = Settings.getMapSource(); - } - // get parameters - Bundle extras = activity.getIntent().getExtras(); + // 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); - final double latitudeIntent = extras.getDouble(EXTRAS_LATITUDE); - final double longitudeIntent = extras.getDouble(EXTRAS_LONGITUDE); - coordsIntent = new Geopoint(latitudeIntent, longitudeIntent); + 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 (coordsIntent.getLatitude() == 0.0 || coordsIntent.getLongitude() == 0.0) { - coordsIntent = null; - } } - 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; @@ -416,9 +395,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto activity.setContentView(mapProvider.getMapLayoutId()); ActivityMixin.setTitle(activity, res.getString(R.string.map_map)); - if (geo == null) { - geo = app.startGeo(geoUpdate); - } if (Settings.isUseCompass() && dir == null) { dir = app.startDir(activity, dirUpdate); } @@ -456,9 +432,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto mapController.setZoom(Settings.getMapZoom()); // start location and directory services - if (geo != null) { - geoUpdate.updateLocation(geo); - } if (dir != null) { dirUpdate.updateDirection(dir); } @@ -470,7 +443,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); @@ -512,15 +485,11 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } app.setAction(StringUtils.defaultIfBlank(geocodeIntent, null)); - if (geo == null) { - geo = app.startGeo(geoUpdate); - } + app.addGeoObserver(geoUpdate); if (Settings.isUseCompass() && dir == null) { dir = app.startDir(activity, dirUpdate); } - geoUpdate.updateLocation(geo); - if (dir != null) { dirUpdate.updateDirection(dir); } @@ -534,12 +503,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(); @@ -560,9 +524,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (dir != null) { dir = app.removeDir(); } - if (geo != null) { - geo = app.removeGeo(); - } savePrefs(); @@ -588,9 +549,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (dir != null) { dir = app.removeDir(); } - if (geo != null) { - geo = app.removeGeo(); - } + app.deleteGeoObserver(geoUpdate); savePrefs(); @@ -616,9 +575,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (dir != null) { dir = app.removeDir(); } - if (geo != null) { - geo = app.removeGeo(); - } savePrefs(); @@ -698,7 +654,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; @@ -723,25 +679,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(); @@ -768,14 +721,11 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto loadDetailsThread.stopIt(); } - if (geo == null) { - geo = app.startGeo(geoUpdate); - } if (Settings.isUseCompass() && dir == null) { dir = app.startDir(activity, dirUpdate); } } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.onPrepareOptionsMenu.onCancel: " + e.toString()); + Log.e("cgeocaches.onPrepareOptionsMenu.onCancel: " + e.toString()); } } }); @@ -806,11 +756,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto ActivityMixin.invalidateOptionsMenu(activity); return true; case MENU_AS_LIST: { - final SearchResult searchResult = new SearchResult(); - search.totalCnt = caches.size(); - for (cgCache cache : caches) { - searchResult.addCache(cache); - } cgeocaches.startActivityMap(activity, search); return true; } @@ -882,19 +827,13 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto 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_COORDS, coordsIntent); } mapIntent.putExtra(EXTRAS_WPTTYPE, waypointTypeIntent != null ? waypointTypeIntent.id : null); mapIntent.putExtra(EXTRAS_MAP_TITLE, mapTitle); - 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; + final int[] mapState = currentMapState(); + if (mapState != null) { mapIntent.putExtra(EXTRAS_MAPSTATE, mapState); } @@ -902,6 +841,25 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto 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) { + return mapStateIntent; + } + + final GeoPointImpl mapCenter = mapView.getMapViewCenter(); + return new int[] { + mapCenter.getLatitudeE6(), + mapCenter.getLongitudeE6(), + mapView.getMapZoomLevel(), + followMyLocation ? 1 : 0 + }; + } + private void savePrefs() { if (mapView == null) { return; @@ -911,21 +869,17 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } // Set center of map to my location if appropriate. - private void myLocationInMiddle() { - if (followMyLocation && geo != null) { - centerMap(geo.coordsNow); + private void myLocationInMiddle(final IGeoData geo) { + if (followMyLocation) { + centerMap(geo.getCoords()); } } // class: update location - private class UpdateLoc implements UpdateLocationCallback { + private class UpdateLoc extends GeoObserver { @Override - public void updateLocation(cgGeo geo) { - if (geo == null) { - return; - } - + protected void updateLocation(final IGeoData geo) { try { boolean repaintRequired = false; @@ -933,20 +887,20 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto overlayPosition = mapView.createAddPositionOverlay(activity); } - if (overlayPosition != null && geo.location != null) { - overlayPosition.setCoordinates(geo.location); + if (overlayPosition != null && geo.getLocation() != null) { + overlayPosition.setCoordinates(geo.getLocation()); } - if (geo.coordsNow != null) { + if (geo.getCoords() != null) { if (followMyLocation) { - myLocationInMiddle(); + myLocationInMiddle(geo); } else { repaintRequired = true; } } - if (!Settings.isUseCompass() || geo.speedNow > 5) { // use GPS when speed is higher than 18 km/h - overlayPosition.setHeading(geo.bearingNow); + if (!Settings.isUseCompass() || geo.getSpeed() > 5) { // use GPS when speed is higher than 18 km/h + overlayPosition.setHeading(geo.getBearing()); repaintRequired = true; } @@ -955,7 +909,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."); } } } @@ -969,7 +923,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto return; } - if (overlayPosition != null && mapView != null && (geo == null || geo.speedNow <= 5)) { // use compass when speed is lower than 18 km/h + if (overlayPosition != null && mapView != null && (app.currentGeo().getSpeed() <= 5)) { // use compass when speed is lower than 18 km/h overlayPosition.setHeading(dir.directionNow); mapView.repaintRequired(overlayPosition); } @@ -1028,11 +982,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 @@ -1042,20 +993,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; @@ -1067,19 +1014,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()); } } } @@ -1116,11 +1059,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; @@ -1129,30 +1068,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()); } } } @@ -1165,8 +1096,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 @@ -1185,34 +1116,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 @@ -1227,8 +1174,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 @@ -1246,11 +1193,10 @@ 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.error == StatusCode.NOT_LOGGED_IN) { + if (search.getError() == StatusCode.NOT_LOGGED_IN) { Login.login(); tokens = null; } else { @@ -1269,10 +1215,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 @@ -1285,8 +1231,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 @@ -1298,30 +1244,29 @@ 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(new cgCoord(waypoint), null, waypoint)); - } - } - itemsToDisplay.add(getItem(new cgCoord(cache), cache, null)); + itemsToDisplay.add(getItem(cache, cache, null)); } overlayCaches.updateItems(itemsToDisplay); @@ -1336,7 +1281,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); @@ -1350,21 +1295,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)); } } @@ -1375,42 +1314,39 @@ 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; } @Override public void run() { - try { - if (mapView == null || CollectionUtils.isEmpty(users)) { - return; - } + if (mapView == null || CollectionUtils.isEmpty(users)) { + return; + } - // display users - List<OtherCachersOverlayItemImpl> items = new ArrayList<OtherCachersOverlayItemImpl>(); + // display users + List<OtherCachersOverlayItemImpl> items = new ArrayList<OtherCachersOverlayItemImpl>(); - int counter = 0; - OtherCachersOverlayItemImpl item = null; + int counter = 0; + OtherCachersOverlayItemImpl item; - for (Go4CacheUser userOne : users) { - if (userOne.getCoords() == null) { - continue; - } + for (Go4CacheUser userOne : users) { + if (userOne.getCoords() == null) { + continue; + } - item = mapProvider.getOtherCachersOverlayItemBase(activity, userOne); - items.add(item); + item = mapProvider.getOtherCachersOverlayItemBase(activity, userOne); + items.add(item); - counter++; - if ((counter % 10) == 0) { - overlayGo4Cache.updateItems(items); - displayHandler.sendEmptyMessage(INVALIDATE_MAP); - } + counter++; + if ((counter % 10) == 0) { + overlayGo4Cache.updateItems(items); + displayHandler.sendEmptyMessage(INVALIDATE_MAP); } - - overlayGo4Cache.updateItems(items); - } finally { } + + overlayGo4Cache.updateItems(items); } } @@ -1426,14 +1362,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } if (coordsIntent != null) { - final cgCoord coord = new cgCoord(); - coord.setCoordType("waypoint"); - coord.setCoords(coordsIntent); - coord.setName("some place"); - final cgWaypoint waypoint = new cgWaypoint("some place", waypointTypeIntent != null ? waypointTypeIntent : WaypointType.WAYPOINT, false); + waypoint.setCoords(coordsIntent); - final CachesOverlayItemImpl item = getItem(coord, null, waypoint); + final CachesOverlayItemImpl item = getItem(waypoint, null, waypoint); overlayCaches.updateItems(item); displayHandler.sendEmptyMessage(INVALIDATE_MAP); @@ -1446,18 +1378,12 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } } - private abstract class DoRunnable implements Runnable { + private static 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(); @@ -1504,11 +1430,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (dir != null) { dir = app.removeDir(); } - if (geo != null) { - geo = app.removeGeo(); - } - for (String geocode : geocodes) { + app.deleteGeoObserver(geoUpdate); + + for (final String geocode : geocodes) { try { if (handler.isCancelled()) { break; @@ -1529,15 +1454,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, 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++; @@ -1552,9 +1477,17 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto // we're done handler.sendEmptyMessage(FINISHED_LOADING_DETAILS); + app.addGeoObserver(geoUpdate); } } + 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) { @@ -1588,46 +1521,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 @@ -1651,7 +1559,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private void switchMyLocationButton() { if (followMyLocation) { myLocSwitch.setImageResource(R.drawable.actionbar_mylocation_on); - myLocationInMiddle(); + myLocationInMiddle(app.currentGeo()); } else { myLocSwitch.setImageResource(R.drawable.actionbar_mylocation_off); } @@ -1717,8 +1625,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); } @@ -1753,12 +1660,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto * Waypoint. Mutally exclusive with cache * @return */ - private CachesOverlayItemImpl getItem(cgCoord coord, cgCache cache, cgWaypoint waypoint) { + private CachesOverlayItemImpl getItem(final IWaypoint coord, final cgCache cache, final cgWaypoint waypoint) { if (cache != null) { - - CachesOverlayItemImpl item = mapProvider.getCachesOverlayItem(coord, cache.getType()); - - int hashcode = new HashCodeBuilder() + final CachesOverlayItemImpl item = mapProvider.getCachesOverlayItem(coord, cache.getType()); + final int hashcode = new HashCodeBuilder() .append(cache.isReliableLatLon()) .append(cache.getType().id) .append(cache.isDisabled() || cache.isArchived()) @@ -1770,23 +1675,20 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto .append(cache.getListId() > 0) .toHashCode(); - LayerDrawable ldFromCache = CGeoMap.overlaysCache.get(hashcode); + final LayerDrawable ldFromCache = CGeoMap.overlaysCache.get(hashcode); if (ldFromCache != null) { item.setMarker(ldFromCache); return item; } - ArrayList<Drawable> layers = new ArrayList<Drawable>(); - ArrayList<int[]> insets = new ArrayList<int[]>(); - + // Set initial capacities to the maximum of layers and insets to avoid dynamic reallocation + final ArrayList<Drawable> layers = new ArrayList<Drawable>(9); + final ArrayList<int[]> insets = new ArrayList<int[]>(8); // background: disabled or not - Drawable marker = getResources().getDrawable(R.drawable.marker); - if (cache.isDisabled() || cache.isArchived()) { - marker = getResources().getDrawable(R.drawable.marker_disabled); - } + final Drawable marker = getResources().getDrawable(cache.isDisabled() || cache.isArchived() ? R.drawable.marker_disabled : R.drawable.marker); layers.add(marker); - int resolution = marker.getIntrinsicWidth() > 40 ? 1 : 0; + final int resolution = marker.getIntrinsicWidth() > 40 ? 1 : 0; // reliable or not if (!cache.isReliableLatLon()) { insets.add(INSET_RELIABLE[resolution]); @@ -1796,7 +1698,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto layers.add(getResources().getDrawable(cache.getType().markerId)); insets.add(INSET_TYPE[resolution]); // own - if ( cache.isOwn() ) { + if (cache.isOwn()) { layers.add(getResources().getDrawable(R.drawable.marker_own)); insets.add(INSET_OWN[resolution]); // if not, checked if stored @@ -1824,11 +1726,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto insets.add(INSET_PERSONALNOTE[resolution]); } - - LayerDrawable ld = new LayerDrawable(layers.toArray(new Drawable[layers.size()])); + final LayerDrawable ld = new LayerDrawable(layers.toArray(new Drawable[layers.size()])); int index = 1; - for ( int[] inset : insets) { + for (final int[] inset : insets) { ld.setLayerInset(index++, inset[0], inset[1], inset[2], inset[3]); } @@ -1836,10 +1737,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto item.setMarker(ld); return item; + } - } else if (waypoint != null) { - - CachesOverlayItemImpl item = mapProvider.getCachesOverlayItem(coord, null); + if (waypoint != null) { + final CachesOverlayItemImpl item = mapProvider.getCachesOverlayItem(coord, null); Drawable[] layers = new Drawable[2]; layers[0] = getResources().getDrawable(R.drawable.marker); layers[1] = getResources().getDrawable(waypoint.getWaypointType().markerId); @@ -1855,7 +1756,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } return null; - } } diff --git a/main/src/cgeo/geocaching/maps/CachesOverlay.java b/main/src/cgeo/geocaching/maps/CachesOverlay.java index 0a952bc..d3a7865 100644 --- a/main/src/cgeo/geocaching/maps/CachesOverlay.java +++ b/main/src/cgeo/geocaching/maps/CachesOverlay.java @@ -1,7 +1,7 @@ package cgeo.geocaching.maps; +import cgeo.geocaching.IWaypoint; import cgeo.geocaching.Settings; -import cgeo.geocaching.cgCoord; import cgeo.geocaching.cgeopopup; import cgeo.geocaching.cgeowaypoint; import cgeo.geocaching.enumerations.CacheType; @@ -12,12 +12,12 @@ import cgeo.geocaching.maps.interfaces.ItemizedOverlayImpl; import cgeo.geocaching.maps.interfaces.MapProjectionImpl; import cgeo.geocaching.maps.interfaces.MapProvider; import cgeo.geocaching.maps.interfaces.MapViewImpl; +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.graphics.Canvas; import android.graphics.DashPathEffect; import android.graphics.Paint; @@ -25,7 +25,6 @@ import android.graphics.Paint.Style; import android.graphics.PaintFlagsDrawFilter; import android.graphics.Point; import android.location.Location; -import android.util.Log; import java.util.ArrayList; import java.util.List; @@ -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,90 @@ 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 cgCoord 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; + return center.x - left.x; + } - 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); } } @@ -200,22 +222,14 @@ public class CachesOverlay extends AbstractItemizedOverlay { return false; } - cgCoord coordinate = item.getCoord(); + 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 +237,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 +248,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 +259,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/MapProviderFactory.java b/main/src/cgeo/geocaching/maps/MapProviderFactory.java index c7865f3..3509209 100644 --- a/main/src/cgeo/geocaching/maps/MapProviderFactory.java +++ b/main/src/cgeo/geocaching/maps/MapProviderFactory.java @@ -16,11 +16,24 @@ public class MapProviderFactory { private static MapProviderFactory instance = null; - private MapProvider[] mapProviders; + private final MapProvider[] mapProviders; private SortedMap<Integer, String> mapSources; private MapProviderFactory() { - mapProviders = new MapProvider[] { new GoogleMapProvider(GOOGLEMAP_BASEID), new MapsforgeMapProvider(MFMAP_BASEID) }; + // add GoogleMapProvider only if google api is available in order to support x86 android emulator + boolean googleMaps = true; + try { + Class.forName("com.google.android.maps.MapActivity"); + } catch (ClassNotFoundException e) { + googleMaps = false; + } + if (googleMaps) { + mapProviders = new MapProvider[] { new GoogleMapProvider(GOOGLEMAP_BASEID), new MapsforgeMapProvider(MFMAP_BASEID) }; + } + else { + mapProviders = new MapProvider[] { new MapsforgeMapProvider(MFMAP_BASEID) }; + } + mapSources = new TreeMap<Integer, String>(); for (MapProvider mp : mapProviders) { mapSources.putAll(mp.getMapSources()); diff --git a/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java b/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java index 4dd217b..6ca050e 100644 --- a/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java +++ b/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java @@ -1,21 +1,19 @@ 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; import cgeo.geocaching.maps.interfaces.MapViewImpl; import cgeo.geocaching.maps.interfaces.OtherCachersOverlayItemImpl; +import cgeo.geocaching.utils.Log; 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 android.util.Log; import java.util.ArrayList; import java.util.List; @@ -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/OtherCachersOverlayItem.java b/main/src/cgeo/geocaching/maps/OtherCachersOverlayItem.java index d71bbcf..9844e83 100644 --- a/main/src/cgeo/geocaching/maps/OtherCachersOverlayItem.java +++ b/main/src/cgeo/geocaching/maps/OtherCachersOverlayItem.java @@ -16,7 +16,7 @@ public class OtherCachersOverlayItem { } public Drawable getMarker() { - Drawable marker = null; + Drawable marker; if (user != null && user.getDate() != null && user.getDate().getTime() >= (System.currentTimeMillis() - (20 * 60 * 1000))) { marker = context.getResources().getDrawable(R.drawable.user_location_active); diff --git a/main/src/cgeo/geocaching/maps/PositionOverlay.java b/main/src/cgeo/geocaching/maps/PositionOverlay.java index a09b6de..9099498 100644 --- a/main/src/cgeo/geocaching/maps/PositionOverlay.java +++ b/main/src/cgeo/geocaching/maps/PositionOverlay.java @@ -150,7 +150,7 @@ public class PositionOverlay implements GeneralOverlay { if (Settings.isMapTrail()) { int size = history.size(); if (size > 1) { - int alpha = 0; + int alpha; int alphaCnt = size - 201; if (alphaCnt < 1) { alphaCnt = 1; @@ -210,7 +210,7 @@ public class PositionOverlay implements GeneralOverlay { marginTop = center.y - heightArrowHalf; Matrix matrix = new Matrix(); - matrix.setRotate(heading.floatValue(), widthArrowHalf, heightArrowHalf); + matrix.setRotate(heading, widthArrowHalf, heightArrowHalf); matrix.postTranslate(marginLeft, marginTop); canvas.drawBitmap(arrow, matrix, null); diff --git a/main/src/cgeo/geocaching/maps/ScaleOverlay.java b/main/src/cgeo/geocaching/maps/ScaleOverlay.java index f43ba25..321624d 100644 --- a/main/src/cgeo/geocaching/maps/ScaleOverlay.java +++ b/main/src/cgeo/geocaching/maps/ScaleOverlay.java @@ -1,14 +1,15 @@ package cgeo.geocaching.maps; -import cgeo.geocaching.Settings; import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.geopoint.IConversion; +import cgeo.geocaching.geopoint.HumanDistance; import cgeo.geocaching.maps.interfaces.GeneralOverlay; import cgeo.geocaching.maps.interfaces.GeoPointImpl; import cgeo.geocaching.maps.interfaces.MapProjectionImpl; import cgeo.geocaching.maps.interfaces.MapViewImpl; import cgeo.geocaching.maps.interfaces.OverlayImpl; +import org.apache.commons.lang3.tuple.ImmutablePair; + import android.app.Activity; import android.graphics.BlurMaskFilter; import android.graphics.Canvas; @@ -25,11 +26,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 +47,25 @@ 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() - if (Settings.isUseMetricUnits()) { - if (distance > 100) { // 100+ km > 1xx km - distanceRound = Math.floor(distance / 100) * 100; - units = "km"; - } else if (distance > 10) { // 10 - 100 km > 1x km - distanceRound = Math.floor(distance / 10) * 10; - units = "km"; - } else if (distance > 1) { // 1 - 10 km > 1.x km - distanceRound = Math.floor(distance); - units = "km"; - } else if (distance > 0.1) { // 100 m - 1 km > 1xx m - distance *= 1000; - distanceRound = Math.floor(distance / 100) * 100; - units = "m"; - } else { // 1 - 100 m > 1x m - distance *= 1000; - distanceRound = Math.round(distance / 10) * 10; - units = "m"; - } - } 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; - units = "mi"; - } else if (distance > 1) { // 1 - 10 mi > 1.x mi - distanceRound = Math.floor(distance); - units = "mi"; - } else if (distance > 0.1) { // 0.1 mi - 1.0 mi > 1xx ft - distance *= 5280; - distanceRound = Math.floor(distance / 100) * 100; - units = "ft"; - } else { // 1 - 100 ft > 1x ft - distance *= 5280; - distanceRound = Math.round(distance / 10) * 10; - units = "ft"; - } - } + final ImmutablePair<Double, String> scaled = HumanDistance.scaleUnit(leftCoords.distanceTo(rightCoords) * SCALE_WIDTH_FACTOR); - pixels = Math.round((pixels / distance) * distanceRound); + final double distanceRound = keepSignificantDigit(scaled.left); + final double pixels = Math.round((mapView.getWidth() * SCALE_WIDTH_FACTOR / scaled.left) * distanceRound); if (blur == null) { blur = new BlurMaskFilter(3, BlurMaskFilter.Blur.NORMAL); @@ -139,15 +96,17 @@ public class ScaleOverlay implements GeneralOverlay { scale.setColor(0xFF000000); } + final String formatString = distanceRound >= 1 ? "%.0f" : "%.1f"; + canvas.drawLine(10, bottom, 10, (bottom - (8 * pixelDensity)), scaleShadow); canvas.drawLine((int) (pixels + 10), bottom, (int) (pixels + 10), (bottom - (8 * pixelDensity)), scaleShadow); canvas.drawLine(8, bottom, (int) (pixels + 12), bottom, scaleShadow); - canvas.drawText(String.format("%.0f", distanceRound) + " " + units, (float) (pixels - (10 * pixelDensity)), (bottom - (10 * pixelDensity)), scaleShadow); + canvas.drawText(String.format(formatString, distanceRound) + " " + scaled.right, (float) (pixels - (10 * pixelDensity)), (bottom - (10 * pixelDensity)), scaleShadow); canvas.drawLine(11, bottom, 11, (bottom - (6 * pixelDensity)), scale); canvas.drawLine((int) (pixels + 9), bottom, (int) (pixels + 9), (bottom - (6 * pixelDensity)), scale); canvas.drawLine(10, bottom, (int) (pixels + 10), bottom, scale); - canvas.drawText(String.format("%.0f", distanceRound) + " " + units, (float) (pixels - (10 * pixelDensity)), (bottom - (10 * pixelDensity)), scale); + canvas.drawText(String.format(formatString, distanceRound) + " " + scaled.right, (float) (pixels - (10 * pixelDensity)), (bottom - (10 * pixelDensity)), scale); } @Override diff --git a/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlayItem.java b/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlayItem.java index 5f41c54..27a1b56 100644 --- a/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlayItem.java +++ b/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlayItem.java @@ -1,6 +1,6 @@ package cgeo.geocaching.maps.google; -import cgeo.geocaching.cgCoord; +import cgeo.geocaching.IWaypoint; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl; @@ -9,16 +9,16 @@ import com.google.android.maps.OverlayItem; public class GoogleCacheOverlayItem extends OverlayItem implements CachesOverlayItemImpl { final private CacheType cacheType; - final private cgCoord coord; + final private IWaypoint coord; - public GoogleCacheOverlayItem(final cgCoord coordinate, final CacheType type) { + public GoogleCacheOverlayItem(final IWaypoint coordinate, final CacheType type) { super(new GeoPoint(coordinate.getCoords().getLatitudeE6(), coordinate.getCoords().getLongitudeE6()), coordinate.getName(), ""); this.cacheType = type; this.coord = coordinate; } - public cgCoord getCoord() { + public IWaypoint getCoord() { return coord; } 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/GoogleMapProvider.java b/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java index 7191428..b659042 100644 --- a/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java +++ b/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java @@ -1,7 +1,7 @@ package cgeo.geocaching.maps.google; +import cgeo.geocaching.IWaypoint; import cgeo.geocaching.R; -import cgeo.geocaching.cgCoord; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.geopoint.Geopoint; @@ -81,15 +81,13 @@ public class GoogleMapProvider implements MapProvider { } @Override - public CachesOverlayItemImpl getCachesOverlayItem(final cgCoord coordinate, final CacheType type) { - GoogleCacheOverlayItem baseItem = new GoogleCacheOverlayItem(coordinate, type); - return baseItem; + public CachesOverlayItemImpl getCachesOverlayItem(final IWaypoint coordinate, final CacheType type) { + return new GoogleCacheOverlayItem(coordinate, type); } @Override public OtherCachersOverlayItemImpl getOtherCachersOverlayItemBase(Context context, Go4CacheUser userOne) { - GoogleOtherCachersOverlayItem baseItem = new GoogleOtherCachersOverlayItem(context, userOne); - return baseItem; + return new GoogleOtherCachersOverlayItem(context, userOne); } } diff --git a/main/src/cgeo/geocaching/maps/google/GoogleMapView.java b/main/src/cgeo/geocaching/maps/google/GoogleMapView.java index 8afba89..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; @@ -15,6 +16,7 @@ import cgeo.geocaching.maps.interfaces.MapViewImpl; import cgeo.geocaching.maps.interfaces.OnMapDragListener; import cgeo.geocaching.maps.interfaces.OverlayImpl; import cgeo.geocaching.maps.interfaces.OverlayImpl.overlayType; +import cgeo.geocaching.utils.Log; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapView; @@ -25,7 +27,6 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.util.AttributeSet; -import android.util.Log; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.Gravity; @@ -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/CachesOverlayItemImpl.java b/main/src/cgeo/geocaching/maps/interfaces/CachesOverlayItemImpl.java index e2bf552..1afc120 100644 --- a/main/src/cgeo/geocaching/maps/interfaces/CachesOverlayItemImpl.java +++ b/main/src/cgeo/geocaching/maps/interfaces/CachesOverlayItemImpl.java @@ -1,6 +1,6 @@ package cgeo.geocaching.maps.interfaces; -import cgeo.geocaching.cgCoord; +import cgeo.geocaching.IWaypoint; import cgeo.geocaching.enumerations.CacheType; /** @@ -12,7 +12,7 @@ import cgeo.geocaching.enumerations.CacheType; */ public interface CachesOverlayItemImpl extends OverlayItemImpl { - public cgCoord getCoord(); + public IWaypoint getCoord(); public CacheType getType(); 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/MapProvider.java b/main/src/cgeo/geocaching/maps/interfaces/MapProvider.java index c2c46ac..dd935c4 100644 --- a/main/src/cgeo/geocaching/maps/interfaces/MapProvider.java +++ b/main/src/cgeo/geocaching/maps/interfaces/MapProvider.java @@ -1,6 +1,6 @@ package cgeo.geocaching.maps.interfaces; -import cgeo.geocaching.cgCoord; +import cgeo.geocaching.IWaypoint; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.go4cache.Go4CacheUser; @@ -31,7 +31,7 @@ public interface MapProvider { public GeoPointImpl getGeoPointBase(final Geopoint coords); - public CachesOverlayItemImpl getCachesOverlayItem(final cgCoord coordinate, final CacheType type); + public CachesOverlayItemImpl getCachesOverlayItem(final IWaypoint iWaypoint, final CacheType type); public OtherCachersOverlayItemImpl getOtherCachersOverlayItemBase(Context context, Go4CacheUser userOne); 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/MapsforgeCacheOverlayItem.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlayItem.java index ccc0e78..f2ffae7 100644 --- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlayItem.java +++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlayItem.java @@ -1,6 +1,6 @@ package cgeo.geocaching.maps.mapsforge; -import cgeo.geocaching.cgCoord; +import cgeo.geocaching.IWaypoint; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl; @@ -11,16 +11,16 @@ import android.graphics.drawable.Drawable; public class MapsforgeCacheOverlayItem extends OverlayItem implements CachesOverlayItemImpl { final private CacheType cacheType; - final private cgCoord coord; + final private IWaypoint coord; - public MapsforgeCacheOverlayItem(cgCoord coordinate, final CacheType type) { + public MapsforgeCacheOverlayItem(IWaypoint coordinate, final CacheType type) { super(new GeoPoint(coordinate.getCoords().getLatitudeE6(), coordinate.getCoords().getLongitudeE6()), coordinate.getName(), ""); this.cacheType = type; this.coord = coordinate; } - public cgCoord getCoord() { + public IWaypoint getCoord() { return coord; } 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/MapsforgeMapProvider.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java index 19c1335..c119fd0 100644 --- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java +++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java @@ -1,7 +1,7 @@ package cgeo.geocaching.maps.mapsforge; +import cgeo.geocaching.IWaypoint; import cgeo.geocaching.R; -import cgeo.geocaching.cgCoord; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.geopoint.Geopoint; @@ -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; @@ -80,15 +82,17 @@ public class MapsforgeMapProvider implements MapProvider { } @Override - public CachesOverlayItemImpl getCachesOverlayItem(final cgCoord coordinate, final CacheType type) { - MapsforgeCacheOverlayItem baseItem = new MapsforgeCacheOverlayItem(coordinate, type); - return baseItem; + public CachesOverlayItemImpl getCachesOverlayItem(final IWaypoint coordinate, final CacheType type) { + return new MapsforgeCacheOverlayItem(coordinate, type); } @Override public OtherCachersOverlayItemImpl getOtherCachersOverlayItemBase(Context context, Go4CacheUser userOne) { - MapsforgeOtherCachersOverlayItem baseItem = new MapsforgeOtherCachersOverlayItem(context, userOne); - return baseItem; + return new MapsforgeOtherCachersOverlayItem(context, userOne); + } + + 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 d14ea8c..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; @@ -13,9 +15,9 @@ import cgeo.geocaching.maps.interfaces.MapViewImpl; import cgeo.geocaching.maps.interfaces.OnMapDragListener; import cgeo.geocaching.maps.interfaces.OverlayImpl; 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; @@ -26,10 +28,10 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.util.AttributeSet; -import android.util.Log; 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 1811110..7e4143e 100644 --- a/main/src/cgeo/geocaching/network/HtmlImage.java +++ b/main/src/cgeo/geocaching/network/HtmlImage.java @@ -1,10 +1,10 @@ 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; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpResponse; @@ -16,7 +16,6 @@ import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.net.Uri; import android.text.Html; -import android.util.Log; import android.view.Display; import android.view.WindowManager; @@ -72,26 +71,26 @@ public class HtmlImage implements Html.ImageGetter { return new BitmapDrawable(getTransparent1x1Image()); } - Bitmap imagePre = null; - - // Load image from cache - if (!onlySave) { - imagePre = 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 HttpResponse httpResponse = Network.request(absoluteURL, null, false); + final File file = LocalStorage.getStorageFile(geocode, url, true, true); + final HttpResponse httpResponse = Network.getRequest(absoluteURL, null, file); if (httpResponse != null) { - final File file = LocalStorage.getStorageFile(geocode, url, true, true); - LocalStorage.saveEntityToFile(httpResponse, file); + final int statusCode = httpResponse.getStatusLine().getStatusCode(); + if (statusCode == 200) { + LocalStorage.saveEntityToFile(httpResponse, file); + } else if (statusCode == 304) { + file.setLastModified(System.currentTimeMillis()); + } } } 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,32 +157,31 @@ 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; } - private final String makeAbsoluteURL(final String url) { - try { - // Check if uri is absolute or not, if not attach the connector hostname - // FIXME: that should also include the scheme - if (Uri.parse(url).isAbsolute()) { - return url; - } else { - final String host = ConnectorFactory.getConnector(geocode).getHost(); - if (StringUtils.isNotEmpty(host)) { - StringBuilder builder = new StringBuilder("http://"); - builder.append(host); - if (!StringUtils.startsWith(url, "/")) { - builder.append('/'); - } - builder.append(url); - return builder.toString(); - } + private String makeAbsoluteURL(final String url) { + // Check if uri is absolute or not, if not attach the connector hostname + // FIXME: that should also include the scheme + if (Uri.parse(url).isAbsolute()) { + return url; + } + + final String host = ConnectorFactory.getConnector(geocode).getHost(); + if (StringUtils.isNotEmpty(host)) { + final StringBuilder builder = new StringBuilder("http://"); + builder.append(host); + if (!StringUtils.startsWith(url, "/")) { + // FIXME: explain why the result URL would be valid if the path does not start with + // a '/', or signal an error. + builder.append('/'); } - } catch (Exception e) { - Log.e(Settings.tag, "HtmlImage.makeAbsoluteURL (parse URL)", e); + builder.append(url); + return builder.toString(); } + return null; } @@ -207,7 +205,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 0afe095..39c0cf5 100644 --- a/main/src/cgeo/geocaching/network/Network.java +++ b/main/src/cgeo/geocaching/network/Network.java @@ -1,11 +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; @@ -16,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; @@ -38,15 +32,14 @@ import org.json.JSONException; import org.json.JSONObject; import android.net.Uri; -import android.util.Log; +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 { @@ -57,13 +50,12 @@ public abstract class Network { @Override public InputStream getContent() throws IOException, IllegalStateException { // the wrapped entity's getContent() decides about repeatability - InputStream wrappedin = wrappedEntity.getContent(); - return new GZIPInputStream(wrappedin); + return new GZIPInputStream(wrappedEntity.getContent()); } @Override public long getContentLength() { - // length of ungzipped content is not known + // length of gunzipped content is not known return -1; } } @@ -74,8 +66,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); @@ -89,7 +79,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() { @@ -108,16 +98,14 @@ public abstract class Network { public void process( final HttpResponse response, final HttpContext context) throws HttpException, IOException { - HttpEntity entity = response.getEntity(); - if (null != entity) { - Header ceheader = entity.getContentEncoding(); - if (ceheader != null) { - HeaderElement[] codecs = ceheader.getElements(); - for (int i = 0; i < codecs.length; i++) { - if (codecs[i].getName().equalsIgnoreCase("gzip")) { - Log.d(Settings.tag, "Decompressing response"); - response.setEntity( - new Network.GzipDecompressingEntity(response.getEntity())); + final HttpEntity entity = response.getEntity(); + if (entity != null) { + final Header contentEncoding = entity.getContentEncoding(); + if (contentEncoding != null) { + for (final HeaderElement codec : contentEncoding.getElements()) { + if (codec.getName().equalsIgnoreCase("gzip")) { + Log.d("Decompressing response"); + response.setEntity(new GzipDecompressingEntity(response.getEntity())); return; } } @@ -130,127 +118,80 @@ 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 * - * @param uri - * @param params - * @return - */ - public static HttpResponse postRequest(final String uri, final List<? extends NameValuePair> params) { - try { - HttpPost request = new HttpPost(uri); - if (params != null) { - request.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8)); - } - request.setHeader("X-Requested-With", "XMLHttpRequest"); - return Network.request(request); - } catch (Exception e) { - // Can be UnsupportedEncodingException, ClientProtocolException or IOException - Log.e(Settings.tag, "postRequest", e); - return null; - } - } - - /** - * GET HTTP request - * - * @param uri - * @param params - * @param xContentType - * @param my - * @param addF - * @return + * @param uri the URI to request + * @param params the parameters to add to the POST request + * @return the HTTP response, or null in case of an encoding error params */ - 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 - * @return + * the parameters to add the the GET request + * @param headers + * the headers to add to the GET request + * @param cacheFile + * 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 String fullUri = params == null ? uri : Uri.parse(uri).buildUpon().encodedQuery(params.toString()).build().toString(); - final HttpRequestBase request = new HttpGet(fullUri); - - request.setHeader("X-Requested-With", "XMLHttpRequest"); - - if (xContentType) { - request.setHeader("Content-Type", "application/x-www-form-urlencoded"); + 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; + } + } } - return Network.request(request); - } + 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()); + } - 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); - } + request.getParams().setParameter(CoreProtocolPNames.USER_AGENT, Network.USER_AGENT); - private static HttpResponse doRequest(final HttpRequestBase request) { - final String reqLogStr = request.getMethod() + " " + hidePassword(request.getURI().toString()); - Log.d(Settings.tag, reqLogStr); + final String reqLogStr = request.getMethod() + " " + Network.hidePassword(request.getURI().toString()); + Log.d(reqLogStr); - final HttpClient client = getHttpClient(); - for (int i = 0; i <= NB_DOWNLOAD_RETRIES; i++) { + 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(Settings.tag, status + Network.formatTimeSpan(before) + reqLogStr); + Log.d(status + Network.formatTimeSpan(before) + reqLogStr); } else { - Log.w(Settings.tag, status + " [" + response.getStatusLine().getReasonPhrase() + "]" + Network.formatTimeSpan(before) + reqLogStr); + 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) + "/" + (NB_DOWNLOAD_RETRIES + 1); - if (i == NB_DOWNLOAD_RETRIES) { - Log.e(Settings.tag, "Failure " + tries + timeSpan + reqLogStr, e); + 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(Settings.tag, "Failure " + tries + " (" + e.toString() + ")" + timeSpan + "- retrying " + reqLogStr); + Log.e("Failure " + tries + " (" + e.toString() + ")" + timeSpan + "- retrying " + reqLogStr); } } } @@ -258,6 +199,79 @@ public abstract class Network { return null; } + private static Parameters cacheHeaders(final File cacheFile) { + if (cacheFile == null || !cacheFile.exists()) { + return null; + } + + final String etag = LocalStorage.getSavedHeader(cacheFile, "etag"); + if (etag != null) { + return new Parameters("If-None-Match", etag); + } + + final String lastModified = LocalStorage.getSavedHeader(cacheFile, "last-modified"); + if (lastModified != null) { + return new Parameters("If-Modified-Since", lastModified); + } + + return null; + } + + /** + * GET HTTP request + * + * @param uri + * the URI to request + * @param params + * 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 getRequest(final String uri, final Parameters params, final File cacheFile) { + return request("GET", uri, params, null, cacheFile); + } + + + /** + * 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); + } + + /** + * 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); + } + + /** + * 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) { // don't use String.format in a pure logging routine, it has very bad performance return " (" + (System.currentTimeMillis() - before) + " ms) "; @@ -268,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; } } @@ -303,62 +308,15 @@ 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 rfc3986URLEncode(String text) { + return StringUtils.replace(URLEncoder.encode(text).replace("+", "%20"), "%7E", "~"); } - public static String urlencode_rfc3986(String text) { - final String encoded = StringUtils.replace(URLEncoder.encode(text).replace("+", "%20"), "%7E", "~"); - - return encoded; - } } diff --git a/main/src/cgeo/geocaching/network/OAuth.java b/main/src/cgeo/geocaching/network/OAuth.java index cefa90d..8cecb22 100644 --- a/main/src/cgeo/geocaching/network/OAuth.java +++ b/main/src/cgeo/geocaching/network/OAuth.java @@ -23,11 +23,11 @@ public class OAuth { final List<String> paramsEncoded = new ArrayList<String>(); for (final NameValuePair nameValue : params) { - paramsEncoded.add(nameValue.getName() + "=" + Network.urlencode_rfc3986(nameValue.getValue())); + paramsEncoded.add(nameValue.getName() + "=" + Network.rfc3986URLEncode(nameValue.getValue())); } final String keysPacked = Settings.getKeyConsumerSecret() + "&" + StringUtils.defaultString(tokenSecret); // both even if empty some of them! - final String requestPacked = method + "&" + Network.urlencode_rfc3986((https ? "https" : "http") + "://" + host + path) + "&" + Network.urlencode_rfc3986(StringUtils.join(paramsEncoded.toArray(), '&')); + final String requestPacked = method + "&" + Network.rfc3986URLEncode((https ? "https" : "http") + "://" + host + path) + "&" + Network.rfc3986URLEncode(StringUtils.join(paramsEncoded.toArray(), '&')); params.put("oauth_signature", CryptUtils.base64Encode(CryptUtils.hashHmac(requestPacked, keysPacked))); } } diff --git a/main/src/cgeo/geocaching/network/Parameters.java b/main/src/cgeo/geocaching/network/Parameters.java index e65bec2..90965e4 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,43 @@ 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) { + return params == null ? new Parameters(keyValues) : 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; + } + 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 bc93d3b..2015375 100644 --- a/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java +++ b/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java @@ -1,9 +1,8 @@ package cgeo.geocaching.sorting; import cgeo.geocaching.cgCache; -import cgeo.geocaching.Settings; +import cgeo.geocaching.utils.Log; -import android.util.Log; /** * abstract super implementation for all cache comparators @@ -12,7 +11,7 @@ import android.util.Log; public abstract class AbstractCacheComparator implements CacheComparator { @Override - public final int compare(cgCache cache1, cgCache cache2) { + public final int compare(final cgCache cache1, final cgCache cache2) { try { // first check that we have all necessary data for the comparison if (!canCompare(cache1, cache2)) { @@ -20,13 +19,13 @@ 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; } /** - * check necessary preconditions (like missing fields) before running the comparison itself + * Check necessary preconditions (like missing fields) before running the comparison itself * * @param cache1 * @param cache2 @@ -35,7 +34,10 @@ public abstract class AbstractCacheComparator implements CacheComparator { protected abstract boolean canCompare(final cgCache cache1, final cgCache cache2); /** - * compares two caches. Logging and exception handling is implemented outside this method already. + * Compares two caches. Logging and exception handling is implemented outside this method already. + * <p/> + * A cache is smaller than another cache if it is desirable to show it first when presented to the user. + * For example, a highly rated cache must be considered smaller than a poorly rated one. * * @param cache1 * @param cache2 diff --git a/main/src/cgeo/geocaching/sorting/DifficultyComparator.java b/main/src/cgeo/geocaching/sorting/DifficultyComparator.java index 0d65660..123bab9 100644 --- a/main/src/cgeo/geocaching/sorting/DifficultyComparator.java +++ b/main/src/cgeo/geocaching/sorting/DifficultyComparator.java @@ -15,11 +15,6 @@ public class DifficultyComparator extends AbstractCacheComparator { @Override protected int compareCaches(final cgCache cache1, final cgCache cache2) { - if (cache1.getDifficulty() > cache2.getDifficulty()) { - return 1; - } else if (cache2.getDifficulty() > cache1.getDifficulty()) { - return -1; - } - return 0; + return Float.compare(cache1.getDifficulty(), cache2.getDifficulty()); } }
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/sorting/EventDateComparator.java b/main/src/cgeo/geocaching/sorting/EventDateComparator.java index 0092901..ac49e66 100644 --- a/main/src/cgeo/geocaching/sorting/EventDateComparator.java +++ b/main/src/cgeo/geocaching/sorting/EventDateComparator.java @@ -1,8 +1,5 @@ package cgeo.geocaching.sorting; -import cgeo.geocaching.cgCache; - - /** * Compares caches by date. Used only for event caches. * @@ -11,13 +8,4 @@ import cgeo.geocaching.cgCache; */ public class EventDateComparator extends DateComparator { - @Override - protected boolean canCompare(cgCache cache1, cgCache cache2) { - return super.canCompare(cache1, cache2); - } - - @Override - protected int compareCaches(cgCache cache1, cgCache cache2) { - return super.compareCaches(cache1, cache2); - } } diff --git a/main/src/cgeo/geocaching/sorting/FindsComparator.java b/main/src/cgeo/geocaching/sorting/FindsComparator.java index 7a1555e..98fe1dd 100644 --- a/main/src/cgeo/geocaching/sorting/FindsComparator.java +++ b/main/src/cgeo/geocaching/sorting/FindsComparator.java @@ -31,7 +31,7 @@ public class FindsComparator extends AbstractCacheComparator { } Integer logged = cache.getLogCounts().get(LogType.LOG_FOUND_IT); if (logged != null) { - finds = logged.intValue(); + finds = logged; } return finds; } diff --git a/main/src/cgeo/geocaching/sorting/GeocodeComparator.java b/main/src/cgeo/geocaching/sorting/GeocodeComparator.java index 1377cce..fb93c0e 100644 --- a/main/src/cgeo/geocaching/sorting/GeocodeComparator.java +++ b/main/src/cgeo/geocaching/sorting/GeocodeComparator.java @@ -17,12 +17,8 @@ public class GeocodeComparator extends AbstractCacheComparator { } @Override - protected int compareCaches(cgCache cache1, cgCache cache2) { - if (cache1.getGeocode().length() > cache2.getGeocode().length()) { - return 1; - } else if (cache2.getGeocode().length() > cache1.getGeocode().length()) { - return -1; - } - return cache1.getGeocode().compareToIgnoreCase(cache2.getGeocode()); + protected int compareCaches(final cgCache cache1, final cgCache cache2) { + final int lengthDiff = cache1.getGeocode().length() - cache2.getGeocode().length(); + return lengthDiff != 0 ? lengthDiff : cache1.getGeocode().compareToIgnoreCase(cache2.getGeocode()); } } diff --git a/main/src/cgeo/geocaching/sorting/InventoryComparator.java b/main/src/cgeo/geocaching/sorting/InventoryComparator.java index b1842d7..d4e9f5e 100644 --- a/main/src/cgeo/geocaching/sorting/InventoryComparator.java +++ b/main/src/cgeo/geocaching/sorting/InventoryComparator.java @@ -11,19 +11,12 @@ import cgeo.geocaching.cgCache; public class InventoryComparator extends AbstractCacheComparator { @Override - protected boolean canCompare(cgCache cache1, cgCache cache2) { + protected boolean canCompare(final cgCache cache1, final cgCache cache2) { return true; } @Override - protected int compareCaches(cgCache cache1, cgCache cache2) { - int itemCount1 = cache1.getInventoryItems(); - int itemCount2 = cache2.getInventoryItems(); - if (itemCount1 < itemCount2) { - return 1; - } else if (itemCount2 < itemCount1) { - return -1; - } - return 0; + protected int compareCaches(final cgCache cache1, final cgCache cache2) { + return cache2.getInventoryItems() - cache1.getInventoryItems(); } } diff --git a/main/src/cgeo/geocaching/sorting/PopularityComparator.java b/main/src/cgeo/geocaching/sorting/PopularityComparator.java index 9fe254a..62ad9a9 100644 --- a/main/src/cgeo/geocaching/sorting/PopularityComparator.java +++ b/main/src/cgeo/geocaching/sorting/PopularityComparator.java @@ -9,17 +9,12 @@ import cgeo.geocaching.cgCache; public class PopularityComparator extends AbstractCacheComparator { @Override - protected boolean canCompare(cgCache cache1, cgCache cache2) { + protected boolean canCompare(final cgCache cache1, final cgCache cache2) { return true; } @Override - protected int compareCaches(cgCache cache1, cgCache cache2) { - if (cache1.getFavoritePoints() < cache2.getFavoritePoints()) { - return 1; - } else if (cache2.getFavoritePoints() < cache1.getFavoritePoints()) { - return -1; - } - return 0; + protected int compareCaches(final cgCache cache1, final cgCache cache2) { + return cache2.getFavoritePoints() - cache1.getFavoritePoints(); } } diff --git a/main/src/cgeo/geocaching/sorting/RatingComparator.java b/main/src/cgeo/geocaching/sorting/RatingComparator.java index 935ccd8..be071c5 100644 --- a/main/src/cgeo/geocaching/sorting/RatingComparator.java +++ b/main/src/cgeo/geocaching/sorting/RatingComparator.java @@ -9,28 +9,15 @@ import cgeo.geocaching.cgCache; public class RatingComparator extends AbstractCacheComparator { @Override - protected boolean canCompare(cgCache cache1, cgCache cache2) { + protected boolean canCompare(final cgCache cache1, final cgCache cache2) { return true; } @Override - protected int compareCaches(cgCache cache1, cgCache cache2) { - float rating1 = cache1.getRating(); - float rating2 = cache2.getRating(); - - // voting can be disabled for caches, then assume an average rating instead - if (rating1 == 0.0) { - rating1 = 2.5f; - } - if (rating2 == 0.0) { - rating2 = 2.5f; - } - - if (rating1 < rating2) { - return 1; - } else if (rating2 < rating1) { - return -1; - } - return 0; + protected int compareCaches(final cgCache cache1, final cgCache cache2) { + final float rating1 = cache1.getRating(); + final float rating2 = cache2.getRating(); + // Voting can be disabled for caches, then assume an average rating instead + return Float.compare(rating2 != 0.0 ? rating2 : 2.5f, rating1 != 0.0 ? rating1 : 2.5f); } }
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/sorting/TerrainComparator.java b/main/src/cgeo/geocaching/sorting/TerrainComparator.java index c0590cb..9058a3c 100644 --- a/main/src/cgeo/geocaching/sorting/TerrainComparator.java +++ b/main/src/cgeo/geocaching/sorting/TerrainComparator.java @@ -9,17 +9,12 @@ import cgeo.geocaching.cgCache; public class TerrainComparator extends AbstractCacheComparator { @Override - protected boolean canCompare(cgCache cache1, cgCache cache2) { + protected boolean canCompare(final cgCache cache1, final cgCache cache2) { return cache1.getTerrain() != 0.0 && cache2.getTerrain() != 0.0; } @Override - protected int compareCaches(cgCache cache1, cgCache cache2) { - if (cache1.getTerrain() > cache2.getTerrain()) { - return 1; - } else if (cache2.getTerrain() > cache1.getTerrain()) { - return -1; - } - return 0; + protected int compareCaches(final cgCache cache1, final cgCache cache2) { + return Float.compare(cache1.getTerrain(), cache2.getTerrain()); } } diff --git a/main/src/cgeo/geocaching/sorting/VisitComparator.java b/main/src/cgeo/geocaching/sorting/VisitComparator.java index a580f2a..548ec7a 100644 --- a/main/src/cgeo/geocaching/sorting/VisitComparator.java +++ b/main/src/cgeo/geocaching/sorting/VisitComparator.java @@ -9,17 +9,12 @@ import cgeo.geocaching.cgCache; public class VisitComparator extends AbstractCacheComparator { @Override - protected boolean canCompare(cgCache cache1, cgCache cache2) { + protected boolean canCompare(final cgCache cache1, final cgCache cache2) { return cache1.getVisitedDate() > 0 && cache2.getVisitedDate() > 0; } @Override - protected int compareCaches(cgCache cache1, cgCache cache2) { - if (cache1.getVisitedDate() > cache2.getVisitedDate()) { - return -1; - } else if (cache1.getVisitedDate() < cache2.getVisitedDate()) { - return 1; - } - return 0; + protected int compareCaches(final cgCache cache1, final cgCache cache2) { + return Long.valueOf(cache2.getVisitedDate()).compareTo(cache1.getVisitedDate()); } } diff --git a/main/src/cgeo/geocaching/sorting/VoteComparator.java b/main/src/cgeo/geocaching/sorting/VoteComparator.java index 82ebdd3..8d9f907 100644 --- a/main/src/cgeo/geocaching/sorting/VoteComparator.java +++ b/main/src/cgeo/geocaching/sorting/VoteComparator.java @@ -18,15 +18,6 @@ public class VoteComparator extends AbstractCacheComparator { @Override protected int compareCaches(cgCache cache1, cgCache cache2) { // if there is no vote available, put that cache at the end of the list - float vote1 = cache1.getMyVote(); - float vote2 = cache2.getMyVote(); - - // compare - if (vote1 < vote2) { - return 1; - } else if (vote2 < vote1) { - return -1; - } - return 0; + return Float.compare(cache2.getMyVote(), cache1.getMyVote()); } } diff --git a/main/src/cgeo/geocaching/twitter/Twitter.java b/main/src/cgeo/geocaching/twitter/Twitter.java index fa1a39d..4a10046 100644 --- a/main/src/cgeo/geocaching/twitter/Twitter.java +++ b/main/src/cgeo/geocaching/twitter/Twitter.java @@ -10,10 +10,10 @@ import cgeo.geocaching.geopoint.GeopointFormatter.Format; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.OAuth; import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.utils.Log; import org.apache.http.HttpResponse; -import android.util.Log; public final class Twitter { public static final int MAX_TWEET_SIZE = 140; @@ -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 fffe12e..86db2d2 100644 --- a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java +++ b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java @@ -6,6 +6,7 @@ import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.OAuth; import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; @@ -18,7 +19,6 @@ import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; @@ -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..327b71d 100644 --- a/main/src/cgeo/geocaching/ui/AddressListAdapter.java +++ b/main/src/cgeo/geocaching/ui/AddressListAdapter.java @@ -21,24 +21,23 @@ import java.util.ArrayList; public class AddressListAdapter extends ArrayAdapter<Address> { - private LayoutInflater inflater; - private AddressListView holder; - private Geopoint location; + final private LayoutInflater inflater; + final private Geopoint location; public AddressListAdapter(final Context context) { super(context, 0); + inflater = ((Activity) context).getLayoutInflater(); + location = cgeoapplication.getInstance().currentGeo().getCoords(); } @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (inflater == null) { - inflater = ((Activity) getContext()).getLayoutInflater(); - } - + public View getView(final int position, final View convertView, final ViewGroup parent) { final Address address = getItem(position); // holder pattern implementation + final AddressListView holder; View view = convertView; + if (view == null) { view = inflater.inflate(R.layout.addresses_item, null); @@ -54,9 +53,9 @@ public class AddressListAdapter extends ArrayAdapter<Address> { view.setOnClickListener(new View.OnClickListener() { @Override - public void onClick(View v) { - Activity activity = (Activity) v.getContext(); - cgeocaches.startActivityAddress(activity, address.getLatitude(), address.getLongitude(), StringUtils.defaultString(address.getAddressLine(0))); + public void onClick(final View v) { + final Activity activity = (Activity) v.getContext(); + cgeocaches.startActivityAddress(activity, new Geopoint(address.getLatitude(), address.getLongitude()), StringUtils.defaultString(address.getAddressLine(0))); activity.finish(); } }); @@ -68,10 +67,6 @@ public class AddressListAdapter extends ArrayAdapter<Address> { } private CharSequence getDistanceText(final Address address) { - if (location == null) { - location = cgeoapplication.getInstance().getLastCoords(); - } - if (location != null && address.hasLatitude() && address.hasLongitude()) { return HumanDistance.getHumanDistance(location.distanceTo(new Geopoint(address.getLatitude(), address.getLongitude()))); } @@ -83,7 +78,7 @@ public class AddressListAdapter extends ArrayAdapter<Address> { final int maxIndex = address.getMaxAddressLineIndex(); final ArrayList<String> lines = new ArrayList<String>(); for (int i = 0; i <= maxIndex; i++) { - String line = address.getAddressLine(i); + final String line = address.getAddressLine(i); if (StringUtils.isNotBlank(line)) { lines.add(line); } diff --git a/main/src/cgeo/geocaching/ui/CacheListAdapter.java b/main/src/cgeo/geocaching/ui/CacheListAdapter.java index 57e2a94..bda53d7 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; @@ -13,13 +12,13 @@ import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.sorting.CacheComparator; import cgeo.geocaching.sorting.DistanceComparator; import cgeo.geocaching.sorting.VisitComparator; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; 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; @@ -29,14 +28,13 @@ import android.text.Spannable; import android.text.Spanned; import android.text.style.StrikethroughSpan; import android.util.DisplayMetrics; -import android.util.Log; +import android.util.SparseArray; import android.view.GestureDetector; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.AccelerateDecelerateInterpolator; -import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.AnimationSet; import android.view.animation.TranslateAnimation; @@ -48,10 +46,8 @@ import android.widget.TextView; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; -import java.util.Map; import java.util.Set; public class CacheListAdapter extends ArrayAdapter<cgCache> { @@ -68,7 +64,7 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { private boolean sort = true; private int checked = 0; private boolean selectMode = false; - final private static Map<Integer, Drawable> gcIconDrawables = new HashMap<Integer, Drawable>(); + final private static SparseArray<Drawable> gcIconDrawables = new SparseArray<Drawable>(); final private Set<CompassMiniView> compasses = new LinkedHashSet<CompassMiniView>(); final private Set<DistanceView> distances = new LinkedHashSet<DistanceView>(); final private int[] ratingBcgs = new int[3]; @@ -76,7 +72,6 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { private static final int SWIPE_MIN_DISTANCE = 60; private static final int SWIPE_MAX_OFF_PATH = 100; private static final int SWIPE_DISTANCE = 80; - private static final float SWIPE_OPACITY = 0.5f; /** * time in milliseconds after which the list may be resorted due to position updates */ @@ -195,17 +190,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 +359,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; } @@ -486,7 +470,7 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { holder.inventory.removeAllViews(); } - ImageView tbIcon = null; + ImageView tbIcon; if (cache.getInventoryItems() > 0) { tbIcon = (ImageView) inflater.inflate(R.layout.trackable_icon, null); tbIcon.setImageResource(R.drawable.trackable_all); @@ -590,8 +574,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 +593,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()) { @@ -626,11 +610,13 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { private static Drawable getCacheIcon(cgCache cache) { int hashCode = getIconHashCode(cache.getType(), cache.hasUserModifiedCoords() || cache.hasFinalDefined()); - if (!gcIconDrawables.containsKey(hashCode)) { - // fallback to mystery icon - hashCode = getIconHashCode(CacheType.MYSTERY, cache.hasUserModifiedCoords() || cache.hasFinalDefined()); + Drawable drawable = gcIconDrawables.get(hashCode); + if (drawable != null) { + return drawable; } + // fallback to mystery icon + hashCode = getIconHashCode(CacheType.MYSTERY, cache.hasUserModifiedCoords() || cache.hasFinalDefined()); return gcIconDrawables.get(hashCode); } @@ -699,10 +685,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 +764,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; @@ -813,21 +796,12 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { showCheckbox.setFillAfter(true); showCheckbox.setInterpolator(new AccelerateDecelerateInterpolator()); - // dim cache info - final Animation dimInfo = new AlphaAnimation(1.0f, SWIPE_OPACITY); - dimInfo.setRepeatCount(0); - dimInfo.setDuration(force ? 0 : 400); - dimInfo.setFillEnabled(true); - dimInfo.setFillAfter(true); - dimInfo.setInterpolator(new AccelerateDecelerateInterpolator()); - // animation set (container) final AnimationSet selectAnimation = new AnimationSet(true); selectAnimation.setFillEnabled(true); selectAnimation.setFillAfter(true); selectAnimation.addAnimation(showCheckbox); - selectAnimation.addAnimation(dimInfo); holder.oneInfo.startAnimation(selectAnimation); cache.setStatusCheckedView(true); @@ -848,21 +822,12 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { hideCheckbox.setFillAfter(true); hideCheckbox.setInterpolator(new AccelerateDecelerateInterpolator()); - // brighten cache info - final Animation brightenInfo = new AlphaAnimation(SWIPE_OPACITY, 1.0f); - brightenInfo.setRepeatCount(0); - brightenInfo.setDuration(force ? 0 : 400); - brightenInfo.setFillEnabled(true); - brightenInfo.setFillAfter(true); - brightenInfo.setInterpolator(new AccelerateDecelerateInterpolator()); - // animation set (container) final AnimationSet selectAnimation = new AnimationSet(true); selectAnimation.setFillEnabled(true); selectAnimation.setFillAfter(true); selectAnimation.addAnimation(hideCheckbox); - selectAnimation.addAnimation(brightenInfo); holder.oneInfo.startAnimation(selectAnimation); cache.setStatusCheckedView(false); @@ -871,4 +836,17 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { public List<cgCache> getFilteredList() { return list; } + + public List<cgCache> getCheckedCaches() { + ArrayList<cgCache> result = new ArrayList<cgCache>(); + int checked = getChecked(); + if (checked > 0) { + for (cgCache cache : list) { + if (cache.isStatusChecked()) { + result.add(cache); + } + } + } + return result; + } } diff --git a/main/src/cgeo/geocaching/ui/CompassMiniView.java b/main/src/cgeo/geocaching/ui/CompassMiniView.java index 1fa4cfb..b51b7a2 100644 --- a/main/src/cgeo/geocaching/ui/CompassMiniView.java +++ b/main/src/cgeo/geocaching/ui/CompassMiniView.java @@ -111,8 +111,8 @@ public class CompassMiniView extends View { // compass margins canvas.setDrawFilter(setfil); - int marginLeft = 0; - int marginTop = 0; + int marginLeft; + int marginTop; int compassArrowWidth = compassArrow.getWidth(); int compassArrowHeight = compassArrow.getWidth(); @@ -136,7 +136,7 @@ public class CompassMiniView extends View { } private int measureWidth(int measureSpec) { - int result = 0; + int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); @@ -154,7 +154,7 @@ public class CompassMiniView extends View { } private int measureHeight(int measureSpec) { - int result = 0; + int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); diff --git a/main/src/cgeo/geocaching/ui/CompassView.java b/main/src/cgeo/geocaching/ui/CompassView.java index 6fc576f..8a295c3 100644 --- a/main/src/cgeo/geocaching/ui/CompassView.java +++ b/main/src/cgeo/geocaching/ui/CompassView.java @@ -1,7 +1,7 @@ package cgeo.geocaching.ui; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; +import cgeo.geocaching.utils.Log; import android.content.Context; import android.graphics.Bitmap; @@ -12,12 +12,10 @@ import android.graphics.PaintFlagsDrawFilter; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; -import android.util.Log; import android.view.View; public class CompassView extends View { - private changeThread watchdog = null; private volatile boolean wantStop = false; private Context context = null; private Bitmap compassUnderlay = null; @@ -58,7 +56,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()); } } }; @@ -95,8 +93,7 @@ public class CompassView extends View { initialDisplay = true; wantStop = false; - watchdog = new changeThread(); - watchdog.start(); + new changeThread().start(); } @Override @@ -212,8 +209,8 @@ public class CompassView extends View { int canvasCenterX = (compassRoseWidth / 2) + ((getWidth() - compassRoseWidth) / 2); int canvasCenterY = (compassRoseHeight / 2) + ((getHeight() - compassRoseHeight) / 2); - int marginLeftTemp = 0; - int marginTopTemp = 0; + int marginLeftTemp; + int marginTopTemp; super.onDraw(canvas); @@ -254,7 +251,7 @@ public class CompassView extends View { } private int measureWidth(int measureSpec) { - int result = 0; + int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); @@ -272,7 +269,7 @@ public class CompassView extends View { } private int measureHeight(int measureSpec) { - int result = 0; + int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); 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 2ebb893..76dc10e 100644 --- a/main/src/cgeo/geocaching/ui/GPXListAdapter.java +++ b/main/src/cgeo/geocaching/ui/GPXListAdapter.java @@ -1,12 +1,11 @@ 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; import android.app.Activity; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -17,7 +16,6 @@ import java.io.File; import java.util.List; public class GPXListAdapter extends ArrayAdapter<File> { - private GPXListView holder = null; private cgeogpxes activity = null; private LayoutInflater inflater = null; @@ -34,13 +32,14 @@ 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; } final File file = getItem(position); View v = rowView; + GPXListView holder; if (v == null) { v = inflater.inflate(R.layout.gpx_item, null); diff --git a/main/src/cgeo/geocaching/ui/MapfileListAdapter.java b/main/src/cgeo/geocaching/ui/MapfileListAdapter.java index 9196a41..a14d120 100644 --- a/main/src/cgeo/geocaching/ui/MapfileListAdapter.java +++ b/main/src/cgeo/geocaching/ui/MapfileListAdapter.java @@ -1,12 +1,11 @@ package cgeo.geocaching.ui; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; import cgeo.geocaching.cgSelectMapfile; +import cgeo.geocaching.utils.Log; import android.app.Activity; import android.graphics.Typeface; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -20,7 +19,6 @@ public class MapfileListAdapter extends ArrayAdapter<File> { private cgSelectMapfile parentView; private LayoutInflater inflater; - private MapfileView holder; public MapfileListAdapter(cgSelectMapfile parentIn, List<File> listIn) { super(parentIn, 0, listIn); @@ -35,13 +33,14 @@ 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; } File file = getItem(position); View v = rowView; + MapfileView holder; if (v == null) { v = inflater.inflate(R.layout.mapfile_item, 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/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/ClipboardUtils.java b/main/src/cgeo/geocaching/utils/ClipboardUtils.java index 865d8d6..e6779ad 100644 --- a/main/src/cgeo/geocaching/utils/ClipboardUtils.java +++ b/main/src/cgeo/geocaching/utils/ClipboardUtils.java @@ -10,6 +10,7 @@ import android.text.ClipboardManager; * This class uses the deprecated function ClipboardManager.setText(CharSequence). * API 11 introduced setPrimaryClip(ClipData) */ +@SuppressWarnings("deprecation") public final class ClipboardUtils { /** diff --git a/main/src/cgeo/geocaching/utils/CryptUtils.java b/main/src/cgeo/geocaching/utils/CryptUtils.java index 907fa1f..f04327e 100644 --- a/main/src/cgeo/geocaching/utils/CryptUtils.java +++ b/main/src/cgeo/geocaching/utils/CryptUtils.java @@ -1,10 +1,8 @@ package cgeo.geocaching.utils; -import cgeo.geocaching.Settings; import android.text.Spannable; import android.text.SpannableStringBuilder; -import android.util.Log; import java.math.BigInteger; import java.security.MessageDigest; @@ -75,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; @@ -89,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; @@ -104,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; @@ -137,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/IObserver.java b/main/src/cgeo/geocaching/utils/IObserver.java new file mode 100644 index 0000000..c7842aa --- /dev/null +++ b/main/src/cgeo/geocaching/utils/IObserver.java @@ -0,0 +1,22 @@ +package cgeo.geocaching.utils; + +/** + * Observer interface. + * <p/> + * An observer will receive updates about the observed object (implementing the {@link ISubject} interface) + * through its {@link #update(T)} method. + * + * @param <T> + * the kind of data to observe + */ +public interface IObserver<T> { + + /** + * Called when an observed object has updated its data. + * + * @param data + * the updated data + */ + void update(final T data); + +} diff --git a/main/src/cgeo/geocaching/utils/ISubject.java b/main/src/cgeo/geocaching/utils/ISubject.java new file mode 100644 index 0000000..f332ee8 --- /dev/null +++ b/main/src/cgeo/geocaching/utils/ISubject.java @@ -0,0 +1,57 @@ +package cgeo.geocaching.utils; + +/** + * Interface for subjects objects. Those can be observed by objects implementing the {@link IObserver} interface. + * + * @param <T> + * the kind of data to observe + */ + +public interface ISubject<T> { + + /** + * Add an observer to the observers list. + * <p/> + * Observers will be notified with no particular order. + * + * @param observer + * the observer to add + * @return true if the observer has been added, false if it was present already + */ + public boolean addObserver(final IObserver<? super T> observer); + + /** + * Delete an observer from the observers list. + * + * @param observer + * the observer to remove + * @return true if the observer has been removed, false if it was not in the list of observers + */ + public boolean deleteObserver(final IObserver<? super T> observer); + + /** + * Number of observers currently observing the object. + * + * @return the number of observers + */ + public int sizeObservers(); + + /** + * Notify all the observers that new data is available. + * <p/> + * The {@link IObserver#update(T)} method of each observer will be called with no particular order. + * + * @param data + * the updated data + * @return true if at least one observer was notified, false if there were no observers + */ + public boolean notifyObservers(final T data); + + /** + * Clear the observers list. + * + * @return true if there were observers before calling this method, false if the observers list was empty + */ + public boolean clearObservers(); + +} diff --git a/main/src/cgeo/geocaching/utils/LRUList.java b/main/src/cgeo/geocaching/utils/LRUList.java deleted file mode 100644 index 13596b1..0000000 --- a/main/src/cgeo/geocaching/utils/LRUList.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 LRUList<T> extends ArrayList<T> { - - private static final long serialVersionUID = -5077882607489806620L; - private final int maxEntries; - - public LRUList(int maxEntries) { - this.maxEntries = maxEntries; - } - - private void removeElements(int count) { - for (int i = 0; i < count; i++) { - this.remove(0); - } - } - - @Override - public boolean add(T item) { - removeElements(this.size() + 1 - maxEntries); - return super.add(item); - } - - @Override - public boolean addAll(Collection<? extends T> collection) { - if (collection.size() > this.size()) { - this.clear(); - for (T item : collection) { - this.add(item); - } - return false; - } else { - removeElements(this.size() + collection.size() - maxEntries); - return super.addAll(collection); - } - } - -} diff --git a/main/src/cgeo/geocaching/utils/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..953fc47 --- /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; + } + + 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..986087f --- /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 E e : map.keySet()) { + s.writeObject(e); + } + } + + /** + * 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 new file mode 100644 index 0000000..9f5bd3d --- /dev/null +++ b/main/src/cgeo/geocaching/utils/Log.java @@ -0,0 +1,69 @@ +package cgeo.geocaching.utils; + + +final public class Log { + + private static final String TAG = "cgeo"; + + private static boolean isDebug = true; + + public static boolean isDebug() { + return isDebug; + } + + public static void setDebugUnsaved(boolean isDebug) { + Log.isDebug = isDebug; + } + + public static void v(final String msg) { + if (isDebug) { + android.util.Log.v(TAG, msg); + } + } + + public static void v(final String msg, final Throwable t) { + if (isDebug) { + android.util.Log.v(TAG, msg, t); + } + } + + public static void d(final String msg) { + if (isDebug) { + android.util.Log.d(TAG, msg); + } + } + + public static void d(final String msg, final Throwable t) { + if (isDebug) { + android.util.Log.d(TAG, msg, t); + } + } + + public static void i(final String msg) { + if (isDebug) { + android.util.Log.i(TAG, msg); + } + } + + public static void i(final String msg, final Throwable t) { + if (isDebug) { + android.util.Log.i(TAG, msg, t); + } + } + + public static void w(final String msg) { + android.util.Log.w(TAG, msg); + } + + public static void w(final String msg, final Throwable t) { + android.util.Log.w(TAG, msg, t); + } + + public static void e(final String msg) { + android.util.Log.e(TAG, msg); + } + + 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 b9bebc9..60866e0 100644 --- a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java +++ b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java @@ -2,14 +2,13 @@ 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; -import android.util.Log; /** * provides all the available templates for logging @@ -56,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) { @@ -71,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) { @@ -90,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); } @@ -134,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; } } diff --git a/main/src/cgeo/geocaching/utils/MemorySubject.java b/main/src/cgeo/geocaching/utils/MemorySubject.java new file mode 100644 index 0000000..c424528 --- /dev/null +++ b/main/src/cgeo/geocaching/utils/MemorySubject.java @@ -0,0 +1,45 @@ +package cgeo.geocaching.utils; + +/** + * Synchronized implementation of the {@link ISubject} interface with an added pull interface. + * + * @param <T> + * the kind of data to observe + */ +public class MemorySubject<T> extends Subject<T> { + + /** + * The latest version of the observed data. + * <p/> + * A child class implementation may want to set this field from its constructors, in case early observers request + * the data before it got a chance to get updated. Otherwise, <code>null</code> will be returned until updated + * data is available. + */ + private T memory; + + @Override + public synchronized boolean addObserver(final IObserver<? super T> observer) { + final boolean added = super.addObserver(observer); + if (added && memory != null) { + observer.update(memory); + } + return added; + } + + @Override + public synchronized boolean notifyObservers(final T data) { + memory = data; + return super.notifyObservers(data); + } + + /** + * Get the memorized version of the data. + * + * @return the initial data set by the subject (which may be <code>null</code>), + * or the updated data if it is available + */ + public synchronized T getMemory() { + return memory; + } + +} diff --git a/main/src/cgeo/geocaching/utils/PeriodicHandler.java b/main/src/cgeo/geocaching/utils/PeriodicHandler.java new file mode 100644 index 0000000..3f6c345 --- /dev/null +++ b/main/src/cgeo/geocaching/utils/PeriodicHandler.java @@ -0,0 +1,74 @@ +package cgeo.geocaching.utils; + +import android.os.Handler; +import android.os.Message; + +/** + * A PeriodicHandler class helps with the implementation of a periodic + * action embedded in a thread with a looper such as the UI thread. + * The act() method will be called periodically. The clock may drift + * as the implementation does not target real-time actions. + * + * The handler will be interrupted if the device goes to sleep. + * + */ +abstract public class PeriodicHandler extends Handler { + + final static private int START = 0; + final static private int STOP = 1; + final static private int ACT = 2; + + final private long period; + + /** + * Create a new PeriodicHandler object. + * + * @param period + * The period in milliseconds. + */ + public PeriodicHandler(final long period) { + this.period = period; + } + + /** + * Subclasses of PeriodicHandler must implement this method. + */ + abstract public void act(); + + @Override + public void handleMessage(final Message msg) { + switch (msg.what) { + case START: + removeMessages(ACT); + sendEmptyMessage(ACT); + break; + case STOP: + removeMessages(ACT); + break; + case ACT: + sendEmptyMessageDelayed(ACT, period); + act(); + } + } + + /** + * Start the periodic handler. + * + * Restarting a handler that is already started will only + * reset its clock. + */ + public void start() { + sendEmptyMessage(START); + } + + /** + * Stop the periodic handler. + * + * If this method is called from the looper thread, this call is + * guaranteed to be synchronous. + */ + public void stop() { + sendMessageAtFrontOfQueue(obtainMessage(STOP)); + } + +} diff --git a/main/src/cgeo/geocaching/utils/Subject.java b/main/src/cgeo/geocaching/utils/Subject.java new file mode 100644 index 0000000..b1754cc --- /dev/null +++ b/main/src/cgeo/geocaching/utils/Subject.java @@ -0,0 +1,76 @@ +package cgeo.geocaching.utils; + +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * Synchronized implementation of the {@link ISubject} interface. + * + * @param <T> + * the kind of data to observe + */ +public class Subject<T> implements ISubject<T> { + + /** + * Collection of observers. + */ + protected final Set<IObserver<? super T>> observers = new LinkedHashSet<IObserver<? super T>>(); + + @Override + public synchronized boolean addObserver(final IObserver<? super T> observer) { + final boolean added = observers.add(observer); + if (added && observers.size() == 1) { + onFirstObserver(); + } + return added; + } + + @Override + public synchronized boolean deleteObserver(final IObserver<? super T> observer) { + final boolean removed = observers.remove(observer); + if (removed && observers.isEmpty()) { + onLastObserver(); + } + return removed; + } + + @Override + public synchronized boolean notifyObservers(final T arg) { + final boolean nonEmpty = !observers.isEmpty(); + for (final IObserver<? super T> observer : observers) { + observer.update(arg); + } + return nonEmpty; + } + + @Override + public synchronized int sizeObservers() { + return observers.size(); + } + + @Override + public synchronized boolean clearObservers() { + final boolean nonEmpty = !observers.isEmpty(); + for (final IObserver<? super T> observer : observers) { + deleteObserver(observer); + } + return nonEmpty; + } + + /** + * Method called when the collection of observers goes from empty to non-empty. + * <p/> + * The default implementation does nothing and may be overwritten by child classes. + */ + protected void onFirstObserver() { + } + + /** + * Method called when the collection of observers goes from non-empty to empty. + * <p/> + * The default implementation does nothing and may be overwritten by child classes. + */ + protected void onLastObserver() { + } + +} |
