diff options
Diffstat (limited to 'main/src')
134 files changed, 3894 insertions, 2780 deletions
diff --git a/main/src/cgeo/geocaching/AbstractLoggingActivity.java b/main/src/cgeo/geocaching/AbstractLoggingActivity.java index 62cb5cb..4816dee 100644 --- a/main/src/cgeo/geocaching/AbstractLoggingActivity.java +++ b/main/src/cgeo/geocaching/AbstractLoggingActivity.java @@ -20,7 +20,7 @@ public abstract class AbstractLoggingActivity extends AbstractActivity { private static final int MENU_SIGNATURE = 1; private static final int MENU_SMILEY = 2; - public AbstractLoggingActivity(String helpTopic) { + protected AbstractLoggingActivity(String helpTopic) { super(helpTopic); } diff --git a/main/src/cgeo/geocaching/AbstractPopupActivity.java b/main/src/cgeo/geocaching/AbstractPopupActivity.java index 830d61a..db9a04c 100644 --- a/main/src/cgeo/geocaching/AbstractPopupActivity.java +++ b/main/src/cgeo/geocaching/AbstractPopupActivity.java @@ -73,7 +73,7 @@ public abstract class AbstractPopupActivity extends AbstractActivity { } }; - public AbstractPopupActivity(String helpTopic, int layout) { + protected AbstractPopupActivity(String helpTopic, int layout) { super(helpTopic); this.layout = layout; } @@ -109,7 +109,7 @@ public abstract class AbstractPopupActivity extends AbstractActivity { } protected void init() { - cache = app.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB); + cache = cgData.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB); if (cache == null) { showToast(res.getString(R.string.err_detail_cache_find)); @@ -118,7 +118,7 @@ public abstract class AbstractPopupActivity extends AbstractActivity { return; } - geocode = cache.getGeocode().toUpperCase(); + geocode = cache.getGeocode(); } private void showInBrowser() { @@ -186,10 +186,10 @@ public abstract class AbstractPopupActivity extends AbstractActivity { case MENU_SHOW_IN_BROWSER: showInBrowser(); return true; - } - - if (LoggingUI.onMenuItemSelected(item, this, cache)) { - return true; + default: + if (LoggingUI.onMenuItemSelected(item, this, cache)) { + return true; + } } return true; @@ -251,7 +251,7 @@ public abstract class AbstractPopupActivity extends AbstractActivity { final String cacheSize = cache.getSize() != CacheSize.UNKNOWN ? " (" + cache.getSize().getL10n() + ")" : ""; details.add(R.string.cache_type, cacheType + cacheSize); - details.add(R.string.cache_geocode, cache.getGeocode().toUpperCase()); + details.add(R.string.cache_geocode, cache.getGeocode()); details.addCacheState(cache); details.addDistance(cache, cacheDistance); @@ -276,7 +276,7 @@ public abstract class AbstractPopupActivity extends AbstractActivity { @Override public void onClick(View arg0) { - CacheDetailActivity.startActivity(AbstractPopupActivity.this, geocode.toUpperCase()); + CacheDetailActivity.startActivity(AbstractPopupActivity.this, geocode); finish(); } }); diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java index 2dcafde..188f939 100644 --- a/main/src/cgeo/geocaching/CacheDetailActivity.java +++ b/main/src/cgeo/geocaching/CacheDetailActivity.java @@ -1,10 +1,11 @@ package cgeo.geocaching; import cgeo.calendar.ICalendar; -import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.activity.AbstractViewPagerActivity; import cgeo.geocaching.activity.Progress; import cgeo.geocaching.apps.cache.GeneralAppsFactory; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; +import cgeo.geocaching.compatibility.Compatibility; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.IConnector; import cgeo.geocaching.connector.gc.GCConnector; @@ -12,10 +13,13 @@ import cgeo.geocaching.enumerations.CacheAttribute; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.LogType; +import cgeo.geocaching.enumerations.WaypointType; import cgeo.geocaching.geopoint.GeopointFormatter; import cgeo.geocaching.geopoint.Units; import cgeo.geocaching.network.HtmlImage; +import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.ui.AbstractCachingPageViewCreator; import cgeo.geocaching.ui.CacheDetailsCreator; import cgeo.geocaching.ui.DecryptTextClickListener; import cgeo.geocaching.ui.EditorDialog; @@ -34,15 +38,16 @@ 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; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; import android.R.color; +import android.app.Activity; import android.app.AlertDialog; +import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -57,10 +62,6 @@ import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.os.Parcelable; -import android.support.v4.view.PagerAdapter; -import android.support.v4.view.ViewPager; -import android.support.v4.view.ViewPager.OnPageChangeListener; import android.text.Editable; import android.text.Html; import android.text.Spannable; @@ -79,11 +80,13 @@ import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewParent; -import android.view.WindowManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; @@ -92,12 +95,10 @@ import android.widget.ScrollView; import android.widget.TextView; import android.widget.TextView.BufferType; -import java.net.URLEncoder; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.EnumSet; -import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -110,9 +111,8 @@ import java.util.regex.Pattern; * * e.g. details, description, logs, waypoints, inventory... */ -public class CacheDetailActivity extends AbstractActivity { +public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailActivity.Page> { - private static final String EXTRAS_PAGE = "page"; private static final int MENU_FIELD_COPY = 1; private static final int MENU_FIELD_TRANSLATE = 2; private static final int MENU_FIELD_TRANSLATE_EN = 3; @@ -129,6 +129,7 @@ public class CacheDetailActivity extends AbstractActivity { private static final int CONTEXT_MENU_WAYPOINT_NAVIGATE = 1238; private static final int CONTEXT_MENU_WAYPOINT_CACHES_AROUND = 1239; private static final int CONTEXT_MENU_WAYPOINT_DEFAULT_NAVIGATION = 1240; + private static final int CONTEXT_MENU_WAYPOINT_RESET_ORIGINAL_CACHE_COORDINATES = 1241; private static final Pattern DARK_COLOR_PATTERN = Pattern.compile(Pattern.quote("color=\"#") + "(0[0-9]){3}" + "\""); @@ -169,33 +170,6 @@ public class CacheDetailActivity extends AbstractActivity { private int contextMenuWPIndex = -1; /** - * A {@link List} of all available pages. - * - * TODO Move to adapter - */ - private final List<Page> pageOrder = new ArrayList<Page>(); - - /** - * Instances of all {@link PageViewCreator}. - */ - private final Map<Page, PageViewCreator> viewCreators = new HashMap<Page, PageViewCreator>(); - - /** - * The {@link ViewPager} for this activity. - */ - private ViewPager viewPager; - - /** - * The {@link ViewPagerAdapter} for this activity. - */ - private ViewPagerAdapter viewPagerAdapter; - - /** - * The {@link TitlePageIndicator} for this activity. - */ - private TitlePageIndicator titleIndicator; - - /** * If another activity is called and can modify the data of this activity, we refresh it on resume. */ private boolean refreshOnResume = false; @@ -226,8 +200,6 @@ public class CacheDetailActivity extends AbstractActivity { setTitle(res.getString(R.string.cache)); String geocode = null; - String guid = null; - String name = null; // TODO Why can it happen that search is not null? onCreate should be called only once and it is not set before. if (search != null) { @@ -242,6 +214,8 @@ public class CacheDetailActivity extends AbstractActivity { final Uri uri = getIntent().getData(); // try to get data from extras + String name = null; + String guid = null; if (geocode == null && extras != null) { geocode = extras.getString("geocode"); name = extras.getString("name"); @@ -250,8 +224,8 @@ public class CacheDetailActivity extends AbstractActivity { // try to get data from URI if (geocode == null && guid == null && uri != null) { - String uriHost = uri.getHost().toLowerCase(); - String uriPath = uri.getPath().toLowerCase(); + String uriHost = uri.getHost().toLowerCase(Locale.US); + String uriPath = uri.getPath().toLowerCase(Locale.US); String uriQuery = uri.getQuery(); if (uriQuery != null) { @@ -265,11 +239,11 @@ public class CacheDetailActivity extends AbstractActivity { guid = uri.getQueryParameter("guid"); if (StringUtils.isNotBlank(geocode)) { - geocode = geocode.toUpperCase(); + geocode = geocode.toUpperCase(Locale.US); guid = null; } else if (StringUtils.isNotBlank(guid)) { geocode = null; - guid = guid.toLowerCase(); + guid = guid.toLowerCase(Locale.US); } else { showToast(res.getString(R.string.err_detail_open)); finish(); @@ -277,7 +251,7 @@ public class CacheDetailActivity extends AbstractActivity { } } else if (uriHost.contains("coord.info")) { if (uriPath != null && uriPath.startsWith("/gc")) { - geocode = uriPath.substring(1).toUpperCase(); + geocode = uriPath.substring(1).toUpperCase(Locale.US); } else { showToast(res.getString(R.string.err_detail_open)); finish(); @@ -300,7 +274,7 @@ public class CacheDetailActivity extends AbstractActivity { if (StringUtils.isNotBlank(name)) { title = name; } else if (null != geocode && StringUtils.isNotBlank(geocode)) { // can't be null, but the compiler doesn't understand StringUtils.isNotBlank() - title = geocode.toUpperCase(); + title = geocode; } progress.show(this, title, res.getString(R.string.cache_dialog_loading_details), true, loadCacheHandler.cancelMessage()); } catch (Exception e) { @@ -316,50 +290,21 @@ public class CacheDetailActivity extends AbstractActivity { } }); - // initialize ViewPager - viewPager = (ViewPager) findViewById(R.id.viewpager); - viewPagerAdapter = new ViewPagerAdapter(); - viewPager.setAdapter(viewPagerAdapter); + final int pageToOpen = Settings.isOpenLastDetailsPage() ? Settings.getLastDetailsPage() : 1; + createViewPager(pageToOpen, new OnPageSelectedListener() { - titleIndicator = (TitlePageIndicator) findViewById(R.id.pager_indicator); - titleIndicator.setViewPager(viewPager); - titleIndicator.setOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageSelected(int position) { if (Settings.isOpenLastDetailsPage()) { Settings.setLastDetailsPage(position); } // lazy loading of cache images - if (pageOrder.get(position) == Page.IMAGES) { + if (getPage(position) == Page.IMAGES) { loadCacheImages(); } } - - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - } - - @Override - public void onPageScrollStateChanged(int state) { - } }); - // switch to entry page (last used or 2) - int entryPageIndex; - if (extras != null && extras.get(EXTRAS_PAGE) != null) { - entryPageIndex = extras.getInt(EXTRAS_PAGE); - } - else { - entryPageIndex = Settings.isOpenLastDetailsPage() ? Settings.getLastDetailsPage() : 1; - } - if (viewPagerAdapter.getCount() < entryPageIndex) { - for (int i = 0; i <= entryPageIndex; i++) { - // we can't switch to a page that is out of bounds, so we add null-pages - pageOrder.add(null); - } - } - viewPager.setCurrentItem(entryPageIndex, false); - // Initialization done. Let's load the data with the given information. new LoadCacheThread(geocode, guid, loadCacheHandler).start(); } @@ -436,10 +381,14 @@ public class CacheDetailActivity extends AbstractActivity { final cgWaypoint waypoint = sortedWaypoints.get(i); final int index = cache.getWaypoints().indexOf(waypoint); menu.setHeaderTitle(res.getString(R.string.waypoint)); - menu.add(CONTEXT_MENU_WAYPOINT_EDIT, index, 0, R.string.waypoint_edit); - menu.add(CONTEXT_MENU_WAYPOINT_DUPLICATE, index, 0, R.string.waypoint_duplicate); + if (waypoint.getWaypointType().equals(WaypointType.ORIGINAL)) { + menu.add(CONTEXT_MENU_WAYPOINT_RESET_ORIGINAL_CACHE_COORDINATES, index, 0, R.string.waypoint_reset_cache_coords); + } else { + menu.add(CONTEXT_MENU_WAYPOINT_EDIT, index, 0, R.string.waypoint_edit); + menu.add(CONTEXT_MENU_WAYPOINT_DUPLICATE, index, 0, R.string.waypoint_duplicate); + } contextMenuWPIndex = index; - if (waypoint.isUserDefined()) { + if (waypoint.isUserDefined() && !waypoint.getWaypointType().equals(WaypointType.ORIGINAL)) { menu.add(CONTEXT_MENU_WAYPOINT_DELETE, index, 0, R.string.waypoint_delete); } if (waypoint.getCoords() != null) { @@ -470,7 +419,7 @@ public class CacheDetailActivity extends AbstractActivity { showToast(res.getString(R.string.translate_length_warning)); } menu.add(viewId, MENU_FIELD_TRANSLATE, 0, res.getString(R.string.translate_to_sys_lang, Locale.getDefault().getDisplayLanguage())); - if (Settings.isUseEnglish() && Locale.getDefault() != Locale.ENGLISH) { + if (Settings.isUseEnglish() && !Locale.getDefault().equals(Locale.ENGLISH)) { menu.add(viewId, MENU_FIELD_TRANSLATE_EN, 0, res.getString(R.string.translate_to_english)); } @@ -511,54 +460,55 @@ public class CacheDetailActivity extends AbstractActivity { } break; - case CONTEXT_MENU_WAYPOINT_EDIT: { - final cgWaypoint waypoint = cache.getWaypoint(index); - if (waypoint != null) { - EditWaypointActivity.startActivityEditWaypoint(this, waypoint.getId()); + case CONTEXT_MENU_WAYPOINT_EDIT: + final cgWaypoint waypointEdit = cache.getWaypoint(index); + if (waypointEdit != null) { + EditWaypointActivity.startActivityEditWaypoint(this, waypointEdit.getId()); refreshOnResume = true; } break; - } case CONTEXT_MENU_WAYPOINT_DUPLICATE: - if (cache.duplicateWaypoint(index)) { - app.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); + final cgWaypoint waypointDuplicate = cache.getWaypoint(index); + if (cache.duplicateWaypoint(waypointDuplicate)) { + cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); notifyDataSetChanged(); } break; case CONTEXT_MENU_WAYPOINT_DELETE: - if (cache.deleteWaypoint(index)) { - app.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); + final cgWaypoint waypointDelete = cache.getWaypoint(index); + if (cache.deleteWaypoint(waypointDelete)) { + cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); notifyDataSetChanged(); } break; - case CONTEXT_MENU_WAYPOINT_DEFAULT_NAVIGATION: { - final cgWaypoint waypoint = cache.getWaypoint(index); - if (waypoint != null) { - NavigationAppFactory.startDefaultNavigationApplication(1, this, waypoint); + case CONTEXT_MENU_WAYPOINT_DEFAULT_NAVIGATION: + final cgWaypoint waypointNavigation = cache.getWaypoint(index); + if (waypointNavigation != null) { + NavigationAppFactory.startDefaultNavigationApplication(1, this, waypointNavigation); } - } break; - case CONTEXT_MENU_WAYPOINT_NAVIGATE: { - final cgWaypoint waypoint = cache.getWaypoint(contextMenuWPIndex); - if (waypoint != null) { - NavigationAppFactory.showNavigationMenu(this, null, waypoint, null); + case CONTEXT_MENU_WAYPOINT_NAVIGATE: + final cgWaypoint waypointNav = cache.getWaypoint(contextMenuWPIndex); + if (waypointNav != null) { + NavigationAppFactory.showNavigationMenu(this, null, waypointNav, null); } - } break; - case CONTEXT_MENU_WAYPOINT_CACHES_AROUND: { - final cgWaypoint waypoint = cache.getWaypoint(index); - if (waypoint != null) { - cgeocaches.startActivityCoordinates(this, waypoint.getCoords()); + case CONTEXT_MENU_WAYPOINT_CACHES_AROUND: + final cgWaypoint waypointAround = cache.getWaypoint(index); + if (waypointAround != null) { + cgeocaches.startActivityCoordinates(this, waypointAround.getCoords()); } - } break; - default: { + + case CONTEXT_MENU_WAYPOINT_RESET_ORIGINAL_CACHE_COORDINATES: + new ResetCacheCoordinatesDialog(cache, cache.getWaypoint(index), this).show(); + break; + + default: if (imagesList != null && imagesList.onContextItemSelected(item)) { return true; } - return onOptionsItemSelected(item); - } } return false; } @@ -594,7 +544,7 @@ public class CacheDetailActivity extends AbstractActivity { public boolean onOptionsItemSelected(MenuItem item) { final int menuItem = item.getItemId(); - switch(menuItem) { + switch (menuItem) { case 0: // no menu selected, but a new sub menu shown return false; @@ -616,16 +566,17 @@ public class CacheDetailActivity extends AbstractActivity { return true; } return false; - } - if (NavigationAppFactory.onMenuItemSelected(item, this, cache)) { - return true; - } - if (GeneralAppsFactory.onMenuItemSelected(item, this, cache)) { - return true; - } - if (LoggingUI.onMenuItemSelected(item, this, cache)) { - refreshOnResume = true; - return true; + default: + if (NavigationAppFactory.onMenuItemSelected(item, this, cache)) { + return true; + } + if (GeneralAppsFactory.onMenuItemSelected(item, this, cache)) { + return true; + } + if (LoggingUI.onMenuItemSelected(item, this, cache)) { + refreshOnResume = true; + return true; + } } return true; @@ -688,49 +639,15 @@ public class CacheDetailActivity extends AbstractActivity { // allow cache to notify CacheDetailActivity when it changes so it can be reloaded cache.setChangeNotificationHandler(cacheChangeNotificationHandler); - // notify all creators that the data has changed - for (PageViewCreator creator : viewCreators.values()) { - creator.notifyDataSetChanged(); - } - - // action bar: title and icon (default: mystery icon) + // action bar: title and icon if (StringUtils.isNotBlank(cache.getName())) { - setTitle(cache.getName() + " (" + cache.getGeocode().toUpperCase() + ')'); + setTitle(cache.getName() + " (" + cache.getGeocode() + ')'); } else { - setTitle(cache.getGeocode().toUpperCase()); + setTitle(cache.getGeocode()); } ((TextView) findViewById(R.id.actionbar_title)).setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(cache.getType().markerId), null, null, null); - // add available pages (remove old pages first) - pageOrder.clear(); - - pageOrder.add(Page.WAYPOINTS); - pageOrder.add(Page.DETAILS); - final int detailsIndex = pageOrder.size() - 1; - pageOrder.add(Page.DESCRIPTION); - if (cache.getLogs().isNotEmpty()) { - pageOrder.add(Page.LOGS); - } - if (CollectionUtils.isNotEmpty(cache.getFriendsLogs())) { - pageOrder.add(Page.LOGSFRIENDS); - } - if (CollectionUtils.isNotEmpty(cache.getInventory())) { - pageOrder.add(Page.INVENTORY); - } - if (CollectionUtils.isNotEmpty(cache.getImages())) { - pageOrder.add(Page.IMAGES); - } - - // switch to details page, if we're out of bounds - if (viewPager.getCurrentItem() < 0 || viewPager.getCurrentItem() >= viewPagerAdapter.getCount()) { - viewPager.setCurrentItem(detailsIndex, false); - } - - // notify the adapter that the data has changed - viewPagerAdapter.notifyDataSetChanged(); - - // notify the indicator that the data has changed - titleIndicator.notifyDataSetChanged(); + reinitializeViewPager(); // rendering done! remove progress popup if any there progress.dismiss(); @@ -933,7 +850,7 @@ public class CacheDetailActivity extends AbstractActivity { cgeocaches.startActivityUserName(CacheDetailActivity.this, name.toString()); return; case 2: - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?u=" + URLEncoder.encode(name.toString())))); + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?u=" + Network.encode(name.toString())))); return; default: break; @@ -948,7 +865,7 @@ public class CacheDetailActivity extends AbstractActivity { if (imagesList != null) { return; } - PageViewCreator creator = viewCreators.get(Page.IMAGES); + PageViewCreator creator = getViewCreator(Page.IMAGES); if (creator == null) { return; } @@ -956,139 +873,17 @@ public class CacheDetailActivity extends AbstractActivity { if (imageView == null) { return; } - imagesList = new ImagesList(CacheDetailActivity.this, cache.getGeocode()); + imagesList = new ImagesList(this, cache.getGeocode()); imagesList.loadImages(imageView, cache.getImages(), ImageType.AllImages, false); } public static void startActivity(final Context context, final String geocode) { final Intent detailIntent = new Intent(context, CacheDetailActivity.class); - detailIntent.putExtra("geocode", geocode.toUpperCase()); - context.startActivity(detailIntent); - } - - public static void startActivity(final Context context, final String geocode, final int page) { - final Intent detailIntent = new Intent(context, CacheDetailActivity.class); - detailIntent.putExtra("geocode", geocode.toUpperCase()); - detailIntent.putExtra(EXTRAS_PAGE, page); + detailIntent.putExtra("geocode", geocode); context.startActivity(detailIntent); } /** - * The ViewPagerAdapter for scrolling through pages of the CacheDetailActivity. - */ - private class ViewPagerAdapter extends PagerAdapter implements TitleProvider { - - @Override - public void destroyItem(View container, int position, Object object) { - ((ViewPager) container).removeView((View) object); - } - - @Override - public void finishUpdate(View container) { - } - - @Override - public int getCount() { - return pageOrder.size(); - } - - @Override - public Object instantiateItem(View container, int position) { - final Page page = pageOrder.get(position); - - PageViewCreator creator = viewCreators.get(page); - - if (null == creator && null != page) { - // The creator is not instantiated yet, let's do it. - switch (page) { - case DETAILS: - creator = new DetailsViewCreator(); - break; - - case DESCRIPTION: - creator = new DescriptionViewCreator(); - break; - - case LOGS: - creator = new LogsViewCreator(true); - break; - - case LOGSFRIENDS: - creator = new LogsViewCreator(false); - break; - - case WAYPOINTS: - creator = new WaypointsViewCreator(); - break; - - case INVENTORY: - creator = new InventoryViewCreator(); - break; - - case IMAGES: - creator = new ImagesViewCreator(); - break; - } - viewCreators.put(page, creator); - } - - View view = null; - - try { - if (null != creator) { - // Result from getView() is maybe cached, but it should be valid because the - // creator should be informed about data-changes with notifyDataSetChanged() - view = creator.getView(); - ((ViewPager) container).addView(view, 0); - } - } catch (Exception e) { - Log.e("ViewPagerAdapter.instantiateItem ", e); - } - - return view; - } - - @Override - public boolean isViewFromObject(View view, Object object) { - return view == object; - } - - @Override - public void restoreState(Parcelable arg0, ClassLoader arg1) { - } - - @Override - public Parcelable saveState() { - return null; - } - - @Override - public void startUpdate(View arg0) { - } - - @Override - public int getItemPosition(Object object) { - // We are doing the caching. So pretend that the view is gone. - // The ViewPager will get it back in instantiateItem() - return POSITION_NONE; - } - - @Override - public String getTitle(int position) { - final Page page = pageOrder.get(position); - if (null == page) { - return ""; - } - // show number of waypoints directly in waypoint title - if (page == Page.WAYPOINTS) { - final int waypointCount = cache.getWaypoints().size(); - return res.getQuantityString(R.plurals.waypoints, waypointCount, waypointCount); - } - return res.getString(page.titleStringId); - } - } - - /** * Enum of all possible pages with methods to get the view and a title. */ public enum Page { @@ -1102,7 +897,7 @@ public class CacheDetailActivity extends AbstractActivity { final private int titleStringId; - private Page(final int titleStringId) { + Page(final int titleStringId) { this.titleStringId = titleStringId; } } @@ -1124,8 +919,7 @@ public class CacheDetailActivity extends AbstractActivity { attributeBox.removeAllViews(); // maximum width for attribute icons is screen width - paddings of parents - attributeBoxMaxWidth = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)) - .getDefaultDisplay().getWidth(); + attributeBoxMaxWidth = Compatibility.getDisplayWidth(); ViewParent child = attributeBox; do { if (child instanceof View) { @@ -1294,36 +1088,10 @@ public class CacheDetailActivity extends AbstractActivity { } } - private interface PageViewCreator { - /** - * Returns a validated view. - * - * @return - */ - public View getDispatchedView(); - - /** - * Returns a (maybe cached) view. - * - * @return - */ - public View getView(); - - /** - * Handles changed data-sets. - */ - public void notifyDataSetChanged(); - } - /** * Creator for details-view. */ - private class DetailsViewCreator implements PageViewCreator { - /** - * The main view for this creator - */ - private ScrollView view; - + private class DetailsViewCreator extends AbstractCachingPageViewCreator<ScrollView> { /** * Reference to the details list, so that the helper-method can access it without an additional argument */ @@ -1335,22 +1103,7 @@ public class CacheDetailActivity extends AbstractActivity { private Thread watchlistThread; @Override - public void notifyDataSetChanged() { - // There is a lot of data in this view, let's update everything - view = null; - } - - @Override - public View getView() { - if (view == null) { - view = (ScrollView) getDispatchedView(); - } - - return view; - } - - @Override - public View getDispatchedView() { + public ScrollView getDispatchedView() { if (cache == null) { // something is really wrong return null; @@ -1378,7 +1131,7 @@ public class CacheDetailActivity extends AbstractActivity { details.add(R.string.cache_name, span); details.add(R.string.cache_type, cache.getType().getL10n()); details.addSize(cache); - details.add(R.string.cache_geocode, cache.getGeocode().toUpperCase()); + details.add(R.string.cache_geocode, cache.getGeocode()); details.addCacheState(cache); details.addDistance(cache, cacheDistanceView); @@ -1428,22 +1181,22 @@ public class CacheDetailActivity extends AbstractActivity { if (cache.getCoords() != null) { TextView valueView = details.add(R.string.cache_coordinates, cache.getCoords().toString()); valueView.setOnClickListener(new View.OnClickListener() { - private int position = 0; - private GeopointFormatter.Format[] availableFormats = new GeopointFormatter.Format[] { - GeopointFormatter.Format.LAT_LON_DECMINUTE, - GeopointFormatter.Format.LAT_LON_DECSECOND, - GeopointFormatter.Format.LAT_LON_DECDEGREE - }; - - // rotate coordinate formats on click - @Override - public void onClick(View view) { - position = (position + 1) % availableFormats.length; + private int position = 0; + private GeopointFormatter.Format[] availableFormats = new GeopointFormatter.Format[] { + GeopointFormatter.Format.LAT_LON_DECMINUTE, + GeopointFormatter.Format.LAT_LON_DECSECOND, + GeopointFormatter.Format.LAT_LON_DECDEGREE + }; + + // rotate coordinate formats on click + @Override + public void onClick(View view) { + position = (position + 1) % availableFormats.length; - final TextView valueView = (TextView) view.findViewById(R.id.value); - valueView.setText(cache.getCoords().format(availableFormats[position])); - } - }); + final TextView valueView = (TextView) view.findViewById(R.id.value); + valueView.setText(cache.getCoords().format(availableFormats[position])); + } + }); registerForContextMenu(valueView); } @@ -1869,38 +1622,26 @@ public class CacheDetailActivity extends AbstractActivity { return; } - final Bitmap bitmap = image.getBitmap(); - if (bitmap == null || bitmap.getWidth() <= 10) { - return; - } + try { + final Bitmap bitmap = image.getBitmap(); + if (bitmap == null || bitmap.getWidth() <= 10) { + return; + } - ((ImageView) view.findViewById(R.id.map_preview)).setImageDrawable(image); - view.findViewById(R.id.map_preview_box).setVisibility(View.VISIBLE); + ((ImageView) view.findViewById(R.id.map_preview)).setImageDrawable(image); + view.findViewById(R.id.map_preview_box).setVisibility(View.VISIBLE); + } catch (Exception e) { + Log.e("CacheDetailActivity.PreviewMapTask", e); + } } } } - private class DescriptionViewCreator implements PageViewCreator { - - private ScrollView view; - - @Override - public void notifyDataSetChanged() { - view = null; - } - - @Override - public View getView() { - if (view == null) { - view = (ScrollView) getDispatchedView(); - } - - return view; - } + private class DescriptionViewCreator extends AbstractCachingPageViewCreator<ScrollView> { @Override - public View getDispatchedView() { + public ScrollView getDispatchedView() { if (cache == null) { // something is really wrong return null; @@ -1947,7 +1688,7 @@ public class CacheDetailActivity extends AbstractActivity { public void update(CharSequence editorText) { cache.setPersonalNote(editorText.toString()); setPersonalNote(personalNoteView); - app.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); + cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); } }); editor.show(); @@ -2143,31 +1884,15 @@ public class CacheDetailActivity extends AbstractActivity { } } - private class LogsViewCreator implements PageViewCreator { - private ListView view; - private boolean allLogs; + private class LogsViewCreator extends AbstractCachingPageViewCreator<ListView> { + private final boolean allLogs; LogsViewCreator(boolean allLogs) { - super(); this.allLogs = allLogs; } @Override - public void notifyDataSetChanged() { - view = null; - } - - @Override - public View getView() { - if (view == null) { - view = (ListView) getDispatchedView(); - } - - return view; - } - - @Override - public View getDispatchedView() { + public ListView getDispatchedView() { if (cache == null) { // something is really wrong return null; @@ -2186,7 +1911,7 @@ public class CacheDetailActivity extends AbstractActivity { } } - if (sortedLogCounts.size() > 0) { + if (!sortedLogCounts.isEmpty()) { // sort the log counts by type id ascending. that way the FOUND, DNF log types are the first and most visible ones Collections.sort(sortedLogCounts, new Comparator<Entry<LogType, Integer>>() { @@ -2240,7 +1965,7 @@ public class CacheDetailActivity extends AbstractActivity { holder.count.setVisibility(View.VISIBLE); if (log.found == -1) { holder.count.setVisibility(View.GONE); - } else { + } else { holder.count.setText(res.getQuantityString(R.plurals.cache_counts, log.found, log.found)); } @@ -2269,23 +1994,12 @@ public class CacheDetailActivity extends AbstractActivity { } // colored marker - holder.statusMarker.setVisibility(View.VISIBLE); - if (log.type == LogType.FOUND_IT - || log.type == LogType.WEBCAM_PHOTO_TAKEN - || log.type == LogType.ATTENDED) { - holder.statusMarker.setImageResource(R.drawable.mark_green); - } else if (log.type == LogType.PUBLISH_LISTING - || log.type == LogType.ENABLE_LISTING - || log.type == LogType.OWNER_MAINTENANCE) { - holder.statusMarker.setImageResource(R.drawable.mark_green_more); - } else if (log.type == LogType.DIDNT_FIND_IT - || log.type == LogType.NEEDS_MAINTENANCE - || log.type == LogType.NEEDS_ARCHIVE) { - holder.statusMarker.setImageResource(R.drawable.mark_red); - } else if (log.type == LogType.TEMP_DISABLE_LISTING - || log.type == LogType.ARCHIVE) { - holder.statusMarker.setImageResource(R.drawable.mark_red_more); - } else { + int marker = log.type.markerId; + if (marker != 0) { + holder.statusMarker.setVisibility(View.VISIBLE); + holder.statusMarker.setImageResource(marker); + } + else { holder.statusMarker.setVisibility(View.GONE); } @@ -2325,26 +2039,10 @@ public class CacheDetailActivity extends AbstractActivity { } } - private class WaypointsViewCreator implements PageViewCreator { - - private ScrollView view; - - @Override - public void notifyDataSetChanged() { - view = null; - } - - @Override - public View getView() { - if (view == null) { - view = (ScrollView) getDispatchedView(); - } - - return view; - } + private class WaypointsViewCreator extends AbstractCachingPageViewCreator<ScrollView> { @Override - public View getDispatchedView() { + public ScrollView getDispatchedView() { if (cache == null) { // something is really wrong return null; @@ -2440,26 +2138,10 @@ public class CacheDetailActivity extends AbstractActivity { } } - private class InventoryViewCreator implements PageViewCreator { - - private ListView view; - - @Override - public void notifyDataSetChanged() { - view = null; - } - - @Override - public View getView() { - if (view == null) { - view = (ListView) getDispatchedView(); - } - - return view; - } + private class InventoryViewCreator extends AbstractCachingPageViewCreator<ListView> { @Override - public View getDispatchedView() { + public ListView getDispatchedView() { if (cache == null) { // something is really wrong return null; @@ -2476,7 +2158,7 @@ public class CacheDetailActivity extends AbstractActivity { Object selection = arg0.getItemAtPosition(arg2); if (selection instanceof cgTrackable) { cgTrackable trackable = (cgTrackable) selection; - cgeotrackable.startActivity(CacheDetailActivity.this, trackable.getGuid(), trackable.getGeocode(), trackable.getName()); + TrackableActivity.startActivity(CacheDetailActivity.this, trackable.getGuid(), trackable.getGeocode(), trackable.getName()); } } }); @@ -2485,23 +2167,7 @@ public class CacheDetailActivity extends AbstractActivity { } } - private class ImagesViewCreator implements PageViewCreator { - - private View view; - - @Override - public void notifyDataSetChanged() { - view = null; - } - - @Override - public View getView() { - if (view == null) { - view = getDispatchedView(); - } - - return view; - } + private class ImagesViewCreator extends AbstractCachingPageViewCreator<View> { @Override public View getDispatchedView() { @@ -2510,7 +2176,7 @@ public class CacheDetailActivity extends AbstractActivity { } view = getLayoutInflater().inflate(R.layout.caches_images, null); - if (imagesList == null && viewPager.getCurrentItem() == pageOrder.indexOf(Page.IMAGES)) { + if (imagesList == null && isCurrentPage(Page.IMAGES)) { loadCacheImages(); } return view; @@ -2530,4 +2196,194 @@ public class CacheDetailActivity extends AbstractActivity { cacheIntent.putExtra("name", cacheName); context.startActivity(cacheIntent); } -} + + /** + * A dialog to allow the user to select reseting coordinates local/remote/both. + */ + private class ResetCacheCoordinatesDialog extends AlertDialog implements OnCheckedChangeListener { + + final CheckBox uploadOption; + final CheckBox resetLocalyOption; + + public ResetCacheCoordinatesDialog(final cgCache cache, final cgWaypoint wpt, final Activity activity) { + super(activity); + + View layout = activity.getLayoutInflater().inflate(R.layout.reset_cache_coords_dialog, null); + setView(layout); + + uploadOption = (CheckBox) layout.findViewById(R.id.upload); + resetLocalyOption = (CheckBox) layout.findViewById(R.id.local); + + if (ConnectorFactory.getConnector(cache).supportsOwnCoordinates()) { + uploadOption.setChecked(true); + uploadOption.setVisibility(View.VISIBLE); + } + + uploadOption.setOnCheckedChangeListener(this); + resetLocalyOption.setOnCheckedChangeListener(this); + + layout.findViewById(R.id.reset).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dismiss(); + final ProgressDialog p = ProgressDialog.show(CacheDetailActivity.this, res.getString(R.string.cache), res.getString(R.string.waypoint_reset), true); + final Handler h = new Handler() { + private boolean remoteFinished = false; + private boolean localFinished = false; + + @Override + public void handleMessage(Message msg) { + if (msg.what == ResetCoordsThread.LOCAL) { + localFinished = true; + } else { + remoteFinished = true; + } + + if ((localFinished || !resetLocalyOption.isChecked()) && (remoteFinished || !uploadOption.isChecked())) { + p.dismiss(); + notifyDataSetChanged(); + } + } + + }; + new ResetCoordsThread(cache, h, wpt, resetLocalyOption.isChecked(), uploadOption.isChecked(), p).start(); + } + }); + } + + @Override + public void onCheckedChanged(CompoundButton arg0, boolean arg1) { + findViewById(R.id.reset).setEnabled( + (uploadOption.isChecked() || resetLocalyOption.isChecked())); + } + } + + private class ResetCoordsThread extends Thread { + + private final cgCache cache; + private final Handler handler; + private final boolean local; + private final boolean remote; + private final cgWaypoint wpt; + private ProgressDialog progress; + public static final int LOCAL = 0; + public static final int ON_WEBSITE = 1; + + public ResetCoordsThread(cgCache cache, Handler handler, final cgWaypoint wpt, boolean local, boolean remote, final ProgressDialog progress) { + this.cache = cache; + this.handler = handler; + this.local = local; + this.remote = remote; + this.wpt = wpt; + this.progress = progress; + } + + @Override + public void run() { + + if (local) { + runOnUiThread(new Runnable() { + @Override + public void run() { + progress.setMessage(res.getString(R.string.waypoint_reset_cache_coords)); + } + }); + cache.setCoords(wpt.getCoords()); + cache.setUserModifiedCoords(false); + cache.deleteWaypointForce(wpt); + cgData.saveChangedCache(cache); + handler.sendEmptyMessage(LOCAL); + } + + IConnector con = ConnectorFactory.getConnector(cache); + if (remote && con.supportsOwnCoordinates()) { + runOnUiThread(new Runnable() { + @Override + public void run() { + progress.setMessage(res.getString(R.string.waypoint_coordinates_being_reset_on_website)); + } + }); + + final boolean result = con.deleteModifiedCoordinates(cache); + + runOnUiThread(new Runnable() { + + @Override + public void run() { + if (result) { + showToast(getString(R.string.waypoint_coordinates_has_been_reset_on_website)); + } else { + showToast(getString(R.string.waypoint_coordinates_upload_error)); + } + handler.sendEmptyMessage(ON_WEBSITE); + notifyDataSetChanged(); + } + + }); + + } + } + } + + @Override + protected String getTitle(Page page) { + // show number of waypoints directly in waypoint title + if (page == Page.WAYPOINTS) { + final int waypointCount = cache.getWaypoints().size(); + return res.getQuantityString(R.plurals.waypoints, waypointCount, waypointCount); + } + return res.getString(page.titleStringId); + } + + @Override + protected Pair<List<? extends Page>, Integer> getOrderedPages() { + final ArrayList<Page> pages = new ArrayList<Page>(); + pages.add(Page.WAYPOINTS); + pages.add(Page.DETAILS); + final int detailsIndex = pages.size() - 1; + pages.add(Page.DESCRIPTION); + if (cache.getLogs().isNotEmpty()) { + pages.add(Page.LOGS); + } + if (CollectionUtils.isNotEmpty(cache.getFriendsLogs())) { + pages.add(Page.LOGSFRIENDS); + } + if (CollectionUtils.isNotEmpty(cache.getInventory())) { + pages.add(Page.INVENTORY); + } + if (CollectionUtils.isNotEmpty(cache.getImages())) { + pages.add(Page.IMAGES); + } + return new ImmutablePair<List<? extends Page>, Integer>(pages, detailsIndex); + } + + @Override + protected AbstractViewPagerActivity.PageViewCreator createViewCreator(Page page) { + switch (page) { + case DETAILS: + return new DetailsViewCreator(); + + case DESCRIPTION: + return new DescriptionViewCreator(); + + case LOGS: + return new LogsViewCreator(true); + + case LOGSFRIENDS: + return new LogsViewCreator(false); + + case WAYPOINTS: + return new WaypointsViewCreator(); + + case INVENTORY: + return new InventoryViewCreator(); + + case IMAGES: + return new ImagesViewCreator(); + + default: + throw new IllegalArgumentException(); + } + } + +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/CachePopup.java b/main/src/cgeo/geocaching/CachePopup.java index e01e4a0..9b0d96d 100644 --- a/main/src/cgeo/geocaching/CachePopup.java +++ b/main/src/cgeo/geocaching/CachePopup.java @@ -79,7 +79,7 @@ public class CachePopup extends AbstractPopupActivity { if (StringUtils.isNotBlank(cache.getName())) { setTitle(cache.getName()); } else { - setTitle(geocode.toUpperCase()); + setTitle(geocode); } // actionbar icon @@ -89,8 +89,6 @@ public class CachePopup extends AbstractPopupActivity { addCacheDetails(); - findViewById(R.id.offline_box).setVisibility(View.VISIBLE); - // offline use final TextView offlineText = (TextView) findViewById(R.id.offline_text); final Button offlineRefresh = (Button) findViewById(R.id.offline_refresh); diff --git a/main/src/cgeo/geocaching/Destination.java b/main/src/cgeo/geocaching/Destination.java index 441e959..10d51be 100644 --- a/main/src/cgeo/geocaching/Destination.java +++ b/main/src/cgeo/geocaching/Destination.java @@ -34,7 +34,13 @@ public final class Destination implements ICoordinates { @Override public boolean equals(final Object obj) { - return obj != null && obj instanceof Destination && ((Destination) obj).coords.equals(coords); + if (this == obj) { + return true; + } + if (!(obj instanceof Destination)) { + return false; + } + return ((Destination) obj).coords.equals(coords); } public long getId() { diff --git a/main/src/cgeo/geocaching/DirectionProvider.java b/main/src/cgeo/geocaching/DirectionProvider.java index 14fd283..c1f83ac 100644 --- a/main/src/cgeo/geocaching/DirectionProvider.java +++ b/main/src/cgeo/geocaching/DirectionProvider.java @@ -14,7 +14,7 @@ public class DirectionProvider extends MemorySubject<Float> implements SensorEve private final SensorManager sensorManager; - // Previous values signalled to observers to avoid resending the same value when the + // Previous values signaled to observers to avoid resending the same value when the // device doesn't change orientation. The orientation is usually given with a 1 degree // precision by Android, so it is not uncommon to obtain exactly the same value several // times. @@ -38,14 +38,14 @@ public class DirectionProvider extends MemorySubject<Float> implements SensorEve @Override public void onAccuracyChanged(final Sensor sensor, int accuracy) { /* - * There is a bug in Android, which appearently causes this method to be called every - * time the sensor _value_ changed, even if the _accuracy_ did not change. So logging - * this event leads to the log being flooded with multiple entries _per second_, - * which I experienced when running cgeo in a building (with GPS and network being - * unreliable). - * - * See for example https://code.google.com/p/android/issues/detail?id=14792 - */ + * There is a bug in Android, which apparently causes this method to be called every + * time the sensor _value_ changed, even if the _accuracy_ did not change. So logging + * this event leads to the log being flooded with multiple entries _per second_, + * which I experienced when running cgeo in a building (with GPS and network being + * unreliable). + * + * See for example https://code.google.com/p/android/issues/detail?id=14792 + */ //Log.i(Settings.tag, "Compass' accuracy is low (" + accuracy + ")"); } diff --git a/main/src/cgeo/geocaching/EditWaypointActivity.java b/main/src/cgeo/geocaching/EditWaypointActivity.java index ef2a2cc..001d73f 100644 --- a/main/src/cgeo/geocaching/EditWaypointActivity.java +++ b/main/src/cgeo/geocaching/EditWaypointActivity.java @@ -2,6 +2,8 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.activity.ActivityMixin; +import cgeo.geocaching.connector.ConnectorFactory; +import cgeo.geocaching.connector.IConnector; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.WaypointType; @@ -27,6 +29,7 @@ import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; import android.widget.Button; +import android.widget.CheckBox; import android.widget.EditText; import android.widget.Spinner; @@ -77,6 +80,8 @@ public class EditWaypointActivity extends AbstractActivity { else { ((EditText) findViewById(R.id.note)).setText(StringUtils.trimToEmpty(waypoint.getNote())); } + + setUploadingCheckBoxVisibleByConnector(ConnectorFactory.getConnector(geocode)); } if (own) { @@ -133,7 +138,7 @@ public class EditWaypointActivity extends AbstractActivity { addWaypoint.setOnClickListener(new coordsListener()); List<String> wayPointNames = new ArrayList<String>(); - for (WaypointType wpt : WaypointType.ALL_TYPES_EXCEPT_OWN) { + for (WaypointType wpt : WaypointType.ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL) { wayPointNames.add(wpt.getL10n()); } AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.name); @@ -152,11 +157,22 @@ public class EditWaypointActivity extends AbstractActivity { initializeWaypointTypeSelector(); } + if (geocode != null) { + IConnector con = ConnectorFactory.getConnector(geocode); + setUploadingCheckBoxVisibleByConnector(con); + } + initializeDistanceUnitSelector(); disableSuggestions((EditText) findViewById(R.id.distance)); } + private void setUploadingCheckBoxVisibleByConnector(IConnector con) { + if (con.supportsOwnCoordinates()) { + findViewById(R.id.uploadCoordsToWebsiteCheckBox).setVisibility(View.VISIBLE); + } + } + @Override public void onResume() { super.onResume(); @@ -193,7 +209,7 @@ public class EditWaypointActivity extends AbstractActivity { Spinner waypointTypeSelector = (Spinner) findViewById(R.id.type); - wpTypes = new ArrayList<WaypointType>(WaypointType.ALL_TYPES_EXCEPT_OWN); + wpTypes = new ArrayList<WaypointType>(WaypointType.ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL); 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); @@ -250,7 +266,7 @@ public class EditWaypointActivity extends AbstractActivity { @Override public void run() { try { - waypoint = app.loadWaypoint(id); + waypoint = cgData.loadWaypoint(id); loadWaypointHandler.sendMessage(Message.obtain()); } catch (Exception e) { @@ -269,7 +285,7 @@ public class EditWaypointActivity extends AbstractActivity { } else if (gpTemp != null) { gp = gpTemp; } - cgCache cache = app.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS); + cgCache cache = cgData.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS); cgeocoords coordsDialog = new cgeocoords(EditWaypointActivity.this, cache, gp, app.currentGeo()); coordsDialog.setCancelable(true); coordsDialog.setOnCoordinateUpdate(new cgeocoords.CoordinateUpdate() { @@ -288,7 +304,7 @@ public class EditWaypointActivity extends AbstractActivity { } } - private class changeWaypointType implements OnItemSelectedListener { + private static class changeWaypointType implements OnItemSelectedListener { private changeWaypointType(EditWaypointActivity wpView) { this.wpView = wpView; @@ -312,7 +328,7 @@ public class EditWaypointActivity extends AbstractActivity { } } - private class changeDistanceUnit implements OnItemSelectedListener { + private static class changeDistanceUnit implements OnItemSelectedListener { private changeDistanceUnit(EditWaypointActivity unitView) { this.unitView = unitView; @@ -335,12 +351,14 @@ public class EditWaypointActivity extends AbstractActivity { @Override public void onClick(View arg0) { + // TODO Show progress across whole function, it is performing very long time on slower devices final String bearingText = ((EditText) findViewById(R.id.bearing)).getText().toString(); // combine distance from EditText and distanceUnit saved from Spinner final String distanceText = ((EditText) findViewById(R.id.distance)).getText().toString() + distanceUnit; final String latText = ((Button) findViewById(R.id.buttonLatitude)).getText().toString(); final String lonText = ((Button) findViewById(R.id.buttonLongitude)).getText().toString(); - + final CheckBox setAsCacheCoordsCheckBox = (CheckBox) findViewById(R.id.setAsCacheCoordsCheckBox); + final CheckBox uploadCoordsToWebsiteCheckBox = (CheckBox) findViewById(R.id.uploadCoordsToWebsiteCheckBox); if (StringUtils.isBlank(bearingText) && StringUtils.isBlank(distanceText) && StringUtils.isBlank(latText) && StringUtils.isBlank(lonText)) { helpDialog(res.getString(R.string.err_point_no_position_given_title), res.getString(R.string.err_point_no_position_given)); @@ -388,8 +406,8 @@ public class EditWaypointActivity extends AbstractActivity { String name = ((EditText) findViewById(R.id.name)).getText().toString().trim(); // if no name is given, just give the waypoint its number as name - if (name.length() == 0) { - name = res.getString(R.string.waypoint) + " " + String.valueOf(wpCount + 1); + if (StringUtils.isEmpty(name)) { + name = res.getString(R.string.waypoint) + " " + (wpCount + 1); } final String note = ((EditText) findViewById(R.id.note)).getText().toString().trim(); @@ -401,20 +419,86 @@ public class EditWaypointActivity extends AbstractActivity { waypoint.setNote(note); waypoint.setId(id); - cgCache cache = app.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS); + cgCache cache = cgData.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS); if (null != cache && cache.addOrChangeWaypoint(waypoint, true)) { - app.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); + cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); StaticMapsProvider.removeWpStaticMaps(id, geocode); if (Settings.isStoreOfflineWpMaps()) { - StaticMapsProvider.storeWaypointStaticMap(cache, EditWaypointActivity.this, waypoint, false); + StaticMapsProvider.storeWaypointStaticMap(cache, waypoint, false); + } + if (setAsCacheCoordsCheckBox.isChecked()) { + if (!cache.hasUserModifiedCoords()) { + final cgWaypoint origWaypoint = new cgWaypoint(cgeoapplication.getInstance().getString(R.string.cache_coordinates_original), WaypointType.ORIGINAL, false); + origWaypoint.setCoords(cache.getCoords()); + cache.addOrChangeWaypoint(origWaypoint, false); + cache.setUserModifiedCoords(true); + } + cache.setCoords(waypoint.getCoords()); + cgData.saveChangedCache(cache); + } + if (uploadCoordsToWebsiteCheckBox.isChecked() && waypoint.getCoords() != null) { + if (cache.supportsOwnCoordinates()) { + final ProgressDialog progress = ProgressDialog.show(EditWaypointActivity.this, getString(R.string.cache), getString(R.string.waypoint_coordinates_uploading_to_website, waypoint.getCoords()), true); + Handler finishHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + progress.dismiss(); + finish(); + } + }; + new UploadModifiedCoordsThread(cache, waypoint.getCoords(), progress, finishHandler).start(); + } else { + showToast(getString(R.string.waypoint_coordinates_couldnt_be_modified_on_website)); + } + } else { + finish(); } - finish(); } else { showToast(res.getString(R.string.err_waypoint_add_failed)); } } } + private class UploadModifiedCoordsThread extends Thread { + + private final Geopoint waypoint_uploaded; + private final ProgressDialog progress; + private final cgCache cache; + private final Handler handler; + + public UploadModifiedCoordsThread(cgCache cache, Geopoint wpt, ProgressDialog progress, Handler finishHandler) { + this.cache = cache; + this.waypoint_uploaded = wpt; + this.progress = progress; + this.handler = finishHandler; + } + + @Override + public void run() { + boolean result = false; + IConnector con = ConnectorFactory.getConnector(cache); + if (con.supportsOwnCoordinates()) { + result = con.uploadModifiedCoordinates(cache, waypoint_uploaded); + } + final boolean res = result; + runOnUiThread(new Runnable() { + + @Override + public void run() { + if (res) { + showToast(getString(R.string.waypoint_coordinates_has_been_modified_on_website, waypoint_uploaded.getCoords().toString())); + } else { + showToast(getString(R.string.waypoint_coordinates_upload_error)); + } + if (progress != null) { + progress.dismiss(); + } + handler.sendMessage(Message.obtain()); + } + }); + } + } + @Override public void goManual(View view) { if (id >= 0) { diff --git a/main/src/cgeo/geocaching/ImagesActivity.java b/main/src/cgeo/geocaching/ImagesActivity.java index 0accf12..82902b5 100644 --- a/main/src/cgeo/geocaching/ImagesActivity.java +++ b/main/src/cgeo/geocaching/ImagesActivity.java @@ -62,7 +62,7 @@ public class ImagesActivity extends AbstractActivity { return; } - offline = app.isOffline(geocode, null) && (imgType == ImageType.SpoilerImages || Settings.isStoreLogImages()); + offline = cgData.isOffline(geocode, null) && (imgType == ImageType.SpoilerImages || Settings.isStoreLogImages()); } @Override @@ -86,7 +86,7 @@ public class ImagesActivity extends AbstractActivity { final Intent logImgIntent = new Intent(fromActivity, ImagesActivity.class); // if resuming our app within this activity, finish it and return to the cache activity logImgIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) - .putExtra(EXTRAS_GEOCODE, geocode.toUpperCase()) + .putExtra(EXTRAS_GEOCODE, geocode) .putExtra(EXTRAS_TYPE, imageType); // avoid forcing the array list as parameter type diff --git a/main/src/cgeo/geocaching/LogTrackableActivity.java b/main/src/cgeo/geocaching/LogTrackableActivity.java index 4ddec72..a4677d0 100644 --- a/main/src/cgeo/geocaching/LogTrackableActivity.java +++ b/main/src/cgeo/geocaching/LogTrackableActivity.java @@ -127,12 +127,12 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat } } - trackable = app.getTrackableByGeocode(geocode); + trackable = cgData.loadTrackable(geocode); if (StringUtils.isNotBlank(trackable.getName())) { setTitle(res.getString(R.string.trackable_touch) + ": " + trackable.getName()); } else { - setTitle(res.getString(R.string.trackable_touch) + ": " + trackable.getGeocode().toUpperCase()); + setTitle(res.getString(R.string.trackable_touch) + ": " + trackable.getGeocode()); } if (guid == null) { @@ -357,7 +357,7 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat public static void startActivity(final Context context, final cgTrackable trackable) { final Intent logTouchIntent = new Intent(context, LogTrackableActivity.class); - logTouchIntent.putExtra("geocode", trackable.getGeocode().toUpperCase()); + logTouchIntent.putExtra("geocode", trackable.getGeocode()); logTouchIntent.putExtra("guid", trackable.getGuid()); logTouchIntent.putExtra("trackingcode", trackable.getTrackingcode()); context.startActivity(logTouchIntent); diff --git a/main/src/cgeo/geocaching/SearchActivity.java b/main/src/cgeo/geocaching/SearchActivity.java index 5f2bddc..4c9a230 100644 --- a/main/src/cgeo/geocaching/SearchActivity.java +++ b/main/src/cgeo/geocaching/SearchActivity.java @@ -28,6 +28,8 @@ import android.widget.AutoCompleteTextView; import android.widget.Button; import android.widget.EditText; +import java.util.Locale; + public class SearchActivity extends AbstractActivity { private static final String EXTRAS_KEYWORDSEARCH = "keywordsearch"; @@ -98,13 +100,18 @@ public class SearchActivity extends AbstractActivity { * @return true if a search was performed, else false */ private boolean instantSearch(final String query, final boolean keywordSearch) { + // first check if this was a scanned URL + String geocode = ConnectorFactory.getGeocodeFromURL(query); + + // otherwise see if this is a pure geocode + if (StringUtils.isEmpty(geocode)) { + geocode = StringUtils.trim(query); + } - // Check if any connector can handle the query as a geocode - final String geocode = StringUtils.trim(query); final IConnector connector = ConnectorFactory.getConnector(geocode); if (connector instanceof ISearchByGeocode) { final Intent cachesIntent = new Intent(this, CacheDetailActivity.class); - cachesIntent.putExtra("geocode", geocode.toUpperCase()); + cachesIntent.putExtra("geocode", geocode.toUpperCase(Locale.US)); startActivity(cachesIntent); return true; } @@ -112,8 +119,8 @@ public class SearchActivity extends AbstractActivity { // Check if the query is a TB code 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()); + final Intent trackablesIntent = new Intent(this, TrackableActivity.class); + trackablesIntent.putExtra("geocode", trackable.toUpperCase(Locale.US)); startActivity(trackablesIntent); return true; } @@ -154,7 +161,7 @@ public class SearchActivity extends AbstractActivity { findByGeocodeFn(); } }); - addHistoryEntries(geocodeEdit, app.geocodesInCache()); + addHistoryEntries(geocodeEdit, cgData.getRecentGeocodesForSearch()); final Button displayByGeocode = (Button) findViewById(R.id.display_geocode); displayByGeocode.setOnClickListener(new findByGeocodeListener()); @@ -206,7 +213,7 @@ public class SearchActivity extends AbstractActivity { findTrackableFn(); } }); - addHistoryEntries(trackable, app.getTrackableCodes()); + addHistoryEntries(trackable, cgData.getTrackableCodes()); disableSuggestions(trackable); @@ -401,8 +408,8 @@ public class SearchActivity extends AbstractActivity { return; } - final Intent trackablesIntent = new Intent(this, cgeotrackable.class); - trackablesIntent.putExtra("geocode", trackableText.toUpperCase()); + final Intent trackablesIntent = new Intent(this, TrackableActivity.class); + trackablesIntent.putExtra("geocode", trackableText.toUpperCase(Locale.US)); startActivity(trackablesIntent); } diff --git a/main/src/cgeo/geocaching/SearchResult.java b/main/src/cgeo/geocaching/SearchResult.java index e21717d..d1b1df6 100644 --- a/main/src/cgeo/geocaching/SearchResult.java +++ b/main/src/cgeo/geocaching/SearchResult.java @@ -40,38 +40,49 @@ public class SearchResult implements Parcelable { } }; + /** + * Build a new empty search result. + */ public SearchResult() { - this((Set<String>) null); + this(new HashSet<String>()); } - public SearchResult(SearchResult searchResult) { - if (searchResult != null) { - this.geocodes = new HashSet<String>(searchResult.geocodes); - this.error = searchResult.error; - this.url = searchResult.url; - this.viewstates = searchResult.viewstates; - this.setTotal(searchResult.getTotal()); - } else { - this.geocodes = new HashSet<String>(); - } + /** + * Copy a search result, for example to apply different filters on it. + * + * @param searchResult the original search result, which cannot be null + */ + public SearchResult(final SearchResult searchResult) { + geocodes = new HashSet<String>(searchResult.geocodes); + error = searchResult.error; + url = searchResult.url; + viewstates = searchResult.viewstates; + setTotal(searchResult.getTotal()); } - 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); - } + /** + * Build a search result from an existing collection of geocodes. + * + * @param geocodes a non-null collection of geocodes + * @param total the total number of geocodes (FIXME: what is the meaning of this number wrt to geocodes.size()?) + */ + public SearchResult(final Collection<String> geocodes, final int total) { + this.geocodes = new HashSet<String>(geocodes.size()); + this.geocodes.addAll(geocodes); this.setTotal(total); } + /** + * Build a search result from an existing collection of geocodes. + * + * @param geocodes a non-null set of geocodes + */ public SearchResult(final Set<String> geocodes) { - this(geocodes, geocodes == null ? 0 : geocodes.size()); + this(geocodes, geocodes.size()); } public SearchResult(final Parcel in) { - ArrayList<String> list = new ArrayList<String>(); + final ArrayList<String> list = new ArrayList<String>(); in.readStringList(list); geocodes = new HashSet<String>(list); error = (StatusCode) in.readSerializable(); @@ -84,14 +95,24 @@ public class SearchResult implements Parcelable { setTotal(in.readInt()); } - public SearchResult(cgCache cache) { - this(); - addCache(cache); + /** + * Build a search result designating a single cache. + * + * @param cache the cache to include + */ + + public SearchResult(final cgCache cache) { + this(Collections.singletonList(cache)); } - public SearchResult(Collection<cgCache> caches) { + /** + * Build a search result from a collection of caches. + * + * @param caches the non-null collection of caches to include + */ + public SearchResult(final Collection<cgCache> caches) { this(); - for (cgCache cache : caches) { + for (final cgCache cache : caches) { addCache(cache); } } @@ -148,7 +169,7 @@ public class SearchResult implements Parcelable { return; } - this.viewstates = viewstates; + System.arraycopy(viewstates, 0, this.viewstates, 0, viewstates.length); } public int getTotal() { @@ -170,8 +191,7 @@ public class SearchResult implements Parcelable { SearchResult result = new SearchResult(this); result.geocodes.clear(); final ArrayList<cgCache> cachesForVote = new ArrayList<cgCache>(); - - final Set<cgCache> caches = cgeoapplication.getInstance().loadCaches(geocodes, LoadFlags.LOAD_CACHE_OR_DB); + final Set<cgCache> caches = cgData.loadCaches(geocodes, LoadFlags.LOAD_CACHE_OR_DB); for (cgCache cache : caches) { // Is there any reason to exclude the cache from the list? final boolean excludeCache = (excludeDisabled && cache.isDisabled()) || @@ -188,13 +208,13 @@ public class SearchResult implements Parcelable { public cgCache getFirstCacheFromResult(final EnumSet<LoadFlag> loadFlags) { if (geocodes != null && geocodes.size() >= 1) { - return cgeoapplication.getInstance().loadCache((String) geocodes.toArray()[0], loadFlags); + return cgData.loadCache((String) geocodes.toArray()[0], loadFlags); } return null; } public Set<cgCache> getCachesFromSearchResult(final EnumSet<LoadFlag> loadFlags) { - return cgeoapplication.getInstance().loadCaches(geocodes, loadFlags); + return cgData.loadCaches(geocodes, loadFlags); } /** Add the geocode to the search. No cache is loaded into the CacheCache */ @@ -213,11 +233,20 @@ public class SearchResult implements Parcelable { /** Add the cache geocode to the search and store the cache in the CacheCache */ public boolean addCache(final cgCache cache) { addGeocode(cache.getGeocode()); - return cgeoapplication.getInstance().saveCache(cache, EnumSet.of(SaveFlag.SAVE_CACHE)); + return cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_CACHE)); } public boolean isEmpty() { return geocodes.isEmpty(); } + public boolean hasUnsavedCaches() { + for (final String geocode : getGeocodes()) { + if (!cgData.isOffline(geocode, null)) { + return true; + } + } + return false; + } + } diff --git a/main/src/cgeo/geocaching/Settings.java b/main/src/cgeo/geocaching/Settings.java index e1ae9c0..a766470 100644 --- a/main/src/cgeo/geocaching/Settings.java +++ b/main/src/cgeo/geocaching/Settings.java @@ -75,7 +75,6 @@ public final class Settings { private static final String KEY_AUTO_VISIT_TRACKABLES = "trackautovisit"; private static final String KEY_AUTO_INSERT_SIGNATURE = "sigautoinsert"; private static final String KEY_ALTITUDE_CORRECTION = "altcorrection"; - private static final String KEY_USE_GOOGLE_NAVIGATION = "usegnav"; private static final String KEY_STORE_LOG_IMAGES = "logimages"; private static final String KEY_EXCLUDE_DISABLED = "excludedisabled"; private static final String KEY_EXCLUDE_OWN = "excludemine"; @@ -192,7 +191,6 @@ public final class Settings { 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)); @@ -672,20 +670,6 @@ public final class Settings { }); } - public static boolean isUseGoogleNavigation() { - return sharedPrefs.getBoolean(KEY_USE_GOOGLE_NAVIGATION, true); - } - - public static void setUseGoogleNavigation(final boolean useGoogleNavigation) { - editSharedSettings(new PrefRunnable() { - - @Override - public void edit(Editor edit) { - edit.putBoolean(KEY_USE_GOOGLE_NAVIGATION, useGoogleNavigation); - } - }); - } - public static boolean isAutoLoadDescription() { return sharedPrefs.getBoolean(KEY_LOAD_DESCRIPTION, false); } @@ -1331,7 +1315,7 @@ public final class Settings { FileUtils.listDir(result, directory, new ExtensionsBasedFileSelector(new String[] { "xml" }), null); - return result.toArray(new File[] {}); + return result.toArray(new File[result.size()]); } private static class ExtensionsBasedFileSelector extends FileSelector { diff --git a/main/src/cgeo/geocaching/SettingsActivity.java b/main/src/cgeo/geocaching/SettingsActivity.java index 823b52f..199e083 100644 --- a/main/src/cgeo/geocaching/SettingsActivity.java +++ b/main/src/cgeo/geocaching/SettingsActivity.java @@ -5,7 +5,6 @@ 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.files.SimpleDirChooser; import cgeo.geocaching.maps.MapProviderFactory; @@ -24,6 +23,7 @@ import ch.boye.httpclientandroidlib.HttpResponse; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openintents.intents.FileManagerIntents; import android.app.ProgressDialog; import android.content.Context; @@ -495,16 +495,6 @@ public class SettingsActivity extends AbstractActivity { } }); - final CheckBox gnavButton = (CheckBox) findViewById(R.id.gnav); - gnavButton.setChecked(Settings.isUseGoogleNavigation()); - gnavButton.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - Settings.setUseGoogleNavigation(gnavButton.isChecked()); - } - }); - final CheckBox logOffline = (CheckBox) findViewById(R.id.log_offline); logOffline.setChecked(Settings.getLogOffline()); logOffline.setOnClickListener(new View.OnClickListener() { @@ -577,9 +567,7 @@ public class SettingsActivity extends AbstractActivity { @Override public void onClick(View v) { - Intent dirChooser = new Intent(SettingsActivity.this, SimpleDirChooser.class); - dirChooser.putExtra(SimpleDirChooser.START_DIR, Settings.getCustomRenderThemeBaseFolder()); - startActivityForResult(dirChooser, SELECT_THEMEFOLDER_REQUEST); + selectDirectory(Settings.getCustomRenderThemeBaseFolder(), SELECT_THEMEFOLDER_REQUEST); } }); @@ -591,9 +579,7 @@ public class SettingsActivity extends AbstractActivity { @Override public void onClick(View v) { - Intent dirChooser = new Intent(SettingsActivity.this, SimpleDirChooser.class); - dirChooser.putExtra(SimpleDirChooser.START_DIR, Settings.getGpxExportDir()); - startActivityForResult(dirChooser, SELECT_GPX_EXPORT_REQUEST); + selectDirectory(Settings.getGpxExportDir(), SELECT_GPX_EXPORT_REQUEST); } }); @@ -605,9 +591,7 @@ public class SettingsActivity extends AbstractActivity { @Override public void onClick(View v) { - Intent dirChooser = new Intent(SettingsActivity.this, SimpleDirChooser.class); - dirChooser.putExtra(SimpleDirChooser.START_DIR, Settings.getGpxImportDir()); - startActivityForResult(dirChooser, SELECT_GPX_IMPORT_REQUEST); + selectDirectory(Settings.getGpxImportDir(), SELECT_GPX_IMPORT_REQUEST); } }); @@ -775,7 +759,7 @@ public class SettingsActivity 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) == 0) { + if (cgData.getAllCachesCount() == 0) { helpDialog(res.getString(R.string.init_backup), res.getString(R.string.init_backup_unnecessary)); return; } @@ -784,7 +768,7 @@ public class SettingsActivity extends AbstractActivity { new Thread() { @Override public void run() { - final String backupFileName = app.backupDatabase(); + final String backupFileName = cgData.backupDatabase(); runOnUiThread(new Runnable() { @Override public void run() { @@ -800,7 +784,7 @@ public class SettingsActivity extends AbstractActivity { private void refreshBackupLabel() { TextView lastBackup = (TextView) findViewById(R.id.backup_last); - File lastBackupFile = cgeoapplication.isRestoreFile(); + File lastBackupFile = cgData.getRestoreFile(); if (lastBackupFile != null) { lastBackup.setText(res.getString(R.string.init_backup_last) + " " + Formatter.formatTime(lastBackupFile.lastModified()) + ", " + Formatter.formatDate(lastBackupFile.lastModified())); } else { @@ -966,9 +950,12 @@ public class SettingsActivity extends AbstractActivity { @Override protected void onActivityResult(int requestCode, int resultCode, final Intent data) { super.onActivityResult(requestCode, resultCode, data); + if (resultCode != RESULT_OK) { + return; + } - if (requestCode == SELECT_MAPFILE_REQUEST) { - if (resultCode == RESULT_OK) { + switch (requestCode) { + case SELECT_MAPFILE_REQUEST: if (data.hasExtra("mapfile")) { final String mapFile = data.getStringExtra("mapfile"); Settings.setMapFile(mapFile); @@ -976,48 +963,72 @@ public class SettingsActivity extends AbstractActivity { showToast(res.getString(R.string.warn_invalid_mapfile)); } } - } - updateMapSourceMenu(); - initMapDirectoryEdittext(true); - } - if (requestCode == SELECT_GPX_EXPORT_REQUEST) { - checkDirectory(resultCode, data, R.id.gpx_exportdir, new RunnableWithArgument<String>() { + updateMapSourceMenu(); + initMapDirectoryEdittext(true); + break; + case SELECT_GPX_EXPORT_REQUEST: + checkDirectory(resultCode, data, R.id.gpx_exportdir, new RunnableWithArgument<String>() { - @Override - public void run(String directory) { - Settings.setGpxExportDir(directory); - } - }); - } - if (requestCode == SELECT_GPX_IMPORT_REQUEST) { - checkDirectory(resultCode, data, R.id.gpx_importdir, new RunnableWithArgument<String>() { + @Override + public void run(String directory) { + Settings.setGpxExportDir(directory); + } + }); + break; + case SELECT_GPX_IMPORT_REQUEST: + checkDirectory(resultCode, data, R.id.gpx_importdir, new RunnableWithArgument<String>() { - @Override - public void run(String directory) { - Settings.setGpxImportDir(directory); - } - }); - } - if (requestCode == SELECT_THEMEFOLDER_REQUEST) { - checkDirectory(resultCode, data, R.id.themefolder, new RunnableWithArgument<String>() { + @Override + public void run(String directory) { + Settings.setGpxImportDir(directory); + } + }); + break; + case SELECT_THEMEFOLDER_REQUEST: + checkDirectory(resultCode, data, R.id.themefolder, new RunnableWithArgument<String>() { - @Override - public void run(String directory) { - Settings.setCustomRenderThemeBaseFolder(directory); - } - }); + @Override + public void run(String directory) { + Settings.setCustomRenderThemeBaseFolder(directory); + } + }); + break; + default: + throw new IllegalArgumentException(); } } private void checkDirectory(int resultCode, Intent data, int textField, RunnableWithArgument<String> runnableSetDir) { - if (resultCode == RESULT_OK) { - if (data.hasExtra(SimpleDirChooser.EXTRA_CHOSEN_DIR)) { - final String directory = data.getStringExtra(SimpleDirChooser.EXTRA_CHOSEN_DIR); - runnableSetDir.run(directory); - EditText directoryText = (EditText) findViewById(textField); - directoryText.setText(directory); - directoryText.requestFocus(); + if (resultCode != RESULT_OK) { + return; + } + // we may come back from either our selfmade chooser or from the Open Intent manager + final String directory = data.hasExtra(SimpleDirChooser.EXTRA_CHOSEN_DIR) ? + data.getStringExtra(SimpleDirChooser.EXTRA_CHOSEN_DIR) : + new File(data.getData().getPath()).getAbsolutePath(); + if (StringUtils.isNotBlank(directory)) { + runnableSetDir.run(directory); + EditText directoryText = (EditText) findViewById(textField); + directoryText.setText(directory); + directoryText.requestFocus(); + } + } + + private void selectDirectory(String startDirectory, int directoryKind) { + Intent dirChooser; + try { + dirChooser = new Intent(FileManagerIntents.ACTION_PICK_DIRECTORY); + if (StringUtils.isNotBlank(startDirectory)) { + dirChooser.setData(Uri.parse("file://" + new File(startDirectory).getAbsolutePath())); } + dirChooser.putExtra(FileManagerIntents.EXTRA_TITLE, res.getString(R.string.simple_dir_chooser_title)); + dirChooser.putExtra(FileManagerIntents.EXTRA_BUTTON_TEXT, res.getString(android.R.string.ok)); + startActivityForResult(dirChooser, directoryKind); + } catch (android.content.ActivityNotFoundException ex) { + // OI file manager not available + dirChooser = new Intent(this, SimpleDirChooser.class); + dirChooser.putExtra(SimpleDirChooser.START_DIR, startDirectory); + startActivityForResult(dirChooser, directoryKind); } } diff --git a/main/src/cgeo/geocaching/StaticMapsActivity.java b/main/src/cgeo/geocaching/StaticMapsActivity.java index 05a18f2..c0a7f47 100644 --- a/main/src/cgeo/geocaching/StaticMapsActivity.java +++ b/main/src/cgeo/geocaching/StaticMapsActivity.java @@ -10,7 +10,6 @@ import android.app.ProgressDialog; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -36,7 +35,6 @@ public class StaticMapsActivity extends AbstractActivity { private LayoutInflater inflater = null; private ProgressDialog waitDialog = null; private LinearLayout smapsView = null; - private BitmapFactory factory = null; private final Handler loadMapsHandler = new Handler() { @Override @@ -131,10 +129,6 @@ public class StaticMapsActivity extends AbstractActivity { @Override public void run() { try { - if (factory == null) { - factory = new BitmapFactory(); - } - // try downloading 2 times for (int trials = 0; trials < 2; trials++) { for (int level = 1; level <= 5; level++) { @@ -183,16 +177,16 @@ public class StaticMapsActivity extends AbstractActivity { } private boolean downloadStaticMaps() { - final cgCache cache = app.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB); + final cgCache cache = cgData.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB); if (waypoint_id == null) { showToast(res.getString(R.string.info_storing_static_maps)); - StaticMapsProvider.storeCacheStaticMap(cache, this, true); + StaticMapsProvider.storeCacheStaticMap(cache, true); return cache.hasStaticMap(); } final cgWaypoint waypoint = cache.getWaypointById(waypoint_id); if (waypoint != null) { showToast(res.getString(R.string.info_storing_static_maps)); - StaticMapsProvider.storeWaypointStaticMap(cache, this, waypoint, true); + StaticMapsProvider.storeWaypointStaticMap(cache, waypoint, true); return StaticMapsProvider.hasStaticMapForWaypoint(geocode, waypoint_id); } showToast(res.getString(R.string.err_detail_not_load_map_static)); diff --git a/main/src/cgeo/geocaching/StaticMapsProvider.java b/main/src/cgeo/geocaching/StaticMapsProvider.java index 87a04fa..49dfb0f 100644 --- a/main/src/cgeo/geocaching/StaticMapsProvider.java +++ b/main/src/cgeo/geocaching/StaticMapsProvider.java @@ -1,5 +1,6 @@ package cgeo.geocaching; +import cgeo.geocaching.compatibility.Compatibility; import cgeo.geocaching.concurrent.BlockingThreadPool; import cgeo.geocaching.files.LocalStorage; import cgeo.geocaching.geopoint.GeopointFormatter.Format; @@ -12,10 +13,10 @@ import ch.boye.httpclientandroidlib.HttpResponse; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Point; import android.util.DisplayMetrics; import android.view.Display; import android.view.WindowManager; @@ -80,11 +81,6 @@ public class StaticMapsProvider { } public static void downloadMaps(cgCache cache) { - final Display display = ((WindowManager) cgeoapplication.getInstance().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); - downloadMaps(cache, display); - } - - private static void downloadMaps(cgCache cache, Display display) { if (cache == null) { Log.e("downloadMaps - missing input parameter cache"); return; @@ -92,7 +88,7 @@ public class StaticMapsProvider { if ((!Settings.isStoreOfflineMaps() && !Settings.isStoreOfflineWpMaps()) || StringUtils.isBlank(cache.getGeocode())) { return; } - int edge = guessMaxDisplaySide(display); + int edge = guessMaxDisplaySide(); if (Settings.isStoreOfflineMaps() && cache.getCoords() != null) { storeCachePreviewMap(cache); @@ -109,8 +105,8 @@ public class StaticMapsProvider { } } - public static void storeWaypointStaticMap(cgCache cache, Activity activity, cgWaypoint waypoint, boolean waitForResult) { - int edge = StaticMapsProvider.guessMaxDisplaySide(activity); + public static void storeWaypointStaticMap(cgCache cache, cgWaypoint waypoint, boolean waitForResult) { + int edge = StaticMapsProvider.guessMaxDisplaySide(); storeWaypointStaticMap(cache.getGeocode(), edge, waypoint, waitForResult); } @@ -132,8 +128,8 @@ public class StaticMapsProvider { downloadMaps(geocode, wpMarkerUrl, WAYPOINT_PREFIX + waypoint.getId() + '_', wpLatlonMap, edge, null, waitForResult); } - public static void storeCacheStaticMap(cgCache cache, Activity activity, final boolean waitForResult) { - int edge = guessMaxDisplaySide(activity); + public static void storeCacheStaticMap(cgCache cache, final boolean waitForResult) { + int edge = guessMaxDisplaySide(); storeCacheStaticMap(cache, edge, waitForResult); } @@ -158,28 +154,25 @@ public class StaticMapsProvider { return; } final String latlonMap = cache.getCoords().format(Format.LAT_LON_DECDEGREE_COMMA); - final String markerUrl = MARKERS_URL + "my_location_mdpi.png"; final Display display = ((WindowManager) cgeoapplication.getInstance().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); DisplayMetrics metrics = new DisplayMetrics(); display.getMetrics(metrics); final int width = metrics.widthPixels; final int height = (int) (110 * metrics.density); + final String markerUrl = MARKERS_URL + "my_location_mdpi.png"; downloadMap(cache.getGeocode(), 15, ROADMAP, markerUrl, PREFIX_PREVIEW, "shadow:false|", latlonMap, width, height, null); } - private static int guessMaxDisplaySide(Display display) { - final int maxWidth = display.getWidth() - 25; - final int maxHeight = display.getHeight() - 25; + private static int guessMaxDisplaySide() { + Point displaySize = Compatibility.getDisplaySize(); + final int maxWidth = displaySize.x - 25; + final int maxHeight = displaySize.y - 25; if (maxWidth > maxHeight) { return maxWidth; } return maxHeight; } - private static int guessMaxDisplaySide(Activity activity) { - return guessMaxDisplaySide(((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()); - } - 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) { diff --git a/main/src/cgeo/geocaching/StoredList.java b/main/src/cgeo/geocaching/StoredList.java index cdff1cb..bb00506 100644 --- a/main/src/cgeo/geocaching/StoredList.java +++ b/main/src/cgeo/geocaching/StoredList.java @@ -50,7 +50,7 @@ public class StoredList { } public void promptForListSelection(final int titleId, final RunnableWithArgument<Integer> runAfterwards, final boolean onlyMoveTargets) { - final List<StoredList> lists = app.getLists(); + final List<StoredList> lists = cgData.getLists(); if (lists == null) { return; @@ -94,7 +94,7 @@ public class StoredList { @Override public void run(final String listName) { - final int newId = app.createList(listName); + final int newId = cgData.createList(listName); if (newId >= cgData.customListIdOffset) { activity.showToast(res.getString(R.string.list_dialog_create_ok)); @@ -137,12 +137,12 @@ public class StoredList { } public void promptForListRename(final int listId, final Runnable runAfterRename) { - final StoredList list = app.getList(listId); + final StoredList list = cgData.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); + cgData.renameList(listId, listName); if (runAfterRename != null) { runAfterRename.run(); } diff --git a/main/src/cgeo/geocaching/TrackableActivity.java b/main/src/cgeo/geocaching/TrackableActivity.java new file mode 100644 index 0000000..b01942f --- /dev/null +++ b/main/src/cgeo/geocaching/TrackableActivity.java @@ -0,0 +1,674 @@ +package cgeo.geocaching; + +import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.activity.AbstractViewPagerActivity; +import cgeo.geocaching.connector.gc.GCParser; +import cgeo.geocaching.enumerations.LogType; +import cgeo.geocaching.geopoint.Units; +import cgeo.geocaching.network.HtmlImage; +import cgeo.geocaching.network.Network; +import cgeo.geocaching.ui.AbstractCachingPageViewCreator; +import cgeo.geocaching.ui.CacheDetailsCreator; +import cgeo.geocaching.ui.Formatter; +import cgeo.geocaching.utils.BaseUtils; +import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.UnknownTagsHandler; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; + +import android.app.ProgressDialog; +import android.content.Intent; +import android.graphics.drawable.BitmapDrawable; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.text.Html; +import android.text.method.LinkMovementMethod; +import android.view.ContextMenu; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.RelativeLayout; +import android.widget.ScrollView; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivity.Page> { + + public enum Page { + DETAILS(R.string.detail), + LOGS(R.string.cache_logs); + + protected final int resId; + + private Page(final int resId) { + this.resId = resId; + } + } + private static final int MENU_LOG_TOUCH = 1; + private static final int MENU_BROWSER_TRACKABLE = 2; + private cgTrackable trackable = null; + private String geocode = null; + private String name = null; + private String guid = null; + private String id = null; + private String contextMenuUser = null; + private LayoutInflater inflater = null; + private ProgressDialog waitDialog = null; + private Handler loadTrackableHandler = new Handler() { + + @Override + public void handleMessage(Message msg) { + if (trackable == null) { + if (waitDialog != null) { + waitDialog.dismiss(); + } + + if (StringUtils.isNotBlank(geocode)) { + showToast(res.getString(R.string.err_tb_find) + " " + geocode + "."); + } else { + showToast(res.getString(R.string.err_tb_find_that)); + } + + finish(); + return; + } + + try { + inflater = getLayoutInflater(); + geocode = trackable.getGeocode(); + + if (StringUtils.isNotBlank(trackable.getName())) { + setTitle(Html.fromHtml(trackable.getName()).toString()); + } else { + setTitle(trackable.getName()); + } + + reinitializeViewPager(); + + } catch (Exception e) { + Log.e("TrackableActivity.loadTrackableHandler: ", e); + } + + if (waitDialog != null) { + waitDialog.dismiss(); + } + } + }; + + public TrackableActivity() { + super("c:geo-trackable-details"); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setTheme(); + setContentView(R.layout.trackable_activity); + setTitle(res.getString(R.string.trackable)); + + // get parameters + Bundle extras = getIntent().getExtras(); + Uri uri = getIntent().getData(); + + // try to get data from extras + if (extras != null) { + geocode = extras.getString("geocode"); + name = extras.getString("name"); + guid = extras.getString("guid"); + id = extras.getString("id"); + } + + // try to get data from URI + if (geocode == null && guid == null && id == null && uri != null) { + String uriHost = uri.getHost().toLowerCase(Locale.US); + if (uriHost.contains("geocaching.com")) { + geocode = uri.getQueryParameter("tracker"); + guid = uri.getQueryParameter("guid"); + id = uri.getQueryParameter("id"); + + if (StringUtils.isNotBlank(geocode)) { + geocode = geocode.toUpperCase(Locale.US); + guid = null; + id = null; + } else if (StringUtils.isNotBlank(guid)) { + geocode = null; + guid = guid.toLowerCase(Locale.US); + id = null; + } else if (StringUtils.isNotBlank(id)) { + geocode = null; + guid = null; + id = id.toLowerCase(Locale.US); + } else { + showToast(res.getString(R.string.err_tb_details_open)); + finish(); + return; + } + } else if (uriHost.contains("coord.info")) { + String uriPath = uri.getPath().toLowerCase(Locale.US); + if (uriPath != null && uriPath.startsWith("/tb")) { + geocode = uriPath.substring(1).toUpperCase(Locale.US); + guid = null; + id = null; + } else { + showToast(res.getString(R.string.err_tb_details_open)); + finish(); + return; + } + } + } + + // no given data + if (geocode == null && guid == null && id == null) { + showToast(res.getString(R.string.err_tb_display)); + finish(); + return; + } + + String message; + if (StringUtils.isNotBlank(name)) { + message = Html.fromHtml(name).toString(); + } else if (StringUtils.isNotBlank(geocode)) { + message = geocode; + } else { + message = res.getString(R.string.trackable); + } + waitDialog = ProgressDialog.show(this, message, res.getString(R.string.trackable_details_loading), true, true); + + createViewPager(0, null); + LoadTrackableThread thread = new LoadTrackableThread(loadTrackableHandler, geocode, guid, id); + thread.start(); + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info) { + super.onCreateContextMenu(menu, view, info); + final int viewId = view.getId(); + + if (viewId == R.id.author) { // Log item author + contextMenuUser = ((TextView) view).getText().toString(); + } else { // Trackable owner, and user holding trackable now + RelativeLayout itemLayout = (RelativeLayout) view.getParent(); + TextView itemName = (TextView) itemLayout.findViewById(R.id.name); + + String selectedName = itemName.getText().toString(); + if (selectedName.equals(res.getString(R.string.trackable_owner))) { + contextMenuUser = trackable.getOwner(); + } else if (selectedName.equals(res.getString(R.string.trackable_spotted))) { + contextMenuUser = trackable.getSpottedName(); + } + } + + menu.setHeaderTitle(res.getString(R.string.user_menu_title) + " " + contextMenuUser); + menu.add(viewId, 1, 0, res.getString(R.string.user_menu_view_hidden)); + menu.add(viewId, 2, 0, res.getString(R.string.user_menu_view_found)); + menu.add(viewId, 3, 0, res.getString(R.string.user_menu_open_browser)); + } + + @Override + public boolean onContextItemSelected(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=" + Network.encode(contextMenuUser)))); + return true; + default: + return false; + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + menu.add(0, MENU_LOG_TOUCH, 0, res.getString(R.string.trackable_log_touch)).setIcon(R.drawable.ic_menu_agenda); // log touch + menu.add(0, MENU_BROWSER_TRACKABLE, 0, res.getString(R.string.trackable_browser_open)).setIcon(R.drawable.ic_menu_info_details); // browser + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case MENU_LOG_TOUCH: + LogTrackableActivity.startActivity(this, trackable); + return true; + case MENU_BROWSER_TRACKABLE: + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(trackable.getUrl()))); + return true; + default: + return false; + } + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + menu.findItem(MENU_LOG_TOUCH).setEnabled(StringUtils.isNotBlank(geocode) && trackable.isLoggable()); + menu.findItem(MENU_BROWSER_TRACKABLE).setEnabled(StringUtils.isNotBlank(trackable.getUrl())); + return super.onPrepareOptionsMenu(menu); + } + + private class LoadTrackableThread extends Thread { + final private Handler handler; + final private String geocode; + final private String guid; + final private String id; + + public LoadTrackableThread(Handler handlerIn, String geocodeIn, String guidIn, String idIn) { + handler = handlerIn; + geocode = geocodeIn; + guid = guidIn; + id = idIn; + } + + @Override + public void run() { + trackable = cgData.loadTrackable(geocode); + + if ((trackable == null || trackable.isLoggable()) && !StringUtils.startsWithIgnoreCase(geocode, "GK")) { + trackable = GCParser.searchTrackable(geocode, guid, id); + } + handler.sendMessage(Message.obtain()); + } + } + + private class UserActionsListener implements View.OnClickListener { + + @Override + public void onClick(View view) { + if (view == null) { + return; + } + + try { + registerForContextMenu(view); + openContextMenu(view); + } catch (Exception e) { + Log.e("TrackableActivity.UserActionsListener.onClick ", e); + } + } + } + + private class TrackableIconThread extends Thread { + final private String url; + final private Handler handler; + + public TrackableIconThread(String urlIn, Handler handlerIn) { + url = urlIn; + handler = handlerIn; + } + + @Override + public void run() { + if (url == null || handler == null) { + return; + } + + try { + HtmlImage imgGetter = new HtmlImage(trackable.getGeocode(), false, 0, false); + + BitmapDrawable image = imgGetter.getDrawable(url); + Message message = handler.obtainMessage(0, image); + handler.sendMessage(message); + } catch (Exception e) { + Log.e("TrackableActivity.TrackableIconThread.run: ", e); + } + } + } + + private static class TrackableIconHandler extends Handler { + final private TextView view; + + public TrackableIconHandler(TextView viewIn) { + view = viewIn; + } + + @Override + public void handleMessage(Message message) { + final BitmapDrawable image = (BitmapDrawable) message.obj; + if (image != null && view != null) { + image.setBounds(0, 0, view.getHeight(), view.getHeight()); + view.setCompoundDrawables(image, null, null, null); + } + } + } + + public static void startActivity(final AbstractActivity fromContext, + final String guid, final String geocode, final String name) { + final Intent trackableIntent = new Intent(fromContext, TrackableActivity.class); + trackableIntent.putExtra("guid", guid); + trackableIntent.putExtra("geocode", geocode); + trackableIntent.putExtra("name", name); + fromContext.startActivity(trackableIntent); + } + + @Override + protected PageViewCreator createViewCreator(Page page) { + switch (page) { + case DETAILS: + return new DetailsViewCreator(); + case LOGS: + return new LogsViewCreator(); + default: + throw new IllegalArgumentException(); + } + } + + @Override + protected String getTitle(Page page) { + return res.getString(page.resId); + } + + @Override + protected Pair<List<? extends Page>, Integer> getOrderedPages() { + List<Page> pages = new ArrayList<TrackableActivity.Page>(); + pages.add(Page.DETAILS); + if (!trackable.getLogs().isEmpty()) { + pages.add(Page.LOGS); + } + return new ImmutablePair<List<? extends Page>, Integer>(pages, 0); + } + + public class LogsViewCreator extends AbstractCachingPageViewCreator<ListView> { + + private class LogViewHolder { + + private final TextView added; + private final TextView type; + private final TextView author; + private final TextView location; + private final TextView log; + private final ImageView marker; + private final LinearLayout logImages; + + public LogViewHolder(View rowView) { + added = ((TextView) rowView.findViewById(R.id.added)); + type = ((TextView) rowView.findViewById(R.id.type)); + author = ((TextView) rowView.findViewById(R.id.author)); + location = ((TextView) rowView.findViewById(R.id.location)); + log = (TextView) rowView.findViewById(R.id.log); + marker = (ImageView) rowView.findViewById(R.id.log_mark); + logImages = (LinearLayout) rowView.findViewById(R.id.log_layout); + } + } + + @Override + public ListView getDispatchedView() { + view = (ListView) getLayoutInflater().inflate(R.layout.trackable_logs_view, null); + + if (trackable != null && trackable.getLogs() != null) { + view.setAdapter(new ArrayAdapter<LogEntry>(TrackableActivity.this, R.layout.trackable_logs_item, trackable.getLogs()) { + @Override + public View getView(int position, View convertView, android.view.ViewGroup parent) { + View rowView = convertView; + if (null == rowView) { + rowView = getLayoutInflater().inflate(R.layout.trackable_logs_item, null); + } + LogViewHolder holder = (LogViewHolder) rowView.getTag(); + if (null == holder) { + holder = new LogViewHolder(rowView); + rowView.setTag(holder); + } + + final LogEntry log = getItem(position); + fillViewHolder(holder, log); + return rowView; + } + }); + } + return view; + } + + protected void fillViewHolder(LogViewHolder holder, LogEntry log) { + if (log.date > 0) { + holder.added.setText(Formatter.formatShortDate(log.date)); + } + + holder.type.setText(log.type.getL10n()); + holder.author.setText(Html.fromHtml(log.author), TextView.BufferType.SPANNABLE); + + if (StringUtils.isBlank(log.cacheName)) { + holder.location.setVisibility(View.GONE); + } else { + holder.location.setText(Html.fromHtml(log.cacheName)); + final String cacheGuid = log.cacheGuid; + final String cacheName = log.cacheName; + holder.location.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View arg0) { + CacheDetailActivity.startActivityGuid(TrackableActivity.this, cacheGuid, Html.fromHtml(cacheName).toString()); + } + }); + } + + TextView logView = holder.log; + logView.setMovementMethod(LinkMovementMethod.getInstance()); + + String logText = log.log; + if (BaseUtils.containsHtml(logText)) { + logText = log.getDisplayText(); + logView.setText(Html.fromHtml(logText, new HtmlImage(null, false, StoredList.TEMPORARY_LIST_ID, false), null), TextView.BufferType.SPANNABLE); + } + else { + logView.setText(logText); + } + + ImageView statusMarker = holder.marker; + // colored marker + int marker = log.type.markerId; + if (marker != 0) { + statusMarker.setVisibility(View.VISIBLE); + statusMarker.setImageResource(marker); + } + else { + statusMarker.setVisibility(View.GONE); + } + + // add LogImages + LinearLayout logLayout = holder.logImages; + + if (log.hasLogImages()) { + + final ArrayList<cgImage> logImages = new ArrayList<cgImage>(log.getLogImages()); + + final View.OnClickListener listener = new View.OnClickListener() { + @Override + public void onClick(View v) { + ImagesActivity.startActivityLogImages(TrackableActivity.this, trackable.getGeocode(), logImages); + } + }; + + LinearLayout log_imgView = (LinearLayout) getLayoutInflater().inflate(R.layout.trackable_logs_img, null); + TextView log_img_title = (TextView) log_imgView.findViewById(R.id.title); + log_img_title.setText(log.getImageTitles()); + log_img_title.setOnClickListener(listener); + logLayout.addView(log_imgView); + } + + holder.author.setOnClickListener(new UserActionsListener()); + } + + } + + public class DetailsViewCreator extends AbstractCachingPageViewCreator<ScrollView> { + + @Override + public ScrollView getDispatchedView() { + view = (ScrollView) getLayoutInflater().inflate(R.layout.trackable_details_view, null); + final CacheDetailsCreator details = new CacheDetailsCreator(TrackableActivity.this, (LinearLayout) view.findViewById(R.id.details_list)); + + // action bar icon + if (StringUtils.isNotBlank(trackable.getIconUrl())) { + final TrackableIconHandler iconHandler = new TrackableIconHandler(((TextView) findViewById(R.id.actionbar_title))); + final TrackableIconThread iconThread = new TrackableIconThread(trackable.getIconUrl(), iconHandler); + iconThread.start(); + } + + // trackable name + details.add(R.string.trackable_name, StringUtils.isNotBlank(trackable.getName()) ? Html.fromHtml(trackable.getName()).toString() : res.getString(R.string.trackable_unknown)); + + // trackable type + String tbType; + if (StringUtils.isNotBlank(trackable.getType())) { + tbType = Html.fromHtml(trackable.getType()).toString(); + } else { + tbType = res.getString(R.string.trackable_unknown); + } + details.add(R.string.trackable_type, tbType); + + // trackable geocode + details.add(R.string.trackable_code, trackable.getGeocode()); + + // trackable owner + TextView owner = details.add(R.string.trackable_owner, res.getString(R.string.trackable_unknown)); + if (StringUtils.isNotBlank(trackable.getOwner())) { + owner.setText(Html.fromHtml(trackable.getOwner()), TextView.BufferType.SPANNABLE); + owner.setOnClickListener(new UserActionsListener()); + } + + // trackable spotted + if (StringUtils.isNotBlank(trackable.getSpottedName()) || + trackable.getSpottedType() == cgTrackable.SPOTTED_UNKNOWN || + trackable.getSpottedType() == cgTrackable.SPOTTED_OWNER) { + boolean showTimeSpan = true; + StringBuilder text; + + if (trackable.getSpottedType() == cgTrackable.SPOTTED_CACHE) { + text = new StringBuilder(res.getString(R.string.trackable_spotted_in_cache) + ' ' + Html.fromHtml(trackable.getSpottedName()).toString()); + } else if (trackable.getSpottedType() == cgTrackable.SPOTTED_USER) { + text = new StringBuilder(res.getString(R.string.trackable_spotted_at_user) + ' ' + Html.fromHtml(trackable.getSpottedName()).toString()); + } else if (trackable.getSpottedType() == cgTrackable.SPOTTED_UNKNOWN) { + text = new StringBuilder(res.getString(R.string.trackable_spotted_unknown_location)); + } else if (trackable.getSpottedType() == cgTrackable.SPOTTED_OWNER) { + text = new StringBuilder(res.getString(R.string.trackable_spotted_owner)); + } else { + text = new StringBuilder("N/A"); + showTimeSpan = false; + } + + // days since last spotting + if (showTimeSpan && trackable.getLogs() != null) { + for (LogEntry log : trackable.getLogs()) { + if (log.type == LogType.RETRIEVED_IT || log.type == LogType.GRABBED_IT || log.type == LogType.DISCOVERED_IT || log.type == LogType.PLACED_IT) { + final int days = log.daysSinceLog(); + text.append(" (").append(res.getQuantityString(R.plurals.days_ago, days, days)).append(')'); + break; + } + } + } + + final TextView spotted = details.add(R.string.trackable_spotted, text.toString()); + spotted.setClickable(true); + if (cgTrackable.SPOTTED_CACHE == trackable.getSpottedType()) { + spotted.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View arg0) { + CacheDetailActivity.startActivityGuid(TrackableActivity.this, trackable.getSpottedGuid(), trackable.getSpottedName()); + } + }); + } else if (cgTrackable.SPOTTED_USER == trackable.getSpottedType()) { + spotted.setOnClickListener(new UserActionsListener()); + } + } + + // trackable origin + if (StringUtils.isNotBlank(trackable.getOrigin())) { + TextView origin = details.add(R.string.trackable_origin, ""); + origin.setText(Html.fromHtml(trackable.getOrigin()), TextView.BufferType.SPANNABLE); + } + + // trackable released + if (trackable.getReleased() != null) { + details.add(R.string.trackable_released, Formatter.formatDate(trackable.getReleased().getTime())); + } + + // trackable distance + if (trackable.getDistance() >= 0) { + details.add(R.string.trackable_distance, Units.getDistanceFromKilometers(trackable.getDistance())); + } + + // trackable goal + if (StringUtils.isNotBlank(trackable.getGoal())) { + view.findViewById(R.id.goal_box).setVisibility(View.VISIBLE); + TextView descView = (TextView) view.findViewById(R.id.goal); + descView.setVisibility(View.VISIBLE); + descView.setText(Html.fromHtml(trackable.getGoal(), new HtmlImage(geocode, true, 0, false), null), TextView.BufferType.SPANNABLE); + descView.setMovementMethod(LinkMovementMethod.getInstance()); + } + + // trackable details + if (StringUtils.isNotBlank(trackable.getDetails())) { + view.findViewById(R.id.details_box).setVisibility(View.VISIBLE); + TextView descView = (TextView) view.findViewById(R.id.details); + descView.setVisibility(View.VISIBLE); + descView.setText(Html.fromHtml(trackable.getDetails(), new HtmlImage(geocode, true, 0, false), new UnknownTagsHandler()), TextView.BufferType.SPANNABLE); + descView.setMovementMethod(LinkMovementMethod.getInstance()); + } + + // trackable image + if (StringUtils.isNotBlank(trackable.getImage())) { + view.findViewById(R.id.image_box).setVisibility(View.VISIBLE); + LinearLayout imgView = (LinearLayout) view.findViewById(R.id.image); + + final ImageView trackableImage = (ImageView) inflater.inflate(R.layout.trackable_image, null); + + trackableImage.setImageResource(R.drawable.image_not_loaded); + trackableImage.setClickable(true); + trackableImage.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View arg0) { + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(trackable.getImage()))); + } + }); + + // try to load image + final Handler handler = new Handler() { + + @Override + public void handleMessage(Message message) { + BitmapDrawable image = (BitmapDrawable) message.obj; + if (image != null) { + trackableImage.setImageDrawable((BitmapDrawable) message.obj); + } + } + }; + + new Thread() { + + @Override + public void run() { + try { + HtmlImage imgGetter = new HtmlImage(geocode, true, 0, false); + + BitmapDrawable image = imgGetter.getDrawable(trackable.getImage()); + Message message = handler.obtainMessage(0, image); + handler.sendMessage(message); + } catch (Exception e) { + Log.e("cgeospoilers.onCreate.onClick.run: ", e); + } + } + }.start(); + + imgView.addView(trackableImage); + } + return view; + } + + } + +} diff --git a/main/src/cgeo/geocaching/VisitCacheActivity.java b/main/src/cgeo/geocaching/VisitCacheActivity.java index 443ef3a..a9d9147 100644 --- a/main/src/cgeo/geocaching/VisitCacheActivity.java +++ b/main/src/cgeo/geocaching/VisitCacheActivity.java @@ -42,6 +42,7 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; +import java.util.Locale; public class VisitCacheActivity extends AbstractLoggingActivity implements DateDialog.DateDialogParent { static final String EXTRAS_FOUND = "found"; @@ -126,7 +127,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD @Override public void onClick(View view) { - final Intent trackablesIntent = new Intent(VisitCacheActivity.this, cgeotrackable.class); + final Intent trackablesIntent = new Intent(VisitCacheActivity.this, TrackableActivity.class); trackablesIntent.putExtra(EXTRAS_GEOCODE, tbCode); startActivity(trackablesIntent); } @@ -250,18 +251,17 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD } if ((StringUtils.isBlank(cacheid)) && StringUtils.isNotBlank(geocode)) { - cacheid = app.getCacheid(geocode); + cacheid = cgData.getCacheidForGeocode(geocode); } if (StringUtils.isBlank(geocode) && StringUtils.isNotBlank(cacheid)) { - geocode = app.getGeocode(cacheid); + geocode = cgData.getGeocodeForGuid(cacheid); } - - cache = cgeoapplication.getInstance().loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB); + cache = cgData.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB); if (StringUtils.isNotBlank(cache.getName())) { setTitle(res.getString(R.string.log_new_log) + ": " + cache.getName()); } else { - setTitle(res.getString(R.string.log_new_log) + ": " + cache.getGeocode().toUpperCase()); + setTitle(res.getString(R.string.log_new_log) + ": " + cache.getGeocode()); } init(); @@ -335,7 +335,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD } private static String ratingTextValue(final double rating) { - return String.format("%.1f", rating); + return String.format(Locale.getDefault(), "%.1f", rating); } @Override @@ -449,7 +449,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD possibleLogTypes = cache.getPossibleLogTypes(); - final LogEntry log = app.loadLogOffline(geocode); + final LogEntry log = cgData.loadLogOffline(geocode); if (log != null) { typeSelected = log.type; date.setTime(new Date(log.date)); @@ -575,7 +575,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD @Override public void onClick(View arg0) { //TODO: unify this method and the code in init() - app.clearLogOffline(geocode); + cgData.clearLogOffline(geocode); if (alreadyFound) { typeSelected = LogType.NOTE; @@ -686,11 +686,11 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD cache.setFound(true); } - app.updateCache(cache); + cgData.saveChangedCache(cache); } if (status == StatusCode.NO_ERROR) { - app.clearLogOffline(geocode); + cgData.clearLogOffline(geocode); } if (status == StatusCode.NO_ERROR && typeSelected == LogType.FOUND_IT && Settings.isUseTwitter() @@ -717,7 +717,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD // Do not erase the saved log if the user has removed all the characters // without using "Clear". This may be a manipulation mistake, and erasing // again will be easy using "Clear" while retyping the text may not be. - if (force || (log.length() > 0 && !StringUtils.equals(log, text))) { + if (force || (StringUtils.isNotEmpty(log) && !StringUtils.equals(log, text))) { cache.logOffline(this, log, date, typeSelected); } text = log; diff --git a/main/src/cgeo/geocaching/WaypointPopup.java b/main/src/cgeo/geocaching/WaypointPopup.java index 7fbfe10..eb0bc17 100644 --- a/main/src/cgeo/geocaching/WaypointPopup.java +++ b/main/src/cgeo/geocaching/WaypointPopup.java @@ -38,12 +38,12 @@ public class WaypointPopup extends AbstractPopupActivity { @Override protected void init() { super.init(); - waypoint = app.loadWaypoint(waypointId); + waypoint = cgData.loadWaypoint(waypointId); try { if (StringUtils.isNotBlank(waypoint.getName())) { setTitle(waypoint.getName()); } else { - setTitle(waypoint.getGeocode().toUpperCase()); + setTitle(waypoint.getGeocode()); } // actionbar icon @@ -53,7 +53,7 @@ public class WaypointPopup extends AbstractPopupActivity { details = new CacheDetailsCreator(this, (LinearLayout) findViewById(R.id.waypoint_details_list)); //Waypoint geocode - details.add(R.string.cache_geocode, waypoint.getPrefix().toUpperCase() + waypoint.getGeocode().toUpperCase().substring(2)); + details.add(R.string.cache_geocode, waypoint.getPrefix() + waypoint.getGeocode().substring(2)); // Edit Button final Button buttonEdit = (Button) findViewById(R.id.edit); diff --git a/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java b/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java new file mode 100644 index 0000000..56431d4 --- /dev/null +++ b/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java @@ -0,0 +1,272 @@ +package cgeo.geocaching.activity; + +import cgeo.geocaching.R; +import cgeo.geocaching.utils.Log; + +import com.viewpagerindicator.TitlePageIndicator; +import com.viewpagerindicator.TitleProvider; + +import org.apache.commons.lang3.tuple.Pair; + +import android.app.Activity; +import android.os.Parcelable; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager; +import android.support.v4.view.ViewPager.OnPageChangeListener; +import android.view.View; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Abstract activity with the ability to manage pages in a view pager. + * + * @param <Page> + * Enum listing all available pages of this activity. The pages available at a certain point of time are + * defined by overriding {@link #getOrderedPages()}. + */ +public abstract class AbstractViewPagerActivity<Page extends Enum<Page>> extends AbstractActivity { + + protected AbstractViewPagerActivity(String helpTopic) { + super(helpTopic); + } + + /** + * A {@link List} of all available pages. + * + * TODO Move to adapter + */ + private final List<Page> pageOrder = new ArrayList<Page>(); + + /** + * Instances of all {@link PageViewCreator}. + */ + private final Map<Page, PageViewCreator> viewCreators = new HashMap<Page, PageViewCreator>(); + + /** + * The {@link ViewPager} for this activity. + */ + private ViewPager viewPager; + + /** + * The {@link ViewPagerAdapter} for this activity. + */ + private ViewPagerAdapter viewPagerAdapter; + + /** + * The {@link TitlePageIndicator} for this activity. + */ + private TitlePageIndicator titleIndicator; + + public interface PageViewCreator { + /** + * Returns a validated view. + * + * @return + */ + public View getDispatchedView(); + + /** + * Returns a (maybe cached) view. + * + * @return + */ + public View getView(); + + /** + * Handles changed data-sets. + */ + public void notifyDataSetChanged(); + } + + /** + * Page selection interface for the view pager. + * + */ + protected interface OnPageSelectedListener { + public void onPageSelected(int position); + } + + /** + * The ViewPagerAdapter for scrolling through pages of the CacheDetailActivity. + */ + private class ViewPagerAdapter extends PagerAdapter implements TitleProvider { + + @Override + public void destroyItem(View container, int position, Object object) { + ((ViewPager) container).removeView((View) object); + } + + @Override + public void finishUpdate(View container) { + } + + @Override + public int getCount() { + return pageOrder.size(); + } + + @Override + public Object instantiateItem(View container, int position) { + final Page page = pageOrder.get(position); + + PageViewCreator creator = viewCreators.get(page); + + if (null == creator && null != page) { + creator = AbstractViewPagerActivity.this.createViewCreator(page); + viewCreators.put(page, creator); + } + + View view = null; + + try { + if (null != creator) { + // Result from getView() is maybe cached, but it should be valid because the + // creator should be informed about data-changes with notifyDataSetChanged() + view = creator.getView(); + ((ViewPager) container).addView(view, 0); + } + } catch (Exception e) { + Log.e("ViewPagerAdapter.instantiateItem ", e); + } + + return view; + } + + @Override + public boolean isViewFromObject(View view, Object object) { + return view == object; + } + + @Override + public void restoreState(Parcelable arg0, ClassLoader arg1) { + } + + @Override + public Parcelable saveState() { + return null; + } + + @Override + public void startUpdate(View arg0) { + } + + @Override + public int getItemPosition(Object object) { + // We are doing the caching. So pretend that the view is gone. + // The ViewPager will get it back in instantiateItem() + return POSITION_NONE; + } + + @Override + public String getTitle(int position) { + final Page page = pageOrder.get(position); + if (null == page) { + return ""; + } + return AbstractViewPagerActivity.this.getTitle(page); + } + + } + + /** + * Create the view pager. Call this from the {@link Activity#onCreate} implementation. + * + * @param startPageIndex + * index of the page shown first + * @param pageSelectedListener + * page selection listener or <code>null</code> + */ + protected final void createViewPager(int startPageIndex, final OnPageSelectedListener pageSelectedListener) { + // initialize ViewPager + viewPager = (ViewPager) findViewById(R.id.viewpager); + viewPagerAdapter = new ViewPagerAdapter(); + viewPager.setAdapter(viewPagerAdapter); + + titleIndicator = (TitlePageIndicator) findViewById(R.id.pager_indicator); + titleIndicator.setViewPager(viewPager); + if (pageSelectedListener != null) { + titleIndicator.setOnPageChangeListener(new OnPageChangeListener() { + @Override + public void onPageSelected(int position) { + pageSelectedListener.onPageSelected(position); + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + } + + @Override + public void onPageScrollStateChanged(int state) { + } + }); + } + + // switch to entry page (last used or 2) + if (viewPagerAdapter.getCount() < startPageIndex) { + for (int i = 0; i <= startPageIndex; i++) { + // we can't switch to a page that is out of bounds, so we add null-pages + pageOrder.add(null); + } + } + viewPager.setCurrentItem(startPageIndex, false); + } + + /** + * create the view creator for the given page + * + * @return new view creator + */ + protected abstract PageViewCreator createViewCreator(Page page); + + /** + * get the title for the given page + */ + protected abstract String getTitle(Page page); + + protected final void reinitializeViewPager() { + // notify all creators that the data has changed + for (PageViewCreator creator : viewCreators.values()) { + creator.notifyDataSetChanged(); + } + + pageOrder.clear(); + final Pair<List<? extends Page>, Integer> pagesAndIndex = getOrderedPages(); + pageOrder.addAll(pagesAndIndex.getLeft()); + + // switch to details page, if we're out of bounds + final int defaultPage = pagesAndIndex.getRight().intValue(); + if (viewPager.getCurrentItem() < 0 || viewPager.getCurrentItem() >= viewPagerAdapter.getCount()) { + viewPager.setCurrentItem(defaultPage, false); + } + + // notify the adapter that the data has changed + viewPagerAdapter.notifyDataSetChanged(); + + // notify the indicator that the data has changed + titleIndicator.notifyDataSetChanged(); + } + + /** + * @return the currently available list of ordered pages, together with the index of the default page + */ + protected abstract Pair<List<? extends Page>, Integer> getOrderedPages(); + + public final Page getPage(int position) { + return pageOrder.get(position); + } + + protected final int getPageIndex(Page page) { + return pageOrder.indexOf(page); + } + + protected final PageViewCreator getViewCreator(Page page) { + return viewCreators.get(page); + } + + protected final boolean isCurrentPage(Page page) { + return viewPager.getCurrentItem() == getPageIndex(page); + } +} diff --git a/main/src/cgeo/geocaching/activity/FilteredActivity.java b/main/src/cgeo/geocaching/activity/FilteredActivity.java new file mode 100644 index 0000000..0370d63 --- /dev/null +++ b/main/src/cgeo/geocaching/activity/FilteredActivity.java @@ -0,0 +1,11 @@ +package cgeo.geocaching.activity; + +import android.view.View; + +public interface FilteredActivity { + /** + * called from the filter bar view + */ + public void showFilterMenu(final View view); + +} diff --git a/main/src/cgeo/geocaching/apps/AbstractLocusApp.java b/main/src/cgeo/geocaching/apps/AbstractLocusApp.java index ac6fc1c..8f61e72 100644 --- a/main/src/cgeo/geocaching/apps/AbstractLocusApp.java +++ b/main/src/cgeo/geocaching/apps/AbstractLocusApp.java @@ -22,6 +22,7 @@ import android.location.Location; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; +import java.util.Locale; /** * for the Locus API: @@ -30,7 +31,7 @@ import java.util.List; */ public abstract class AbstractLocusApp extends AbstractApp { private static final String INTENT = Intent.ACTION_VIEW; - private static final SimpleDateFormat ISO8601DATE = new SimpleDateFormat("yyyy-MM-dd'T'"); + private static final SimpleDateFormat ISO8601DATE = new SimpleDateFormat("yyyy-MM-dd'T'", Locale.US); protected AbstractLocusApp() { super(getString(R.string.caches_map_locus), INTENT); @@ -47,11 +48,11 @@ public abstract class AbstractLocusApp extends AbstractApp { /** * Display a list of caches / waypoints in Locus - * + * * @param objectsToShow * which caches/waypoints to show * @param withCacheWaypoints - * wether to give waypoints of caches to Locus or not + * Whether to give waypoints of caches to Locus or not * @param activity */ protected static boolean showInLocus(final List<?> objectsToShow, final boolean withCacheWaypoints, final boolean export, @@ -85,7 +86,7 @@ public abstract class AbstractLocusApp extends AbstractApp { final ArrayList<PointsData> data = new ArrayList<PointsData>(); data.add(pd); DisplayData.sendDataCursor(activity, data, - "content://" + LocusDataStorageProvider.class.getCanonicalName().toLowerCase(), + "content://" + LocusDataStorageProvider.class.getCanonicalName().toLowerCase(Locale.US), export); } diff --git a/main/src/cgeo/geocaching/apps/cache/navi/AbstractNavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/AbstractNavigationApp.java deleted file mode 100644 index 27cb47c..0000000 --- a/main/src/cgeo/geocaching/apps/cache/navi/AbstractNavigationApp.java +++ /dev/null @@ -1,26 +0,0 @@ -package cgeo.geocaching.apps.cache.navi; - -import cgeo.geocaching.cgWaypoint; -import cgeo.geocaching.apps.AbstractApp; -import cgeo.geocaching.geopoint.Geopoint; - -abstract class AbstractNavigationApp extends AbstractApp implements NavigationApp { - - protected AbstractNavigationApp(String name, String intent, String packageName) { - super(name, intent, packageName); - } - - protected AbstractNavigationApp(String name, String intent) { - super(name, intent); - } - - @Override - public boolean isEnabled(cgWaypoint waypoint) { - return waypoint != null; - } - - @Override - public boolean isEnabled(Geopoint geopoint) { - return geopoint != null; - } -} diff --git a/main/src/cgeo/geocaching/apps/cache/navi/AbstractStaticMapsApp.java b/main/src/cgeo/geocaching/apps/cache/navi/AbstractStaticMapsApp.java index f27b53c..85a4b93 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/AbstractStaticMapsApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/AbstractStaticMapsApp.java @@ -5,8 +5,8 @@ import cgeo.geocaching.R; import cgeo.geocaching.StaticMapsActivity; import cgeo.geocaching.StaticMapsProvider; import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgData; import cgeo.geocaching.cgWaypoint; -import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.apps.AbstractApp; @@ -15,7 +15,7 @@ import org.apache.commons.lang3.StringUtils; import android.app.Activity; abstract class AbstractStaticMapsApp extends AbstractApp implements CacheNavigationApp, WaypointNavigationApp { - public AbstractStaticMapsApp(String name) { + protected AbstractStaticMapsApp(String name) { super(name, null); } @@ -30,11 +30,12 @@ abstract class AbstractStaticMapsApp extends AbstractApp implements CacheNavigat } protected static boolean hasStaticMap(cgWaypoint waypoint) { - if (waypoint==null) + if (waypoint==null) { return false; + } String geocode = waypoint.getGeocode(); int id = waypoint.getId(); - if (StringUtils.isNotEmpty(geocode) && cgeoapplication.getInstance().isOffline(geocode, null)) { + if (StringUtils.isNotEmpty(geocode) && cgData.isOffline(geocode, null)) { return StaticMapsProvider.hasStaticMapForWaypoint(geocode, id); } return false; diff --git a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsDirectionApp.java b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsDirectionApp.java new file mode 100644 index 0000000..db4fc1c --- /dev/null +++ b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsDirectionApp.java @@ -0,0 +1,48 @@ +package cgeo.geocaching.apps.cache.navi; + +import cgeo.geocaching.IGeoData; +import cgeo.geocaching.R; +import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.maps.MapProviderFactory; +import cgeo.geocaching.utils.Log; + +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; + +public class GoogleMapsDirectionApp extends AbstractPointNavigationApp { + + protected GoogleMapsDirectionApp() { + super(getString(R.string.cache_menu_maps_directions), null); + } + + @Override + public boolean isInstalled() { + return MapProviderFactory.isGoogleMapsInstalled(); + } + + @Override + public void navigate(Activity activity, Geopoint coords) { + try { + IGeoData geo = cgeoapplication.getInstance().currentGeo(); + final Geopoint coordsNow = geo == null ? null : geo.getCoords(); + + 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()))); + } + + } catch (Exception e) { + Log.i("GoogleMapsDirection: application not available."); + } + + } + +} diff --git a/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java index 7258e11..f1616ad 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java @@ -1,10 +1,6 @@ package cgeo.geocaching.apps.cache.navi; -import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; -import cgeo.geocaching.cgeoapplication; -import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.utils.Log; @@ -12,10 +8,13 @@ import android.app.Activity; import android.content.Intent; import android.net.Uri; -class GoogleNavigationApp extends AbstractPointNavigationApp { +abstract class GoogleNavigationApp extends AbstractPointNavigationApp { - GoogleNavigationApp() { - super(getString(R.string.cache_menu_tbt), null); + private final String mode; + + protected GoogleNavigationApp(final int nameResourceId, final String mode) { + super(getString(nameResourceId), null); + this.mode = mode; } @Override @@ -23,49 +22,27 @@ class GoogleNavigationApp extends AbstractPointNavigationApp { return true; } - private static boolean navigateToCoordinates(Activity activity, final Geopoint coords) { - IGeoData geo = cgeoapplication.getInstance().currentGeo(); - final Geopoint coordsNow = geo == null ? null : geo.getCoords(); - - // Google Navigation - if (Settings.isUseGoogleNavigation()) { - try { - activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri - .parse("google.navigation:ll=" + coords.getLatitude() + "," - + coords.getLongitude()))); - - return true; - } catch (Exception e) { - // nothing - } - } - - // Google Maps Directions + @Override + public void navigate(Activity activity, Geopoint coords) { 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()))); - } + activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri + .parse("google.navigation:ll=" + coords.getLatitude() + "," + + coords.getLongitude() + mode))); - return true; } catch (Exception e) { - // nothing + Log.i("cgBase.runNavigation: No navigation application available."); } + } - Log.i("cgBase.runNavigation: No navigation application available."); - return false; + static class GoogleNavigationWalkingApp extends GoogleNavigationApp { + GoogleNavigationWalkingApp() { + super(R.string.cache_menu_navigation_walk, "&mode=w"); + } } - @Override - public void navigate(Activity activity, Geopoint coords) { - if (!navigateToCoordinates(activity, coords)) { - ActivityMixin.showToast(activity, getString(R.string.err_navigation_no)); + static class GoogleNavigationDrivingApp extends GoogleNavigationApp { + GoogleNavigationDrivingApp() { + super(R.string.cache_menu_navigation_drive, "&mode=d"); } } }
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/apps/cache/navi/NavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/NavigationApp.java deleted file mode 100644 index 52d16cf..0000000 --- a/main/src/cgeo/geocaching/apps/cache/navi/NavigationApp.java +++ /dev/null @@ -1,18 +0,0 @@ -package cgeo.geocaching.apps.cache.navi; - -import cgeo.geocaching.cgCache; -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 Activity activity, - final cgCache cache, final cgWaypoint waypoint, - final Geopoint coords); - - boolean isEnabled(final cgWaypoint waypoint); - - boolean isEnabled(final Geopoint geopoint); -} diff --git a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java index 57a71bb..0ff4af2 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java @@ -8,6 +8,8 @@ import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.apps.AbstractAppFactory; import cgeo.geocaching.apps.App; +import cgeo.geocaching.apps.cache.navi.GoogleNavigationApp.GoogleNavigationDrivingApp; +import cgeo.geocaching.apps.cache.navi.GoogleNavigationApp.GoogleNavigationWalkingApp; import cgeo.geocaching.geopoint.Geopoint; import android.app.Activity; @@ -40,7 +42,7 @@ public final class NavigationAppFactory extends AbstractAppFactory { /** Google Maps */ GOOGLE_MAPS(new GoogleMapsApp(), 6), /** Google Navigation */ - GOOGLE_NAVIGATION(new GoogleNavigationApp(), 7), + GOOGLE_NAVIGATION(new GoogleNavigationDrivingApp(), 7), /** Google Streetview */ GOOGLE_STREETVIEW(new StreetviewApp(), 8), /** The external OruxMaps app */ @@ -48,7 +50,15 @@ public final class NavigationAppFactory extends AbstractAppFactory { /** The external navigon app */ NAVIGON(new NavigonApp(), 10), /** The external Sygic app */ - SYGIC(new SygicNavigationApp(), 11); + SYGIC(new SygicNavigationApp(), 11), + /** + * Google Navigation in walking mode + */ + GOOGLE_NAVIGATION_WALK(new GoogleNavigationWalkingApp(), 12), + /** + * Google Maps Directions + */ + GOOGLE_MAPS_DIRECTIONS(new GoogleMapsDirectionApp(), 13); NavigationAppsEnum(App app, int id) { this.app = app; diff --git a/main/src/cgeo/geocaching/cgCache.java b/main/src/cgeo/geocaching/cgCache.java index 7035d65..7fbbf0c 100644 --- a/main/src/cgeo/geocaching/cgCache.java +++ b/main/src/cgeo/geocaching/cgCache.java @@ -38,7 +38,6 @@ import android.net.Uri; import android.os.Handler; import android.os.Message; import android.text.Html; -import android.text.Spannable; import java.util.ArrayList; import java.util.Calendar; @@ -66,7 +65,6 @@ public class cgCache implements ICache, IWaypoint { private String guid = ""; private CacheType cacheType = CacheType.UNKNOWN; private String name = ""; - private Spannable nameSp = null; private String ownerDisplayName = ""; private String ownerUserId = ""; private Date hidden = null; @@ -99,20 +97,20 @@ public class cgCache implements ICache, IWaypoint { private LazyInitializedList<String> attributes = new LazyInitializedList<String>() { @Override protected List<String> loadFromDatabase() { - return cgeoapplication.getInstance().loadAttributes(geocode); + return cgData.loadAttributes(geocode); } }; private LazyInitializedList<cgWaypoint> waypoints = new LazyInitializedList<cgWaypoint>() { @Override protected List<cgWaypoint> loadFromDatabase() { - return cgeoapplication.getInstance().loadWaypoints(geocode); + return cgData.loadWaypoints(geocode); } }; private List<cgImage> spoilers = null; private LazyInitializedList<LogEntry> logs = new LazyInitializedList<LogEntry>() { @Override protected List<LogEntry> loadFromDatabase() { - return cgeoapplication.getInstance().loadLogs(geocode); + return cgData.loadLogs(geocode); } }; private List<cgTrackable> inventory = null; @@ -227,9 +225,6 @@ public class cgCache implements ICache, IWaypoint { if (StringUtils.isBlank(name)) { name = other.name; } - if (StringUtils.isBlank(nameSp)) { - nameSp = other.nameSp; - } if (StringUtils.isBlank(ownerDisplayName)) { ownerDisplayName = other.ownerDisplayName; } @@ -294,12 +289,12 @@ public class cgCache implements ICache, IWaypoint { attributes.set(other.attributes); } if (waypoints.isEmpty()) { - waypoints.set(other.waypoints); + this.setWaypoints(other.waypoints.asList(), false); } else { ArrayList<cgWaypoint> newPoints = new ArrayList<cgWaypoint>(waypoints.asList()); - cgWaypoint.mergeWayPoints(newPoints, other.getWaypoints(), false); - waypoints.set(newPoints); + cgWaypoint.mergeWayPoints(newPoints, other.waypoints.asList(), false); + this.setWaypoints(newPoints, false); } if (spoilers == null) { spoilers = other.spoilers; @@ -315,12 +310,21 @@ public class cgCache implements ICache, IWaypoint { if (logs.isEmpty()) { // keep last known logs if none logs.set(other.logs); } - if (logCounts.size() == 0) { + if (logCounts.isEmpty()) { logCounts = other.logCounts; } - if (!userModifiedCoords) { - userModifiedCoords = other.userModifiedCoords; + + // if cache has ORIGINAL type waypoint ... it is considered that it has modified coordinates, otherwise not + userModifiedCoords = false; + if (waypoints != null) { + for (cgWaypoint wpt : waypoints) { + if (wpt.getWaypointType() == WaypointType.ORIGINAL) { + userModifiedCoords = true; + break; + } + } } + if (!reliableLatLon) { reliableLatLon = other.reliableLatLon; } @@ -340,7 +344,8 @@ public class cgCache implements ICache, IWaypoint { /** * Compare two caches quickly. For map and list fields only the references are compared ! * - * @param other the other cache to compare this one to + * @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) { @@ -376,7 +381,6 @@ public class cgCache implements ICache, IWaypoint { (direction != null ? direction.equals(other.direction) : null == other.direction) && (distance != null ? distance.equals(other.distance) : null == other.distance) && (elevation != null ? elevation.equals(other.elevation) : null == other.elevation) && - nameSp == other.nameSp && rating == other.rating && votes == other.votes && myVote == other.myVote && @@ -441,7 +445,7 @@ public class cgCache implements ICache, IWaypoint { } Intent logVisitIntent = new Intent((Activity) fromActivity, VisitCacheActivity.class); logVisitIntent.putExtra(VisitCacheActivity.EXTRAS_ID, cacheId); - logVisitIntent.putExtra(VisitCacheActivity.EXTRAS_GEOCODE, geocode.toUpperCase()); + logVisitIntent.putExtra(VisitCacheActivity.EXTRAS_GEOCODE, geocode); logVisitIntent.putExtra(VisitCacheActivity.EXTRAS_FOUND, found); ((Activity) fromActivity).startActivity(logVisitIntent); @@ -457,13 +461,12 @@ public class cgCache implements ICache, IWaypoint { if (logType == LogType.UNKNOWN) { return; } - cgeoapplication app = (cgeoapplication) fromActivity.getApplication(); - final boolean status = app.saveLogOffline(geocode, date.getTime(), logType, log); + final boolean status = cgData.saveLogOffline(geocode, date.getTime(), logType, log); Resources res = fromActivity.getResources(); if (status) { ActivityMixin.showToast(fromActivity, res.getString(R.string.info_log_saved)); - app.saveVisitDate(geocode); + cgData.saveVisitDate(geocode); logOffline = true; notifyChange(); @@ -538,6 +541,10 @@ public class cgCache implements ICache, IWaypoint { return getConnector().supportsLogging(); } + public boolean supportsOwnCoordinates() { + return getConnector().supportsOwnCoordinates(); + } + @Override public float getDifficulty() { return difficulty; @@ -603,7 +610,7 @@ public class cgCache implements ICache, IWaypoint { @Override public String getDescription() { if (description == null) { - description = StringUtils.defaultString(cgeoapplication.getInstance().getCacheDescription(geocode)); + description = StringUtils.defaultString(cgData.getCacheDescription(geocode)); } return description; } @@ -661,7 +668,7 @@ public class cgCache implements ICache, IWaypoint { } StringBuilder subject = new StringBuilder("Geocache "); - subject.append(geocode.toUpperCase()); + subject.append(geocode); if (StringUtils.isNotBlank(name)) { subject.append(" - ").append(name); } @@ -700,7 +707,6 @@ public class cgCache implements ICache, IWaypoint { this.favorite = favourite; } - @Override public boolean isWatchlist() { return onWatchlist; @@ -809,14 +815,6 @@ public class cgCache implements ICache, IWaypoint { this.detailed = detailed; } - public Spannable getNameSp() { - return nameSp; - } - - public void setNameSp(Spannable nameSp) { - this.nameSp = nameSp; - } - public void setHidden(final Date hidden) { if (hidden == null) { this.hidden = null; @@ -958,8 +956,7 @@ public class cgCache implements ICache, IWaypoint { } } } - - return saveToDatabase && cgeoapplication.getInstance().saveWaypoints(this); + return saveToDatabase && cgData.saveWaypoints(this); } /** @@ -1015,7 +1012,7 @@ public class cgCache implements ICache, IWaypoint { } public void setGeocode(String geocode) { - this.geocode = geocode; + this.geocode = StringUtils.upperCase(geocode); } public void setCacheId(String cacheId) { @@ -1166,8 +1163,7 @@ public class cgCache implements ICache, IWaypoint { // when waypoint was edited, finalDefined may have changed resetFinalDefined(); } - - return saveToDatabase && cgeoapplication.getInstance().saveWaypoint(waypoint.getId(), geocode, waypoint); + return saveToDatabase && cgData.saveWaypoint(waypoint.getId(), geocode, waypoint); } public boolean hasWaypoints() { @@ -1201,43 +1197,47 @@ public class cgCache implements ICache, IWaypoint { } public void setUserModifiedCoords(boolean coordsChanged) { - this.userModifiedCoords = coordsChanged; + userModifiedCoords = coordsChanged; } /** * Duplicate a waypoint. * - * @param index the waypoint to duplicate + * @param original + * the waypoint to duplicate * @return <code>true</code> if the waypoint was duplicated, <code>false</code> otherwise (invalid index) */ - public boolean duplicateWaypoint(final int index) { - final cgWaypoint original = getWaypoint(index); + public boolean duplicateWaypoint(final cgWaypoint original) { if (original == null) { return false; } + final int index = getWaypointIndex(original); 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().saveWaypoint(-1, geocode, copy); + return cgData.saveWaypoint(-1, geocode, copy); } /** * delete a user defined waypoint * - * @param index - * of the waypoint in cache's waypoint list + * @param waypoint + * to be removed from cache * @return <code>true</code>, if the waypoint was deleted */ - public boolean deleteWaypoint(final int index) { - final cgWaypoint waypoint = getWaypoint(index); + public boolean deleteWaypoint(final cgWaypoint waypoint) { if (waypoint == null) { return false; } + if (waypoint.getId() <= 0) { + return false; + } if (waypoint.isUserDefined()) { + final int index = getWaypointIndex(waypoint); waypoints.remove(index); - cgeoapplication.getInstance().deleteWaypoint(waypoint.getId()); - cgeoapplication.getInstance().removeCache(geocode, EnumSet.of(RemoveFlag.REMOVE_CACHE)); + cgData.deleteWaypoint(waypoint.getId()); + cgData.removeCache(geocode, EnumSet.of(RemoveFlag.REMOVE_CACHE)); // Check status if Final is defined if (waypoint.isFinalWithCoords()) { resetFinalDefined(); @@ -1248,19 +1248,17 @@ public class cgCache implements ICache, IWaypoint { } /** - * delete a user defined waypoint + * deletes any waypoint * * @param waypoint - * to be removed from cache - * @return <code>true</code>, if the waypoint was deleted */ - public boolean deleteWaypoint(final cgWaypoint waypoint) { - if (waypoint.getId() <= 0) { - return false; - } + public void deleteWaypointForce(cgWaypoint waypoint) { final int index = getWaypointIndex(waypoint); - return index >= 0 && deleteWaypoint(index); + waypoints.remove(index); + cgData.deleteWaypoint(waypoint.getId()); + cgData.removeCache(geocode, EnumSet.of(RemoveFlag.REMOVE_CACHE)); + resetFinalDefined(); } /** @@ -1283,7 +1281,8 @@ public class cgCache implements ICache, IWaypoint { /** * Retrieve a given waypoint. * - * @param index the index of the waypoint + * @param index + * the index of the waypoint * @return waypoint or <code>null</code> if index is out of range */ public cgWaypoint getWaypoint(final int index) { @@ -1293,7 +1292,8 @@ public class cgCache implements ICache, IWaypoint { /** * Lookup a waypoint by its id. * - * @param id the id of the waypoint to look for + * @param id + * the id of the waypoint to look for * @return waypoint or <code>null</code> */ public cgWaypoint getWaypointById(final int id) { @@ -1391,8 +1391,8 @@ public class cgCache implements ICache, IWaypoint { public void drop(Handler handler) { try { - cgeoapplication.getInstance().markDropped(Collections.singletonList(this)); - cgeoapplication.getInstance().removeCache(getGeocode(), EnumSet.of(RemoveFlag.REMOVE_CACHE)); + cgData.markDropped(Collections.singletonList(this)); + cgData.removeCache(getGeocode(), EnumSet.of(RemoveFlag.REMOVE_CACHE)); handler.sendMessage(Message.obtain()); } catch (Exception e) { @@ -1402,48 +1402,48 @@ public class cgCache implements ICache, IWaypoint { public void checkFields() { if (StringUtils.isBlank(getGeocode())) { - Log.e("geo code not parsed correctly"); + Log.w("geo code not parsed correctly for " + geocode); } if (StringUtils.isBlank(getName())) { - Log.e("name not parsed correctly"); + Log.w("name not parsed correctly for " + geocode); } if (StringUtils.isBlank(getGuid())) { - Log.e("guid not parsed correctly"); + Log.w("guid not parsed correctly for " + geocode); } if (getTerrain() == 0.0) { - Log.e("terrain not parsed correctly"); + Log.w("terrain not parsed correctly for " + geocode); } if (getDifficulty() == 0.0) { - Log.e("difficulty not parsed correctly"); + Log.w("difficulty not parsed correctly for " + geocode); } if (StringUtils.isBlank(getOwnerDisplayName())) { - Log.e("owner display name not parsed correctly"); + Log.w("owner display name not parsed correctly for " + geocode); } if (StringUtils.isBlank(getOwnerUserId())) { - Log.e("owner user id real not parsed correctly"); + Log.w("owner user id real not parsed correctly for " + geocode); } if (getHiddenDate() == null) { - Log.e("hidden not parsed correctly"); + Log.w("hidden not parsed correctly for " + geocode); } if (getFavoritePoints() < 0) { - Log.e("favoriteCount not parsed correctly"); + Log.w("favoriteCount not parsed correctly for " + geocode); } if (getSize() == null) { - Log.e("size not parsed correctly"); + Log.w("size not parsed correctly for " + geocode); } if (getType() == null || getType() == CacheType.UNKNOWN) { - Log.e("type not parsed correctly"); + Log.w("type not parsed correctly for " + geocode); } if (getCoords() == null) { - Log.e("coordinates not parsed correctly"); + Log.w("coordinates not parsed correctly for " + geocode); } if (StringUtils.isBlank(getLocation())) { - Log.e("location not parsed correctly"); + Log.w("location not parsed correctly for " + geocode); } } public void refresh(int newListId, CancellableHandler handler) { - cgeoapplication.getInstance().removeCache(geocode, EnumSet.of(RemoveFlag.REMOVE_CACHE)); + cgData.removeCache(geocode, EnumSet.of(RemoveFlag.REMOVE_CACHE)); storeCache(null, geocode, newListId, true, handler); } @@ -1516,7 +1516,7 @@ public class cgCache implements ICache, IWaypoint { } cache.setListId(listId); - cgeoapplication.getInstance().saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); + cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); if (CancellableHandler.isCancelled(handler)) { return; @@ -1538,10 +1538,9 @@ public class cgCache implements ICache, IWaypoint { return null; } - final cgeoapplication app = cgeoapplication.getInstance(); - if (!forceReload && listId == StoredList.TEMPORARY_LIST_ID && (app.isOffline(geocode, guid) || app.isThere(geocode, guid, true, true))) { + if (!forceReload && listId == StoredList.TEMPORARY_LIST_ID && (cgData.isOffline(geocode, guid) || cgData.isThere(geocode, guid, true, true))) { final SearchResult search = new SearchResult(); - final String realGeocode = StringUtils.isNotBlank(geocode) ? geocode : app.getGeocode(guid); + final String realGeocode = StringUtils.isNotBlank(geocode) ? geocode : cgData.getGeocodeForGuid(guid); search.addGeocode(realGeocode); return search; } @@ -1613,8 +1612,7 @@ public class cgCache implements ICache, IWaypoint { * @return */ public boolean hasAttribute(CacheAttribute attribute, boolean yes) { - // lazy loading of attributes - cgCache fullCache = cgeoapplication.getInstance().loadCache(getGeocode(), EnumSet.of(LoadFlag.LOAD_ATTRIBUTES)); + cgCache fullCache = cgData.loadCache(getGeocode(), EnumSet.of(LoadFlag.LOAD_ATTRIBUTES)); if (fullCache == null) { fullCache = this; } diff --git a/main/src/cgeo/geocaching/cgData.java b/main/src/cgeo/geocaching/cgData.java index b822c2b..78611b8 100644 --- a/main/src/cgeo/geocaching/cgData.java +++ b/main/src/cgeo/geocaching/cgData.java @@ -23,7 +23,6 @@ import android.content.ContextWrapper; import android.content.res.Resources; import android.database.Cursor; import android.database.DatabaseUtils; -import android.database.DatabaseUtils.InsertHelper; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteDoneException; @@ -48,6 +47,10 @@ import java.util.regex.Pattern; public class cgData { + private cgData() { + // utility class + } + public enum StorageLocation { HEAP, CACHE, @@ -72,9 +75,9 @@ public class cgData { * holds the column indexes of the cache table to avoid lookups */ private static int[] cacheColumnIndex; - private CacheCache cacheCache = new CacheCache(); - private SQLiteDatabase database = null; - private static final int dbVersion = 64; + private static CacheCache cacheCache = new CacheCache(); + private static SQLiteDatabase database = null; + private static final int dbVersion = 65; public static final int customListIdOffset = 10; private static final String dbName = "data"; private static final String dbTableCaches = "cg_caches"; @@ -151,9 +154,6 @@ public class cgData { + "updated long not null, " // date of save + "attribute text " + "); "; - private final static int ATTRIBUTES_GEOCODE = 2; - private final static int ATTRIBUTES_UPDATED = 3; - private final static int ATTRIBUTES_ATTRIBUTE = 4; private static final String dbCreateWaypoints = "" + "create table " + dbTableWaypoints + " (" @@ -191,14 +191,6 @@ public class cgData { + "found integer not null default 0, " + "friend integer " + "); "; - private final static int LOGS_GEOCODE = 2; - private final static int LOGS_UPDATED = 3; - private final static int LOGS_TYPE = 4; - private final static int LOGS_AUTHOR = 5; - private final static int LOGS_LOG = 6; - private final static int LOGS_DATE = 7; - private final static int LOGS_FOUND = 8; - private final static int LOGS_FRIEND = 9; private static final String dbCreateLogCount = "" + "create table " + dbTableLogCount + " (" @@ -246,10 +238,10 @@ public class cgData { + "longitude double " + "); "; - private HashMap<String, SQLiteStatement> statements = new HashMap<String, SQLiteStatement>(); private static boolean newlyCreatedDatabase = false; + private static boolean databaseCleaned = false; - public synchronized void init() { + public synchronized static void init() { if (database != null) { return; } @@ -262,35 +254,28 @@ public class cgData { } } - public void closeDb() { + public static void closeDb() { if (database == null) { return; } cacheCache.removeAllFromCache(); - clearPreparedStatements(); + PreparedStatements.clearPreparedStatements(); database.close(); database = null; } - private void clearPreparedStatements() { - for (SQLiteStatement statement : statements.values()) { - statement.close(); - } - statements.clear(); - } - - private static File backupFile() { + private static File getBackupFile() { return new File(LocalStorage.getStorage(), "cgeo.sqlite"); } - public String backupDatabase() { + public static String backupDatabase() { if (!LocalStorage.isExternalStorageAvailable()) { Log.w("Database wasn't backed up: no external memory"); return null; } - final File target = backupFile(); + final File target = getBackupFile(); closeDb(); final boolean backupDone = LocalStorage.copy(databasePath(), target); init(); @@ -304,7 +289,7 @@ public class cgData { return target.getPath(); } - public boolean moveDatabase() { + public static boolean moveDatabase() { if (!LocalStorage.isExternalStorageAvailable()) { Log.w("Database was not moved: external memory not available"); return false; @@ -340,18 +325,18 @@ public class cgData { return databasePath(Settings.isDbOnSDCard()); } - public static File isRestoreFile() { - final File fileSourceFile = backupFile(); + public static File getRestoreFile() { + final File fileSourceFile = getBackupFile(); return fileSourceFile.exists() ? fileSourceFile : null; } - public boolean restoreDatabase() { + public static boolean restoreDatabase() { if (!LocalStorage.isExternalStorageAvailable()) { Log.w("Database wasn't restored: no external memory"); return false; } - final File sourceFile = backupFile(); + final File sourceFile = getBackupFile(); closeDb(); final boolean restoreDone = LocalStorage.copy(sourceFile, databasePath()); init(); @@ -473,7 +458,7 @@ public class cgData { try { db.execSQL(dbCreateLogImages); } catch (Exception e) { - Log.e("Failed to upgrade to ver. 54: " + e.toString()); + Log.e("Failed to upgrade to ver. 54", e); } } @@ -482,7 +467,7 @@ public class cgData { try { db.execSQL("alter table " + dbTableCaches + " add column personal_note text"); } catch (Exception e) { - Log.e("Failed to upgrade to ver. 55: " + e.toString()); + Log.e("Failed to upgrade to ver. 55", e); } } @@ -494,7 +479,7 @@ public class cgData { "lower(attribute) where attribute like \"%_yes\" " + "or attribute like \"%_no\""); } catch (Exception e) { - Log.e("Failed to upgrade to ver. 56: " + e.toString()); + Log.e("Failed to upgrade to ver. 56", e); } } @@ -509,7 +494,7 @@ public class cgData { db.execSQL("drop index in_f"); createIndices(db); } catch (Exception e) { - Log.e("Failed to upgrade to ver. 57: " + e.toString()); + Log.e("Failed to upgrade to ver. 57", e); } } @@ -627,7 +612,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("Failed to upgrade to ver. 61: " + e.toString()); + Log.e("Failed to upgrade to ver. 61", e); } } @@ -638,7 +623,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("Failed to upgrade to ver. 62: " + e.toString()); + Log.e("Failed to upgrade to ver. 62", e); } } @@ -646,7 +631,7 @@ public class cgData { try { removeDoubleUnderscoreMapFiles(); } catch (Exception e) { - Log.e("Failed to upgrade to ver. 63: " + e.toString()); + Log.e("Failed to upgrade to ver. 63", e); } } @@ -661,6 +646,15 @@ public class cgData { Log.e("Failed to upgrade to ver. 64", e); } } + + if (oldVersion < 65) { + try { + // Set all waypoints where name is Original coordinates to type ORIGINAL + db.execSQL("update " + dbTableWaypoints + " set type='original', own=0 where name='Original Coordinates'"); + } catch (Exception e) { + Log.e("Failed to upgrade to ver. 65:", e); + } + } } db.setTransactionSuccessful(); @@ -680,13 +674,15 @@ public class cgData { final FilenameFilter filter = new FilenameFilter() { @Override public boolean accept(File dir, String filename) { - return (filename.startsWith("map_") && filename.contains("__")); + return filename.startsWith("map_") && filename.contains("__"); } }; - for (File dir : geocodeDirs) { - File[] wrongFiles = dir.listFiles(filter); - for (File wrongFile : wrongFiles) { - wrongFile.delete(); + for (final File dir : geocodeDirs) { + final File[] wrongFiles = dir.listFiles(filter); + if (wrongFiles != null) { + for (final File wrongFile : wrongFiles) { + wrongFile.delete(); + } } } } @@ -751,7 +747,7 @@ public class cgData { db.execSQL("drop table if exists " + dbTableTrackables); } - public String[] allDetailedThere() { + public static String[] getRecentGeocodesForSearch() { init(); Cursor cursor = null; @@ -770,11 +766,10 @@ public class cgData { "100"); if (cursor != null) { - int index; if (cursor.getCount() > 0) { cursor.moveToFirst(); - index = cursor.getColumnIndex("geocode"); + int index = cursor.getColumnIndex("geocode"); do { list.add(cursor.getString(index)); @@ -785,7 +780,7 @@ public class cgData { } } } catch (Exception e) { - Log.e("cgData.allDetailedThere: " + e.toString()); + Log.e("cgData.allDetailedThere", e); } if (cursor != null) { @@ -795,7 +790,7 @@ public class cgData { return list.toArray(new String[list.size()]); } - public boolean isThere(String geocode, String guid, boolean detailed, boolean checkTime) { + public static boolean isThere(String geocode, String guid, boolean detailed, boolean checkTime) { init(); Cursor cursor = null; @@ -831,13 +826,12 @@ public class cgData { } if (cursor != null) { - int index; cnt = cursor.getCount(); if (cnt > 0) { cursor.moveToFirst(); - index = cursor.getColumnIndex("updated"); + int index = cursor.getColumnIndex("updated"); dataUpdated = cursor.getLong(index); index = cursor.getColumnIndex("detailedupdate"); dataDetailedUpdate = cursor.getLong(index); @@ -846,7 +840,7 @@ public class cgData { } } } catch (Exception e) { - Log.e("cgData.isThere: " + e.toString()); + Log.e("cgData.isThere", e); } if (cursor != null) { @@ -878,7 +872,7 @@ public class cgData { } /** is cache stored in one of the lists (not only temporary) */ - public boolean isOffline(String geocode, String guid) { + public static boolean isOffline(String geocode, String guid) { if (StringUtils.isBlank(geocode) && StringUtils.isBlank(guid)) { return false; } @@ -888,11 +882,11 @@ public class cgData { final SQLiteStatement listId; final String value; if (StringUtils.isNotBlank(geocode)) { - listId = getStatementListIdFromGeocode(); + listId = PreparedStatements.getListIdOfGeocode(); value = geocode; } else { - listId = getStatementListIdFromGuid(); + listId = PreparedStatements.getListIdOfGuid(); value = guid; } synchronized (listId) { @@ -908,14 +902,14 @@ public class cgData { return false; } - public String getGeocodeForGuid(String guid) { + public static String getGeocodeForGuid(String guid) { if (StringUtils.isBlank(guid)) { return null; } init(); try { - final SQLiteStatement description = getStatementGeocode(); + final SQLiteStatement description = PreparedStatements.getGeocodeOfGuid(); synchronized (description) { description.bindString(1, guid); return description.simpleQueryForString(); @@ -929,14 +923,14 @@ public class cgData { return null; } - public String getCacheidForGeocode(String geocode) { + public static String getCacheidForGeocode(String geocode) { if (StringUtils.isBlank(geocode)) { return null; } init(); try { - final SQLiteStatement description = getStatementCacheId(); + final SQLiteStatement description = PreparedStatements.getCacheIdOfGeocode(); synchronized (description) { description.bindString(1, geocode); return description.simpleQueryForString(); @@ -959,7 +953,7 @@ public class cgData { * * @return true = cache saved successfully to the CacheCache/DB */ - public boolean saveCache(cgCache cache, EnumSet<LoadFlags.SaveFlag> saveFlags) { + public static boolean saveCache(cgCache cache, EnumSet<LoadFlags.SaveFlag> saveFlags) { if (cache == null) { throw new IllegalArgumentException("cache must not be null"); } @@ -1039,12 +1033,12 @@ public class cgData { values.put("coordsChanged", cache.hasUserModifiedCoords() ? 1 : 0); values.put("finalDefined", cache.hasFinalDefined() ? 1 : 0); - boolean result = false; init(); //try to update record else insert fresh.. database.beginTransaction(); + boolean result = false; try { saveAttributesWithoutTransaction(cache); saveOriginalWaypointsWithoutTransaction(cache); @@ -1062,7 +1056,7 @@ public class cgData { database.setTransactionSuccessful(); result = true; } catch (Exception e) { - // nothing + Log.e("SaveCache", e); } finally { database.endTransaction(); } @@ -1070,25 +1064,21 @@ public class cgData { return result; } - private void saveAttributesWithoutTransaction(final cgCache cache) { + private static void saveAttributesWithoutTransaction(final cgCache cache) { String geocode = cache.getGeocode(); database.delete(dbTableAttributes, "geocode = ?", new String[]{geocode}); - if (cache.getAttributes().isNotEmpty()) { - - InsertHelper helper = new InsertHelper(database, dbTableAttributes); - long timeStamp = System.currentTimeMillis(); - - for (String attribute : cache.getAttributes()) { - helper.prepareForInsert(); - - helper.bind(ATTRIBUTES_GEOCODE, geocode); - helper.bind(ATTRIBUTES_UPDATED, timeStamp); - helper.bind(ATTRIBUTES_ATTRIBUTE, attribute); + if (cache.getAttributes().isEmpty()) { + return; + } + SQLiteStatement statement = PreparedStatements.getInsertAttribute(); + final long timestamp = System.currentTimeMillis(); + for (String attribute : cache.getAttributes()) { + statement.bindString(1, geocode); + statement.bindLong(2, timestamp); + statement.bindString(3, attribute); - helper.execute(); - } - helper.close(); + statement.executeInsert(); } } @@ -1098,16 +1088,14 @@ public class cgData { * @param destination * a destination to save */ - public void saveSearchedDestination(final Destination destination) { + public static void saveSearchedDestination(final Destination destination) { init(); database.beginTransaction(); try { - ContentValues values = new ContentValues(); - values.put("date", destination.getDate()); - putCoords(values, destination.getCoords()); - database.insert(dbTableSearchDestionationHistory, null, values); + SQLiteStatement insertDestination = PreparedStatements.getInsertSearchDestination(destination); + insertDestination.executeInsert(); database.setTransactionSuccessful(); } catch (Exception e) { Log.e("Updating searchedDestinations db failed", e); @@ -1116,11 +1104,11 @@ public class cgData { } } - public boolean saveWaypoints(final cgCache cache) { - boolean result = false; + public static boolean saveWaypoints(final cgCache cache) { init(); database.beginTransaction(); + boolean result = false; try { saveOriginalWaypointsWithoutTransaction(cache); database.setTransactionSuccessful(); @@ -1133,7 +1121,7 @@ public class cgData { return result; } - private void saveOriginalWaypointsWithoutTransaction(final cgCache cache) { + private static void saveOriginalWaypointsWithoutTransaction(final cgCache cache) { String geocode = cache.getGeocode(); database.delete(dbTableWaypoints, "geocode = ? and type <> ? and own = 0", new String[]{geocode, "own"}); @@ -1196,15 +1184,15 @@ public class cgData { return new Geopoint(cursor.getDouble(indexLat), cursor.getDouble(indexLon)); } - public boolean saveWaypoint(int id, String geocode, cgWaypoint waypoint) { + private static boolean saveWaypointInternal(int id, String geocode, cgWaypoint waypoint) { if ((StringUtils.isBlank(geocode) && id <= 0) || waypoint == null) { return false; } init(); - boolean ok = false; database.beginTransaction(); + boolean ok = false; try { ContentValues values = new ContentValues(); values.put("geocode", geocode); @@ -1234,7 +1222,7 @@ public class cgData { return ok; } - public boolean deleteWaypoint(int id) { + public static boolean deleteWaypoint(int id) { if (id == 0) { return false; } @@ -1244,28 +1232,32 @@ public class cgData { return database.delete(dbTableWaypoints, "_id = " + id, null) > 0; } - private void saveSpoilersWithoutTransaction(final cgCache cache) { + private static void saveSpoilersWithoutTransaction(final cgCache cache) { String geocode = cache.getGeocode(); database.delete(dbTableSpoilers, "geocode = ?", new String[]{geocode}); List<cgImage> spoilers = cache.getSpoilers(); if (CollectionUtils.isNotEmpty(spoilers)) { - ContentValues values = new ContentValues(); - long timeStamp = System.currentTimeMillis(); + SQLiteStatement insertSpoiler = PreparedStatements.getInsertSpoiler(); + final 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()); - - database.insert(dbTableSpoilers, null, values); + insertSpoiler.bindString(1, geocode); + insertSpoiler.bindLong(2, timestamp); + insertSpoiler.bindString(3, spoiler.getUrl()); + insertSpoiler.bindString(4, spoiler.getTitle()); + final String description = spoiler.getDescription(); + if (description != null) { + insertSpoiler.bindString(5, description); + } + else { + insertSpoiler.bindNull(5); + } + insertSpoiler.executeInsert(); } } } - private void saveLogsWithoutTransaction(final String geocode, final Iterable<LogEntry> logs) { + private static void saveLogsWithoutTransaction(final String geocode, final Iterable<LogEntry> logs) { // TODO delete logimages referring these logs database.delete(dbTableLogs, "geocode = ?", new String[]{geocode}); @@ -1273,59 +1265,51 @@ public class cgData { return; } - InsertHelper helper = new InsertHelper(database, dbTableLogs); - long timeStamp = System.currentTimeMillis(); + SQLiteStatement insertLog = PreparedStatements.getInsertLog(); + final 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(); - + insertLog.bindString(1, geocode); + insertLog.bindLong(2, timestamp); + insertLog.bindLong(3, log.type.id); + insertLog.bindString(4, log.author); + insertLog.bindString(5, log.log); + insertLog.bindLong(6, log.date); + insertLog.bindLong(7, log.found); + insertLog.bindLong(8, log.friend ? 1 : 0); + long logId = insertLog.executeInsert(); if (log.hasLogImages()) { - ContentValues values = new ContentValues(); + SQLiteStatement insertImage = PreparedStatements.getInsertLogImage(); for (cgImage img : log.getLogImages()) { - values.clear(); - values.put("log_id", log_id); - values.put("title", img.getTitle()); - values.put("url", img.getUrl()); - database.insert(dbTableLogImages, null, values); + insertImage.bindLong(1, logId); + insertImage.bindString(2, img.getTitle()); + insertImage.bindString(3, img.getUrl()); + insertImage.executeInsert(); } } } - helper.close(); } - private void saveLogCountsWithoutTransaction(final cgCache cache) { + private static void saveLogCountsWithoutTransaction(final cgCache cache) { String geocode = cache.getGeocode(); database.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(); - long timeStamp = System.currentTimeMillis(); + SQLiteStatement insertLogCounts = PreparedStatements.getInsertLogCounts(); + final long timestamp = System.currentTimeMillis(); for (Entry<LogType, Integer> pair : logCountsItems) { - values.clear(); - values.put("geocode", geocode); - values.put("updated", timeStamp); - values.put("type", pair.getKey().id); - values.put("count", pair.getValue()); + insertLogCounts.bindString(1, geocode); + insertLogCounts.bindLong(2, timestamp); + insertLogCounts.bindLong(3, pair.getKey().id); + insertLogCounts.bindLong(4, pair.getValue()); - database.insert(dbTableLogCount, null, values); + insertLogCounts.executeInsert(); } } } - public boolean saveTrackable(final cgTrackable trackable) { + public static boolean saveTrackable(final cgTrackable trackable) { init(); database.beginTransaction(); @@ -1339,7 +1323,7 @@ public class cgData { return true; } - private void saveInventoryWithoutTransaction(final String geocode, final List<cgTrackable> trackables) { + private static void saveInventoryWithoutTransaction(final String geocode, final List<cgTrackable> trackables) { if (geocode != null) { database.delete(dbTableTrackables, "geocode = ?", new String[]{geocode}); } @@ -1376,7 +1360,7 @@ public class cgData { } } - public Viewport getBounds(final Set<String> geocodes) { + public static Viewport getBounds(final Set<String> geocodes) { if (CollectionUtils.isEmpty(geocodes)) { return null; } @@ -1392,7 +1376,7 @@ public class cgData { * The Geocode GCXXXX * @return the loaded cache (if found). Can be null */ - public cgCache loadCache(final String geocode, final EnumSet<LoadFlag> loadFlags) { + public static cgCache loadCache(final String geocode, final EnumSet<LoadFlag> loadFlags) { if (StringUtils.isBlank(geocode)) { throw new IllegalArgumentException("geocode must not be empty"); } @@ -1407,7 +1391,7 @@ public class cgData { * @param geocodes * @return Set of loaded caches. Never null. */ - public Set<cgCache> loadCaches(final Set<String> geocodes, final EnumSet<LoadFlag> loadFlags) { + public static Set<cgCache> loadCaches(final Set<String> geocodes, final EnumSet<LoadFlag> loadFlags) { if (CollectionUtils.isEmpty(geocodes)) { return new HashSet<cgCache>(); } @@ -1451,7 +1435,7 @@ public class cgData { } if (remaining.size() >= 1) { - Log.e("cgData.loadCaches(" + remaining.toString() + ") failed"); + Log.i("cgData.loadCaches(" + remaining.toString() + ") failed"); } return result; } @@ -1463,7 +1447,7 @@ public class cgData { * @param loadFlags * @return Set of loaded caches. Never null. */ - private Set<cgCache> loadCachesFromGeocodes(final Set<String> geocodes, final EnumSet<LoadFlag> loadFlags) { + private static Set<cgCache> loadCachesFromGeocodes(final Set<String> geocodes, final EnumSet<LoadFlag> loadFlags) { if (CollectionUtils.isEmpty(geocodes)) { return Collections.emptySet(); } @@ -1498,7 +1482,6 @@ public class cgData { final Set<cgCache> caches = new HashSet<cgCache>(); int logIndex = -1; do { - //Extracted Method = LOADDBMINIMAL cgCache cache = cgData.createCacheFromDatabaseContent(cursor); if (loadFlags.contains(LoadFlag.LOAD_ATTRIBUTES)) { @@ -1575,7 +1558,6 @@ public class cgData { * @return Cache from DB */ private static cgCache createCacheFromDatabaseContent(Cursor cursor) { - int index; cgCache cache = new cgCache(); if (cacheColumnIndex == null) { @@ -1644,7 +1626,7 @@ public class cgData { cache.setHint(cursor.getString(cacheColumnIndex[14])); cache.setSize(CacheSize.getById(cursor.getString(cacheColumnIndex[15]))); cache.setDifficulty(cursor.getFloat(cacheColumnIndex[16])); - index = cacheColumnIndex[17]; + int index = cacheColumnIndex[17]; if (cursor.isNull(index)) { cache.setDirection(null); } else { @@ -1689,7 +1671,7 @@ public class cgData { return cache; } - public List<String> loadAttributes(String geocode) { + public static List<String> loadAttributes(String geocode) { if (StringUtils.isBlank(geocode)) { return null; } @@ -1724,15 +1706,13 @@ public class cgData { return attributes; } - public cgWaypoint loadWaypoint(int id) { + public static cgWaypoint loadWaypoint(int id) { if (id == 0) { return null; } init(); - cgWaypoint waypoint = null; - Cursor cursor = database.query( dbTableWaypoints, WAYPOINT_COLUMNS, @@ -1745,6 +1725,7 @@ public class cgData { Log.d("cgData.loadWaypoint(" + id + ")"); + cgWaypoint waypoint = null; if (cursor != null && cursor.getCount() > 0) { cursor.moveToFirst(); @@ -1758,7 +1739,7 @@ public class cgData { return waypoint; } - public List<cgWaypoint> loadWaypoints(final String geocode) { + public static List<cgWaypoint> loadWaypoints(final String geocode) { if (StringUtils.isBlank(geocode)) { return null; } @@ -1812,7 +1793,7 @@ public class cgData { return waypoint; } - private List<cgImage> loadSpoilers(String geocode) { + private static List<cgImage> loadSpoilers(String geocode) { if (StringUtils.isBlank(geocode)) { return null; } @@ -1857,7 +1838,7 @@ public class cgData { * * @return A list of previously entered destinations or an empty list. */ - public List<Destination> loadHistoryOfSearchedLocations() { + public static List<Destination> loadHistoryOfSearchedLocations() { init(); Cursor cursor = database.query(dbTableSearchDestionationHistory, @@ -1896,11 +1877,11 @@ public class cgData { return destinations; } - public boolean clearSearchedDestinations() { - boolean success = true; + public static boolean clearSearchedDestinations() { init(); database.beginTransaction(); + boolean success = true; try { database.delete(dbTableSearchDestionationHistory, null, null); database.setTransactionSuccessful(); @@ -1914,7 +1895,7 @@ public class cgData { return success; } - public List<LogEntry> loadLogs(String geocode) { + public static List<LogEntry> loadLogs(String geocode) { List<LogEntry> logs = new ArrayList<LogEntry>(); if (StringUtils.isBlank(geocode)) { @@ -1967,7 +1948,7 @@ public class cgData { return logs; } - public Map<LogType, Integer> loadLogCounts(String geocode) { + public static Map<LogType, Integer> loadLogCounts(String geocode) { if (StringUtils.isBlank(geocode)) { return null; } @@ -2006,7 +1987,7 @@ public class cgData { return logCounts; } - private List<cgTrackable> loadInventory(String geocode) { + private static List<cgTrackable> loadInventory(String geocode) { if (StringUtils.isBlank(geocode)) { return null; } @@ -2042,7 +2023,7 @@ public class cgData { return trackables; } - public cgTrackable loadTrackable(String geocode) { + public static cgTrackable loadTrackable(String geocode) { if (StringUtils.isBlank(geocode)) { return null; } @@ -2073,7 +2054,7 @@ public class cgData { return trackable; } - private cgTrackable createTrackableFromDatabaseContent(Cursor cursor) { + private static cgTrackable createTrackableFromDatabaseContent(Cursor cursor) { cgTrackable trackable = new cgTrackable(); trackable.setGeocode(cursor.getString(cursor.getColumnIndex("tbcode"))); trackable.setGuid(cursor.getString(cursor.getColumnIndex("guid"))); @@ -2095,103 +2076,99 @@ public class cgData { } /** - * Number of caches stored. The number is shown on the starting activity of c:geo + * Number of caches stored for a given type and/or list * - * @param detailedOnly * @param cacheType * @param list * @return */ - public int getAllStoredCachesCount(final boolean detailedOnly, final CacheType cacheType, final int list) { + public static int getAllStoredCachesCount(final CacheType cacheType, final int list) { if (cacheType == null) { throw new IllegalArgumentException("cacheType must not be null"); } - init(); - - String listSql; - String listSqlW; - if (list == 0) { - listSql = " where reason >= 1"; - listSqlW = " and reason >= 1"; - } else if (list >= 1) { - listSql = " where reason = " + list; - listSqlW = " and reason = " + list; - } else { - return 0; + if (list <= 0) { + throw new IllegalArgumentException("list must be > 0"); } + init(); - int count = 0; try { - String sql; - if (!detailedOnly) { - if (cacheType == CacheType.ALL) { - sql = "select count(_id) from " + dbTableCaches + listSql; - } else { - sql = "select count(_id) from " + dbTableCaches + " where type = " + DatabaseUtils.sqlEscapeString(cacheType.id) + listSqlW; - } + StringBuilder sql = new StringBuilder("select count(_id) from " + dbTableCaches + " where detailed = 1"); + String typeKey; + int reasonIndex; + if (cacheType != CacheType.ALL) { + sql.append(" and type = ?"); + typeKey = cacheType.id; + reasonIndex = 2; + } + else { + typeKey = "all_types"; + reasonIndex = 1; + } + String listKey; + if (list == StoredList.ALL_LIST_ID) { + sql.append(" and reason > 0"); + listKey = "all_list"; } else { - if (cacheType == CacheType.ALL) { - sql = "select count(_id) from " + dbTableCaches + " where detailed = 1" + listSqlW; - } else { - sql = "select count(_id) from " + dbTableCaches + " where detailed = 1 and type = " + DatabaseUtils.sqlEscapeString(cacheType.id) + listSqlW; - } + sql.append(" and reason = ?"); + listKey = "list"; + } + + String key = "CountCaches_" + typeKey + "_" + listKey; + + SQLiteStatement compiledStmnt = PreparedStatements.getStatement(key, sql.toString()); + if (cacheType != CacheType.ALL) { + compiledStmnt.bindString(1, cacheType.id); + } + if (list != StoredList.ALL_LIST_ID) { + compiledStmnt.bindLong(reasonIndex, list); } - SQLiteStatement compiledStmnt = database.compileStatement(sql); - count = (int) compiledStmnt.simpleQueryForLong(); - compiledStmnt.close(); + return (int) compiledStmnt.simpleQueryForLong(); } catch (Exception e) { - Log.e("cgData.loadAllStoredCachesCount: " + e.toString()); + Log.e("cgData.loadAllStoredCachesCount", e); } - return count; + return 0; } - public int getAllHistoricCachesCount() { + public static int getAllHistoryCachesCount() { init(); - int count = 0; - try { - SQLiteStatement sqlCount = database.compileStatement("select count(_id) from " + dbTableCaches + " where visiteddate > 0"); - count = (int) sqlCount.simpleQueryForLong(); - sqlCount.close(); + return (int) PreparedStatements.getCountHistoryCaches().simpleQueryForLong(); } catch (Exception e) { - Log.e("cgData.getAllHistoricCachesCount: " + e.toString()); + Log.e("cgData.getAllHistoricCachesCount", e); } - return count; + return 0; } /** * 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 + * @return a non-null set of geocodes */ - public Set<String> loadBatchOfStoredGeocodes(final boolean detailedOnly, final Geopoint coords, final CacheType cacheType, final int listId) { + private static Set<String> loadBatchOfStoredGeocodes(final Geopoint coords, final CacheType cacheType, final int listId) { if (cacheType == null) { throw new IllegalArgumentException("cacheType must not be null"); } init(); - Set<String> geocodes = new HashSet<String>(); - - StringBuilder specifySql = new StringBuilder(); + final Set<String> geocodes = new HashSet<String>(); - specifySql.append("reason "); - specifySql.append(listId != StoredList.ALL_LIST_ID ? "=" + Math.max(listId, 1) : ">= " + StoredList.STANDARD_LIST_ID); + final StringBuilder selection = new StringBuilder(); - if (detailedOnly) { - specifySql.append(" and detailed = 1 "); - } + selection.append("reason "); + selection.append(listId != StoredList.ALL_LIST_ID ? "=" + Math.max(listId, 1) : ">= " + StoredList.STANDARD_LIST_ID); + selection.append(" and detailed = 1 "); + String[] selectionArgs = null; if (cacheType != CacheType.ALL) { - specifySql.append(" and type = "); - specifySql.append(DatabaseUtils.sqlEscapeString(cacheType.id)); + selection.append(" and type = ?"); + selectionArgs = new String[] { String.valueOf(cacheType.id) }; } try { @@ -2201,8 +2178,8 @@ public class cgData { dbTableCaches, new String[]{"geocode", "(abs(latitude-" + String.format((Locale) null, "%.6f", coords.getLatitude()) + ") + abs(longitude-" + String.format((Locale) null, "%.6f", coords.getLongitude()) + ")) as dif"}, - specifySql.toString(), - null, + selection.toString(), + selectionArgs, null, null, "dif", @@ -2211,8 +2188,8 @@ public class cgData { cursor = database.query( dbTableCaches, new String[]{"geocode"}, - specifySql.toString(), - null, + selection.toString(), + selectionArgs, null, null, "geocode"); @@ -2229,68 +2206,56 @@ public class cgData { cursor.close(); } catch (Exception e) { - Log.e("cgData.loadBatchOfStoredGeocodes: " + e.toString()); + Log.e("cgData.loadBatchOfStoredGeocodes", e); } return geocodes; } - public Set<String> loadBatchOfHistoricGeocodes(final boolean detailedOnly, final CacheType cacheType) { + private static Set<String> loadBatchOfHistoricGeocodes(final boolean detailedOnly, final CacheType cacheType) { init(); - Set<String> geocodes = new HashSet<String>(); + final Set<String> geocodes = new HashSet<String>(); - StringBuilder specifySql = new StringBuilder(); - specifySql.append("visiteddate > 0"); + final StringBuilder selection = new StringBuilder("visiteddate > 0"); if (detailedOnly) { - specifySql.append(" and detailed = 1"); + selection.append(" and detailed = 1"); } + String[] selectionArgs = null; if (cacheType != CacheType.ALL) { - specifySql.append(" and type = "); - specifySql.append(DatabaseUtils.sqlEscapeString(cacheType.id)); + selection.append(" and type = ?"); + selectionArgs = new String[] { String.valueOf(cacheType.id) }; } try { - Cursor cursor = database.query( + final Cursor cursor = database.query( dbTableCaches, new String[]{"geocode"}, - specifySql.toString(), - null, + selection.toString(), + selectionArgs, null, null, "visiteddate", null); - - 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(); + while (cursor.moveToNext()) { + geocodes.add(cursor.getString(0)); } + cursor.close(); } catch (Exception e) { - Log.e("cgData.loadBatchOfHistoricGeocodes: " + e.toString()); + Log.e("cgData.loadBatchOfHistoricGeocodes", e); } return geocodes; } /** Retrieve all stored caches from DB */ - public Set<String> loadCachedInViewport(final Viewport viewport, final CacheType cacheType) { + public static SearchResult 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 Viewport viewport, final CacheType cacheType) { + public static SearchResult loadStoredInViewport(final Viewport viewport, final CacheType cacheType) { return loadInViewport(true, viewport, cacheType); } @@ -2306,7 +2271,7 @@ public class cgData { * @param cacheType * @return Set with geocodes */ - private Set<String> loadInViewport(final boolean stored, final Viewport viewport, final CacheType cacheType) { + private static SearchResult loadInViewport(final boolean stored, final Viewport viewport, final CacheType cacheType) { init(); final Set<String> geocodes = new HashSet<String>(); @@ -2317,25 +2282,26 @@ public class cgData { } // viewport limitation - final StringBuilder where = new StringBuilder(buildCoordinateWhere(dbTableCaches, viewport)); + final StringBuilder selection = new StringBuilder(buildCoordinateWhere(dbTableCaches, viewport)); // cacheType limitation + String[] selectionArgs = null; if (cacheType != CacheType.ALL) { - where.append(" and type = "); - where.append(DatabaseUtils.sqlEscapeString(cacheType.id)); + selection.append(" and type = ?"); + selectionArgs = new String[] { String.valueOf(cacheType.id) }; } // offline caches only if (stored) { - where.append(" and reason >= " + StoredList.STANDARD_LIST_ID); + selection.append(" and reason >= " + StoredList.STANDARD_LIST_ID); } try { final Cursor cursor = database.query( dbTableCaches, new String[]{"geocode"}, - where.toString(), - null, + selection.toString(), + selectionArgs, null, null, null, @@ -2350,14 +2316,14 @@ public class cgData { } cursor.close(); } catch (Exception e) { - Log.e("cgData.loadInViewport: " + e.toString()); + Log.e("cgData.loadInViewport", e); } - return geocodes; + return new SearchResult(geocodes); } /** delete caches from the DB store 3 days or more before */ - public void clean() { + public static void clean() { clean(false); } @@ -2367,15 +2333,19 @@ public class cgData { * @param more * true = all caches false = caches stored 3 days or more before */ - public void clean(boolean more) { + public static void clean(boolean more) { + if (databaseCleaned) { + return; + } + init(); Log.d("Database clean: started"); - Cursor cursor; Set<String> geocodes = new HashSet<String>(); try { + Cursor cursor; if (more) { cursor = database.query( dbTableCaches, @@ -2420,24 +2390,20 @@ public class cgData { removeCaches(geocodes, LoadFlags.REMOVE_ALL); } - final SQLiteStatement countSql = database.compileStatement("select count(_id) from " + dbTableCaches + " where reason = 0"); - final int count = (int) countSql.simpleQueryForLong(); - countSql.close(); - Log.d("Database clean: " + count + " geocaches remaining for listId=0"); - } catch (Exception e) { - Log.w("cgData.clean: " + e.toString()); + Log.w("cgData.clean", e); } Log.d("Database clean: finished"); + databaseCleaned = true; } - public void removeAllFromCache() { + public static void removeAllFromCache() { // clean up CacheCache cacheCache.removeAllFromCache(); } - public void removeCache(final String geocode, EnumSet<LoadFlags.RemoveFlag> removeFlags) { + public static void removeCache(final String geocode, EnumSet<LoadFlags.RemoveFlag> removeFlags) { removeCaches(Collections.singleton(geocode), removeFlags); } @@ -2447,7 +2413,7 @@ public class cgData { * @param geocodes * list of geocodes to drop from cache */ - public void removeCaches(final Set<String> geocodes, EnumSet<LoadFlags.RemoveFlag> removeFlags) { + public static void removeCaches(final Set<String> geocodes, EnumSet<LoadFlags.RemoveFlag> removeFlags) { if (CollectionUtils.isEmpty(geocodes)) { return; } @@ -2494,7 +2460,7 @@ public class cgData { } } - public boolean saveLogOffline(String geocode, Date date, LogType type, String log) { + public static boolean saveLogOffline(String geocode, Date date, LogType type, String log) { if (StringUtils.isBlank(geocode)) { Log.e("cgData.saveLogOffline: cannot log a blank geocode"); return false; @@ -2521,7 +2487,7 @@ public class cgData { return id != -1; } - public LogEntry loadLogOffline(String geocode) { + public static LogEntry loadLogOffline(String geocode) { if (StringUtils.isBlank(geocode)) { return null; } @@ -2557,7 +2523,7 @@ public class cgData { return log; } - public void clearLogOffline(String geocode) { + public static void clearLogOffline(String geocode) { if (StringUtils.isBlank(geocode)) { return; } @@ -2567,35 +2533,14 @@ public class cgData { database.delete(dbTableLogsOffline, "geocode = ?", new String[]{geocode}); } - private SQLiteStatement getStatementLogCount() { - return getStatement("LogCountFromGeocode", "SELECT count(_id) FROM " + dbTableLogsOffline + " WHERE geocode = ?"); - } - - private synchronized SQLiteStatement getStatement(final String key, final String query) { - SQLiteStatement statement = statements.get(key); - if (statement == null) { - statement = database.compileStatement(query); - statements.put(key, statement); - } - return statement; - } - - private SQLiteStatement getStatementCountStandardList() { - return getStatement("CountStandardList", "SELECT count(_id) FROM " + dbTableCaches + " WHERE reason = " + StoredList.STANDARD_LIST_ID); - } - - private SQLiteStatement getStatementCountAllLists() { - return getStatement("CountAllLists", "SELECT count(_id) FROM " + dbTableCaches + " WHERE reason >= " + StoredList.STANDARD_LIST_ID); - } - - public boolean hasLogOffline(final String geocode) { + public static boolean hasLogOffline(final String geocode) { if (StringUtils.isBlank(geocode)) { return false; } init(); try { - final SQLiteStatement logCount = getStatementLogCount(); + final SQLiteStatement logCount = PreparedStatements.getLogCountOfGeocode(); synchronized (logCount) { logCount.bindString(1, geocode); return logCount.simpleQueryForLong() > 0; @@ -2607,7 +2552,7 @@ public class cgData { return false; } - public void setVisitDate(List<String> geocodes, long visitedDate) { + private static void setVisitDate(List<String> geocodes, long visitedDate) { if (geocodes.isEmpty()) { return; } @@ -2616,11 +2561,12 @@ public class cgData { database.beginTransaction(); try { - ContentValues values = new ContentValues(); - values.put("visiteddate", visitedDate); + SQLiteStatement setVisit = PreparedStatements.getUpdateVisitDate(); for (String geocode : geocodes) { - database.update(dbTableCaches, values, "geocode = ?", new String[]{geocode}); + setVisit.bindLong(1, visitedDate); + setVisit.bindString(2, geocode); + setVisit.execute(); } database.setTransactionSuccessful(); } finally { @@ -2628,11 +2574,12 @@ public class cgData { } } - public List<StoredList> getLists(Resources res) { + public static List<StoredList> getLists() { init(); + Resources res = cgeoapplication.getInstance().getResources(); List<StoredList> lists = new ArrayList<StoredList>(); - lists.add(new StoredList(StoredList.STANDARD_LIST_ID, res.getString(R.string.list_inbox), (int) getStatementCountStandardList().simpleQueryForLong())); + lists.add(new StoredList(StoredList.STANDARD_LIST_ID, res.getString(R.string.list_inbox), (int) PreparedStatements.getCountCachesOnStandardList().simpleQueryForLong())); try { String query = "SELECT l._id as _id, l.title as title, COUNT(c._id) as count" + @@ -2646,7 +2593,7 @@ public class cgData { lists.addAll(storedLists); } catch (Exception e) { - Log.e("cgData.readLists: " + e.toString()); + Log.e("cgData.readLists", e); } return lists; } @@ -2674,14 +2621,14 @@ public class cgData { return result; } - public StoredList getList(int id, Resources res) { + public static StoredList getList(int id) { init(); if (id >= customListIdOffset) { Cursor cursor = database.query( dbTableLists, new String[]{"_id", "title"}, - "_id = " + (id - customListIdOffset), - null, + "_id = ? ", + new String[] { String.valueOf(id - customListIdOffset) }, null, null, null); @@ -2691,18 +2638,23 @@ public class cgData { } } + Resources res = cgeoapplication.getInstance().getResources(); if (id == StoredList.ALL_LIST_ID) { - return new StoredList(StoredList.ALL_LIST_ID, res.getString(R.string.list_all_lists), (int) getStatementCountAllLists().simpleQueryForLong()); + return new StoredList(StoredList.ALL_LIST_ID, res.getString(R.string.list_all_lists), getAllCachesCount()); } // fall back to standard list in case of invalid list id if (id == StoredList.STANDARD_LIST_ID || id >= customListIdOffset) { - return new StoredList(StoredList.STANDARD_LIST_ID, res.getString(R.string.list_inbox), (int) getStatementCountStandardList().simpleQueryForLong()); + return new StoredList(StoredList.STANDARD_LIST_ID, res.getString(R.string.list_inbox), (int) PreparedStatements.getCountCachesOnStandardList().simpleQueryForLong()); } return null; } + public static int getAllCachesCount() { + return (int) PreparedStatements.getCountAllCaches().simpleQueryForLong(); + } + /** * Create a new list * @@ -2710,7 +2662,7 @@ public class cgData { * Name * @return new listId */ - public int createList(String name) { + public static int createList(String name) { int id = -1; if (StringUtils.isBlank(name)) { return id; @@ -2740,15 +2692,15 @@ public class cgData { * New name of list * @return Number of lists changed */ - public int renameList(final int listId, final String name) { + public static int renameList(final int listId, final String name) { if (StringUtils.isBlank(name) || StoredList.STANDARD_LIST_ID == listId) { return 0; } init(); - int count = 0; database.beginTransaction(); + int count = 0; try { ContentValues values = new ContentValues(); values.put("title", name); @@ -2769,23 +2721,23 @@ public class cgData { * @param listId * @return true if the list got deleted, false else */ - public boolean removeList(int listId) { - boolean status = false; + public static boolean removeList(int listId) { if (listId < customListIdOffset) { - return status; + return false; } init(); database.beginTransaction(); + boolean status = false; try { int cnt = database.delete(dbTableLists, "_id = " + (listId - customListIdOffset), null); if (cnt > 0) { // move caches from deleted list to standard list - ContentValues values = new ContentValues(); - values.put("reason", StoredList.STANDARD_LIST_ID); - database.update(dbTableCaches, values, "reason = " + listId, null); + SQLiteStatement moveToStandard = PreparedStatements.getMoveToStandardList(); + moveToStandard.bindLong(1, listId); + moveToStandard.execute(); status = true; } @@ -2798,7 +2750,7 @@ public class cgData { return status; } - public void moveToList(final List<cgCache> caches, final int listId) { + public static void moveToList(final List<cgCache> caches, final int listId) { if (listId == StoredList.ALL_LIST_ID) { return; } @@ -2807,13 +2759,14 @@ public class cgData { } init(); - final ContentValues values = new ContentValues(); - values.put("reason", listId); + SQLiteStatement move = PreparedStatements.getMoveToList(); database.beginTransaction(); try { for (cgCache cache : caches) { - database.update(dbTableCaches, values, "geocode = ?", new String[]{cache.getGeocode()}); + move.bindLong(1, listId); + move.bindString(2, cache.getGeocode()); + move.execute(); cache.setListId(listId); } database.setTransactionSuccessful(); @@ -2822,61 +2775,39 @@ public class cgData { } } - public synchronized boolean status() { + public static boolean isInitialized() { return database != null; - } - public boolean removeSearchedDestination(Destination destination) { - boolean success = true; + public static boolean removeSearchedDestination(Destination destination) { if (destination == null) { - success = false; - } else { - init(); - - database.beginTransaction(); - try { - database.delete(dbTableSearchDestionationHistory, "_id = " + destination.getId(), null); - database.setTransactionSuccessful(); - } catch (Exception e) { - Log.e("Unable to remove searched destination", e); - success = false; - } finally { - database.endTransaction(); - } + return false; } + init(); - return success; - } - - private SQLiteStatement getStatementDescription() { - return getStatement("descriptionFromGeocode", "SELECT description FROM " + dbTableCaches + " WHERE geocode = ?"); - } - - private SQLiteStatement getStatementListIdFromGeocode() { - return getStatement("listFromGeocode", "SELECT reason FROM " + dbTableCaches + " WHERE geocode = ?"); - } - - private SQLiteStatement getStatementListIdFromGuid() { - return getStatement("listFromGeocode", "SELECT reason FROM " + dbTableCaches + " WHERE guid = ?"); - } - - private SQLiteStatement getStatementCacheId() { - return getStatement("cacheIdFromGeocode", "SELECT cacheid FROM " + dbTableCaches + " WHERE geocode = ?"); - } + database.beginTransaction(); + boolean result = false; + try { + database.delete(dbTableSearchDestionationHistory, "_id = " + destination.getId(), null); + database.setTransactionSuccessful(); + result = true; + } catch (Exception e) { + Log.e("Unable to remove searched destination", e); + } finally { + database.endTransaction(); + } - private SQLiteStatement getStatementGeocode() { - return getStatement("geocodeFromGuid", "SELECT geocode FROM " + dbTableCaches + " WHERE guid = ?"); + return result; } - public String getCacheDescription(String geocode) { + public static String getCacheDescription(String geocode) { if (StringUtils.isBlank(geocode)) { return null; } init(); try { - final SQLiteStatement description = getStatementDescription(); + final SQLiteStatement description = PreparedStatements.getDescriptionOfGeocode(); synchronized (description) { description.bindString(1, geocode); return description.simpleQueryForString(); @@ -2909,7 +2840,7 @@ public class cgData { private static String whereGeocodeIn(Set<String> geocodes) { final StringBuilder where = new StringBuilder(); - if (geocodes != null && geocodes.size() > 0) { + if (geocodes != null && !geocodes.isEmpty()) { StringBuilder all = new StringBuilder(); for (String geocode : geocodes) { if (all.length() > 0) { @@ -2933,7 +2864,7 @@ public class cgData { * @return */ - public Set<cgWaypoint> loadWaypoints(final Viewport viewport, boolean excludeMine, boolean excludeDisabled, CacheType type) { + public static Set<cgWaypoint> loadWaypoints(final Viewport viewport, boolean excludeMine, boolean excludeDisabled, CacheType type) { final StringBuilder where = new StringBuilder(buildCoordinateWhere(dbTableWaypoints, viewport)); if (excludeMine) { where.append(" and ").append(dbTableCaches).append(".own == 0 and ").append(dbTableCaches).append(".found == 0"); @@ -2942,7 +2873,7 @@ public class cgData { where.append(" and ").append(dbTableCaches).append(".disabled == 0"); } if (type != CacheType.ALL) { - where.append(" and ").append(dbTableCaches).append(".type == '").append(type.id).append("'"); + where.append(" and ").append(dbTableCaches).append(".type == '").append(type.id).append('\''); } init(); @@ -2968,7 +2899,7 @@ public class cgData { } } - public String[] getTrackableCodes() { + public static String[] getTrackableCodes() { init(); final Cursor cursor = database.query( @@ -2997,4 +2928,150 @@ public class cgData { return list.toArray(new String[list.size()]); } + public static boolean saveChangedCache(cgCache cache) { + return cgData.saveCache(cache, cache.getStorageLocation().contains(StorageLocation.DATABASE) ? LoadFlags.SAVE_ALL : EnumSet.of(SaveFlag.SAVE_CACHE)); + } + + private static class PreparedStatements { + + private static HashMap<String, SQLiteStatement> statements = new HashMap<String, SQLiteStatement>(); + + public static SQLiteStatement getMoveToStandardList() { + return getStatement("MoveToStandardList", "UPDATE " + dbTableCaches + " SET reason = " + StoredList.STANDARD_LIST_ID + " WHERE reason = ?"); + } + + public static SQLiteStatement getMoveToList() { + return getStatement("MoveToList", "UPDATE " + dbTableCaches + " SET reason = ? WHERE geocode = ?"); + } + + public static SQLiteStatement getUpdateVisitDate() { + return getStatement("UpdateVisitDate", "UPDATE " + dbTableCaches + " SET visiteddate = ? WHERE geocode = ?"); + } + + public static SQLiteStatement getInsertLogImage() { + return getStatement("InsertLogImage", "INSERT INTO " + dbTableLogImages + " (log_id, title, url) VALUES (?, ?, ?)"); + } + + public static SQLiteStatement getInsertLogCounts() { + return getStatement("InsertLogCounts", "INSERT INTO " + dbTableLogCount + " (geocode, updated, type, count) VALUES (?, ?, ?, ?)"); + } + + public static SQLiteStatement getInsertSpoiler() { + return getStatement("InsertSpoiler", "INSERT INTO " + dbTableSpoilers + " (geocode, updated, url, title, description) VALUES (?, ?, ?, ?, ?)"); + } + + public static SQLiteStatement getInsertSearchDestination(Destination destination) { + final SQLiteStatement statement = getStatement("InsertSearch", "INSERT INTO " + dbTableSearchDestionationHistory + " (date, latitude, longitude) VALUES (?, ?, ?)"); + statement.bindLong(1, destination.getDate()); + final Geopoint coords = destination.getCoords(); + statement.bindDouble(2, coords.getLatitude()); + statement.bindDouble(3, coords.getLongitude()); + return statement; + } + + private static void clearPreparedStatements() { + for (SQLiteStatement statement : statements.values()) { + statement.close(); + } + statements.clear(); + } + + private static synchronized SQLiteStatement getStatement(final String key, final String query) { + SQLiteStatement statement = statements.get(key); + if (statement == null) { + Log.d("Compiling " + key); + statement = database.compileStatement(query); + statements.put(key, statement); + } + return statement; + } + + public static SQLiteStatement getCountHistoryCaches() { + return getStatement("HistoryCount", "select count(_id) from " + dbTableCaches + " where visiteddate > 0"); + } + + private static SQLiteStatement getLogCountOfGeocode() { + return getStatement("LogCountFromGeocode", "SELECT count(_id) FROM " + cgData.dbTableLogsOffline + " WHERE geocode = ?"); + } + + private static SQLiteStatement getCountCachesOnStandardList() { + return getStatement("CountStandardList", "SELECT count(_id) FROM " + dbTableCaches + " WHERE reason = " + StoredList.STANDARD_LIST_ID); + } + + private static SQLiteStatement getCountAllCaches() { + return getStatement("CountAllLists", "SELECT count(_id) FROM " + dbTableCaches + " WHERE reason >= " + StoredList.STANDARD_LIST_ID); + } + + private static SQLiteStatement getInsertLog() { + return getStatement("InsertLog", "INSERT INTO " + dbTableLogs + " (geocode, updated, type, author, log, date, found, friend) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); + } + + private static SQLiteStatement getInsertAttribute() { + return getStatement("InsertAttribute", "INSERT INTO " + dbTableAttributes + " (geocode, updated, attribute) VALUES (?, ?, ?)"); + } + + private static SQLiteStatement getDescriptionOfGeocode() { + return getStatement("descriptionFromGeocode", "SELECT description FROM " + dbTableCaches + " WHERE geocode = ?"); + } + + private static SQLiteStatement getListIdOfGeocode() { + return getStatement("listFromGeocode", "SELECT reason FROM " + dbTableCaches + " WHERE geocode = ?"); + } + + private static SQLiteStatement getListIdOfGuid() { + return getStatement("listFromGeocode", "SELECT reason FROM " + dbTableCaches + " WHERE guid = ?"); + } + + private static SQLiteStatement getCacheIdOfGeocode() { + return getStatement("cacheIdFromGeocode", "SELECT cacheid FROM " + dbTableCaches + " WHERE geocode = ?"); + } + + private static SQLiteStatement getGeocodeOfGuid() { + return getStatement("geocodeFromGuid", "SELECT geocode FROM " + dbTableCaches + " WHERE guid = ?"); + } + + } + + public static void saveVisitDate(final String geocode) { + setVisitDate(Collections.singletonList(geocode), System.currentTimeMillis()); + } + + public static void markDropped(List<cgCache> caches) { + moveToList(caches, StoredList.TEMPORARY_LIST_ID); + } + + public static Viewport getBounds(String geocode) { + if (geocode == null) { + return null; + } + + return cgData.getBounds(Collections.singleton(geocode)); + } + + public static void clearVisitDate(List<cgCache> caches) { + ArrayList<String> geocodes = new ArrayList<String>(caches.size()); + for (cgCache cache : caches) { + geocodes.add(cache.getGeocode()); + } + setVisitDate(geocodes, 0); + } + + public static SearchResult getBatchOfStoredCaches(Geopoint coords, CacheType cacheType, int listId) { + final Set<String> geocodes = cgData.loadBatchOfStoredGeocodes(coords, cacheType, listId); + return new SearchResult(geocodes, cgData.getAllStoredCachesCount(cacheType, listId)); + } + + public static SearchResult getHistoryOfCaches(boolean detailedOnly, CacheType cacheType) { + final Set<String> geocodes = cgData.loadBatchOfHistoricGeocodes(detailedOnly, cacheType); + return new SearchResult(geocodes, cgData.getAllHistoryCachesCount()); + } + + public static boolean saveWaypoint(int id, String geocode, cgWaypoint waypoint) { + if (cgData.saveWaypointInternal(id, geocode, waypoint)) { + cgData.removeCache(geocode, EnumSet.of(RemoveFlag.REMOVE_CACHE)); + return true; + } + return false; + } + } diff --git a/main/src/cgeo/geocaching/cgTrackable.java b/main/src/cgeo/geocaching/cgTrackable.java index 7ed3424..b03a783 100644 --- a/main/src/cgeo/geocaching/cgTrackable.java +++ b/main/src/cgeo/geocaching/cgTrackable.java @@ -38,8 +38,8 @@ public class cgTrackable implements ILogable { private String trackingcode = null; public String getUrl() { - if (StringUtils.startsWithIgnoreCase(geocode, "GK")) { - String hex = geocode.substring(3); + if (StringUtils.startsWithIgnoreCase(getGeocode(), "GK")) { + String hex = getGeocode().substring(3); try { int id = Integer.parseInt(hex, 16); return "http://geokrety.org/konkret.php?id=" + id; @@ -48,7 +48,7 @@ public class cgTrackable implements ILogable { return null; } } - return "http://www.geocaching.com//track/details.aspx?tracker=" + geocode.toUpperCase(); + return "http://www.geocaching.com//track/details.aspx?tracker=" + geocode; } public String getGuid() { @@ -65,7 +65,7 @@ public class cgTrackable implements ILogable { } public void setGeocode(String geocode) { - this.geocode = geocode; + this.geocode = StringUtils.upperCase(geocode); } public String getIconUrl() { @@ -208,7 +208,7 @@ public class cgTrackable implements ILogable { } public boolean isLoggable() { - return !StringUtils.startsWithIgnoreCase(geocode, "GK"); + return !StringUtils.startsWithIgnoreCase(getGeocode(), "GK"); } public String getTrackingcode() { diff --git a/main/src/cgeo/geocaching/cgWaypoint.java b/main/src/cgeo/geocaching/cgWaypoint.java index 0e21c08..4b7b95e 100644 --- a/main/src/cgeo/geocaching/cgWaypoint.java +++ b/main/src/cgeo/geocaching/cgWaypoint.java @@ -86,7 +86,7 @@ public class cgWaypoint implements IWaypoint, Comparable<cgWaypoint> { for (cgWaypoint old : oldPoints) { if (old != null) { boolean merged = false; - if (old.name != null && old.name.length() > 0) { + if (StringUtils.isNotEmpty(old.name)) { for (cgWaypoint waypoint : newPoints) { if (waypoint != null && waypoint.name != null) { if (old.name.equalsIgnoreCase(waypoint.name)) { @@ -156,7 +156,7 @@ public class cgWaypoint implements IWaypoint, Comparable<cgWaypoint> { } public String getUrl() { - return "http://www.geocaching.com//seek/cache_details.aspx?wp=" + geocode.toUpperCase(); + return "http://www.geocaching.com//seek/cache_details.aspx?wp=" + geocode; } @Override @@ -174,7 +174,7 @@ public class cgWaypoint implements IWaypoint, Comparable<cgWaypoint> { } public void setGeocode(String geocode) { - this.geocode = geocode; + this.geocode = StringUtils.upperCase(geocode); } @Override diff --git a/main/src/cgeo/geocaching/cgeo.java b/main/src/cgeo/geocaching/cgeo.java index c80ec6f..c5a7e5b 100644 --- a/main/src/cgeo/geocaching/cgeo.java +++ b/main/src/cgeo/geocaching/cgeo.java @@ -415,7 +415,7 @@ public class cgeo extends AbstractActivity { // context menu for offline button if (v.getId() == R.id.search_offline) { menu.setHeaderTitle(res.getString(R.string.list_title)); - for (final StoredList list : app.getLists()) { + for (final StoredList list : cgData.getLists()) { menu.add(Menu.NONE, MENU_OPEN_LIST + list.id, Menu.NONE, list.getTitleAndCount()); } return; @@ -572,7 +572,7 @@ public class cgeo extends AbstractActivity { } private void checkRestore() { - if (!cgData.isNewlyCreatedDatebase() || null == cgData.isRestoreFile()) { + if (!cgData.isNewlyCreatedDatebase() || null == cgData.getRestoreFile()) { return; } new AlertDialog.Builder(this) @@ -759,7 +759,7 @@ public class cgeo extends AbstractActivity { } int checks = 0; - while (!app.storageStatus()) { + while (!cgData.isInitialized()) { try { wait(500); checks++; @@ -772,7 +772,7 @@ public class cgeo extends AbstractActivity { } } - countBubbleCnt = app.getAllStoredCachesCount(true, CacheType.ALL); + countBubbleCnt = cgData.getAllCachesCount(); countBubbleHandler.sendEmptyMessage(0); } @@ -797,7 +797,7 @@ public class cgeo extends AbstractActivity { } cleanupRunning = true; - app.cleanDatabase(more); + cgData.clean(more); cleanupRunning = false; if (version > 0) { diff --git a/main/src/cgeo/geocaching/cgeoapplication.java b/main/src/cgeo/geocaching/cgeoapplication.java index 9e221cd..1371a00 100644 --- a/main/src/cgeo/geocaching/cgeoapplication.java +++ b/main/src/cgeo/geocaching/cgeoapplication.java @@ -1,21 +1,10 @@ package cgeo.geocaching; -import cgeo.geocaching.cgData.StorageLocation; import cgeo.geocaching.activity.ActivityMixin; -import cgeo.geocaching.enumerations.CacheType; -import cgeo.geocaching.enumerations.LoadFlags; -import cgeo.geocaching.enumerations.LoadFlags.LoadFlag; -import cgeo.geocaching.enumerations.LoadFlags.RemoveFlag; -import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; -import cgeo.geocaching.enumerations.LogType; -import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.network.StatusUpdater; import cgeo.geocaching.utils.IObserver; import cgeo.geocaching.utils.Log; -import org.apache.commons.lang3.StringUtils; - import android.app.Activity; import android.app.Application; import android.app.ProgressDialog; @@ -23,27 +12,17 @@ import android.content.res.Resources; import android.os.Handler; import android.os.Message; -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.EnumSet; -import java.util.List; -import java.util.Map; -import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; public class cgeoapplication extends Application { - final private cgData storage = new cgData(); private volatile GeoDataProvider geo; private volatile DirectionProvider dir; public boolean firstRun = true; // c:geo is just launched public boolean showLoginToast = true; //login toast shown just once. - private boolean databaseCleaned = false; // database was cleaned private boolean liveMapHintShown = false; // livemap hint has been shown final private StatusUpdater statusUpdater = new StatusUpdater(); - private static cgeoapplication instance = null; + private static cgeoapplication instance; public cgeoapplication() { instance = this; @@ -61,29 +40,21 @@ public class cgeoapplication extends Application { @Override public void onLowMemory() { Log.i("Cleaning applications cache."); - removeAllFromCache(); - } - - public void removeAllFromCache() { - storage.removeAllFromCache(); + cgData.removeAllFromCache(); } @Override public void onTerminate() { Log.d("Terminating c:geo…"); - storage.clean(); - storage.closeDb(); + cgData.clean(); + cgData.closeDb(); super.onTerminate(); } - public String backupDatabase() { - return storage.backupDatabase(); - } - /** - * Move the database to/from external storage in a new thread, + * Move the database to/from external cgdata in a new thread, * showing a progress window * * @param fromActivity @@ -105,18 +76,13 @@ public class cgeoapplication extends Application { @Override public void run() { - atomic.set(storage.moveDatabase()); + atomic.set(cgData.moveDatabase()); handler.sendMessage(handler.obtainMessage()); } }; moveThread.start(); } - - public static File isRestoreFile() { - return cgData.isRestoreFile(); - } - /** * restore the database in a new thread, showing a progress window * @@ -140,7 +106,7 @@ public class cgeoapplication extends Application { @Override public void run() { - atomic.set(storage.restoreDatabase()); + atomic.set(cgData.restoreDatabase()); handler.sendMessage(handler.obtainMessage()); } }; @@ -203,280 +169,6 @@ public class cgeoapplication extends Application { return statusUpdater; } - public boolean storageStatus() { - return storage.status(); - } - - public void cleanDatabase(boolean more) { - if (databaseCleaned) { - return; - } - - storage.clean(more); - databaseCleaned = true; - } - - /** {@link cgData#isThere(String, String, boolean, boolean)} */ - public boolean isThere(String geocode, String guid, boolean detailed, boolean checkTime) { - return storage.isThere(geocode, guid, detailed, checkTime); - } - - /** {@link cgData#isOffline(String, String)} */ - public boolean isOffline(String geocode, String guid) { - return storage.isOffline(geocode, guid); - } - - /** {@link cgData#getGeocodeForGuid(String)} */ - public String getGeocode(String guid) { - return storage.getGeocodeForGuid(guid); - } - - /** {@link cgData#getCacheidForGeocode(String)} */ - public String getCacheid(String geocode) { - return storage.getCacheidForGeocode(geocode); - } - - public boolean hasUnsavedCaches(final SearchResult search) { - if (search == null) { - return false; - } - - for (final String geocode : search.getGeocodes()) { - if (!isOffline(geocode, null)) { - return true; - } - } - return false; - } - - public cgTrackable getTrackableByGeocode(String geocode) { - if (StringUtils.isBlank(geocode)) { - return null; - } - - return storage.loadTrackable(geocode); - } - - /** {@link cgData#allDetailedThere()} */ - public String[] geocodesInCache() { - return storage.allDetailedThere(); - } - - public Viewport getBounds(String geocode) { - if (geocode == null) { - return null; - } - - return getBounds(Collections.singleton(geocode)); - } - - /** {@link cgData#getBounds(Set)} */ - 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); - return new SearchResult(geocodes, getAllStoredCachesCount(true, cacheType, listId)); - } - - /** {@link cgData#loadHistoryOfSearchedLocations()} */ - public List<Destination> getHistoryOfSearchedLocations() { - return storage.loadHistoryOfSearchedLocations(); - } - - public SearchResult getHistoryOfCaches(final boolean detailedOnly, final CacheType cacheType) { - final Set<String> geocodes = storage.loadBatchOfHistoricGeocodes(detailedOnly, cacheType); - return new SearchResult(geocodes, getAllHistoricCachesCount()); - } - - /** {@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(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, 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); - } - - /** {@link cgData#getAllHistoricCachesCount()} */ - public int getAllHistoricCachesCount() { - return storage.getAllHistoricCachesCount(); - } - - /** {@link cgData#moveToList(List, int)} */ - public void markStored(List<cgCache> caches, int listId) { - storage.moveToList(caches, listId); - } - - /** {@link cgData#moveToList(List, int)} */ - public void markDropped(List<cgCache> caches) { - storage.moveToList(caches, StoredList.TEMPORARY_LIST_ID); - } - - /** {@link cgData#clearSearchedDestinations()} */ - public boolean clearSearchedDestinations() { - return storage.clearSearchedDestinations(); - } - - /** {@link cgData#saveSearchedDestination(Destination)} */ - public void saveSearchedDestination(Destination destination) { - storage.saveSearchedDestination(destination); - } - - /** {@link cgData#saveWaypoints(cgCache)} */ - public boolean saveWaypoints(final cgCache cache) { - return storage.saveWaypoints(cache); - } - - public boolean saveWaypoint(int id, String geocode, cgWaypoint waypoint) { - if (storage.saveWaypoint(id, geocode, waypoint)) { - this.removeCache(geocode, EnumSet.of(RemoveFlag.REMOVE_CACHE)); - return true; - } - return false; - } - - /** {@link cgData#deleteWaypoint(int)} */ - public boolean deleteWaypoint(int id) { - return storage.deleteWaypoint(id); - } - - public boolean saveTrackable(cgTrackable trackable) { - return storage.saveTrackable(trackable); - } - - /** {@link cgData#loadLogCounts(String)} */ - public Map<LogType, Integer> loadLogCounts(String geocode) { - return storage.loadLogCounts(geocode); - } - - /** {@link cgData#loadWaypoint(int)} */ - public cgWaypoint loadWaypoint(int id) { - return storage.loadWaypoint(id); - } - - /** {@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 LogEntry loadLogOffline(String geocode) { - return storage.loadLogOffline(geocode); - } - - /** {@link cgData#clearLogOffline(String)} */ - public void clearLogOffline(String geocode) { - storage.clearLogOffline(geocode); - } - - /** {@link cgData#setVisitDate(List, long)} */ - public void saveVisitDate(String geocode) { - storage.setVisitDate(Collections.singletonList(geocode), System.currentTimeMillis()); - } - - /** {@link cgData#setVisitDate(List, long)} */ - public void clearVisitDate(List<cgCache> caches) { - ArrayList<String> geocodes = new ArrayList<String>(caches.size()); - for (cgCache cache : caches) { - geocodes.add(cache.getGeocode()); - } - storage.setVisitDate(geocodes, 0); - } - - /** {@link cgData#getLists(Resources)} */ - public List<StoredList> getLists() { - return storage.getLists(getResources()); - } - - /** {@link cgData#getList(int, Resources)} */ - public StoredList getList(int id) { - return storage.getList(id, getResources()); - } - - /** {@link cgData#createList(String)} */ - public int createList(String title) { - return storage.createList(title); - } - - /** {@link cgData#renameList(int, String)} */ - public int renameList(final int listId, final String title) { - return storage.renameList(listId, title); - } - - /** {@link cgData#removeList(int)} */ - public boolean removeList(int id) { - return storage.removeList(id); - } - - /** {@link cgData#removeSearchedDestination(Destination)} */ - public boolean removeSearchedDestinations(Destination destination) { - return storage.removeSearchedDestination(destination); - } - - /** {@link cgData#moveToList(List, int)} */ - public void moveToList(List<cgCache> caches, int listId) { - storage.moveToList(caches, listId); - } - - /** {@link cgData#getCacheDescription(String)} */ - public String getCacheDescription(String geocode) { - return storage.getCacheDescription(geocode); - } - - /** {@link cgData#loadCaches} */ - public cgCache loadCache(final String geocode, final EnumSet<LoadFlag> loadFlags) { - return storage.loadCache(geocode, loadFlags); - } - - /** {@link cgData#loadCaches} */ - public Set<cgCache> loadCaches(final Set<String> geocodes, final EnumSet<LoadFlag> loadFlags) { - return storage.loadCaches(geocodes, loadFlags); - } - - /** - * Update a cache in the DB or in the CacheCace depending on it's storage location - * - * {@link cgData#saveCache} - */ - public boolean updateCache(cgCache cache) { - return saveCache(cache, cache.getStorageLocation().contains(StorageLocation.DATABASE) ? LoadFlags.SAVE_ALL : EnumSet.of(SaveFlag.SAVE_CACHE)); - } - - /** {@link cgData#saveCache} */ - public boolean saveCache(cgCache cache, EnumSet<LoadFlags.SaveFlag> saveFlags) { - return storage.saveCache(cache, saveFlags); - } - - /** {@link cgData#removeCache} */ - public void removeCache(String geocode, EnumSet<LoadFlags.RemoveFlag> removeFlags) { - storage.removeCache(geocode, removeFlags); - } - - /** {@link cgData#removeCaches} */ - public void removeCaches(final Set<String> geocodes, EnumSet<LoadFlags.RemoveFlag> removeFlags) { - storage.removeCaches(geocodes, removeFlags); - } - - public Set<cgWaypoint> getWaypointsInViewport(final Viewport viewport, boolean excludeMine, boolean excludeDisabled, CacheType type) { - return storage.loadWaypoints(viewport, excludeMine, excludeDisabled, type); - } - public boolean isLiveMapHintShown() { return liveMapHintShown; } @@ -485,20 +177,4 @@ public class cgeoapplication extends Application { liveMapHintShown = true; } - public String[] getTrackableCodes() { - return storage.getTrackableCodes(); - } - - public List<LogEntry> loadLogs(final String geocode) { - return storage.loadLogs(geocode); - } - - public List<String> loadAttributes(final String geocode) { - return storage.loadAttributes(geocode); - } - - public List<cgWaypoint> loadWaypoints(final String geocode) { - return storage.loadWaypoints(geocode); - } - } diff --git a/main/src/cgeo/geocaching/cgeocaches.java b/main/src/cgeo/geocaching/cgeocaches.java index 57fdb9c..ce43faa 100644 --- a/main/src/cgeo/geocaching/cgeocaches.java +++ b/main/src/cgeo/geocaching/cgeocaches.java @@ -3,6 +3,7 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.activity.AbstractListActivity; import cgeo.geocaching.activity.ActivityMixin; +import cgeo.geocaching.activity.FilteredActivity; import cgeo.geocaching.activity.Progress; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; import cgeo.geocaching.apps.cachelist.CacheListAppFactory; @@ -28,6 +29,7 @@ import cgeo.geocaching.sorting.EventDateComparator; import cgeo.geocaching.sorting.VisitComparator; import cgeo.geocaching.ui.CacheListAdapter; import cgeo.geocaching.ui.LoggingUI; +import cgeo.geocaching.ui.WeakReferenceHandler; import cgeo.geocaching.utils.GeoDirHandler; import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.RunnableWithArgument; @@ -64,7 +66,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -public class cgeocaches extends AbstractListActivity { +public class cgeocaches extends AbstractListActivity implements FilteredActivity { private static final String EXTRAS_USERNAME = "username"; private static final String EXTRAS_ADDRESS = "address"; @@ -156,57 +158,42 @@ public class cgeocaches extends AbstractListActivity { */ private MenuItem navigationMenu; - private Handler loadCachesHandler = new Handler() { - - @Override - public void handleMessage(Message msg) { - try { - setAdapter(); - - updateTitle(); - - setDateComparatorForEventList(); + public void handleCachesLoaded() { + try { + setAdapter(); - showFooterMoreCaches(); + updateTitle(); - if (search != null && search.getError() == StatusCode.UNAPPROVED_LICENSE) { - AlertDialog.Builder dialog = new AlertDialog.Builder(cgeocaches.this); - dialog.setTitle(res.getString(R.string.license)); - dialog.setMessage(res.getString(R.string.err_license)); - dialog.setCancelable(true); - dialog.setNegativeButton(res.getString(R.string.license_dismiss), new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int id) { - Cookies.clearCookies(); - dialog.cancel(); - } - }); - dialog.setPositiveButton(res.getString(R.string.license_show), new DialogInterface.OnClickListener() { + setDateComparatorForEventList(); - @Override - public void onClick(DialogInterface dialog, int id) { - Cookies.clearCookies(); - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/software/agreement.aspx?ID=0"))); - } - }); + showFooterMoreCaches(); - AlertDialog alert = dialog.create(); - alert.show(); - } else if (search != null && search.getError() != null) { - showToast(res.getString(R.string.err_download_fail) + ' ' + search.getError().getErrorString(res) + '.'); + if (search != null && search.getError() == StatusCode.UNAPPROVED_LICENSE) { + AlertDialog.Builder dialog = new AlertDialog.Builder(this); + dialog.setTitle(res.getString(R.string.license)); + dialog.setMessage(res.getString(R.string.err_license)); + dialog.setCancelable(true); + dialog.setNegativeButton(res.getString(R.string.license_dismiss), new DialogInterface.OnClickListener() { - hideLoading(); - showProgress(false); + @Override + public void onClick(DialogInterface dialog, int id) { + Cookies.clearCookies(); + dialog.cancel(); + } + }); + dialog.setPositiveButton(res.getString(R.string.license_show), new DialogInterface.OnClickListener() { - finish(); - return; - } + @Override + public void onClick(DialogInterface dialog, int id) { + Cookies.clearCookies(); + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/software/agreement.aspx?ID=0"))); + } + }); - setAdapterCurrentCoordinates(false); - } catch (Exception e) { - showToast(res.getString(R.string.err_detail_cache_find_any)); - Log.e("cgeocaches.loadCachesHandler: " + e.toString()); + AlertDialog alert = dialog.create(); + alert.show(); + } else if (search != null && search.getError() != null) { + showToast(res.getString(R.string.err_download_fail) + ' ' + search.getError().getErrorString(res) + '.'); hideLoading(); showProgress(false); @@ -215,18 +202,48 @@ public class cgeocaches extends AbstractListActivity { return; } - try { - hideLoading(); - showProgress(false); - } catch (Exception e2) { - Log.e("cgeocaches.loadCachesHandler.2: " + e2.toString()); - } + setAdapterCurrentCoordinates(false); + } catch (Exception e) { + showToast(res.getString(R.string.err_detail_cache_find_any)); + Log.e("cgeocaches.loadCachesHandler: " + e.toString()); - if (adapter != null) { - adapter.setSelectMode(false); + hideLoading(); + showProgress(false); + + finish(); + return; + } + + try { + hideLoading(); + showProgress(false); + } catch (Exception e2) { + Log.e("cgeocaches.loadCachesHandler.2: " + e2.toString()); + } + + if (adapter != null) { + adapter.setSelectMode(false); + } + } + + private Handler loadCachesHandler = new LoadCachesHandler(this); + + private static class LoadCachesHandler extends WeakReferenceHandler<cgeocaches> { + + protected LoadCachesHandler(cgeocaches activity) { + super(activity); + } + + @Override + public void handleMessage(Message msg) { + final cgeocaches activity = getActivity(); + if (activity == null) { + return; } + activity.handleCachesLoaded(); } - }; + } + private Handler loadNextPageHandler = new Handler() { @Override @@ -479,7 +496,7 @@ public class cgeocaches extends AbstractListActivity { listId = StoredList.STANDARD_LIST_ID; title = res.getString(R.string.stored_caches_button); } else { - final StoredList list = app.getList(listId); + final StoredList list = cgData.getList(listId); // list.id may be different if listId was not valid listId = list.id; title = list.title; @@ -642,7 +659,7 @@ public class cgeocaches extends AbstractListActivity { // refresh standard list if it has changed (new caches downloaded) if (type == CacheListType.OFFLINE && listId >= StoredList.STANDARD_LIST_ID && search != null) { - SearchResult newSearch = cgeoapplication.getInstance().getBatchOfStoredCaches(true, coords, Settings.getCacheType(), listId); + SearchResult newSearch = cgData.getBatchOfStoredCaches(coords, Settings.getCacheType(), listId); if (newSearch != null && newSearch.getTotal() != search.getTotal()) { refreshCurrentList(); } @@ -784,7 +801,7 @@ public class cgeocaches extends AbstractListActivity { item.setVisible(isNonDefaultList); } - final boolean multipleLists = app.getLists().size() >= 2; + final boolean multipleLists = cgData.getLists().size() >= 2; item = menu.findItem(MENU_SWITCH_LIST); if (item != null) { item.setVisible(multipleLists); @@ -864,20 +881,7 @@ public class cgeocaches extends AbstractListActivity { invalidateOptionsMenuCompatible(); return false; 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); - } - } - } - }); + showFilterMenu(null); return true; case MENU_SORT: new ComparatorUserInterface(this).selectComparator(adapter.getCacheComparator(), new RunnableWithArgument<CacheComparator>() { @@ -901,9 +905,30 @@ public class cgeocaches extends AbstractListActivity { moveCachesToOtherList(); invalidateOptionsMenuCompatible(); return true; + default: + return CacheListAppFactory.onMenuItemSelected(item, cacheList, this, search); } + } - return CacheListAppFactory.onMenuItemSelected(item, cacheList, this, search); + /** + * called from the filter bar view + */ + @Override + public void showFilterMenu(final View view) { + 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); + } + } + } + }); } private void setComparator(final CacheComparator comparator) { @@ -944,7 +969,7 @@ public class cgeocaches extends AbstractListActivity { } if (cache.isOffline()) { menu.add(0, MENU_DROP_CACHE, 0, res.getString(R.string.cache_offline_drop)); - final List<StoredList> cacheLists = app.getLists(); + final List<StoredList> cacheLists = cgData.getLists(); if (cacheLists.size() > 1) { menu.add(0, MENU_MOVE_TO_LIST, 0, res.getString(R.string.cache_menu_move_list)); } @@ -960,7 +985,7 @@ public class cgeocaches extends AbstractListActivity { @Override public void run(Integer newListId) { - app.moveToList(adapter.getCheckedOrAllCaches(), newListId); + cgData.moveToList(adapter.getCheckedOrAllCaches(), newListId); adapter.setSelectMode(false); refreshCurrentList(); @@ -1003,7 +1028,7 @@ public class cgeocaches extends AbstractListActivity { break; case MENU_CACHE_DETAILS: final Intent cachesIntent = new Intent(this, CacheDetailActivity.class); - cachesIntent.putExtra("geocode", cache.getGeocode().toUpperCase()); + cachesIntent.putExtra("geocode", cache.getGeocode()); cachesIntent.putExtra("name", cache.getName()); startActivity(cachesIntent); break; @@ -1021,7 +1046,7 @@ public class cgeocaches extends AbstractListActivity { @Override public void run(Integer newListId) { - app.moveToList(Collections.singletonList(cache), newListId); + cgData.moveToList(Collections.singletonList(cache), newListId); adapter.setSelectMode(false); refreshCurrentList(); } @@ -1283,7 +1308,7 @@ public class cgeocaches extends AbstractListActivity { @Override public void run() { - search = cgeoapplication.getInstance().getBatchOfStoredCaches(true, coords, Settings.getCacheType(), listId); + search = cgData.getBatchOfStoredCaches(coords, Settings.getCacheType(), listId); replaceCacheListFromSearch(); loadCachesHandler.sendMessage(Message.obtain()); } @@ -1292,7 +1317,7 @@ public class cgeocaches extends AbstractListActivity { private class LoadByHistoryThread extends Thread { @Override public void run() { - search = cgeoapplication.getInstance().getHistoryOfCaches(true, coords != null ? Settings.getCacheType() : CacheType.ALL); + search = cgData.getHistoryOfCaches(true, coords != null ? Settings.getCacheType() : CacheType.ALL); replaceCacheListFromSearch(); loadCachesHandler.sendMessage(Message.obtain()); } @@ -1501,13 +1526,13 @@ public class cgeocaches extends AbstractListActivity { @Override public void run() { - int ret = MSG_DONE; removeGeoAndDir(); int delay = -1; int times = 0; + int ret = MSG_DONE; while (!needToStop && times < 3 * 60 / 5) // maximum: 3 minutes, every 5 seconds { //download new code @@ -1581,7 +1606,7 @@ public class cgeocaches extends AbstractListActivity { @Override public void run() { removeGeoAndDir(); - app.markDropped(selected); + cgData.markDropped(selected); handler.sendEmptyMessage(MSG_DONE); startGeoAndDir(); @@ -1600,7 +1625,7 @@ public class cgeocaches extends AbstractListActivity { @Override public void run() { - app.clearVisitDate(selected); + cgData.clearVisitDate(selected); handler.sendEmptyMessage(MSG_DONE); } } @@ -1650,7 +1675,7 @@ public class cgeocaches extends AbstractListActivity { return; } - StoredList list = app.getList(id); + StoredList list = cgData.getList(id); if (list == null) { return; } @@ -1693,7 +1718,7 @@ public class cgeocaches extends AbstractListActivity { @Override public void run() { final List<cgCache> caches = adapter.getCheckedCaches(); - app.moveToList(caches, listId); + cgData.moveToList(caches, listId); handler.sendEmptyMessage(listId); } } @@ -1725,7 +1750,7 @@ public class cgeocaches extends AbstractListActivity { } private void removeListInternal() { - if (app.removeList(listId)) { + if (cgData.removeList(listId)) { showToast(res.getString(R.string.list_dialog_remove_ok)); switchListById(StoredList.STANDARD_LIST_ID); } else { diff --git a/main/src/cgeo/geocaching/cgeocoords.java b/main/src/cgeo/geocaching/cgeocoords.java index 1cf9630..0c2ffbf 100644 --- a/main/src/cgeo/geocaching/cgeocoords.java +++ b/main/src/cgeo/geocaching/cgeocoords.java @@ -378,6 +378,8 @@ public class cgeocoords extends Dialog { break; case Plain: // This case has been handled above + default: + throw new IllegalArgumentException(); } return true; diff --git a/main/src/cgeo/geocaching/cgeonavigate.java b/main/src/cgeo/geocaching/cgeonavigate.java index 64b7cd8..3c6bf73 100644 --- a/main/src/cgeo/geocaching/cgeonavigate.java +++ b/main/src/cgeo/geocaching/cgeonavigate.java @@ -61,8 +61,7 @@ public class cgeonavigate extends AbstractActivity { // get parameters Bundle extras = getIntent().getExtras(); if (extras != null) { - final String geocode = extras.getString(EXTRAS_GEOCODE); - title = geocode; + title = extras.getString(EXTRAS_GEOCODE); final String name = extras.getString(EXTRAS_NAME); dstCoords = (Geopoint) extras.getParcelable(EXTRAS_COORDS); info = extras.getString(EXTRAS_CACHE_INFO); @@ -293,7 +292,7 @@ public class cgeonavigate extends AbstractActivity { final Intent navigateIntent = new Intent(context, cgeonavigate.class); navigateIntent.putExtra(EXTRAS_COORDS, coords); - navigateIntent.putExtra(EXTRAS_GEOCODE, geocode.toUpperCase()); + navigateIntent.putExtra(EXTRAS_GEOCODE, geocode); 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 025b96a..e399a97 100644 --- a/main/src/cgeo/geocaching/cgeopoint.java +++ b/main/src/cgeo/geocaching/cgeopoint.java @@ -207,7 +207,7 @@ public class cgeopoint extends AbstractActivity { private List<Destination> getHistoryOfSearchedLocations() { if (historyOfSearchedLocations == null) { // Load from database - historyOfSearchedLocations = app.getHistoryOfSearchedLocations(); + historyOfSearchedLocations = cgData.loadHistoryOfSearchedLocations(); } return historyOfSearchedLocations; @@ -304,7 +304,7 @@ public class cgeopoint extends AbstractActivity { } } - private class changeDistanceUnit implements OnItemSelectedListener { + private static class changeDistanceUnit implements OnItemSelectedListener { private changeDistanceUnit(cgeopoint unitView) { this.unitView = unitView; @@ -393,7 +393,7 @@ public class cgeopoint extends AbstractActivity { getHistoryOfSearchedLocations().add(0, loc); // Save location - app.saveSearchedDestination(loc); + cgData.saveSearchedDestination(loc); // Ensure to remove the footer historyListView.removeFooterView(getEmptyHistoryFooter()); @@ -405,7 +405,7 @@ public class cgeopoint extends AbstractActivity { getHistoryOfSearchedLocations().remove(destination); // Save - app.removeSearchedDestinations(destination); + cgData.removeSearchedDestination(destination); if (getHistoryOfSearchedLocations().isEmpty()) { if (historyListView.getFooterViewsCount() == 0) { @@ -424,7 +424,7 @@ public class cgeopoint extends AbstractActivity { getHistoryOfSearchedLocations().clear(); // Save - app.clearSearchedDestinations(); + cgData.clearSearchedDestinations(); if (historyListView.getFooterViewsCount() == 0) { historyListView.addFooterView(getEmptyHistoryFooter()); @@ -487,8 +487,6 @@ public class cgeopoint extends AbstractActivity { } private Geopoint getDestination() { - Geopoint result; - Geopoint coords; String bearingText = ((EditText) findViewById(R.id.bearing)).getText().toString(); // combine distance from EditText and distanceUnit saved from Spinner @@ -502,6 +500,7 @@ public class cgeopoint extends AbstractActivity { return null; } + Geopoint coords; if (StringUtils.isNotBlank(latText) && StringUtils.isNotBlank(lonText)) { try { coords = new Geopoint(latText, lonText); @@ -518,6 +517,7 @@ public class cgeopoint extends AbstractActivity { coords = app.currentGeo().getCoords(); } + Geopoint result; if (StringUtils.isNotBlank(bearingText) && StringUtils.isNotBlank(distanceText)) { // bearing & distance double bearing; diff --git a/main/src/cgeo/geocaching/cgeotrackable.java b/main/src/cgeo/geocaching/cgeotrackable.java deleted file mode 100644 index 93b410a..0000000 --- a/main/src/cgeo/geocaching/cgeotrackable.java +++ /dev/null @@ -1,574 +0,0 @@ -package cgeo.geocaching; - -import cgeo.geocaching.activity.AbstractActivity; -import cgeo.geocaching.connector.gc.GCParser; -import cgeo.geocaching.enumerations.LogType; -import cgeo.geocaching.geopoint.Units; -import cgeo.geocaching.network.HtmlImage; -import cgeo.geocaching.ui.CacheDetailsCreator; -import cgeo.geocaching.ui.Formatter; -import cgeo.geocaching.utils.BaseUtils; -import cgeo.geocaching.utils.Log; -import cgeo.geocaching.utils.UnknownTagsHandler; - -import org.apache.commons.lang3.StringUtils; - -import android.app.ProgressDialog; -import android.content.Intent; -import android.graphics.drawable.BitmapDrawable; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.text.Html; -import android.text.method.LinkMovementMethod; -import android.view.ContextMenu; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Arrays; - -public class cgeotrackable extends AbstractActivity { - private static final int MENU_LOG_TOUCH = 1; - private static final int MENU_BROWSER_TRACKABLE = 2; - private cgTrackable trackable = null; - private String geocode = null; - private String name = null; - private String guid = null; - private String id = null; - private String contextMenuUser = null; - private LayoutInflater inflater = null; - private ProgressDialog waitDialog = null; - private Handler loadTrackableHandler = new Handler() { - - @Override - public void handleMessage(Message msg) { - if (trackable == null) { - if (waitDialog != null) { - waitDialog.dismiss(); - } - - if (StringUtils.isNotBlank(geocode)) { - showToast(res.getString(R.string.err_tb_find) + " " + geocode + "."); - } else { - showToast(res.getString(R.string.err_tb_find_that)); - } - - finish(); - return; - } - - try { - inflater = getLayoutInflater(); - geocode = trackable.getGeocode().toUpperCase(); - - if (StringUtils.isNotBlank(trackable.getName())) { - setTitle(Html.fromHtml(trackable.getName()).toString()); - } else { - setTitle(trackable.getName().toUpperCase()); - } - - findViewById(R.id.details_list_box).setVisibility(View.VISIBLE); - final CacheDetailsCreator details = new CacheDetailsCreator(cgeotrackable.this, (LinearLayout) findViewById(R.id.details_list)); - - // action bar icon - if (StringUtils.isNotBlank(trackable.getIconUrl())) { - final TrackableIconHandler iconHandler = new TrackableIconHandler(((TextView) findViewById(R.id.actionbar_title))); - final TrackableIconThread iconThread = new TrackableIconThread(trackable.getIconUrl(), iconHandler); - iconThread.start(); - } - - // trackable name - details.add(R.string.trackable_name, StringUtils.isNotBlank(trackable.getName()) ? Html.fromHtml(trackable.getName()).toString() : res.getString(R.string.trackable_unknown)); - - // trackable type - String tbType; - if (StringUtils.isNotBlank(trackable.getType())) { - tbType = Html.fromHtml(trackable.getType()).toString(); - } else { - tbType = res.getString(R.string.trackable_unknown); - } - details.add(R.string.trackable_type, tbType); - - // trackable geocode - details.add(R.string.trackable_code, trackable.getGeocode().toUpperCase()); - - // trackable owner - TextView owner = details.add(R.string.trackable_owner, res.getString(R.string.trackable_unknown)); - if (StringUtils.isNotBlank(trackable.getOwner())) { - owner.setText(Html.fromHtml(trackable.getOwner()), TextView.BufferType.SPANNABLE); - owner.setOnClickListener(new UserActionsListener()); - } - - // trackable spotted - if (StringUtils.isNotBlank(trackable.getSpottedName()) || - trackable.getSpottedType() == cgTrackable.SPOTTED_UNKNOWN || - trackable.getSpottedType() == cgTrackable.SPOTTED_OWNER - ) { - boolean showTimeSpan = true; - StringBuilder text; - - if (trackable.getSpottedType() == cgTrackable.SPOTTED_CACHE) { - text = new StringBuilder(res.getString(R.string.trackable_spotted_in_cache) + ' ' + Html.fromHtml(trackable.getSpottedName()).toString()); - } else if (trackable.getSpottedType() == cgTrackable.SPOTTED_USER) { - text = new StringBuilder(res.getString(R.string.trackable_spotted_at_user) + ' ' + Html.fromHtml(trackable.getSpottedName()).toString()); - } else if (trackable.getSpottedType() == cgTrackable.SPOTTED_UNKNOWN) { - text = new StringBuilder(res.getString(R.string.trackable_spotted_unknown_location)); - } else if (trackable.getSpottedType() == cgTrackable.SPOTTED_OWNER) { - text = new StringBuilder(res.getString(R.string.trackable_spotted_owner)); - } else { - text = new StringBuilder("N/A"); - showTimeSpan = false; - } - - // days since last spotting - if (showTimeSpan && trackable.getLogs() != null) { - for (LogEntry log : trackable.getLogs()) { - if (log.type == LogType.RETRIEVED_IT || log.type == LogType.GRABBED_IT || log.type == LogType.DISCOVERED_IT || log.type == LogType.PLACED_IT) { - final int days = log.daysSinceLog(); - text.append(" (").append(res.getQuantityString(R.plurals.days_ago, days, days)).append(')'); - break; - } - } - } - - final TextView spotted = details.add(R.string.trackable_spotted, text.toString()); - spotted.setClickable(true); - if (cgTrackable.SPOTTED_CACHE == trackable.getSpottedType()) { - spotted.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View arg0) { - CacheDetailActivity.startActivityGuid(cgeotrackable.this, trackable.getSpottedGuid(), trackable.getSpottedName()); - } - }); - } else if (cgTrackable.SPOTTED_USER == trackable.getSpottedType()) { - spotted.setOnClickListener(new UserActionsListener()); - } - } - - // trackable origin - if (StringUtils.isNotBlank(trackable.getOrigin())) { - TextView origin = details.add(R.string.trackable_origin, ""); - origin.setText(Html.fromHtml(trackable.getOrigin()), TextView.BufferType.SPANNABLE); - } - - // trackable released - if (trackable.getReleased() != null) { - details.add(R.string.trackable_released, Formatter.formatDate(trackable.getReleased().getTime())); - } - - // trackable distance - if (trackable.getDistance() >= 0) { - details.add(R.string.trackable_distance, Units.getDistanceFromKilometers(trackable.getDistance())); - } - - // trackable goal - if (StringUtils.isNotBlank(trackable.getGoal())) { - findViewById(R.id.goal_box).setVisibility(View.VISIBLE); - TextView descView = (TextView) findViewById(R.id.goal); - descView.setVisibility(View.VISIBLE); - descView.setText(Html.fromHtml(trackable.getGoal(), new HtmlImage(geocode, true, 0, false), null), TextView.BufferType.SPANNABLE); - descView.setMovementMethod(LinkMovementMethod.getInstance()); - } - - // trackable details - if (StringUtils.isNotBlank(trackable.getDetails())) { - findViewById(R.id.details_box).setVisibility(View.VISIBLE); - TextView descView = (TextView) findViewById(R.id.details); - descView.setVisibility(View.VISIBLE); - descView.setText(Html.fromHtml(trackable.getDetails(), new HtmlImage(geocode, true, 0, false), new UnknownTagsHandler()), TextView.BufferType.SPANNABLE); - descView.setMovementMethod(LinkMovementMethod.getInstance()); - } - - // trackable image - if (StringUtils.isNotBlank(trackable.getImage())) { - findViewById(R.id.image_box).setVisibility(View.VISIBLE); - LinearLayout imgView = (LinearLayout) findViewById(R.id.image); - - final ImageView trackableImage = (ImageView) inflater.inflate(R.layout.trackable_image, null); - - trackableImage.setImageResource(R.drawable.image_not_loaded); - trackableImage.setClickable(true); - trackableImage.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View arg0) { - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(trackable.getImage()))); - } - }); - - // try to load image - final Handler handler = new Handler() { - - @Override - public void handleMessage(Message message) { - BitmapDrawable image = (BitmapDrawable) message.obj; - if (image != null) { - trackableImage.setImageDrawable((BitmapDrawable) message.obj); - } - } - }; - - new Thread() { - - @Override - public void run() { - BitmapDrawable image; - try { - HtmlImage imgGetter = new HtmlImage(geocode, true, 0, false); - - image = imgGetter.getDrawable(trackable.getImage()); - Message message = handler.obtainMessage(0, image); - handler.sendMessage(message); - } catch (Exception e) { - Log.e("cgeospoilers.onCreate.onClick.run: " + e.toString()); - } - } - }.start(); - - imgView.addView(trackableImage); - } - } catch (Exception e) { - Log.e("cgeotrackable.loadTrackableHandler: " + e.toString() + Arrays.toString(e.getStackTrace())); - } - - displayLogs(); - - if (waitDialog != null) { - waitDialog.dismiss(); - } - } - }; - - public cgeotrackable() { - super("c:geo-trackable-details"); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setTheme(); - setContentView(R.layout.trackable_detail); - setTitle(res.getString(R.string.trackable)); - - // get parameters - Bundle extras = getIntent().getExtras(); - Uri uri = getIntent().getData(); - - // try to get data from extras - if (extras != null) { - geocode = extras.getString("geocode"); - name = extras.getString("name"); - guid = extras.getString("guid"); - id = extras.getString("id"); - } - - // try to get data from URI - if (geocode == null && guid == null && id == null && uri != null) { - String uriHost = uri.getHost().toLowerCase(); - if (uriHost.contains("geocaching.com")) { - geocode = uri.getQueryParameter("tracker"); - guid = uri.getQueryParameter("guid"); - id = uri.getQueryParameter("id"); - - if (StringUtils.isNotBlank(geocode)) { - geocode = geocode.toUpperCase(); - guid = null; - id = null; - } else if (StringUtils.isNotBlank(guid)) { - geocode = null; - guid = guid.toLowerCase(); - id = null; - } else if (StringUtils.isNotBlank(id)) { - geocode = null; - guid = null; - id = id.toLowerCase(); - } else { - showToast(res.getString(R.string.err_tb_details_open)); - finish(); - return; - } - } else if (uriHost.contains("coord.info")) { - String uriPath = uri.getPath().toLowerCase(); - if (uriPath != null && uriPath.startsWith("/tb")) { - geocode = uriPath.substring(1).toUpperCase(); - guid = null; - id = null; - } else { - showToast(res.getString(R.string.err_tb_details_open)); - finish(); - return; - } - } - } - - // no given data - if (geocode == null && guid == null && id == null) { - showToast(res.getString(R.string.err_tb_display)); - finish(); - return; - } - - String message; - if (StringUtils.isNotBlank(name)) { - message = Html.fromHtml(name).toString(); - } else if (StringUtils.isNotBlank(geocode)) { - message = geocode.toUpperCase(); - } else { - message = res.getString(R.string.trackable); - } - waitDialog = ProgressDialog.show(this, message, res.getString(R.string.trackable_details_loading), true, true); - - LoadTrackableThread thread = new LoadTrackableThread(loadTrackableHandler, geocode, guid, id); - thread.start(); - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info) { - super.onCreateContextMenu(menu, view, info); - final int viewId = view.getId(); - - if (viewId == R.id.author) { // Log item author - contextMenuUser = ((TextView) view).getText().toString(); - } else { // Trackable owner, and user holding trackable now - RelativeLayout itemLayout = (RelativeLayout) view.getParent(); - TextView itemName = (TextView) itemLayout.findViewById(R.id.name); - - String selectedName = itemName.getText().toString(); - if (selectedName.equals(res.getString(R.string.trackable_owner))) { - contextMenuUser = trackable.getOwner(); - } else if (selectedName.equals(res.getString(R.string.trackable_spotted))) { - contextMenuUser = trackable.getSpottedName(); - } - } - - menu.setHeaderTitle(res.getString(R.string.user_menu_title) + " " + contextMenuUser); - menu.add(viewId, 1, 0, res.getString(R.string.user_menu_view_hidden)); - menu.add(viewId, 2, 0, res.getString(R.string.user_menu_view_found)); - menu.add(viewId, 3, 0, res.getString(R.string.user_menu_open_browser)); - } - - @Override - public boolean onContextItemSelected(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; - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - menu.add(0, MENU_LOG_TOUCH, 0, res.getString(R.string.trackable_log_touch)).setIcon(R.drawable.ic_menu_agenda); // log touch - menu.add(0, MENU_BROWSER_TRACKABLE, 0, res.getString(R.string.trackable_browser_open)).setIcon(R.drawable.ic_menu_info_details); // browser - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case MENU_LOG_TOUCH: - LogTrackableActivity.startActivity(this, trackable); - return true; - case MENU_BROWSER_TRACKABLE: - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(trackable.getUrl()))); - return true; - } - return false; - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - menu.findItem(MENU_LOG_TOUCH).setEnabled(StringUtils.isNotBlank(geocode) && trackable.isLoggable()); - menu.findItem(MENU_BROWSER_TRACKABLE).setEnabled(StringUtils.isNotBlank(trackable.getUrl())); - return super.onPrepareOptionsMenu(menu); - } - - private class LoadTrackableThread extends Thread { - final private Handler handler; - final private String geocode; - final private String guid; - final private String id; - - public LoadTrackableThread(Handler handlerIn, String geocodeIn, String guidIn, String idIn) { - handler = handlerIn; - geocode = geocodeIn; - guid = guidIn; - id = idIn; - } - - @Override - public void run() { - // for non TB trackables, we should just use what we have in the database - trackable = cgeoapplication.getInstance().getTrackableByGeocode(geocode); - - if ((trackable == null || trackable.isLoggable()) && !StringUtils.startsWithIgnoreCase(geocode, "GK")) { - trackable = GCParser.searchTrackable(geocode, guid, id); - } - handler.sendMessage(Message.obtain()); - } - } - - private void displayLogs() { - // trackable logs - LinearLayout listView = (LinearLayout) findViewById(R.id.log_list); - listView.removeAllViews(); - - RelativeLayout rowView; - - if (trackable != null && trackable.getLogs() != null) { - 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(Formatter.formatShortDate(log.date)); - } - - ((TextView) rowView.findViewById(R.id.type)).setText(log.type.getL10n()); - ((TextView) rowView.findViewById(R.id.author)).setText(Html.fromHtml(log.author), TextView.BufferType.SPANNABLE); - - if (StringUtils.isBlank(log.cacheName)) { - rowView.findViewById(R.id.location).setVisibility(View.GONE); - } else { - ((TextView) rowView.findViewById(R.id.location)).setText(Html.fromHtml(log.cacheName)); - final String cacheGuid = log.cacheGuid; - final String cacheName = log.cacheName; - rowView.findViewById(R.id.location).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View arg0) { - CacheDetailActivity.startActivityGuid(cgeotrackable.this, cacheGuid, Html.fromHtml(cacheName).toString()); - } - }); - } - - TextView logView = (TextView) rowView.findViewById(R.id.log); - logView.setMovementMethod(LinkMovementMethod.getInstance()); - - String logText = log.log; - if (BaseUtils.containsHtml(logText)) { - logText = log.getDisplayText(); - logView.setText(Html.fromHtml(logText, new HtmlImage(null, false, StoredList.TEMPORARY_LIST_ID, false), null), TextView.BufferType.SPANNABLE); - } - else { - logView.setText(logText); - } - - // add LogImages - LinearLayout logLayout = (LinearLayout) rowView.findViewById(R.id.log_layout); - - if (log.hasLogImages()) { - - final ArrayList<cgImage> logImages = new ArrayList<cgImage>(log.getLogImages()); - - final View.OnClickListener listener = new View.OnClickListener() { - @Override - public void onClick(View v) { - ImagesActivity.startActivityLogImages(cgeotrackable.this, trackable.getGeocode(), logImages); - } - }; - - LinearLayout log_imgView = (LinearLayout) getLayoutInflater().inflate(R.layout.trackable_logs_img, null); - TextView log_img_title = (TextView) log_imgView.findViewById(R.id.title); - log_img_title.setText(log.getImageTitles()); - log_img_title.setOnClickListener(listener); - logLayout.addView(log_imgView); - } - - rowView.findViewById(R.id.author).setOnClickListener(new UserActionsListener()); - listView.addView(rowView); - } - - if (trackable.getLogs().size() > 0) { - findViewById(R.id.log_box).setVisibility(View.VISIBLE); - } - } - } - - private class UserActionsListener implements View.OnClickListener { - - @Override - public void onClick(View view) { - if (view == null) { - return; - } - - try { - registerForContextMenu(view); - openContextMenu(view); - } catch (Exception e) { - Log.e("cgeotrackable.UserActionsListener.onClick ", e); - } - } - } - - private class TrackableIconThread extends Thread { - final private String url; - final private Handler handler; - - public TrackableIconThread(String urlIn, Handler handlerIn) { - url = urlIn; - handler = handlerIn; - } - - @Override - public void run() { - if (url == null || handler == null) { - return; - } - - BitmapDrawable image; - try { - HtmlImage imgGetter = new HtmlImage(trackable.getGeocode(), false, 0, false); - - image = imgGetter.getDrawable(url); - Message message = handler.obtainMessage(0, image); - handler.sendMessage(message); - } catch (Exception e) { - Log.e("cgeotrackable.TrackableIconThread.run: " + e.toString()); - } - } - } - - private static class TrackableIconHandler extends Handler { - final private TextView view; - - public TrackableIconHandler(TextView viewIn) { - view = viewIn; - } - - @Override - public void handleMessage(Message message) { - final BitmapDrawable image = (BitmapDrawable) message.obj; - if (image != null && view != null) { - image.setBounds(0, 0, view.getHeight(), view.getHeight()); - view.setCompoundDrawables(image, null, null, null); - } - } - } - - public static void startActivity(final AbstractActivity fromContext, - final String guid, final String geocode, final String name) { - final Intent trackableIntent = new Intent(fromContext, cgeotrackable.class); - trackableIntent.putExtra("guid", guid); - trackableIntent.putExtra("geocode", geocode); - trackableIntent.putExtra("name", name); - fromContext.startActivity(trackableIntent); - } -} diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel11Dummy.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel11Emulation.java index 9c2bb8c..6a23ed5 100644 --- a/main/src/cgeo/geocaching/compatibility/AndroidLevel11Dummy.java +++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel11Emulation.java @@ -3,9 +3,9 @@ package cgeo.geocaching.compatibility; import android.app.Activity; /** - * dummy class which has no functionality in the level 11 API + * implement level 11 API using older methods */ -public class AndroidLevel11Dummy implements AndroidLevel11Interface { +public class AndroidLevel11Emulation implements AndroidLevel11Interface { @Override public void invalidateOptionsMenu(final Activity activity) { diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel13.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel13.java new file mode 100644 index 0000000..4eac205 --- /dev/null +++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel13.java @@ -0,0 +1,31 @@ +package cgeo.geocaching.compatibility; + +import cgeo.geocaching.cgeoapplication; + +import android.annotation.TargetApi; +import android.content.Context; +import android.graphics.Point; +import android.view.WindowManager; + +@TargetApi(value = 13) +public class AndroidLevel13 implements AndroidLevel13Interface { + + @Override + public int getDisplayWidth() { + return getDisplaySize().x; + } + + @Override + public Point getDisplaySize() { + Point dimensions = new Point(); + ((WindowManager) cgeoapplication.getInstance().getSystemService(Context.WINDOW_SERVICE)) + .getDefaultDisplay().getSize(dimensions); + return dimensions; + } + + @Override + public int getDisplayHeight() { + return getDisplaySize().y; + } + +} diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel13Emulation.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel13Emulation.java new file mode 100644 index 0000000..2257d83 --- /dev/null +++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel13Emulation.java @@ -0,0 +1,33 @@ +package cgeo.geocaching.compatibility; + +import cgeo.geocaching.cgeoapplication; + +import android.content.Context; +import android.graphics.Point; +import android.view.Display; +import android.view.WindowManager; + +@SuppressWarnings("deprecation") +public class AndroidLevel13Emulation implements AndroidLevel13Interface { + + @Override + public int getDisplayWidth() { + return getDisplay().getWidth(); + } + + @Override + public int getDisplayHeight() { + return getDisplay().getHeight(); + } + + @Override + public Point getDisplaySize() { + final Display display = getDisplay(); + return new Point(display.getWidth(), display.getHeight()); + } + + private static Display getDisplay() { + return ((WindowManager) cgeoapplication.getInstance().getSystemService(Context.WINDOW_SERVICE)) + .getDefaultDisplay(); + } +} diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel13Interface.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel13Interface.java new file mode 100644 index 0000000..f4e1975 --- /dev/null +++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel13Interface.java @@ -0,0 +1,11 @@ +package cgeo.geocaching.compatibility; + +import android.graphics.Point; + +public interface AndroidLevel13Interface { + int getDisplayWidth(); + + int getDisplayHeight(); + + Point getDisplaySize(); +} diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java index ea5a795..a388adb 100644 --- a/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java +++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java @@ -6,6 +6,7 @@ import android.annotation.TargetApi; import android.app.Activity; import android.app.backup.BackupManager; import android.view.Display; +import android.view.Surface; @TargetApi(8) public class AndroidLevel8 implements AndroidLevel8Interface { @@ -21,4 +22,23 @@ public class AndroidLevel8 implements AndroidLevel8Interface { Log.i("Requesting settings backup with settings manager"); BackupManager.dataChanged(name); } + + @Override + public int getRotationOffset(final Activity activity) { + try { + final int rotation = getRotation(activity); + if (rotation == Surface.ROTATION_90) { + return 90; + } else if (rotation == Surface.ROTATION_180) { + return 180; + } else if (rotation == Surface.ROTATION_270) { + return 270; + } + } catch (final Exception e) { + // This should never happen: IllegalArgumentException, IllegalAccessException or InvocationTargetException + Log.e("Cannot call getRotation()", e); + } + + return 0; + } } diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel8Dummy.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel8Dummy.java deleted file mode 100644 index d0ab911..0000000 --- a/main/src/cgeo/geocaching/compatibility/AndroidLevel8Dummy.java +++ /dev/null @@ -1,16 +0,0 @@ -package cgeo.geocaching.compatibility; - -import android.app.Activity; - -public class AndroidLevel8Dummy implements AndroidLevel8Interface { - - @Override - public int getRotation(final Activity activity) { - return 0; - } - - @Override - public void dataChanged(final String name) { - // do nothing - } -} diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel8Emulation.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel8Emulation.java new file mode 100644 index 0000000..197993d --- /dev/null +++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel8Emulation.java @@ -0,0 +1,30 @@ +package cgeo.geocaching.compatibility; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.res.Configuration; +import android.view.Display; + +@TargetApi(value = 7) +public class AndroidLevel8Emulation implements AndroidLevel8Interface { + + @Override + public int getRotation(final Activity activity) { + return 0; + } + + @Override + public void dataChanged(final String name) { + // do nothing + } + + @Override + public int getRotationOffset(Activity activity) { + final Display display = activity.getWindowManager().getDefaultDisplay(); + final int rotation = display.getOrientation(); + if (rotation == Configuration.ORIENTATION_LANDSCAPE) { + return 90; + } + return 0; + } +} diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel8Interface.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel8Interface.java index b1c4f81..761c23a 100644 --- a/main/src/cgeo/geocaching/compatibility/AndroidLevel8Interface.java +++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel8Interface.java @@ -6,4 +6,5 @@ public interface AndroidLevel8Interface { public int getRotation(final Activity activity); public void dataChanged(final String name); + public int getRotationOffset(final Activity activity); }
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/compatibility/Compatibility.java b/main/src/cgeo/geocaching/compatibility/Compatibility.java index 0821655..05a3331 100644 --- a/main/src/cgeo/geocaching/compatibility/Compatibility.java +++ b/main/src/cgeo/geocaching/compatibility/Compatibility.java @@ -8,11 +8,9 @@ import org.apache.commons.lang3.reflect.MethodUtils; import android.app.Activity; import android.content.Intent; -import android.content.res.Configuration; +import android.graphics.Point; import android.os.Build; import android.text.InputType; -import android.view.Display; -import android.view.Surface; import android.widget.EditText; public final class Compatibility { @@ -23,19 +21,26 @@ public final class Compatibility { private final static AndroidLevel8Interface level8; private final static AndroidLevel11Interface level11; + private final static AndroidLevel13Interface level13; static { if (isLevel8) { level8 = new AndroidLevel8(); } else { - level8 = new AndroidLevel8Dummy(); + level8 = new AndroidLevel8Emulation(); } if (sdkVersion >= 11) { level11 = new AndroidLevel11(); } else { - level11 = new AndroidLevel11Dummy(); + level11 = new AndroidLevel11Emulation(); + } + if (sdkVersion >= 13) { + level13 = new AndroidLevel13(); + } + else { + level13 = new AndroidLevel13Emulation(); } } @@ -47,29 +52,7 @@ public final class Compatibility { * @return the adjusted direction, in the [0, 360[ range */ public static float getDirectionNow(final float directionNowPre, final Activity activity) { - float offset = 0; - if (isLevel8) { - try { - final int rotation = level8.getRotation(activity); - if (rotation == Surface.ROTATION_90) { - offset = 90; - } else if (rotation == Surface.ROTATION_180) { - offset = 180; - } else if (rotation == Surface.ROTATION_270) { - offset = 270; - } - } catch (final Exception e) { - // This should never happen: IllegalArgumentException, IllegalAccessException or InvocationTargetException - Log.e("Cannot call getRotation()", e); - } - } else { - final Display display = activity.getWindowManager().getDefaultDisplay(); - final int rotation = display.getOrientation(); - if (rotation == Configuration.ORIENTATION_LANDSCAPE) { - offset = 90; - } - } - return AngleUtils.normalize(directionNowPre + offset); + return AngleUtils.normalize(directionNowPre + level8.getRotationOffset(activity)); } public static void dataChanged(final String name) { @@ -113,4 +96,16 @@ public final class Compatibility { level11.invalidateOptionsMenu(activity); } + public static int getDisplayWidth() { + return level13.getDisplayWidth(); + } + + public static int getDisplayHeight() { + return level13.getDisplayHeight(); + } + + public static Point getDisplaySize() { + return level13.getDisplaySize(); + } + } diff --git a/main/src/cgeo/geocaching/connector/AbstractConnector.java b/main/src/cgeo/geocaching/connector/AbstractConnector.java index aa75f3b..0308ae7 100644 --- a/main/src/cgeo/geocaching/connector/AbstractConnector.java +++ b/main/src/cgeo/geocaching/connector/AbstractConnector.java @@ -2,8 +2,11 @@ package cgeo.geocaching.connector; import cgeo.geocaching.SearchResult; import cgeo.geocaching.cgCache; +import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.Viewport; +import org.apache.commons.lang3.StringUtils; + public abstract class AbstractConnector implements IConnector { @Override @@ -17,6 +20,31 @@ public abstract class AbstractConnector implements IConnector { } @Override + public boolean supportsOwnCoordinates() { + return false; + } + + /** + * Uploading modified coordinates to website + * + * @param cache + * @param wpt + * @return success + */ + @Override + public boolean uploadModifiedCoordinates(cgCache cache, Geopoint wpt) { + throw new UnsupportedOperationException(); + } + + /** + * {@link IConnector} + */ + @Override + public boolean deleteModifiedCoordinates(cgCache cache) { + throw new UnsupportedOperationException(); + } + + @Override public boolean supportsFavoritePoints() { return false; } @@ -37,7 +65,7 @@ public abstract class AbstractConnector implements IConnector { } @Override - public SearchResult searchByViewport(Viewport viewport, String tokens[]) { + public SearchResult searchByViewport(Viewport viewport, String[] tokens) { return null; } @@ -65,4 +93,18 @@ public abstract class AbstractConnector implements IConnector { public String[] getTokens() { return null; } + + @Override + public String getGeocodeFromUrl(final String url) { + final String urlPrefix = getCacheUrlPrefix(); + if (StringUtils.startsWith(url, urlPrefix)) { + String geocode = url.substring(urlPrefix.length()); + if (canHandle(geocode)) { + return geocode; + } + } + return null; + } + + abstract protected String getCacheUrlPrefix(); } diff --git a/main/src/cgeo/geocaching/connector/ConnectorFactory.java b/main/src/cgeo/geocaching/connector/ConnectorFactory.java index b9b8263..bc4dcc0 100644 --- a/main/src/cgeo/geocaching/connector/ConnectorFactory.java +++ b/main/src/cgeo/geocaching/connector/ConnectorFactory.java @@ -81,4 +81,14 @@ public final class ConnectorFactory { return GCConnector.getInstance().searchByViewport(viewport, tokens); } + public static String getGeocodeFromURL(final String url) { + for (IConnector connector : connectors) { + String geocode = connector.getGeocodeFromUrl(url); + if (StringUtils.isNotBlank(geocode)) { + return geocode; + } + } + return null; + } + } diff --git a/main/src/cgeo/geocaching/connector/GeocachingAustraliaConnector.java b/main/src/cgeo/geocaching/connector/GeocachingAustraliaConnector.java index 771f5d2..30d1a4b 100644 --- a/main/src/cgeo/geocaching/connector/GeocachingAustraliaConnector.java +++ b/main/src/cgeo/geocaching/connector/GeocachingAustraliaConnector.java @@ -13,7 +13,7 @@ public class GeocachingAustraliaConnector extends AbstractConnector { @Override public String getCacheUrl(final cgCache cache) { - return "http://" + getHost() + "/cache/" + cache.getGeocode(); + return getCacheUrlPrefix() + cache.getGeocode(); } @Override @@ -25,4 +25,9 @@ public class GeocachingAustraliaConnector extends AbstractConnector { public boolean canHandle(final String geocode) { return (StringUtils.startsWithIgnoreCase(geocode, "GA") || StringUtils.startsWithIgnoreCase(geocode, "TP")) && isNumericId(geocode.substring(2)); } + + @Override + protected String getCacheUrlPrefix() { + return "http://" + getHost() + "/cache/"; + } } diff --git a/main/src/cgeo/geocaching/connector/GeopeitusConnector.java b/main/src/cgeo/geocaching/connector/GeopeitusConnector.java index fa19d80..6ef91db 100644 --- a/main/src/cgeo/geocaching/connector/GeopeitusConnector.java +++ b/main/src/cgeo/geocaching/connector/GeopeitusConnector.java @@ -13,7 +13,7 @@ public class GeopeitusConnector extends AbstractConnector { @Override public String getCacheUrl(final cgCache cache) { - return "http://" + getHost() + "/aare/" + StringUtils.stripStart(cache.getGeocode().substring(2), "0"); + return getCacheUrlPrefix() + StringUtils.stripStart(cache.getGeocode().substring(2), "0"); } @Override @@ -25,4 +25,9 @@ public class GeopeitusConnector extends AbstractConnector { public boolean canHandle(String geocode) { return StringUtils.startsWith(geocode, "GE") && isNumericId(geocode.substring(2)); } + + @Override + protected String getCacheUrlPrefix() { + return "http://" + getHost() + "/aare/"; + } } diff --git a/main/src/cgeo/geocaching/connector/IConnector.java b/main/src/cgeo/geocaching/connector/IConnector.java index 9111955..69cc7d1 100644 --- a/main/src/cgeo/geocaching/connector/IConnector.java +++ b/main/src/cgeo/geocaching/connector/IConnector.java @@ -2,6 +2,7 @@ package cgeo.geocaching.connector; import cgeo.geocaching.SearchResult; import cgeo.geocaching.cgCache; +import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.Viewport; public interface IConnector { @@ -37,7 +38,7 @@ public interface IConnector { /** * enable/disable favorite points controls in cache details - * + * * @return */ public boolean supportsFavoritePoints(); @@ -104,4 +105,36 @@ public interface IConnector { */ public String[] getTokens(); + /** + * extract a geocode from the given URL, if this connector can handle that URL somehow + * + * @param url + * @return + */ + public String getGeocodeFromUrl(final String url); + + /** + * enable/disable uploading modified coordinates to website + * + * @return true, when uploading is possible + */ + public boolean supportsOwnCoordinates(); + + /** + * Uploading modified coordinates to website + * + * @param cache + * @param wpt + * @return success + */ + public boolean uploadModifiedCoordinates(cgCache cache, Geopoint wpt); + + /** + * Reseting of modified coordinates on website to details + * + * @param cache + * @return success + */ + public boolean deleteModifiedCoordinates(cgCache cache); + } diff --git a/main/src/cgeo/geocaching/connector/UnknownConnector.java b/main/src/cgeo/geocaching/connector/UnknownConnector.java index 5e8d3f3..991d31c 100644 --- a/main/src/cgeo/geocaching/connector/UnknownConnector.java +++ b/main/src/cgeo/geocaching/connector/UnknownConnector.java @@ -25,4 +25,9 @@ public class UnknownConnector extends AbstractConnector { public boolean canHandle(final String geocode) { return StringUtils.isNotBlank(geocode); } + + @Override + protected String getCacheUrlPrefix() { + return null; + } } diff --git a/main/src/cgeo/geocaching/connector/gc/AbstractSearchThread.java b/main/src/cgeo/geocaching/connector/gc/AbstractSearchThread.java index d0e45f6..f19064d 100644 --- a/main/src/cgeo/geocaching/connector/gc/AbstractSearchThread.java +++ b/main/src/cgeo/geocaching/connector/gc/AbstractSearchThread.java @@ -12,7 +12,7 @@ abstract public class AbstractSearchThread extends Thread { private final Handler handler; private static AbstractSearchThread currentInstance; - public AbstractSearchThread(final Handler handler) { + protected AbstractSearchThread(final Handler handler) { this.handler = handler; } diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java index 5607d97..5de170b 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java +++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java @@ -3,7 +3,7 @@ package cgeo.geocaching.connector.gc; import cgeo.geocaching.R; import cgeo.geocaching.SearchResult; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.cgData; import cgeo.geocaching.connector.AbstractConnector; import cgeo.geocaching.connector.capability.ISearchByCenter; import cgeo.geocaching.connector.capability.ISearchByGeocode; @@ -20,18 +20,22 @@ import java.util.regex.Pattern; public class GCConnector extends AbstractConnector implements ISearchByGeocode, ISearchByCenter { - private static GCConnector instance; + private static final String HTTP_COORD_INFO = "http://coord.info/"; private static final Pattern gpxZipFilePattern = Pattern.compile("\\d{7,}(_.+)?\\.zip", Pattern.CASE_INSENSITIVE); private GCConnector() { // singleton } + /** + * initialization on demand holder pattern + */ + private static class Holder { + private static final GCConnector INSTANCE = new GCConnector(); + } + public static GCConnector getInstance() { - if (instance == null) { - instance = new GCConnector(); - } - return instance; + return Holder.INSTANCE; } @Override @@ -49,6 +53,11 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, } @Override + public boolean supportsOwnCoordinates() { + return true; + } + + @Override public boolean supportsWatchList() { return true; } @@ -82,11 +91,10 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, if (StringUtils.isEmpty(page)) { final SearchResult search = new SearchResult(); - if (cgeoapplication.getInstance().isThere(geocode, guid, true, false)) { + if (cgData.isThere(geocode, guid, true, false)) { if (StringUtils.isBlank(geocode) && StringUtils.isNotBlank(guid)) { Log.i("Loading old cache from cache."); - - search.addGeocode(cgeoapplication.getInstance().getGeocode(guid)); + search.addGeocode(cgData.getGeocodeForGuid(guid)); } else { search.addGeocode(geocode); } @@ -102,7 +110,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, final SearchResult searchResult = GCParser.parseCache(page, handler); if (searchResult == null || CollectionUtils.isEmpty(searchResult.getGeocodes())) { - Log.e("GCConnector.searchByGeocode: No cache parsed"); + Log.w("GCConnector.searchByGeocode: No cache parsed"); return searchResult; } @@ -128,7 +136,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, public static boolean addToWatchlist(cgCache cache) { final boolean added = GCParser.addToWatchlist(cache); if (added) { - cgeoapplication.getInstance().updateCache(cache); + cgData.saveChangedCache(cache); } return added; } @@ -136,7 +144,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, public static boolean removeFromWatchlist(cgCache cache) { final boolean removed = GCParser.removeFromWatchlist(cache); if (removed) { - cgeoapplication.getInstance().updateCache(cache); + cgData.saveChangedCache(cache); } return removed; } @@ -144,7 +152,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, public static boolean addToFavorites(cgCache cache) { final boolean added = GCParser.addToFavorites(cache); if (added) { - cgeoapplication.getInstance().updateCache(cache); + cgData.saveChangedCache(cache); } return added; } @@ -152,12 +160,30 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, public static boolean removeFromFavorites(cgCache cache) { final boolean removed = GCParser.removeFromFavorites(cache); if (removed) { - cgeoapplication.getInstance().updateCache(cache); + cgData.saveChangedCache(cache); } return removed; } @Override + public boolean uploadModifiedCoordinates(cgCache cache, Geopoint wpt) { + final boolean uploaded = GCParser.uploadModifiedCoordinates(cache, wpt); + if (uploaded) { + cgData.saveChangedCache(cache); + } + return uploaded; + } + + @Override + public boolean deleteModifiedCoordinates(cgCache cache) { + final boolean deleted = GCParser.deleteModifiedCoordinates(cache); + if (deleted) { + cgData.saveChangedCache(cache); + } + return deleted; + } + + @Override public SearchResult searchByCenter(Geopoint center) { // TODO make search by coordinate use this method. currently it is just a marker that this connector supports search by center return null; @@ -168,4 +194,8 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, return true; } + @Override + protected String getCacheUrlPrefix() { + return HTTP_COORD_INFO; + } } diff --git a/main/src/cgeo/geocaching/connector/gc/GCConstants.java b/main/src/cgeo/geocaching/connector/gc/GCConstants.java index 4745d90..a474e70 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCConstants.java +++ b/main/src/cgeo/geocaching/connector/gc/GCConstants.java @@ -1,5 +1,6 @@ package cgeo.geocaching.connector.gc; +import java.util.Locale; import java.util.regex.Pattern; /** @@ -49,7 +50,7 @@ public final class GCConstants { public final static Pattern PATTERN_FAVORITE = Pattern.compile("<div id=\"pnlFavoriteCache\">"); // without 'class="hideMe"' inside the tag ! public final static Pattern PATTERN_FAVORITECOUNT = Pattern.compile("<a id=\"uxFavContainerLink\"[^>]+>[^<]*<div[^<]*<span class=\"favorite-value\">\\D*([0-9]+?)</span>"); public final static Pattern PATTERN_COUNTLOGS = Pattern.compile("<span id=\"ctl00_ContentBody_lblFindCounts\"><p(.+?)</p></span>"); - public final static Pattern PATTERN_LOGBOOK = Pattern.compile("initalLogs = (\\{.+\\});"); + public final static Pattern PATTERN_LOGBOOK = Pattern.compile("initalLogs = (\\{.+\\});"); // The "inital" typo really comes from gc.com site /** Two groups ! */ public final static Pattern PATTERN_COUNTLOG = Pattern.compile("<img src=\"/images/logtypes/([0-9]+)\\.png\"[^>]+> (\\d*[,.]?\\d+)"); public static final Pattern PATTERN_PREMIUMMEMBERS = Pattern.compile("<p class=\"Warning NoBottomSpacing\">This is a Premium Member Only cache.</p>"); @@ -103,7 +104,7 @@ public final class GCConstants { public final static Pattern PATTERN_TRACKABLE_ICON = Pattern.compile("<img id=\"ctl00_ContentBody_BugTypeImage\" class=\"TravelBugHeaderIcon\" src=\"([^\"]+)\"[^>]*>"); public final static Pattern PATTERN_TRACKABLE_TYPE = Pattern.compile("<img id=\"ctl00_ContentBody_BugTypeImage\" class=\"TravelBugHeaderIcon\" src=\"[^\"]+\" alt=\"([^\"]+)\"[^>]*>"); public final static Pattern PATTERN_TRACKABLE_DISTANCE = Pattern.compile("<h4[^>]*\\W*Tracking History \\(([0-9.,]+(km|mi))[^\\)]*\\)"); - public final static Pattern PATTERN_TRACKABLE_LOG = Pattern.compile("<tr class=\"Data BorderTop .+?src=\"/images/logtypes/([^.]+)\\.png[^>]+> ([^<]+)</td>.+?guid.+?>([^<]+)</a>.+?(?:guid=([^\"]+)\">(<span[^>]+>)?([^<]+)</.+?)?<td colspan=\"4\">(.+?)(?:<ul.+?ul>)?\\s*</td>\\s*</tr>"); + public final static Pattern PATTERN_TRACKABLE_LOG = Pattern.compile("<tr class=\"Data BorderTop .+?src=\"/images/logtypes/([^.]+)\\.png[^>]+> ([^<]+)</td>.+?guid.+?>([^<]+)</a>.+?(?:guid=([^\"]+)\">(<span[^>]+>)?([^<]+)</.+?)?<td colspan=\"4\">\\s*<div>(.*?)</div>\\s*(?:<ul.+?ul>)?\\s*</td>\\s*</tr>"); public final static Pattern PATTERN_TRACKABLE_LOG_IMAGES = Pattern.compile("<li><a href=\"([^\"]+)\".+?LogImgTitle.+?>([^<]+)</"); /** @@ -164,8 +165,9 @@ public final class GCConstants { public final static String STRING_PREMIUMONLY_2 = "Sorry, the owner of this listing has made it viewable to Premium Members only."; public final static String STRING_PREMIUMONLY_1 = "has chosen to make this cache listing visible to Premium Members only."; - public final static String STRING_UNPUBLISHED_OWNER = "Cache is Unpublished"; + public final static String STRING_UNPUBLISHED_OWNER = "cache has not been published yet"; public final static String STRING_UNPUBLISHED_OTHER = "you cannot view this cache listing until it has been published"; + public final static String STRING_UNPUBLISHED_FROM_SEARCH = "UnpublishedCacheSearchWidget"; public final static String STRING_UNKNOWN_ERROR = "An Error Has Occurred"; public final static String STRING_DISABLED = "<li>This cache is temporarily unavailable."; public final static String STRING_ARCHIVED = "<li>This cache has been archived,"; @@ -185,14 +187,14 @@ public final class GCConstants { * see http://support.groundspeak.com/index.php?pg=kb.printer.friendly&id=1#p221 */ public static long gccodeToGCId(final String gccode) { - long gcid = 0; long base = GC_BASE31; - String geocodeWO = gccode.substring(2).toUpperCase(); + String geocodeWO = gccode.substring(2).toUpperCase(Locale.US); if ((geocodeWO.length() < 4) || (geocodeWO.length() == 4 && SEQUENCE_GCID.indexOf(geocodeWO.charAt(0)) < 16)) { base = GC_BASE16; } + long gcid = 0; for (int p = 0; p < geocodeWO.length(); p++) { gcid = base * gcid + SEQUENCE_GCID.indexOf(geocodeWO.charAt(p)); } diff --git a/main/src/cgeo/geocaching/connector/gc/GCMap.java b/main/src/cgeo/geocaching/connector/gc/GCMap.java index 681a1d7..9a8123d 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCMap.java +++ b/main/src/cgeo/geocaching/connector/gc/GCMap.java @@ -3,6 +3,7 @@ package cgeo.geocaching.connector.gc; import cgeo.geocaching.SearchResult; import cgeo.geocaching.Settings; import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgData; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; @@ -40,10 +41,10 @@ public class GCMap { final SearchResult result = new SearchResult(); final String geocodeList = StringUtils.join(geocodes.toArray(), "|"); - final String referer = GCConstants.URL_LIVE_MAP_DETAILS; try { final Parameters params = new Parameters("i", geocodeList, "_", String.valueOf(System.currentTimeMillis())); + final String referer = GCConstants.URL_LIVE_MAP_DETAILS; final String data = StringUtils.defaultString(Tile.requestMapInfo(referer, params, referer)); // Example JSON information @@ -166,6 +167,8 @@ public class GCMap { // iterate over the data and construct all caches in this tile Map<String, List<UTFGridPosition>> positions = new HashMap<String, List<UTFGridPosition>>(); // JSON id as key + Map<String, List<UTFGridPosition>> singlePositions = new HashMap<String, List<UTFGridPosition>>(); // JSON id as key + for (int i = 1; i < keys.length(); i++) { // index 0 is empty String key = keys.getString(i); if (StringUtils.isNotBlank(key)) { @@ -177,12 +180,20 @@ public class GCMap { nameCache.put(id, cacheInfo.getString("n")); List<UTFGridPosition> listOfPositions = positions.get(id); + List<UTFGridPosition> singleListOfPositions = singlePositions.get(id); + if (listOfPositions == null) { listOfPositions = new ArrayList<UTFGridPosition>(); positions.put(id, listOfPositions); + singleListOfPositions = new ArrayList<UTFGridPosition>(); + singlePositions.put(id, singleListOfPositions); } listOfPositions.add(pos); + if (dataForKey.length() == 1) { + singleListOfPositions.add(pos); + } + } } } @@ -198,12 +209,16 @@ public class GCMap { cache.setName(nameCache.get(id)); cache.setZoomlevel(tile.getZoomlevel()); cache.setCoords(tile.getCoord(xy)); - 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()); + if (strategy.flags.contains(StrategyFlag.PARSE_TILES) && bitmap != null) { + for (UTFGridPosition singlePos : singlePositions.get(id)) { + if (IconDecoder.parseMapPNG(cache, bitmap, singlePos, tile.getZoomlevel())) { + break; // cache parsed + } + } } else { cache.setType(CacheType.UNKNOWN); } + boolean exclude = false; if (Settings.isExcludeMyCaches() && (cache.isFound() || cache.isOwn())) { // workaround for BM exclude = true; @@ -313,7 +328,7 @@ public class GCMap { String data = Tile.requestMapInfo(GCConstants.URL_MAP_INFO, params, GCConstants.URL_LIVE_MAP); if (StringUtils.isEmpty(data)) { - Log.e("GCBase.searchByViewport: No data from server for tile (" + tile.getX() + "/" + tile.getY() + ")"); + Log.w("GCBase.searchByViewport: No data from server for tile (" + tile.getX() + "/" + tile.getY() + ")"); } else { final SearchResult search = GCMap.parseMapJSON(data, tile, bitmap, strategy); if (search == null || CollectionUtils.isEmpty(search.getGeocodes())) { @@ -341,7 +356,7 @@ public class GCMap { if (search != null && !search.isEmpty()) { final Set<String> geocodes = search.getGeocodes(); if (Settings.isPremiumMember()) { - lastSearchViewport = cgeoapplication.getInstance().getBounds(geocodes); + lastSearchViewport = cgData.getBounds(geocodes); } else { lastSearchViewport = new Viewport(center, center); } diff --git a/main/src/cgeo/geocaching/connector/gc/GCParser.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java index 895a9c8..c40d470 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCParser.java +++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java @@ -6,6 +6,7 @@ import cgeo.geocaching.SearchResult; import cgeo.geocaching.Settings; import cgeo.geocaching.TrackableLog; import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgData; import cgeo.geocaching.cgImage; import cgeo.geocaching.cgTrackable; import cgeo.geocaching.cgWaypoint; @@ -43,12 +44,7 @@ import org.json.JSONObject; import android.net.Uri; import android.text.Html; -import android.text.Spannable; -import android.text.Spanned; -import android.text.style.ForegroundColorSpan; -import android.text.style.StrikethroughSpan; -import java.net.URLDecoder; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -71,8 +67,6 @@ public abstract class GCParser { } final List<String> cids = new ArrayList<String>(); - String recaptchaChallenge = null; - String recaptchaText = null; String page = pageContent; final SearchResult searchResult = new SearchResult(); @@ -81,6 +75,7 @@ public abstract class GCParser { // recaptcha AbstractSearchThread thread = AbstractSearchThread.getCurrentInstance(); + String recaptchaChallenge = null; if (showCaptcha) { String recaptchaJsParam = BaseUtils.getMatch(page, GCConstants.PATTERN_SEARCH_RECAPTCHA, false, null); @@ -163,23 +158,26 @@ public abstract class GCParser { continue; } - String inventoryPre = null; - - cache.setGeocode(BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_GEOCODE, true, 1, cache.getGeocode(), true).toUpperCase()); + cache.setGeocode(BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_GEOCODE, true, 1, cache.getGeocode(), true)); // cache type cache.setType(CacheType.getByPattern(BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_TYPE, true, 1, null, true))); // cache direction - image if (Settings.getLoadDirImg()) { - cache.setDirectionImg(URLDecoder.decode(BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_DIRECTION, true, 1, cache.getDirectionImg(), true))); + cache.setDirectionImg(Network.decode(BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_DIRECTION, true, 1, cache.getDirectionImg(), true))); } // cache inventory final Matcher matcherTbs = GCConstants.PATTERN_SEARCH_TRACKABLES.matcher(row); + String inventoryPre = null; while (matcherTbs.find()) { if (matcherTbs.groupCount() > 0) { - cache.setInventoryItems(Integer.parseInt(matcherTbs.group(1))); + try { + cache.setInventoryItems(Integer.parseInt(matcherTbs.group(1))); + } catch (NumberFormatException e) { + Log.e("Error parsing trackables count", e); + } inventoryPre = matcherTbs.group(2); } } @@ -222,16 +220,6 @@ public abstract class GCParser { Log.w("GCParser.parseSearch: Failed to parse favourite count"); } - if (cache.getNameSp() == null) { - cache.setNameSp((new Spannable.Factory()).newSpannable(cache.getName())); - if (cache.isDisabled() || cache.isArchived()) { // strike - cache.getNameSp().setSpan(new StrikethroughSpan(), 0, cache.getNameSp().toString().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } - if (cache.isArchived()) { - cache.getNameSp().setSpan(new ForegroundColorSpan(cgeoapplication.getInstance().getResources().getColor(R.color.archived_cache_color)), 0, cache.getNameSp().toString().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } - } - searchResult.addCache(cache); } @@ -245,6 +233,7 @@ public abstract class GCParser { Log.w("GCParser.parseSearch: Failed to parse cache count"); } + String recaptchaText = null; if (thread != null && recaptchaChallenge != null) { if (thread.getText() == null) { thread.waitForUser(); @@ -253,7 +242,7 @@ public abstract class GCParser { recaptchaText = thread.getText(); } - if (cids.size() > 0 && (Settings.isPremiumMember() || showCaptcha) && (recaptchaChallenge == null || StringUtils.isNotBlank(recaptchaText))) { + if (!cids.isEmpty() && (Settings.isPremiumMember() || showCaptcha) && (recaptchaChallenge == null || StringUtils.isNotBlank(recaptchaText))) { Log.i("Trying to get .loc for " + cids.size() + " caches"); try { @@ -326,7 +315,7 @@ public abstract class GCParser { // save full detailed caches CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_cache); - cgeoapplication.getInstance().saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); + cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); // update progress message so user knows we're still working. This is more of a place holder than // actual indication of what the program is doing @@ -345,7 +334,7 @@ public abstract class GCParser { final SearchResult searchResult = new SearchResult(); - if (page.contains(GCConstants.STRING_UNPUBLISHED_OTHER) || page.contains(GCConstants.STRING_UNPUBLISHED_OWNER)) { + if (page.contains(GCConstants.STRING_UNPUBLISHED_OTHER) || page.contains(GCConstants.STRING_UNPUBLISHED_OWNER) || page.contains(GCConstants.STRING_UNPUBLISHED_FROM_SEARCH)) { searchResult.setError(StatusCode.UNPUBLISHED_CACHE); return searchResult; } @@ -383,10 +372,12 @@ public abstract class GCParser { cache.setName(cacheName); // owner real name - cache.setOwnerUserId(URLDecoder.decode(BaseUtils.getMatch(page, GCConstants.PATTERN_OWNER_USERID, true, cache.getOwnerUserId()))); + cache.setOwnerUserId(Network.decode(BaseUtils.getMatch(page, GCConstants.PATTERN_OWNER_USERID, true, cache.getOwnerUserId()))); cache.setOwn(StringUtils.equalsIgnoreCase(cache.getOwnerUserId(), Settings.getUsername())); + cache.setUserModifiedCoords(false); + String tableInside = page; int pos = tableInside.indexOf(GCConstants.STRING_CACHEDETAILS); @@ -401,13 +392,21 @@ public abstract class GCParser { // cache terrain String result = BaseUtils.getMatch(tableInside, GCConstants.PATTERN_TERRAIN, true, null); if (result != null) { - cache.setTerrain(Float.parseFloat(StringUtils.replaceChars(result, '_', '.'))); + try { + cache.setTerrain(Float.parseFloat(StringUtils.replaceChars(result, '_', '.'))); + } catch (NumberFormatException e) { + Log.e("Error parsing terrain value", e); + } } // cache difficulty result = BaseUtils.getMatch(tableInside, GCConstants.PATTERN_DIFFICULTY, true, null); if (result != null) { - cache.setDifficulty(Float.parseFloat(StringUtils.replaceChars(result, '_', '.'))); + try { + cache.setDifficulty(Float.parseFloat(StringUtils.replaceChars(result, '_', '.'))); + } catch (NumberFormatException e) { + Log.e("Error parsing difficulty value", e); + } } // owner @@ -432,10 +431,14 @@ public abstract class GCParser { } // favourite - cache.setFavoritePoints(Integer.parseInt(BaseUtils.getMatch(tableInside, GCConstants.PATTERN_FAVORITECOUNT, true, "0"))); + try { + cache.setFavoritePoints(Integer.parseInt(BaseUtils.getMatch(tableInside, GCConstants.PATTERN_FAVORITECOUNT, true, "0"))); + } catch (NumberFormatException e) { + Log.e("Error parsing favourite count", e); + } // cache size - cache.setSize(CacheSize.getById(BaseUtils.getMatch(tableInside, GCConstants.PATTERN_SIZE, true, CacheSize.NOT_CHOSEN.id).toLowerCase())); + cache.setSize(CacheSize.getById(BaseUtils.getMatch(tableInside, GCConstants.PATTERN_SIZE, true, CacheSize.NOT_CHOSEN.id))); } // cache found @@ -503,15 +506,15 @@ public abstract class GCParser { while (matcherAttributesInside.find()) { if (matcherAttributesInside.groupCount() > 1 && !matcherAttributesInside.group(2).equalsIgnoreCase("blank")) { // by default, use the tooltip of the attribute - String attribute = matcherAttributesInside.group(2).toLowerCase(); + String attribute = matcherAttributesInside.group(2).toLowerCase(Locale.US); // if the image name can be recognized, use the image name as attribute - String imageName = matcherAttributesInside.group(1).trim(); - if (imageName.length() > 0) { + final String imageName = matcherAttributesInside.group(1).trim(); + if (StringUtils.isNotEmpty(imageName)) { int start = imageName.lastIndexOf('/'); int end = imageName.lastIndexOf('.'); if (start >= 0 && end >= 0) { - attribute = imageName.substring(start + 1, end).replace('-', '_').toLowerCase(); + attribute = imageName.substring(start + 1, end).replace('-', '_').toLowerCase(Locale.US); } } attributes.add(attribute); @@ -620,7 +623,7 @@ public abstract class GCParser { final String originalCoords = BaseUtils.getMatch(page, GCConstants.PATTERN_LATLON_ORIG, false, null); if (null != originalCoords) { - final cgWaypoint waypoint = new cgWaypoint(cgeoapplication.getInstance().getString(R.string.cache_coordinates_original), WaypointType.WAYPOINT, false); + final cgWaypoint waypoint = new cgWaypoint(cgeoapplication.getInstance().getString(R.string.cache_coordinates_original), WaypointType.ORIGINAL, false); waypoint.setCoords(new Geopoint(originalCoords)); cache.addOrChangeWaypoint(waypoint, false); cache.setUserModifiedCoords(true); @@ -628,10 +631,7 @@ public abstract class GCParser { } catch (Geopoint.GeopointException e) { } - int wpBegin; - int wpEnd; - - wpBegin = page.indexOf("<table class=\"Table\" id=\"ctl00_ContentBody_Waypoints\">"); + int wpBegin = page.indexOf("<table class=\"Table\" id=\"ctl00_ContentBody_Waypoints\">"); if (wpBegin != -1) { // parse waypoints if (CancellableHandler.isCancelled(handler)) { return null; @@ -640,7 +640,7 @@ public abstract class GCParser { String wpList = page.substring(wpBegin); - wpEnd = wpList.indexOf("</p>"); + int wpEnd = wpList.indexOf("</p>"); if (wpEnd > -1 && wpEnd <= wpList.length()) { wpList = wpList.substring(0, wpEnd); } @@ -657,9 +657,8 @@ public abstract class GCParser { final String[] wpItems = wpList.split("<tr"); - String[] wp; for (int j = 1; j < wpItems.length; j++) { - wp = wpItems[j].split("<td"); + String[] wp = wpItems[j].split("<td"); // waypoint name // res is null during the unit tests @@ -750,7 +749,7 @@ public abstract class GCParser { final SearchResult searchResult = parseSearch(url, page, showCaptcha); if (searchResult == null || CollectionUtils.isEmpty(searchResult.getGeocodes())) { - Log.e("GCParser.searchByNextPage: No cache parsed"); + Log.w("GCParser.searchByNextPage: No cache parsed"); return search; } @@ -917,7 +916,7 @@ public abstract class GCParser { trackable = parseTrackable(page, geocode); if (trackable == null) { - Log.e("GCParser.searchTrackable: No trackable parsed"); + Log.w("GCParser.searchTrackable: No trackable parsed"); return null; } @@ -1052,7 +1051,7 @@ public abstract class GCParser { Log.i("Log successfully posted to cache #" + cacheid); if (geocode != null) { - cgeoapplication.getInstance().saveVisitDate(geocode); + cgData.saveVisitDate(geocode); } Login.getLoginStatus(page); @@ -1250,8 +1249,6 @@ public abstract class GCParser { * * @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 */ static cgTrackable parseTrackable(final String page, final String possibleTrackingcode) { @@ -1267,7 +1264,7 @@ public abstract class GCParser { final cgTrackable trackable = new cgTrackable(); // trackable geocode - trackable.setGeocode(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GEOCODE, true, trackable.getGeocode()).toUpperCase()); + trackable.setGeocode(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GEOCODE, true, trackable.getGeocode())); // trackable id trackable.setGuid(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GUID, true, trackable.getGuid())); @@ -1398,7 +1395,8 @@ public abstract class GCParser { } // 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)); + final String logEntry = matcherLogs.group(0); + final Matcher matcherLogImages = GCConstants.PATTERN_TRACKABLE_LOG_IMAGES.matcher(logEntry); /* * 1. Image URL * 2. Image title @@ -1421,7 +1419,7 @@ public abstract class GCParser { } if (cgeoapplication.getInstance() != null) { - cgeoapplication.getInstance().saveTrackable(trackable); + cgData.saveTrackable(trackable); } return trackable; @@ -1560,10 +1558,13 @@ public abstract class GCParser { 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)); + try { + int type = Integer.parseInt(typeMatcher.group(2)); + if (type > 0) { + types.add(LogType.getById(type)); + } + } catch (NumberFormatException e) { + Log.e("Error parsing log types", e); } } } @@ -1673,4 +1674,48 @@ public abstract class GCParser { } } + public static boolean uploadModifiedCoordinates(cgCache cache, Geopoint wpt) { + return editModifiedCoordinates(cache, wpt); + } + + public static boolean deleteModifiedCoordinates(cgCache cache) { + return editModifiedCoordinates(cache, null); + } + + public static boolean editModifiedCoordinates(cgCache cache, Geopoint wpt) { + final String page = requestHtmlPage(cache.getGeocode(), null, "n", "0"); + final String userToken = BaseUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, ""); + if (StringUtils.isEmpty(userToken)) { + return false; + } + + try { + JSONObject jo; + if (wpt != null) { + jo = new JSONObject().put("dto", (new JSONObject().put("ut", userToken) + .put("data", new JSONObject() + .put("lat", wpt.getLatitudeE6() / 1E6) + .put("lng", wpt.getLongitudeE6() / 1E6)))); + } else { + jo = new JSONObject().put("dto", (new JSONObject().put("ut", userToken))); + } + + final String uriSuffix = wpt != null ? "SetUserCoordinate" : "ResetUserCoordinate"; + + final String uriPrefix = "http://www.geocaching.com/seek/cache_details.aspx/"; + HttpResponse response = Network.postJsonRequest(uriPrefix + uriSuffix, jo); + Log.i("Sending to " + uriPrefix + uriSuffix + " :" + jo.toString()); + + if (response != null && response.getStatusLine().getStatusCode() == 200) { + Log.i("GCParser.editModifiedCoordinates - edited on GC.com"); + return true; + } + + } catch (JSONException e) { + Log.e("Unknown exception with json wrap code", e); + } + Log.e("GCParser.deleteModifiedCoordinates - cannot delete modified coords"); + return false; + } + } diff --git a/main/src/cgeo/geocaching/connector/gc/GCSmiliesProvider.java b/main/src/cgeo/geocaching/connector/gc/GCSmiliesProvider.java index 1083a89..eba9301 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCSmiliesProvider.java +++ b/main/src/cgeo/geocaching/connector/gc/GCSmiliesProvider.java @@ -26,7 +26,7 @@ public class GCSmiliesProvider { public final String text; - private Smiley(final String text) { + Smiley(final String text) { this.text = text; } diff --git a/main/src/cgeo/geocaching/connector/gc/IconDecoder.java b/main/src/cgeo/geocaching/connector/gc/IconDecoder.java index 74e78cc..1452157 100644 --- a/main/src/cgeo/geocaching/connector/gc/IconDecoder.java +++ b/main/src/cgeo/geocaching/connector/gc/IconDecoder.java @@ -11,106 +11,191 @@ import android.graphics.Bitmap; */ public abstract class IconDecoder { - public static void parseMapPNG(final cgCache cache, Bitmap bitmap, UTFGridPosition xy, int zoomlevel) { + public static boolean parseMapPNG(final cgCache cache, Bitmap bitmap, UTFGridPosition xy, int zoomlevel) { if (zoomlevel >= 14) { - parseMapPNG14(cache, bitmap, xy); - } else { - parseMapPNG13(cache, bitmap, xy); + return parseMapPNG14(cache, bitmap, xy); } + if (zoomlevel <= 11) { + return parseMapPNG11(cache, bitmap, xy); + } + return parseMapPNG13(cache, bitmap, xy); } - private static final int[] OFFSET_X = new int[] { 0, -1, -1, 0, 1, 1, 1, 0, -1, -2, -2, -2, -2, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2 }; - private static final int[] OFFSET_Y = new int[] { 0, 0, 1, 1, 1, 0, -1, -1, -1, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2, -2, -2, -2 }; + public static int CT_TRADITIONAL = 0; + public static int CT_MULTI = 1; + public static int CT_MYSTERY = 2; + public static int CT_EVENT = 3; + public static int CT_VIRTUAL = 4; + public static int CT_FOUND = 5; + public static int CT_OWN = 6; + public static int CT_MEGAEVENT = 7; + public static int CT_CITO = 8; + public static int CT_WEBCAM = 9; + public static int CT_WHEREIGO = 10; + public static int CT_EARTH = 11; + public static int CT_LETTERBOX = 12; /** - * The icon decoder walks a spiral around the center pixel position of the cache - * and searches for characteristic colors. + * The icon decoder over all 16 pixels of image . It should not be invoked on any part of image that might overlay + * with other caches. + * Is uses decision tree to determine right type. * * @param cache * @param bitmap * @param xy + * @return true if parsing was successful */ - private static void parseMapPNG13(final cgCache cache, Bitmap bitmap, UTFGridPosition xy) { - final int xCenter = xy.getX() * 4 + 2; - final int yCenter = xy.getY() * 4 + 2; + private static boolean parseMapPNG13(final cgCache cache, Bitmap bitmap, UTFGridPosition xy) { + final int topX = xy.getX() * 4; + final int topY = xy.getY() * 4; final int bitmapWidth = bitmap.getWidth(); final int bitmapHeight = bitmap.getHeight(); - int countMulti = 0; - int countFound = 0; + if ((topX < 0) || (topY < 0) || (topX + 4 > bitmapWidth) || (topY + 4 > bitmapHeight)) { + return false; //out of image position + } - for (int i = 0; i < OFFSET_X.length; i++) { + int[] pngType = new int[7]; + for (int x = topX; x < topX + 4; x++) { + for (int y = topY; y < topY + 4; y++) { + int color = bitmap.getPixel(x, y); - // assert that we are still in the tile - final int x = xCenter + OFFSET_X[i]; - if (x < 0 || x >= bitmapWidth) { - continue; - } - - final int y = yCenter + OFFSET_Y[i]; - if (y < 0 || y >= bitmapHeight) { - continue; - } + if ((color & 0xFFFFFF) == 0x5f5f5f) { + continue; //Border in every icon is the same and therefore no use to us + } + if ((color >>> 24) != 255) { + continue; //transparent pixels (or semi_transparent) are only shadows of border + } - int color = bitmap.getPixel(x, y) & 0x00FFFFFF; + int red = (color & 0xFF0000) >> 16; + int green = (color & 0xFF00) >> 8; + int blue = color & 0xFF; - // transparent pixels are not interesting - if (color == 0) { - continue; + int type = getCacheTypeFromPixel13(red, green, blue); + pngType[type]++; } + } - int red = (color & 0xFF0000) >> 16; - int green = (color & 0xFF00) >> 8; - int blue = color & 0xFF; + int type = -1; + int count = 0; - // these are quite sure, so one pixel is enough for matching - if (green > 0x80 && green > red && green > blue) { - cache.setType(CacheType.TRADITIONAL); - return; - } - if (blue > 0x80 && blue > red && blue > green) { - cache.setType(CacheType.MYSTERY); - return; - } - if (red > 0x90 && blue < 0x10 && green < 0x10) { - cache.setType(CacheType.EVENT); - return; + for (int x = 0; x < 7; x++) + { + if (pngType[x] > count) { + count = pngType[x]; + type = x; } + } - // next two are hard to distinguish, therefore we sample all pixels of the spiral - if (red > 0xFA && green > 0xD0) { - countMulti++; + if (count > 1) { // 2 pixels need to detect same type and we say good to go + switch (type) { + case 0: + cache.setType(CacheType.TRADITIONAL); + return true; + case 1: + cache.setType(CacheType.MULTI); + return true; + case 2: + cache.setType(CacheType.MYSTERY); //mystery, whereigo, groundspeak HQ and mystery is most common + return true; + case 3: + cache.setType(CacheType.EVENT); //event, cito, mega-event and event is most common + return true; + case 4: + cache.setType(CacheType.EARTH); //It's an image of ghost (webcam, earth, virtual) and earth in most common + return true; + case 5: + cache.setFound(true); + return true; + case 6: + cache.setOwn(true); + return true; } - if (red < 0xF3 && red > 0xa0 && green > 0x20 && blue < 0x80) { - countFound++; + } + return false; + } + + /** + * The icon decoder over all 16 pixels of image . It should not be invoked on any part of image that might overlay + * with other caches. + * Is uses decision tree to determine right type. + * + * @param cache + * @param bitmap + * @param xy + * @return true if parsing was successful + */ + private static boolean parseMapPNG11(final cgCache cache, Bitmap bitmap, UTFGridPosition xy) { + final int topX = xy.getX() * 4; + final int topY = xy.getY() * 4; + final int bitmapWidth = bitmap.getWidth(); + final int bitmapHeight = bitmap.getHeight(); + + if ((topX < 0) || (topY < 0) || (topX + 4 > bitmapWidth) || (topY + 4 > bitmapHeight)) { + return false; //out of image position + } + + int[] pngType = new int[5]; + for (int x = topX; x < topX + 4; x++) { + for (int y = topY; y < topY + 4; y++) { + int color = bitmap.getPixel(x, y); + + + if ((color >>> 24) != 255) { + continue; //transparent pixels (or semi_transparent) are only shadows of border + } + + int r = (color & 0xFF0000) >> 16; + int g = (color & 0xFF00) >> 8; + int b = color & 0xFF; + + //Duplicate colors does not add any value + if (((r == 52) && (g == 52) && (b == 52)) || + ((r == 69) && (g == 69) && (b == 69)) || + ((r == 90) && (g == 90) && (b == 90)) || + ((r == 233) && (g == 233) && (b == 234)) || + ((r == 255) && (g == 255) && (b == 255))) { + continue; + } + + int type = getCacheTypeFromPixel11(r, g, b); + pngType[type]++; } } - // now check whether we are sure about found/multi - if (countFound > countMulti && countFound >= 2) { - cache.setFound(true); + int type = -1; + int count = 0; + + for (int x = 0; x < 5; x++) + { + if (pngType[x] > count) { + count = pngType[x]; + type = x; + } } - if (countMulti > countFound && countMulti >= 5) { - cache.setType(CacheType.MULTI); + + if (count > 1) { // 2 pixels need to detect same type and we say good to go + switch (type) { + case 0: + cache.setType(CacheType.TRADITIONAL); + return true; + case 1: + cache.setType(CacheType.MULTI); + return true; + case 2: + cache.setType(CacheType.MYSTERY); //mystery, whereigo, groundspeak HQ and mystery is most common + return true; + case 3: + cache.setType(CacheType.EVENT); //event, cito, mega-event and event is most common + return true; + case 4: + cache.setType(CacheType.EARTH); //webcam, earth, virtual and earth in most common + return true; + } } + return false; } - // Pixel colors in tile - private final static int COLOR_BORDER_GRAY = 0x5F5F5F; - private final static int COLOR_TRADITIONAL = 0x316013; - private final static int COLOR_MYSTERY = 0x243C97; - private final static int COLOR_MULTI = 0xFFDE19; - private final static int COLOR_FOUND = 0xFBEA5D; - - // Offset inside cache icon - private final static int POSX_TRADI = 7; - private final static int POSY_TRADI = -12; - private final static int POSX_MULTI = 5; // for orange 8 - private final static int POSY_MULTI = -9; // for orange 10 - private final static int POSX_MYSTERY = 5; - private final static int POSY_MYSTERY = -13; - private final static int POSX_FOUND = 10; - private final static int POSY_FOUND = -8; /** * For level 14 find the borders of the icons and then use a single pixel and color to match. @@ -119,44 +204,376 @@ public abstract class IconDecoder { * @param bitmap * @param xy */ - private static void parseMapPNG14(cgCache cache, Bitmap bitmap, UTFGridPosition xy) { - int x = xy.getX() * 4 + 2; - int y = xy.getY() * 4 + 2; + private static boolean parseMapPNG14(cgCache cache, Bitmap bitmap, UTFGridPosition xy) { + final int topX = xy.getX() * 4; + final int topY = xy.getY() * 4; + final int bitmapWidth = bitmap.getWidth(); + final int bitmapHeight = bitmap.getHeight(); + + if ((topX < 0) || (topY < 0) || (topX + 4 > bitmapWidth) || (topY + 4 > bitmapHeight)) { + return false; //out of image position + } + + int[] pngType = new int[13]; + for (int x = topX; x < topX + 4; x++) { + for (int y = topY; y < topY + 4; y++) { + int color = bitmap.getPixel(x, y); + + if ((color & 0xFFFFFF) == 0x5f5f5f) { + continue; //Border in every icon is the same and therefore no use to us + } + if ((color >>> 24) != 255) { + continue; //transparent pixels (or semi_transparent) are only shadows of border + } + + int r = (color & 0xFF0000) >> 16; + int g = (color & 0xFF00) >> 8; + int b = color & 0xFF; + + //Duplicate colors does not add any value + if (((r == 216) && (g == 216) && (b == 216)) || + ((r == 23) && (g == 23) && (b == 23)) || + ((r == 240) && (g == 240) && (b == 240)) || + ((r == 44) && (g == 44) && (b == 44)) || + ((r == 228) && (g == 228) && (b == 228)) || + ((r == 225) && (g == 225) && (b == 225)) || + ((r == 199) && (g == 199) && (b == 199)) || + ((r == 161) && (g == 161) && (b == 161)) || + ((r == 8) && (g == 8) && (b == 8)) || + ((r == 200) && (g == 200) && (b == 200)) || + ((r == 255) && (g == 255) && (b == 255)) || + ((r == 250) && (g == 250) && (b == 250)) || + ((r == 95) && (g == 95) && (b == 95)) || + ((r == 236) && (g == 236) && (b == 236)) || + ((r == 215) && (g == 215) && (b == 215)) || + ((r == 232) && (g == 232) && (b == 232)) || + ((r == 217) && (g == 217) && (b == 217)) || + ((r == 0) && (g == 0) && (b == 0)) || + ((r == 167) && (g == 167) && (b == 167)) || + ((r == 247) && (g == 247) && (b == 247)) || + ((r == 144) && (g == 144) && (b == 144)) || + ((r == 231) && (g == 231) && (b == 231)) || + ((r == 248) && (g == 248) && (b == 248))) { + continue; + } - // search for left border - int countX = 0; - while ((bitmap.getPixel(x, y) & 0x00FFFFFF) != COLOR_BORDER_GRAY) { - if (--x < 0 || ++countX > 20) { - return; + int type = getCacheTypeFromPixel14(r, g, b); + pngType[type]++; } } - // search for bottom border - int countY = 0; - while ((bitmap.getPixel(x, y) & 0x00FFFFFF) != 0x000000) { - if (++y >= Tile.TILE_SIZE || ++countY > 20) { - return; + + int type = -1; + int count = 0; + + for (int x = 0; x < 7; x++) + { + if (pngType[x] > count) { + count = pngType[x]; + type = x; + } + } + /* + * public static int CT_MEGAEVENT = 7; + * public static int CT_CITO = 8; + * public static int CT_WEBCAM = 9; + * public static int CT_WHEREIGO = 10; + * public static int CT_EARTH = 11; + * public static int CT_LETTERBOX = 12; + */ + if (count > 1) { // 2 pixels need to detect same type and we say good to go + switch (type) { + case 0: + cache.setType(CacheType.TRADITIONAL); + return true; + case 1: + cache.setType(CacheType.MULTI); + return true; + case 2: + cache.setType(CacheType.MYSTERY); + return true; + case 3: + cache.setType(CacheType.EVENT); + return true; + case 4: + cache.setType(CacheType.VIRTUAL); + return true; + case 5: + cache.setFound(true); + return true; + case 6: + cache.setOwn(true); + return true; + case 7: + cache.setType(CacheType.MEGA_EVENT); + return true; + case 8: + cache.setType(CacheType.CITO); + return true; + case 9: + cache.setType(CacheType.WEBCAM); + return true; + case 10: + cache.setType(CacheType.WHERIGO); + return true; + case 11: + cache.setType(CacheType.EARTH); + return true; + case 12: + cache.setType(CacheType.LETTERBOX); + return true; + } + } + return false; + + } + + /** + * This method returns detected type from specific pixel from geocaching.com live map. + * It was constructed based on classification tree made by Orange (http://orange.biolab.si/) + * Input file was made from every non-transparent pixel of every possible "middle" cache icon from GC map + * + * @param r + * Red component of pixel (from 0 - 255) + * @param g + * Green component of pixel (from 0 - 255) + * @param b + * Blue component of pixel (from 0 - 255) + * @return Value from 0 to 6 representing detected type or state of the cache. + */ + private static int getCacheTypeFromPixel13(int r, int g, int b) { + if (g < 110) { + if (r > 87) { + return ((g > 73) && (b < 63)) ? CT_FOUND : CT_EVENT; + } + return CT_MYSTERY; + } + if (b > 137) { + if ((r < 184) && (g > 190)) { + return CT_TRADITIONAL; + } + if ((r < 184) && (g < 191) && (r < 136)) { + return CT_MYSTERY; } + return CT_VIRTUAL; } + if (r < 158) { + return ((r > 129) && (r < 153)) ? CT_FOUND : CT_TRADITIONAL; + } + if (b > 33) { + if (b > 57) { + if (b > 100) { + return (r > 229) ? CT_MULTI : CT_EVENT; + } + return ((r > 254) && (g < 236)) ? CT_MULTI : CT_FOUND; + } + if ((g > 173) && ((g < 224))) { + return ((r < 243) && (r > 223)) ? CT_FOUND : CT_OWN; + } + return CT_FOUND; + } + return CT_MULTI; + } - try { - if ((bitmap.getPixel(x + POSX_TRADI, y + POSY_TRADI) & 0x00FFFFFF) == COLOR_TRADITIONAL) { - cache.setType(CacheType.TRADITIONAL); - return; + /** + * This method returns detected type from specific pixel from geocaching.com live map level 14 or higher. + * It was constructed based on classification tree made by Orange (http://orange.biolab.si/) + * Input file was made from every non-transparent pixel of every possible "full" cache icon from GC map + * + * @param r + * Red component of pixel (from 0 - 255) + * @param g + * Green component of pixel (from 0 - 255) + * @param b + * Blue component of pixel (from 0 - 255) + * @return Value from 0 to 6 representing detected type or state of the cache. + */ + private static int getCacheTypeFromPixel14(int r, int g, int b) { + if (b < 140) { + if (r > 155) { + if (g < 159) { + if (r < 173) { + return (r > 161) ? CT_MEGAEVENT : CT_OWN; + } + if (r < 206) { + if (b > 49) { + return (b > 83) ? CT_EVENT : CT_FOUND; + } + return (b < 31) ? CT_EARTH : CT_FOUND; + } + return (r < 221) ? CT_FOUND : CT_MULTI; + } + if (r > 210) { + if (g < 188) { + return CT_FOUND; + } + if (r < 246) { + return CT_OWN; + } + if (r < 254) { + return CT_FOUND; + } + if (r < 255) { + return CT_EVENT; + } + if (g < 208) { + return CT_EARTH; + } + if (g > 225) { + return CT_EARTH; + } + return (b < 36) ? CT_MULTI : CT_OWN; + } + return (b < 66) ? CT_OWN : CT_EARTH; + } + if (r < 63) { + if (b > 26) { + if (b < 29) { + return CT_WEBCAM; + } + if (g > 102) { + return CT_CITO; + } + return (r < 26) ? CT_CITO : CT_WEBCAM; + } + if (g < 38) { + return CT_WEBCAM; + } + return (r < 41) ? CT_EARTH : CT_TRADITIONAL; + } + if (b < 119) { + if (g < 81) { + return CT_WEBCAM; + } + if (b < 90) { + return CT_OWN; + } + return (r < 104) ? CT_WEBCAM : CT_OWN; + } + if (r < 132) { + return (b < 124) ? CT_MULTI : CT_WHEREIGO; + } + if (g > 164) { + return CT_TRADITIONAL; + } + if (b < 134) { + return CT_OWN; + } + return (b > 137) ? CT_OWN : CT_WHEREIGO; + } + if (b < 245) { + if (r < 180) { + if (b < 218) { + if (g < 71) { + return CT_MYSTERY; + } + if (r < 96) { + return CT_WHEREIGO; + } + if (b > 165) { + return CT_WHEREIGO; + } + if (r < 153) { + return CT_WHEREIGO; + } + if (r < 160) { + return CT_WEBCAM; + } + return (r < 162) ? CT_WHEREIGO : CT_WEBCAM; + } + return (r < 158) ? CT_MEGAEVENT : CT_EARTH; } - if ((bitmap.getPixel(x + POSX_MYSTERY, y + POSY_MYSTERY) & 0x00FFFFFF) == COLOR_MYSTERY) { - cache.setType(CacheType.MYSTERY); - return; + if (g > 232) { + if (g > 247) { + return CT_CITO; + } + if (r < 237) { + return CT_OWN; + } + if (g < 238) { + return CT_OWN; + } + if (r > 243) { + return CT_WEBCAM; + } + return (g > 238) ? CT_OWN : CT_WEBCAM; } - if ((bitmap.getPixel(x + POSX_MULTI, y + POSY_MULTI) & 0x00FFFFFF) == COLOR_MULTI) { - cache.setType(CacheType.MULTI); - return; + if (r < 228) { + if (b > 238) { + return CT_MYSTERY; + } + if (r < 193) { + if (r < 184) { + return CT_OWN; + } + if (g < 186) { + return CT_WHEREIGO; + } + return (r > 189) ? CT_WHEREIGO : CT_OWN; + } + if (g < 223) { + if (r > 216) { + return CT_OWN; + } + if (g > 217) { + return CT_WHEREIGO; + } + if (b > 211) { + return CT_WEBCAM; + } + if (b < 196) { + return CT_WEBCAM; + } + if (r > 210) { + return CT_OWN; + } + return (g > 206) ? CT_WHEREIGO : CT_OWN; + } + if (g < 224) { + return CT_OWN; + } + return (r < 226) ? CT_WHEREIGO : CT_OWN; } - if ((bitmap.getPixel(x + POSX_FOUND, y + POSY_FOUND) & 0x00FFFFFF) == COLOR_FOUND) { - cache.setFound(true); + return (b < 216) ? CT_FOUND : CT_OWN; + } + if (r < 238) { + if (r > 141) { + return (r > 185) ? CT_LETTERBOX : CT_CITO; } - } catch (IllegalArgumentException e) { - // intentionally left blank + return (r < 41) ? CT_EARTH : CT_LETTERBOX; } + return (r < 243) ? CT_WHEREIGO : CT_OWN; + } + /** + * This method returns detected type from specific pixel from geocaching.com live map level 11 or lower. + * It was constructed based on classification tree made by Orange (http://orange.biolab.si/) + * Input file was made from every non-transparent pixel of every possible "full" cache icon from GC map + * + * @param r + * Red component of pixel (from 0 - 255) + * @param g + * Green component of pixel (from 0 - 255) + * @param b + * Blue component of pixel (from 0 - 255) + * @return Value from 0 to 4 representing detected type or state of the cache. + */ + private static int getCacheTypeFromPixel11(int r, int g, int b) { + if (b < 139) { + if (g > 104) { + if (r < 173) { + return CT_TRADITIONAL; + } + return (r > 225) ? CT_MULTI : CT_EVENT; + } + if (b < 25) { + return CT_EVENT; + } + return (r < 87) ? CT_MYSTERY : CT_EVENT; + } + if (r > 140) { + return (r < 197) ? CT_TRADITIONAL : CT_VIRTUAL; + } + return CT_MYSTERY; } + } diff --git a/main/src/cgeo/geocaching/connector/gc/Login.java b/main/src/cgeo/geocaching/connector/gc/Login.java index c3f29cc..494bcee 100644 --- a/main/src/cgeo/geocaching/connector/gc/Login.java +++ b/main/src/cgeo/geocaching/connector/gc/Login.java @@ -361,14 +361,13 @@ public abstract class Login { String[] viewstates = new String[count]; // Get the viewstates - int no; final Matcher matcherViewstates = GCConstants.PATTERN_VIEWSTATES.matcher(page); while (matcherViewstates.find()) { String sno = matcherViewstates.group(1); // number of viewstate - if (sno.length() == 0) { + int no; + if (StringUtils.isEmpty(sno)) { no = 0; - } - else { + } else { try { no = Integer.parseInt(sno); } catch (NumberFormatException e) { diff --git a/main/src/cgeo/geocaching/connector/gc/Tile.java b/main/src/cgeo/geocaching/connector/gc/Tile.java index 5404446..73ded4d 100644 --- a/main/src/cgeo/geocaching/connector/gc/Tile.java +++ b/main/src/cgeo/geocaching/connector/gc/Tile.java @@ -17,6 +17,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; +import java.util.Locale; import java.util.Set; /** @@ -99,7 +100,7 @@ public class Tile { /** * Calculate latitude/longitude for a given x/y position in this tile. - * + * * @see <a * href="http://developers.cloudmade.com/projects/tiles/examples/convert-coordinates-to-tile-numbers">Cloudmade</a> */ @@ -115,7 +116,7 @@ public class Tile { @Override public String toString() { - return String.format("(%d/%d), zoom=%d", tileX, tileY, zoomlevel); + return String.format(Locale.US, "(%d/%d), zoom=%d", tileX, tileY, zoomlevel); } /** diff --git a/main/src/cgeo/geocaching/connector/gc/UTFGrid.java b/main/src/cgeo/geocaching/connector/gc/UTFGrid.java index a4eeff5..6d20eb6 100644 --- a/main/src/cgeo/geocaching/connector/gc/UTFGrid.java +++ b/main/src/cgeo/geocaching/connector/gc/UTFGrid.java @@ -29,7 +29,7 @@ public final class UTFGrid { } /** Calculate from a list of positions (x/y) the coords */ - protected static UTFGridPosition getPositionInGrid(List<UTFGridPosition> positions) { + public static UTFGridPosition getPositionInGrid(List<UTFGridPosition> positions) { int minX = GRID_MAXX; int maxX = 0; int minY = GRID_MAXY; diff --git a/main/src/cgeo/geocaching/connector/oc/OCConnector.java b/main/src/cgeo/geocaching/connector/oc/OCConnector.java index 34bf019..c098d12 100644 --- a/main/src/cgeo/geocaching/connector/oc/OCConnector.java +++ b/main/src/cgeo/geocaching/connector/oc/OCConnector.java @@ -33,7 +33,7 @@ public class OCConnector extends AbstractConnector { @Override public String getCacheUrl(cgCache cache) { - return "http://" + host + "/viewcache.php?wp=" + cache.getGeocode(); + return getCacheUrlPrefix() + cache.getGeocode(); } @Override @@ -45,4 +45,10 @@ public class OCConnector extends AbstractConnector { public boolean isZippedGPXFile(String fileName) { return gpxZipFilePattern.matcher(fileName).matches(); } + + @Override + protected String getCacheUrlPrefix() { + return "http://" + host + "/viewcache.php?wp="; + } + } diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java index 87cc3a1..1121cc5 100644 --- a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java +++ b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java @@ -2,8 +2,8 @@ package cgeo.geocaching.connector.oc; import cgeo.geocaching.LogEntry; import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgData; import cgeo.geocaching.cgImage; -import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.IConnector; import cgeo.geocaching.enumerations.CacheSize; @@ -153,9 +153,8 @@ final public class OkapiClient { final JSONArray images = response.getJSONArray(CACHE_IMAGES); if (images != null) { - JSONObject imageResponse; for (int i = 0; i < images.length(); i++) { - imageResponse = images.getJSONObject(i); + JSONObject imageResponse = images.getJSONObject(i); if (imageResponse.getBoolean(CACHE_IMAGE_IS_SPOILER)) { final String title = imageResponse.getString(CACHE_IMAGE_CAPTION); final String url = absoluteUrl(imageResponse.getString(CACHE_IMAGE_URL), cache.getGeocode()); @@ -171,9 +170,8 @@ final public class OkapiClient { cache.setUpdated(System.currentTimeMillis()); cache.setDetailedUpdate(cache.getUpdated()); cache.setDetailed(true); - // save full detailed caches - cgeoapplication.getInstance().saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); + cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); } catch (JSONException e) { Log.e("OkapiClient.parseCache", e); } diff --git a/main/src/cgeo/geocaching/connector/ox/OXConnector.java b/main/src/cgeo/geocaching/connector/ox/OXConnector.java index 38bb496..98b1656 100644 --- a/main/src/cgeo/geocaching/connector/ox/OXConnector.java +++ b/main/src/cgeo/geocaching/connector/ox/OXConnector.java @@ -27,7 +27,7 @@ public class OXConnector extends AbstractConnector implements ISearchByCenter, I @Override public String getCacheUrl(cgCache cache) { - return "http://www.opencaching.com/#!geocache/" + cache.getGeocode(); + return getCacheUrlPrefix() + cache.getGeocode(); } @Override @@ -64,4 +64,9 @@ public class OXConnector extends AbstractConnector implements ISearchByCenter, I } return new SearchResult(caches); } + + @Override + protected String getCacheUrlPrefix() { + return "http://www.opencaching.com/#!geocache/"; + } } diff --git a/main/src/cgeo/geocaching/enumerations/CacheAttribute.java b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java index a31b0cc..01d76f5 100644 --- a/main/src/cgeo/geocaching/enumerations/CacheAttribute.java +++ b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java @@ -88,7 +88,7 @@ public enum CacheAttribute { 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) { + 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; @@ -110,15 +110,6 @@ public enum CacheAttribute { 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) { diff --git a/main/src/cgeo/geocaching/enumerations/CacheSize.java b/main/src/cgeo/geocaching/enumerations/CacheSize.java index 155c9a5..726ebe2 100644 --- a/main/src/cgeo/geocaching/enumerations/CacheSize.java +++ b/main/src/cgeo/geocaching/enumerations/CacheSize.java @@ -5,6 +5,7 @@ import cgeo.geocaching.cgeoapplication; import java.util.Collections; import java.util.HashMap; +import java.util.Locale; import java.util.Map; /** @@ -24,7 +25,7 @@ public enum CacheSize { public final int comparable; private final int stringId; - private CacheSize(String id, int comparable, int stringId) { + CacheSize(String id, int comparable, int stringId) { this.id = id; this.comparable = comparable; this.stringId = stringId; @@ -34,7 +35,7 @@ public enum CacheSize { static { final HashMap<String, CacheSize> mapping = new HashMap<String, CacheSize>(); for (CacheSize cs : values()) { - mapping.put(cs.id.toLowerCase(), cs); + mapping.put(cs.id.toLowerCase(Locale.US), cs); } // add medium as additional string for Regular mapping.put("medium", CacheSize.REGULAR); @@ -51,7 +52,7 @@ public enum CacheSize { return result; } // only if String was not found, normalize it - final CacheSize resultNormalized = CacheSize.FIND_BY_ID.get(id.toLowerCase().trim()); + final CacheSize resultNormalized = CacheSize.FIND_BY_ID.get(id.toLowerCase(Locale.US).trim()); if (resultNormalized != null) { return resultNormalized; } diff --git a/main/src/cgeo/geocaching/enumerations/CacheType.java b/main/src/cgeo/geocaching/enumerations/CacheType.java index 730c989..028b2b1 100644 --- a/main/src/cgeo/geocaching/enumerations/CacheType.java +++ b/main/src/cgeo/geocaching/enumerations/CacheType.java @@ -5,6 +5,7 @@ import cgeo.geocaching.cgeoapplication; import java.util.Collections; import java.util.HashMap; +import java.util.Locale; import java.util.Map; /** @@ -44,7 +45,7 @@ public enum CacheType { private final int stringId; public final int markerId; - private CacheType(String id, String pattern, String guid, int stringId, int markerId) { + CacheType(String id, String pattern, String guid, int stringId, int markerId) { this.id = id; this.pattern = pattern; this.guid = guid; @@ -59,14 +60,14 @@ public enum CacheType { final HashMap<String, CacheType> mappingPattern = new HashMap<String, CacheType>(); for (CacheType ct : values()) { mappingId.put(ct.id, ct); - mappingPattern.put(ct.pattern.toLowerCase(), ct); + mappingPattern.put(ct.pattern.toLowerCase(Locale.US), ct); } FIND_BY_ID = Collections.unmodifiableMap(mappingId); FIND_BY_PATTERN = Collections.unmodifiableMap(mappingPattern); } public static CacheType getById(final String id) { - final CacheType result = (id != null) ? CacheType.FIND_BY_ID.get(id.toLowerCase().trim()) : null; + final CacheType result = (id != null) ? CacheType.FIND_BY_ID.get(id.toLowerCase(Locale.US).trim()) : null; if (result == null) { return UNKNOWN; } @@ -74,7 +75,7 @@ public enum CacheType { } public static CacheType getByPattern(final String pattern) { - final CacheType result = (pattern != null) ? CacheType.FIND_BY_PATTERN.get(pattern.toLowerCase().trim()) : null; + final CacheType result = (pattern != null) ? CacheType.FIND_BY_PATTERN.get(pattern.toLowerCase(Locale.US).trim()) : null; if (result == null) { return UNKNOWN; } diff --git a/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java b/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java index e9dbc5d..5f5b2c9 100644 --- a/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java +++ b/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java @@ -26,7 +26,7 @@ public interface LiveMapStrategy { public final EnumSet<StrategyFlag> flags; private final int stringId; - private Strategy(int id, EnumSet<StrategyFlag> flags, int stringId) { + Strategy(int id, EnumSet<StrategyFlag> flags, int stringId) { this.id = id; this.flags = flags; this.stringId = stringId; diff --git a/main/src/cgeo/geocaching/enumerations/LocationProviderType.java b/main/src/cgeo/geocaching/enumerations/LocationProviderType.java index 36a09bf..f2c79fe 100644 --- a/main/src/cgeo/geocaching/enumerations/LocationProviderType.java +++ b/main/src/cgeo/geocaching/enumerations/LocationProviderType.java @@ -9,7 +9,7 @@ public enum LocationProviderType { public final int resourceId; - private LocationProviderType(final int resourceId) { + LocationProviderType(final int resourceId) { this.resourceId = resourceId; } } diff --git a/main/src/cgeo/geocaching/enumerations/LogType.java b/main/src/cgeo/geocaching/enumerations/LogType.java index 332ef03..5918fe1 100644 --- a/main/src/cgeo/geocaching/enumerations/LogType.java +++ b/main/src/cgeo/geocaching/enumerations/LogType.java @@ -5,6 +5,7 @@ import cgeo.geocaching.cgeoapplication; import java.util.Collections; import java.util.HashMap; +import java.util.Locale; import java.util.Map; @@ -14,43 +15,50 @@ import java.util.Map; */ public enum LogType { - FOUND_IT(2, "2", "found it", R.string.log_found), - DIDNT_FIND_IT(3, "3", "didn't find it", R.string.log_dnf), + FOUND_IT(2, "2", "found it", R.string.log_found, R.drawable.mark_green), + DIDNT_FIND_IT(3, "3", "didn't find it", R.string.log_dnf, R.drawable.mark_red), NOTE(4, "4", "write note", R.string.log_note), - PUBLISH_LISTING(1003, "24", "publish listing", R.string.log_published), - ENABLE_LISTING(23, "23", "enable listing", R.string.log_enabled), - ARCHIVE(5, "5", "archive", R.string.log_archived), - UNARCHIVE(12, "12", "unarchive", R.string.log_unarchived), - TEMP_DISABLE_LISTING(22, "22", "temporarily disable listing", R.string.log_disabled), - NEEDS_ARCHIVE(7, "7", "needs archived", R.string.log_needs_archived), + PUBLISH_LISTING(1003, "24", "publish listing", R.string.log_published, R.drawable.mark_green_more), + ENABLE_LISTING(23, "23", "enable listing", R.string.log_enabled, R.drawable.mark_green_more), + ARCHIVE(5, "5", "archive", R.string.log_archived, R.drawable.mark_red_more), + UNARCHIVE(12, "12", "unarchive", R.string.log_unarchived, R.drawable.mark_green_more), + TEMP_DISABLE_LISTING(22, "22", "temporarily disable listing", R.string.log_disabled, R.drawable.mark_red_more), + NEEDS_ARCHIVE(7, "7", "needs archived", R.string.log_needs_archived, R.drawable.mark_red), WILL_ATTEND(9, "9", "will attend", R.string.log_attend), - ATTENDED(10, "10", "attended", R.string.log_attended), - RETRIEVED_IT(13, "13", "retrieved it", R.string.log_retrieved), + ATTENDED(10, "10", "attended", R.string.log_attended, R.drawable.mark_green), + RETRIEVED_IT(13, "13", "retrieved it", R.string.log_retrieved, R.drawable.mark_green), PLACED_IT(14, "14", "placed it", R.string.log_placed), - GRABBED_IT(19, "19", "grabbed it", R.string.log_grabbed), - NEEDS_MAINTENANCE(45, "45", "needs maintenance", R.string.log_maintenance_needed), - OWNER_MAINTENANCE(46, "46", "owner maintenance", R.string.log_maintained), + GRABBED_IT(19, "19", "grabbed it", R.string.log_grabbed, R.drawable.mark_green), + NEEDS_MAINTENANCE(45, "45", "needs maintenance", R.string.log_maintenance_needed, R.drawable.mark_red), + OWNER_MAINTENANCE(46, "46", "owner maintenance", R.string.log_maintained, R.drawable.mark_green_more), UPDATE_COORDINATES(47, "47", "update coordinates", R.string.log_update), - DISCOVERED_IT(48, "48", "discovered it", R.string.log_discovered), + DISCOVERED_IT(48, "48", "discovered it", R.string.log_discovered, R.drawable.mark_green), POST_REVIEWER_NOTE(18, "68", "post reviewer note", R.string.log_reviewer), - VISIT(1001, "75", "visit", R.string.log_tb_visit), - WEBCAM_PHOTO_TAKEN(11, "11", "webcam photo taken", R.string.log_webcam), + VISIT(1001, "75", "visit", R.string.log_tb_visit, R.drawable.mark_green), + WEBCAM_PHOTO_TAKEN(11, "11", "webcam photo taken", R.string.log_webcam, R.drawable.mark_green), ANNOUNCEMENT(74, "74", "announcement", R.string.log_announcement), MOVE_COLLECTION(69, "69", "unused_collection", R.string.log_movecollection), MOVE_INVENTORY(70, "70", "unused_inventory", R.string.log_moveinventory), RETRACT(25, "25", "retract listing", R.string.log_retractlisting), - UNKNOWN(0, "unknown", "", R.string.err_unknown); // LogType not init. yet + MARKED_MISSING(16, "16", "marked missing", R.string.log_marked_missing, R.drawable.mark_red), + UNKNOWN(0, "unknown", "", R.string.err_unknown, R.drawable.mark_red); // LogType not init. yet public final int id; public final String iconName; public final String type; private final int stringId; + public final int markerId; - private LogType(int id, String iconName, String type, int stringId) { + LogType(int id, String iconName, String type, int stringId, int markerId) { this.id = id; this.iconName = iconName; this.type = type; this.stringId = stringId; + this.markerId = markerId; + } + + LogType(int id, String iconName, String type, int stringId) { + this(id, iconName, type, stringId, R.drawable.mark_gray); } private final static Map<String, LogType> FIND_BY_ICONNAME; @@ -76,7 +84,7 @@ public enum LogType { } public static LogType getByIconName(final String imageType) { - final LogType result = imageType != null ? LogType.FIND_BY_ICONNAME.get(imageType.toLowerCase().trim()) : null; + final LogType result = imageType != null ? LogType.FIND_BY_ICONNAME.get(imageType.toLowerCase(Locale.US).trim()) : null; if (result == null) { return UNKNOWN; } @@ -84,7 +92,7 @@ public enum LogType { } public static LogType getByType(final String type) { - final LogType result = type != null ? LogType.FIND_BY_TYPE.get(type.toLowerCase().trim()) : null; + final LogType result = type != null ? LogType.FIND_BY_TYPE.get(type.toLowerCase(Locale.US).trim()) : null; if (result == null) { return UNKNOWN; } diff --git a/main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java b/main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java index 13b8d03..68a17a5 100644 --- a/main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java +++ b/main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java @@ -11,7 +11,7 @@ public enum LogTypeTrackable { final public String action; final public int resourceId; - private LogTypeTrackable(int id, String action, int resourceId) { + LogTypeTrackable(int id, String action, int resourceId) { this.id = id; this.action = action; this.resourceId = resourceId; diff --git a/main/src/cgeo/geocaching/enumerations/WaypointType.java b/main/src/cgeo/geocaching/enumerations/WaypointType.java index 52eb318..748c432 100644 --- a/main/src/cgeo/geocaching/enumerations/WaypointType.java +++ b/main/src/cgeo/geocaching/enumerations/WaypointType.java @@ -19,13 +19,14 @@ public enum WaypointType { PUZZLE("puzzle", R.string.wp_puzzle, R.drawable.waypoint_puzzle), STAGE("stage", R.string.wp_stage, R.drawable.waypoint_stage), TRAILHEAD("trailhead", R.string.wp_trailhead, R.drawable.waypoint_trailhead), - WAYPOINT("waypoint", R.string.wp_waypoint, R.drawable.waypoint_waypoint); + WAYPOINT("waypoint", R.string.wp_waypoint, R.drawable.waypoint_waypoint), + ORIGINAL("original", R.string.wp_original, R.drawable.waypoint_waypoint); public final String id; public final int stringId; public final int markerId; - private WaypointType(String id, int stringId, int markerId) { + WaypointType(String id, int stringId, int markerId) { this.id = id; this.stringId = stringId; this.markerId = markerId; @@ -36,13 +37,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 Set<WaypointType> ALL_TYPES_EXCEPT_OWN = new HashSet<WaypointType>(); + public static final Set<WaypointType> ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL = 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.add(wt); + if (wt != WaypointType.OWN && wt != WaypointType.ORIGINAL) { + ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL.add(wt); } } FIND_BY_ID = Collections.unmodifiableMap(mapping); @@ -67,7 +68,6 @@ public enum WaypointType { return cgeoapplication.getInstance().getBaseContext().getResources().getString(stringId); } - @Override public final String toString() { return getL10n(); diff --git a/main/src/cgeo/geocaching/export/FieldnoteExport.java b/main/src/cgeo/geocaching/export/FieldnoteExport.java index 11214db..65dc291 100644 --- a/main/src/cgeo/geocaching/export/FieldnoteExport.java +++ b/main/src/cgeo/geocaching/export/FieldnoteExport.java @@ -3,7 +3,7 @@ package cgeo.geocaching.export; import cgeo.geocaching.LogEntry; import cgeo.geocaching.R; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.cgData; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.activity.Progress; import cgeo.geocaching.connector.gc.Login; @@ -12,7 +12,9 @@ import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.utils.Log; +import org.apache.commons.lang3.CharEncoding; import org.apache.commons.lang3.StringUtils; +import org.mapsforge.core.IOUtils; import android.app.Activity; import android.app.AlertDialog; @@ -31,6 +33,7 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Locale; +import java.util.TimeZone; /** * Exports offline-logs in the Groundspeak Field Note format.<br> @@ -42,6 +45,9 @@ import java.util.Locale; 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'", Locale.US); + static { + fieldNoteDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + } protected FieldnoteExport() { super(getString(R.string.export_fieldnotes)); @@ -135,13 +141,11 @@ class FieldnoteExport extends AbstractExport { @Override protected Boolean doInBackground(Void... params) { final StringBuilder fieldNoteBuffer = new StringBuilder(); - final cgeoapplication app = cgeoapplication.getInstance(); - try { int i = 0; for (cgCache cache : caches) { if (cache.isLogOffline()) { - appendFieldNote(fieldNoteBuffer, cache, app.loadLogOffline(cache.getGeocode())); + appendFieldNote(fieldNoteBuffer, cache, cgData.loadLogOffline(cache.getGeocode())); publishProgress(++i); } } @@ -152,40 +156,30 @@ class FieldnoteExport extends AbstractExport { fieldNoteBuffer.append('\n'); - if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { - exportLocation.mkdirs(); + if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + return false; + } - SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US); - exportFile = new File(exportLocation.toString() + '/' + fileNameDateFormat.format(new Date()) + ".txt"); + exportLocation.mkdirs(); - OutputStream os; - Writer fw = null; - try { - os = new FileOutputStream(exportFile); - fw = new OutputStreamWriter(os, "UTF-16"); - 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 { + SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US); + exportFile = new File(exportLocation.toString() + '/' + fileNameDateFormat.format(new Date()) + ".txt"); + + Writer fw = null; + try { + OutputStream os = new FileOutputStream(exportFile); + fw = new OutputStreamWriter(os, CharEncoding.UTF_16); + fw.write(fieldNoteBuffer.toString()); + } catch (IOException e) { + Log.e("FieldnoteExport.ExportTask export", e); return false; + } finally { + IOUtils.closeQuietly(fw); } if (upload) { publishProgress(STATUS_UPLOAD); - final String uri = "http://www.geocaching.com/my/uploadfieldnotes.aspx"; - if (!Login.isActualLoginStatus()) { // no need to upload (possibly large file) if we're not logged in final StatusCode loginState = Login.login(); @@ -194,6 +188,7 @@ class FieldnoteExport extends AbstractExport { } } + final String uri = "http://www.geocaching.com/my/uploadfieldnotes.aspx"; String page = Network.getResponseData(Network.getRequest(uri)); if (!Login.getLoginStatus(page)) { diff --git a/main/src/cgeo/geocaching/export/GpxExport.java b/main/src/cgeo/geocaching/export/GpxExport.java index 7573db9..3aec114 100644 --- a/main/src/cgeo/geocaching/export/GpxExport.java +++ b/main/src/cgeo/geocaching/export/GpxExport.java @@ -4,8 +4,8 @@ import cgeo.geocaching.LogEntry; import cgeo.geocaching.R; import cgeo.geocaching.Settings; import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgData; import cgeo.geocaching.cgWaypoint; -import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.activity.Progress; import cgeo.geocaching.enumerations.CacheAttribute; @@ -51,7 +51,7 @@ class GpxExport extends AbstractExport { if (null == activity) { // No activity given, so no user interaction possible. // Start export with default parameters. - new ExportTask(caches, activity).execute((Void) null); + new ExportTask(caches, null).execute((Void) null); } else { // Show configuration dialog @@ -143,8 +143,7 @@ class GpxExport extends AbstractExport { 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++) { - // reload the cache. otherwise logs, attributes and other detailed information is not available - final cgCache cache = cgeoapplication.getInstance().loadCache(caches.get(i).getGeocode(), LoadFlags.LOAD_ALL_DB_ONLY); + final cgCache cache = cgData.loadCache(caches.get(i).getGeocode(), LoadFlags.LOAD_ALL_DB_ONLY); gpx.write("<wpt "); gpx.write("lat=\""); diff --git a/main/src/cgeo/geocaching/files/FileList.java b/main/src/cgeo/geocaching/files/FileList.java index df95085..19d3305 100644 --- a/main/src/cgeo/geocaching/files/FileList.java +++ b/main/src/cgeo/geocaching/files/FileList.java @@ -283,8 +283,8 @@ public abstract class FileList<T extends ArrayAdapter<File>> extends AbstractLis private void setExtensions(final String[] extensionsIn) { extensions = extensionsIn; for (int i = 0; i < extensions.length; i++) { - String extension = extensions[i]; - if (extension.length() == 0 || extension.charAt(0) != '.') { + final String extension = extensions[i]; + if (StringUtils.isEmpty(extension) || extension.charAt(0) != '.') { extensions[i] = "." + extension; } } diff --git a/main/src/cgeo/geocaching/files/GPXImporter.java b/main/src/cgeo/geocaching/files/GPXImporter.java index fb78360..750d5e0 100644 --- a/main/src/cgeo/geocaching/files/GPXImporter.java +++ b/main/src/cgeo/geocaching/files/GPXImporter.java @@ -5,7 +5,7 @@ import cgeo.geocaching.SearchResult; import cgeo.geocaching.Settings;
import cgeo.geocaching.StaticMapsProvider;
import cgeo.geocaching.cgCache;
-import cgeo.geocaching.cgeoapplication;
+import cgeo.geocaching.cgData;
import cgeo.geocaching.activity.IAbstractActivity;
import cgeo.geocaching.activity.Progress;
import cgeo.geocaching.enumerations.LoadFlags;
@@ -124,7 +124,7 @@ public class GPXImporter { final Handler importStepHandler;
final CancellableHandler progressHandler;
- public ImportThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ protected ImportThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
this.listId = listId;
this.importStepHandler = importStepHandler;
this.progressHandler = progressHandler;
@@ -132,10 +132,9 @@ public class GPXImporter { @Override
public void run() {
- final Collection<cgCache> caches;
try {
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_START));
- caches = doImport();
+ final Collection<cgCache> caches = doImport();
Log.i("Imported successfully " + caches.size() + " caches.");
final SearchResult search = new SearchResult();
@@ -171,10 +170,9 @@ public class GPXImporter { protected abstract Collection<cgCache> doImport() throws IOException, ParserException;
private boolean importStaticMaps(final SearchResult importedCaches) {
- final cgeoapplication app = cgeoapplication.getInstance();
int storedCacheMaps = 0;
for (String geocode : importedCaches.getGeocodes()) {
- cgCache cache = app.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS);
+ cgCache cache = cgData.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS);
Log.d("GPXImporter.ImportThread.importStaticMaps start downloadMaps for cache " + geocode);
StaticMapsProvider.downloadMaps(cache);
storedCacheMaps++;
@@ -206,7 +204,7 @@ public class GPXImporter { static abstract class ImportGpxThread extends ImportThread {
- public ImportGpxThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ protected ImportGpxThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
super(listId, importStepHandler, progressHandler);
}
@@ -276,7 +274,7 @@ public class GPXImporter { static abstract class ImportGpxZipThread extends ImportGpxThread {
- public ImportGpxZipThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ protected ImportGpxZipThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
super(listId, importStepHandler, progressHandler);
}
diff --git a/main/src/cgeo/geocaching/files/GPXParser.java b/main/src/cgeo/geocaching/files/GPXParser.java index b9d3f53..2ac19bb 100644 --- a/main/src/cgeo/geocaching/files/GPXParser.java +++ b/main/src/cgeo/geocaching/files/GPXParser.java @@ -4,6 +4,7 @@ import cgeo.geocaching.LogEntry; import cgeo.geocaching.R; import cgeo.geocaching.StoredList; import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgData; import cgeo.geocaching.cgTrackable; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.cgeoapplication; @@ -287,7 +288,7 @@ public abstract class GPXParser extends FileParser { // take the name as code, if nothing else is available if (StringUtils.isBlank(cache.getGeocode())) { if (StringUtils.isNotBlank(name)) { - cache.setGeocode(name.trim().toUpperCase()); + cache.setGeocode(name.trim()); } } @@ -311,8 +312,8 @@ public abstract class GPXParser extends FileParser { // finally store the cache in the database result.add(geocode); - cgeoapplication.getInstance().saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); - cgeoapplication.getInstance().removeAllFromCache(); + cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); + cgData.removeAllFromCache(); showProgressMessage(progressHandler, progressStream.getProgress()); } else if (StringUtils.isNotBlank(cache.getName()) && StringUtils.containsIgnoreCase(type, "waypoint")) { @@ -326,10 +327,9 @@ public abstract class GPXParser extends FileParser { fixCache(cache); if (cache.getName().length() > 2) { - final String cacheGeocodeForWaypoint = "GC" + cache.getName().substring(2).toUpperCase(); - + final String cacheGeocodeForWaypoint = "GC" + cache.getName().substring(2).toUpperCase(Locale.US); // lookup cache for waypoint in already parsed caches - final cgCache cacheForWaypoint = cgeoapplication.getInstance().loadCache(cacheGeocodeForWaypoint, LoadFlags.LOAD_CACHE_OR_DB); + final cgCache cacheForWaypoint = cgData.loadCache(cacheGeocodeForWaypoint, LoadFlags.LOAD_CACHE_OR_DB); if (cacheForWaypoint != null) { final cgWaypoint waypoint = new cgWaypoint(cache.getShortdesc(), convertWaypointSym2Type(sym), false); waypoint.setId(-1); @@ -347,7 +347,7 @@ public abstract class GPXParser extends FileParser { newPoints.add(waypoint); cgWaypoint.mergeWayPoints(newPoints, mergedWayPoints, true); cacheForWaypoint.setWaypoints(newPoints, false); - cgeoapplication.getInstance().saveCache(cacheForWaypoint, EnumSet.of(SaveFlag.SAVE_DB)); + cgData.saveCache(cacheForWaypoint, EnumSet.of(SaveFlag.SAVE_DB)); showProgressMessage(progressHandler, progressStream.getProgress()); } } @@ -410,7 +410,7 @@ public abstract class GPXParser extends FileParser { public void end(String body) { final String[] content = body.split("\\|"); if (content.length > 0) { - type = content[0].toLowerCase().trim(); + type = content[0].toLowerCase(Locale.US).trim(); } } }); @@ -420,7 +420,7 @@ public abstract class GPXParser extends FileParser { @Override public void end(final String body) { - sym = body.toLowerCase(); + sym = body.toLowerCase(Locale.US); if (sym.contains("geocache") && sym.contains("found")) { cache.setFound(true); } @@ -526,7 +526,7 @@ public abstract class GPXParser extends FileParser { @Override public void end(String body) { - cache.setType(CacheType.getByPattern(validate(body.toLowerCase()))); + cache.setType(CacheType.getByPattern(validate(body))); } }); @@ -535,7 +535,7 @@ public abstract class GPXParser extends FileParser { @Override public void end(String body) { - cache.setSize(CacheSize.getById(validate(body.toLowerCase()))); + cache.setSize(CacheSize.getById(validate(body))); } }); @@ -665,7 +665,7 @@ public abstract class GPXParser extends FileParser { try { if (attrs.getIndex("ref") > -1) { - trackable.setGeocode(attrs.getValue("ref").toUpperCase()); + trackable.setGeocode(attrs.getValue("ref")); } } catch (Exception e) { // nothing @@ -745,7 +745,7 @@ public abstract class GPXParser extends FileParser { @Override public void end(String body) { - final String logType = validate(body).toLowerCase(); + final String logType = validate(body); log.type = LogType.getByType(logType); } }); @@ -772,9 +772,9 @@ public abstract class GPXParser extends FileParser { try { progressStream = new ProgressInputStream(stream); Xml.parse(progressStream, Xml.Encoding.UTF_8, root.getContentHandler()); - return cgeoapplication.getInstance().loadCaches(result, EnumSet.of(LoadFlag.LOAD_DB_MINIMAL)); + return cgData.loadCaches(result, EnumSet.of(LoadFlag.LOAD_DB_MINIMAL)); } catch (SAXException e) { - Log.e("Cannot parse .gpx file as GPX " + version + ": could not parse XML - " + e.toString()); + Log.w("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); } } @@ -806,17 +806,21 @@ public abstract class GPXParser extends FileParser { static WaypointType convertWaypointSym2Type(final String sym) { if ("parking area".equalsIgnoreCase(sym)) { return WaypointType.PARKING; - } else if ("stages of a multicache".equalsIgnoreCase(sym)) { + } + if ("stages of a multicache".equalsIgnoreCase(sym)) { return WaypointType.STAGE; - } else if ("question to answer".equalsIgnoreCase(sym)) { + } + if ("question to answer".equalsIgnoreCase(sym)) { return WaypointType.PUZZLE; - } else if ("trailhead".equalsIgnoreCase(sym)) { + } + if ("trailhead".equalsIgnoreCase(sym)) { return WaypointType.TRAILHEAD; - } else if ("final location".equalsIgnoreCase(sym)) { + } + if ("final location".equalsIgnoreCase(sym)) { return WaypointType.FINAL; } // this is not fully correct, but lets also look for localized waypoint types - for (WaypointType waypointType : WaypointType.ALL_TYPES_EXCEPT_OWN) { + for (WaypointType waypointType : WaypointType.ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL) { final String localized = waypointType.getL10n(); if (StringUtils.isNotEmpty(localized)) { if (localized.equalsIgnoreCase(sym)) { diff --git a/main/src/cgeo/geocaching/files/LocParser.java b/main/src/cgeo/geocaching/files/LocParser.java index b17b203..982ef4c 100644 --- a/main/src/cgeo/geocaching/files/LocParser.java +++ b/main/src/cgeo/geocaching/files/LocParser.java @@ -2,7 +2,7 @@ package cgeo.geocaching.files; import cgeo.geocaching.SearchResult; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.cgData; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LoadFlags; @@ -65,7 +65,7 @@ public final class LocParser extends FileParser { contained.add(geocode); } } - Set<cgCache> caches = cgeoapplication.getInstance().loadCaches(contained, LoadFlags.LOAD_CACHE_OR_DB); + Set<cgCache> caches = cgData.loadCaches(contained, LoadFlags.LOAD_CACHE_OR_DB); for (cgCache cache : caches) { cgCache coord = cidCoords.get(cache.getGeocode()); copyCoordToCache(coord, cache); @@ -77,7 +77,7 @@ public final class LocParser extends FileParser { cache.setDifficulty(coord.getDifficulty()); cache.setTerrain(coord.getTerrain()); cache.setSize(coord.getSize()); - cache.setGeocode(coord.getGeocode().toUpperCase()); + cache.setGeocode(coord.getGeocode()); cache.setReliableLatLon(true); if (StringUtils.isBlank(cache.getName())) { cache.setName(coord.getName()); @@ -149,8 +149,7 @@ public final class LocParser extends FileParser { 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()); + cache.setGeocode(matcherGeocode.group(1).trim()); } final Matcher matcherName = patternName.matcher(pointString); diff --git a/main/src/cgeo/geocaching/files/LocalStorage.java b/main/src/cgeo/geocaching/files/LocalStorage.java index da0f981..4cf28f7 100644 --- a/main/src/cgeo/geocaching/files/LocalStorage.java +++ b/main/src/cgeo/geocaching/files/LocalStorage.java @@ -299,9 +299,9 @@ public class LocalStorage { } private static boolean copy(final InputStream input, final OutputStream output) { - final byte[] buffer = new byte[4096]; - int length; try { + int length; + final byte[] buffer = new byte[4096]; while ((length = input.read(buffer)) > 0) { output.write(buffer, 0, length); } diff --git a/main/src/cgeo/geocaching/files/ParserException.java b/main/src/cgeo/geocaching/files/ParserException.java index 5aa152c..c0076cc 100644 --- a/main/src/cgeo/geocaching/files/ParserException.java +++ b/main/src/cgeo/geocaching/files/ParserException.java @@ -13,10 +13,6 @@ public class ParserException extends Exception { super(detailMessage); } - public ParserException(Throwable throwable) { - super(throwable); - } - public ParserException(String detailMessage, Throwable throwable) { super(detailMessage, throwable); } diff --git a/main/src/cgeo/geocaching/files/SimpleDirChooser.java b/main/src/cgeo/geocaching/files/SimpleDirChooser.java index 346780d..9e99aec 100644 --- a/main/src/cgeo/geocaching/files/SimpleDirChooser.java +++ b/main/src/cgeo/geocaching/files/SimpleDirChooser.java @@ -18,7 +18,6 @@ import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; -import android.widget.ListView; import android.widget.TextView; import java.io.File; @@ -43,7 +42,10 @@ public class SimpleDirChooser extends ListActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final Bundle extras = getIntent().getExtras(); - String startDir = extras.getString(START_DIR); + String startDir = ""; + if (extras != null) { + startDir = extras.getString(START_DIR); + } if (StringUtils.isBlank(startDir)) { startDir = Environment.getExternalStorageDirectory().getPath(); } else { @@ -101,11 +103,6 @@ public class SimpleDirChooser extends ListActivity { this.setListAdapter(adapter); } - @Override - protected void onListItemClick(ListView l, View v, int position, long id) { - super.onListItemClick(l, v, position, id); - } - public class FileArrayAdapter extends ArrayAdapter<Option> { private Context content; @@ -200,7 +197,7 @@ public class SimpleDirChooser extends ListActivity { } } - public class Option implements Comparable<Option> { + public static class Option implements Comparable<Option> { private final String name; private final String path; private boolean checked = false; diff --git a/main/src/cgeo/geocaching/filter/AbstractFilter.java b/main/src/cgeo/geocaching/filter/AbstractFilter.java index 44d6d3f..f78a218 100644 --- a/main/src/cgeo/geocaching/filter/AbstractFilter.java +++ b/main/src/cgeo/geocaching/filter/AbstractFilter.java @@ -8,7 +8,7 @@ import java.util.List; abstract class AbstractFilter implements IFilter { private final String name; - public AbstractFilter(String name) { + protected AbstractFilter(String name) { this.name = name; } diff --git a/main/src/cgeo/geocaching/filter/AbstractRangeFilter.java b/main/src/cgeo/geocaching/filter/AbstractRangeFilter.java index ff3fce5..e84174a 100644 --- a/main/src/cgeo/geocaching/filter/AbstractRangeFilter.java +++ b/main/src/cgeo/geocaching/filter/AbstractRangeFilter.java @@ -8,8 +8,8 @@ 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))); + protected AbstractRangeFilter(int ressourceId, int range) { + super(cgeoapplication.getInstance().getResources().getString(ressourceId) + ' ' + (range == 5 ? '5' : range + " + " + String.format("%.1f", range + 0.5))); this.rangeMin = range; rangeMax = rangeMin + 1f; } diff --git a/main/src/cgeo/geocaching/filter/AttributeFilter.java b/main/src/cgeo/geocaching/filter/AttributeFilter.java index 2565178..837e9d1 100644 --- a/main/src/cgeo/geocaching/filter/AttributeFilter.java +++ b/main/src/cgeo/geocaching/filter/AttributeFilter.java @@ -2,6 +2,7 @@ package cgeo.geocaching.filter; import cgeo.geocaching.R; import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgData; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.LoadFlags.LoadFlag; @@ -34,7 +35,7 @@ class AttributeFilter extends AbstractFilter { @Override public boolean accepts(final cgCache cache) { - cgCache fullCache = cgeoapplication.getInstance().loadCache(cache.getGeocode(), EnumSet.of(LoadFlag.LOAD_ATTRIBUTES)); + cgCache fullCache = cgData.loadCache(cache.getGeocode(), EnumSet.of(LoadFlag.LOAD_ATTRIBUTES)); if (fullCache == null) { fullCache = cache; } diff --git a/main/src/cgeo/geocaching/filter/FilterUserInterface.java b/main/src/cgeo/geocaching/filter/FilterUserInterface.java index 230bc91..e2472fd 100644 --- a/main/src/cgeo/geocaching/filter/FilterUserInterface.java +++ b/main/src/cgeo/geocaching/filter/FilterUserInterface.java @@ -73,7 +73,7 @@ public final class FilterUserInterface { public void selectFilter(final RunnableWithArgument<IFilter> runAfterwards) { final AlertDialog.Builder builder = new AlertDialog.Builder(activity); - builder.setTitle(R.string.caches_filter); + builder.setTitle(R.string.caches_filter_title); final ArrayAdapter<FactoryEntry> adapter = new ArrayAdapter<FactoryEntry>(activity, android.R.layout.select_dialog_item, registry); diff --git a/main/src/cgeo/geocaching/gcvote/GCVote.java b/main/src/cgeo/geocaching/gcvote/GCVote.java index 5a00009..3d87724 100644 --- a/main/src/cgeo/geocaching/gcvote/GCVote.java +++ b/main/src/cgeo/geocaching/gcvote/GCVote.java @@ -98,10 +98,9 @@ public final class GCVote { return null; } - String voteData; final Matcher matcherVoteElement = patternVoteElement.matcher(page); while (matcherVoteElement.find()) { - voteData = matcherVoteElement.group(1); + String voteData = matcherVoteElement.group(1); if (voteData == null) { continue; } diff --git a/main/src/cgeo/geocaching/geopoint/DistanceParser.java b/main/src/cgeo/geocaching/geopoint/DistanceParser.java index 5f02895..d8db8e4 100644 --- a/main/src/cgeo/geocaching/geopoint/DistanceParser.java +++ b/main/src/cgeo/geocaching/geopoint/DistanceParser.java @@ -1,5 +1,8 @@ package cgeo.geocaching.geopoint; +import org.apache.commons.lang3.StringUtils; + +import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -26,9 +29,9 @@ public final class DistanceParser { } final float value = Float.parseFloat(matcher.group(1).replace(',', '.')); - final String unit = matcher.group(2).toLowerCase(); + final String unit = matcher.group(2).toLowerCase(Locale.US); - if (unit.equals("m") || (unit.length() == 0 && metricUnit)) { + if (unit.equals("m") || (StringUtils.isEmpty(unit) && metricUnit)) { return value / 1000; } if (unit.equals("km")) { diff --git a/main/src/cgeo/geocaching/geopoint/Geopoint.java b/main/src/cgeo/geocaching/geopoint/Geopoint.java index 7d585ac..0dfdbcb 100644 --- a/main/src/cgeo/geocaching/geopoint/Geopoint.java +++ b/main/src/cgeo/geocaching/geopoint/Geopoint.java @@ -102,7 +102,7 @@ public final class Geopoint implements ICoordinates, Parcelable { * @param lonDegFrac */ public Geopoint(final String latDir, final String latDeg, final String latDegFrac, - final String lonDir, final String lonDeg, final String lonDegFrac) { + final String lonDir, final String lonDeg, final String lonDegFrac) { latitude = Double.parseDouble(latDeg + "." + addZeros(Integer.parseInt(latDegFrac), 5)) * getLatSign(latDir); longitude = Double.parseDouble(lonDeg + "." + addZeros(Integer.parseInt(lonDegFrac), 5)) * @@ -122,7 +122,7 @@ public final class Geopoint implements ICoordinates, Parcelable { * @param lonMinFrac */ public Geopoint(final String latDir, final String latDeg, final String latMin, final String latMinFrac, - final String lonDir, final String lonDeg, final String lonMin, final String lonMinFrac) { + final String lonDir, final String lonDeg, final String lonMin, final String lonMinFrac) { latitude = (Double.parseDouble(latDeg) + Double.parseDouble(latMin + "." + addZeros(Integer.parseInt(latMinFrac), 3)) / 60) * (getLatSign(latDir)); longitude = (Double.parseDouble(lonDeg) + Double.parseDouble(lonMin + "." + addZeros(Integer.parseInt(lonMinFrac), 3)) / 60) * @@ -144,7 +144,7 @@ public final class Geopoint implements ICoordinates, Parcelable { * @param lonSecFrac */ public Geopoint(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) { + final String lonDir, final String lonDeg, final String lonMin, final String lonSec, final String lonSecFrac) { latitude = (Double.parseDouble(latDeg) + Double.parseDouble(latMin) / 60 + Double.parseDouble(latSec + "." + addZeros(Integer.parseInt(latSecFrac), 3)) / 3600) * (getLatSign(latDir)); longitude = (Double.parseDouble(lonDeg) + Double.parseDouble(lonMin) / 60 + Double.parseDouble(lonSec + "." + addZeros(Integer.parseInt(lonSecFrac), 3)) / 3600) * @@ -259,7 +259,7 @@ public final class Geopoint implements ICoordinates, Parcelable { if (this == obj) { return true; } - if (obj == null || !(obj instanceof Geopoint)) { + if (!(obj instanceof Geopoint)) { return false; } final Geopoint gp = (Geopoint) obj; @@ -280,8 +280,7 @@ public final class Geopoint implements ICoordinates, Parcelable { * tolerance in km * @return true if similar, false otherwise */ - public boolean isEqualTo(Geopoint gp, double tolerance) - { + public boolean isEqualTo(Geopoint gp, double tolerance) { return null != gp && distanceTo(gp) <= tolerance; } @@ -293,42 +292,35 @@ public final class Geopoint implements ICoordinates, Parcelable { * @see GeopointFormatter * @return formatted coordinates */ - public String format(GeopointFormatter.Format format) - { + public String format(GeopointFormatter.Format format) { return GeopointFormatter.format(format, this); } /** * Returns formatted coordinates with default format. * Default format is decimalminutes, e.g. N 52° 36.123 E 010° 03.456 - * + * * @return formatted coordinates */ @Override - public String toString() - { + public String toString() { return format(GeopointFormatter.Format.LAT_LON_DECMINUTE); } - abstract public static class GeopointException - extends RuntimeException - { + abstract public static class GeopointException extends NumberFormatException { private static final long serialVersionUID = 1L; - public GeopointException(String msg) + protected GeopointException(String msg) { super(msg); } } - public static class ParseException - extends GeopointException - { + public static class ParseException extends GeopointException { private static final long serialVersionUID = 1L; public final int resource; - public ParseException(final String msg, final GeopointParser.LatLon faulty) - { + 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; } diff --git a/main/src/cgeo/geocaching/geopoint/GeopointFormatter.java b/main/src/cgeo/geocaching/geopoint/GeopointFormatter.java index c706e77..0e676ce 100644 --- a/main/src/cgeo/geocaching/geopoint/GeopointFormatter.java +++ b/main/src/cgeo/geocaching/geopoint/GeopointFormatter.java @@ -10,7 +10,7 @@ public class GeopointFormatter /** * Predefined formats. */ - public static enum Format { + public enum Format { /** Example: "10,123456 -0,123456" */ LAT_LON_DECDEGREE, @@ -61,13 +61,13 @@ public class GeopointFormatter switch (format) { case LAT_LON_DECDEGREE: - return String.format("%.6f %.6f", latSigned, lonSigned); + return String.format(Locale.getDefault(), "%.6f %.6f", latSigned, lonSigned); case LAT_LON_DECDEGREE_COMMA: return String.format((Locale) null, "%.6f,%.6f", latSigned, lonSigned); case LAT_LON_DECMINUTE: - return String.format("%c %02d° %06.3f · %c %03d° %06.3f", + return String.format(Locale.getDefault(), "%c %02d° %06.3f · %c %03d° %06.3f", gp.getLatDir(), gp.getLatDeg(), gp.getLatMinRaw(), gp.getLonDir(), gp.getLonDeg(), gp.getLonMinRaw()); case LAT_LON_DECMINUTE_RAW: @@ -75,7 +75,7 @@ public class GeopointFormatter gp.getLatDir(), gp.getLatDeg(), gp.getLatMinRaw(), gp.getLonDir(), gp.getLonDeg(), gp.getLonMinRaw()); case LAT_LON_DECSECOND: - return String.format("%c %02d° %02d' %06.3f\" · %c %03d° %02d' %06.3f\"", + return String.format(Locale.getDefault(), "%c %02d° %02d' %06.3f\" · %c %03d° %02d' %06.3f\"", gp.getLatDir(), gp.getLatDeg(), gp.getLatMin(), gp.getLatSecRaw(), gp.getLonDir(), gp.getLonDeg(), gp.getLonMin(), gp.getLonSecRaw()); @@ -83,23 +83,22 @@ public class GeopointFormatter return String.format((Locale) null, "%.6f", latSigned); case LAT_DECMINUTE: - return String.format("%c %02d° %06.3f", gp.getLatDir(), gp.getLatDeg(), gp.getLatMinRaw()); + return String.format(Locale.getDefault(), "%c %02d° %06.3f", gp.getLatDir(), gp.getLatDeg(), gp.getLatMinRaw()); case LAT_DECMINUTE_RAW: - return String.format("%c %02d %06.3f", gp.getLatDir(), gp.getLatDeg(), gp.getLatMinRaw()); + return String.format(Locale.getDefault(), "%c %02d %06.3f", gp.getLatDir(), gp.getLatDeg(), gp.getLatMinRaw()); case LON_DECDEGREE_RAW: return String.format((Locale) null, "%.6f", lonSigned); case LON_DECMINUTE: - return String.format("%c %03d° %06.3f", gp.getLonDir(), gp.getLonDeg(), gp.getLonMinRaw()); + return String.format(Locale.getDefault(), "%c %03d° %06.3f", gp.getLonDir(), gp.getLonDeg(), gp.getLonMinRaw()); case LON_DECMINUTE_RAW: - return String.format("%c %03d %06.3f", gp.getLonDir(), gp.getLonDeg(), gp.getLonMinRaw()); + return String.format(Locale.getDefault(), "%c %03d %06.3f", gp.getLonDir(), gp.getLonDeg(), gp.getLonMinRaw()); + default: + throw new IllegalArgumentException(); } - - // Keep the compiler happy even though it cannot happen - return null; } } diff --git a/main/src/cgeo/geocaching/geopoint/Viewport.java b/main/src/cgeo/geocaching/geopoint/Viewport.java index 97ee21d..4aca538 100644 --- a/main/src/cgeo/geocaching/geopoint/Viewport.java +++ b/main/src/cgeo/geocaching/geopoint/Viewport.java @@ -164,7 +164,10 @@ public class Viewport { @Override public boolean equals(final Object other) { - if (other == null || !(other instanceof Viewport)) { + if (this == other) { + return true; + } + if (!(other instanceof Viewport)) { return false; } final Viewport vp = (Viewport) other; diff --git a/main/src/cgeo/geocaching/maps/AbstractMapSource.java b/main/src/cgeo/geocaching/maps/AbstractMapSource.java index 90a61d2..1d219d3 100644 --- a/main/src/cgeo/geocaching/maps/AbstractMapSource.java +++ b/main/src/cgeo/geocaching/maps/AbstractMapSource.java @@ -9,7 +9,7 @@ public abstract class AbstractMapSource implements MapSource { private final MapProvider mapProvider; private final String id; - public AbstractMapSource(final String id, final MapProvider mapProvider, final String name) { + protected AbstractMapSource(final String id, final MapProvider mapProvider, final String name) { this.id = id; this.mapProvider = mapProvider; this.name = name; diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java index 6856a63..32814c4 100644 --- a/main/src/cgeo/geocaching/maps/CGeoMap.java +++ b/main/src/cgeo/geocaching/maps/CGeoMap.java @@ -9,6 +9,7 @@ import cgeo.geocaching.SearchResult; import cgeo.geocaching.Settings; import cgeo.geocaching.StoredList; import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgData; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.cgeocaches; @@ -226,7 +227,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } countVisibleCaches(); - if (caches != null && caches.size() > 0 && !mapTitle.contains("[")) { + if (caches != null && !caches.isEmpty() && !mapTitle.contains("[")) { title.append(" [").append(cachesCnt); if (cachesCnt != caches.size()) { title.append('/').append(caches.size()); @@ -338,7 +339,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto final List<cgCache> protectedCaches = caches.getAsList(); int count = 0; - if (protectedCaches.size() > 0) { + if (!protectedCaches.isEmpty()) { final Viewport viewport = mapView.getViewport(); for (final cgCache cache : protectedCaches) { @@ -368,7 +369,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto activity = this.getActivity(); app = (cgeoapplication) activity.getApplication(); - int countBubbleCnt = app.getAllStoredCachesCount(true, CacheType.ALL); + int countBubbleCnt = cgData.getAllCachesCount(); caches = new LeastRecentlyUsedSet<cgCache>(MAX_CACHES + countBubbleCnt); final MapProvider mapProvider = Settings.getMapProvider(); @@ -494,7 +495,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (!CollectionUtils.isEmpty(dirtyCaches)) { for (String geocode : dirtyCaches) { - cgCache cache = app.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS); + cgCache cache = cgData.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS); // remove to update the cache caches.remove(cache); caches.add(cache); @@ -577,9 +578,8 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } } - MenuItem item; try { - item = menu.findItem(MENU_TRAIL_MODE); // show trail + MenuItem item = menu.findItem(MENU_TRAIL_MODE); if (Settings.isMapTrail()) { item.setTitle(res.getString(R.string.map_trail_hide)); } else { @@ -594,7 +594,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } final Set<String> geocodesInViewport = getGeocodesForCachesInViewport(); - menu.findItem(MENU_STORE_CACHES).setEnabled(!isLoading() && CollectionUtils.isNotEmpty(geocodesInViewport) && app.hasUnsavedCaches(new SearchResult(geocodesInViewport))); + menu.findItem(MENU_STORE_CACHES).setEnabled(!isLoading() && CollectionUtils.isNotEmpty(geocodesInViewport) && new SearchResult(geocodesInViewport).hasUnsavedCaches()); item = menu.findItem(MENU_CIRCLE_MODE); // show circles if (overlayCaches != null && overlayCaches.getCircles()) { @@ -640,7 +640,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto final List<String> geocodes = new ArrayList<String>(); for (final String geocode : geocodesInViewport) { - if (!app.isOffline(geocode, null)) { + if (!cgData.isOffline(geocode, null)) { geocodes.add(geocode); } } @@ -750,9 +750,9 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto currentTheme = currentThemeFile.getName(); } - int currentItem = 0; List<String> names = new ArrayList<String>(); names.add(res.getString(R.string.map_theme_builtin)); + int currentItem = 0; for (File file : themeFiles) { if (currentTheme.equalsIgnoreCase(file.getName())) { currentItem = names.size(); @@ -766,7 +766,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto builder.setTitle(R.string.map_theme_select); - builder.setSingleChoiceItems(names.toArray(new String[] {}), selectedItem, + builder.setSingleChoiceItems(names.toArray(new String[names.size()]), selectedItem, new DialogInterface.OnClickListener() { @Override @@ -790,7 +790,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } /** - * @return a Set of geocodes corresponding to the caches that are shown on screen. + * @return a non-null Set of geocodes corresponding to the caches that are shown on screen. */ private Set<String> getGeocodesForCachesInViewport() { final Set<String> geocodes = new HashSet<String>(); @@ -1118,21 +1118,17 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto SearchResult searchResult; if (mapMode == MapMode.LIVE) { - if (isLiveEnabled) { - searchResult = new SearchResult(); - } else { - searchResult = new SearchResult(app.getStoredInViewport(viewport, Settings.getCacheType())); - } + searchResult = isLiveEnabled ? new SearchResult() : new SearchResult(cgData.loadStoredInViewport(viewport, Settings.getCacheType())); } else { // map started from another activity - searchResult = new SearchResult(searchIntent); + searchResult = searchIntent != null ? new SearchResult(searchIntent) : new SearchResult(); if (geocodeIntent != null) { searchResult.addGeocode(geocodeIntent); } } // live mode search result if (isLiveEnabled) { - SearchResult liveResult = new SearchResult(app.getCachedInViewport(viewport, Settings.getCacheType())); + SearchResult liveResult = new SearchResult(cgData.loadCachedInViewport(viewport, Settings.getCacheType())); searchResult.addGeocodes(liveResult.getGeocodes()); } @@ -1160,7 +1156,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (isLiveEnabled || mapMode == MapMode.COORDS) { //All visible waypoints CacheType type = Settings.getCacheType(); - Set<cgWaypoint> waypointsInViewport = app.getWaypointsInViewport(viewport, Settings.isExcludeMyCaches(), Settings.isExcludeDisabledCaches(), type); + Set<cgWaypoint> waypointsInViewport = cgData.loadWaypoints(viewport, Settings.isExcludeMyCaches(), Settings.isExcludeDisabledCaches(), type); waypoints.addAll(waypointsInViewport); } else @@ -1340,7 +1336,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto final protected Viewport viewport; - public DoRunnable(final Viewport viewport) { + protected DoRunnable(final Viewport viewport) { this.viewport = viewport; } @@ -1394,7 +1390,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto break; } - if (!app.isOffline(geocode, null)) { + if (!cgData.isOffline(geocode, null)) { if ((System.currentTimeMillis() - last) < 1500) { try { int delay = 1000 + (int) (Math.random() * 1000.0) - (int) (System.currentTimeMillis() - last); @@ -1484,9 +1480,9 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto Viewport viewport = null; if (geocodeCenter != null) { - viewport = app.getBounds(geocodeCenter); + viewport = cgData.getBounds(geocodeCenter); } else if (searchCenter != null) { - viewport = app.getBounds(searchCenter.getGeocodes()); + viewport = cgData.getBounds(searchCenter.getGeocodes()); } if (viewport == null) { diff --git a/main/src/cgeo/geocaching/maps/CachesOverlay.java b/main/src/cgeo/geocaching/maps/CachesOverlay.java index b656900..044f69b 100644 --- a/main/src/cgeo/geocaching/maps/CachesOverlay.java +++ b/main/src/cgeo/geocaching/maps/CachesOverlay.java @@ -6,7 +6,7 @@ import cgeo.geocaching.R; import cgeo.geocaching.Settings; import cgeo.geocaching.WaypointPopup; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.cgData; import cgeo.geocaching.activity.Progress; import cgeo.geocaching.connector.gc.GCMap; import cgeo.geocaching.enumerations.CacheType; @@ -209,10 +209,9 @@ public class CachesOverlay extends AbstractItemizedOverlay { progress.show(context, context.getResources().getString(R.string.map_live), context.getResources().getString(R.string.cache_dialog_loading_details), true, null); - CachesOverlayItemImpl item = null; - // prevent concurrent changes getOverlayImpl().lock(); + CachesOverlayItemImpl item = null; try { if (index < items.size()) { item = items.get(index); @@ -228,7 +227,7 @@ public class CachesOverlay extends AbstractItemizedOverlay { final IWaypoint coordinate = item.getCoord(); if (StringUtils.isNotBlank(coordinate.getCoordType()) && coordinate.getCoordType().equalsIgnoreCase("cache") && StringUtils.isNotBlank(coordinate.getGeocode())) { - cgCache cache = cgeoapplication.getInstance().loadCache(coordinate.getGeocode(), LoadFlags.LOAD_CACHE_OR_DB); + cgCache cache = cgData.loadCache(coordinate.getGeocode(), LoadFlags.LOAD_CACHE_OR_DB); RequestDetailsThread requestDetailsThread = new RequestDetailsThread(cache); if (!requestDetailsThread.requestRequired()) { // don't show popup if we have enough details diff --git a/main/src/cgeo/geocaching/maps/MapProviderFactory.java b/main/src/cgeo/geocaching/maps/MapProviderFactory.java index cb1f87f..483189f 100644 --- a/main/src/cgeo/geocaching/maps/MapProviderFactory.java +++ b/main/src/cgeo/geocaching/maps/MapProviderFactory.java @@ -23,7 +23,7 @@ public class MapProviderFactory { MapsforgeMapProvider.getInstance(); } - private static boolean isGoogleMapsInstalled() { + public static boolean isGoogleMapsInstalled() { boolean googleMaps = true; try { Class.forName("com.google.android.maps.MapActivity"); diff --git a/main/src/cgeo/geocaching/maps/PositionOverlay.java b/main/src/cgeo/geocaching/maps/PositionOverlay.java index 1aa2d3b..fec67ef 100644 --- a/main/src/cgeo/geocaching/maps/PositionOverlay.java +++ b/main/src/cgeo/geocaching/maps/PositionOverlay.java @@ -158,7 +158,6 @@ public class PositionOverlay implements GeneralOverlay { if (Settings.isMapTrail()) { int size = history.size(); if (size > 1) { - int alpha; int alphaCnt = size - 201; if (alphaCnt < 1) { alphaCnt = 1; @@ -172,6 +171,7 @@ public class PositionOverlay implements GeneralOverlay { projection.toPixels(mapItemFactory.getGeoPointBase(new Geopoint(prev)), historyPointP); projection.toPixels(mapItemFactory.getGeoPointBase(new Geopoint(now)), historyPointN); + int alpha; if ((alphaCnt - cnt) > 0) { alpha = 255 / (alphaCnt - cnt); } @@ -211,11 +211,8 @@ public class PositionOverlay implements GeneralOverlay { heightArrowHalf = arrow.getHeight() / 2; } - int marginLeft; - int marginTop; - - marginLeft = center.x - widthArrowHalf; - marginTop = center.y - heightArrowHalf; + int marginLeft = center.x - widthArrowHalf; + int marginTop = center.y - heightArrowHalf; Matrix matrix = new Matrix(); matrix.setRotate(heading, widthArrowHalf, heightArrowHalf); diff --git a/main/src/cgeo/geocaching/maps/google/GoogleMapActivity.java b/main/src/cgeo/geocaching/maps/google/GoogleMapActivity.java index 0377fe9..5649d19 100644 --- a/main/src/cgeo/geocaching/maps/google/GoogleMapActivity.java +++ b/main/src/cgeo/geocaching/maps/google/GoogleMapActivity.java @@ -1,5 +1,6 @@ package cgeo.geocaching.maps.google; +import cgeo.geocaching.activity.FilteredActivity; import cgeo.geocaching.maps.AbstractMap; import cgeo.geocaching.maps.CGeoMap; import cgeo.geocaching.maps.interfaces.MapActivityImpl; @@ -12,7 +13,7 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; -public class GoogleMapActivity extends MapActivity implements MapActivityImpl { +public class GoogleMapActivity extends MapActivity implements MapActivityImpl, FilteredActivity { private AbstractMap mapBase; @@ -127,4 +128,8 @@ public class GoogleMapActivity extends MapActivity implements MapActivityImpl { mapBase.goManual(view); } + @Override + public void showFilterMenu(View view) { + // do nothing, the filter bar only shows the global filter + } } diff --git a/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java b/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java index 6973338..1fa38ad 100644 --- a/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java +++ b/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java @@ -16,7 +16,6 @@ public final class GoogleMapProvider extends AbstractMapProvider { public static final String GOOGLE_MAP_ID = "GOOGLE_MAP"; public static final String GOOGLE_SATELLITE_ID = "GOOGLE_SATELLITE"; - private static GoogleMapProvider instance; private final MapItemFactory mapItemFactory; @@ -29,15 +28,16 @@ public final class GoogleMapProvider extends AbstractMapProvider { mapItemFactory = new GoogleMapItemFactory(); } + private static class Holder { + private static final GoogleMapProvider INSTANCE = new GoogleMapProvider(); + } + public static GoogleMapProvider getInstance() { - if (instance == null) { - instance = new GoogleMapProvider(); - } - return instance; + return Holder.INSTANCE; } public static boolean isSatelliteSource(final MapSource mapSource) { - return mapSource != null && mapSource instanceof GoogleSatelliteSource; + return mapSource instanceof GoogleSatelliteSource; } @Override @@ -67,7 +67,7 @@ public final class GoogleMapProvider extends AbstractMapProvider { private static abstract class AbstractGoogleMapSource extends AbstractMapSource { - public AbstractGoogleMapSource(final String id, final MapProvider mapProvider, final String name) { + protected AbstractGoogleMapSource(final String id, final MapProvider mapProvider, final String name) { super(id, mapProvider, name); } diff --git a/main/src/cgeo/geocaching/maps/google/GoogleOverlay.java b/main/src/cgeo/geocaching/maps/google/GoogleOverlay.java index d86eafe..773f9ff 100644 --- a/main/src/cgeo/geocaching/maps/google/GoogleOverlay.java +++ b/main/src/cgeo/geocaching/maps/google/GoogleOverlay.java @@ -27,6 +27,9 @@ public class GoogleOverlay extends Overlay implements OverlayImpl { break; case ScaleOverlay: overlayBase = new ScaleOverlay(activityIn, this); + break; + default: + throw new IllegalArgumentException(); } } diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java index 6cb2539..f850402 100644 --- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java +++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java @@ -1,5 +1,6 @@ package cgeo.geocaching.maps.mapsforge; +import cgeo.geocaching.activity.FilteredActivity; import cgeo.geocaching.maps.AbstractMap; import cgeo.geocaching.maps.CGeoMap; import cgeo.geocaching.maps.interfaces.MapActivityImpl; @@ -12,7 +13,7 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; -public class MapsforgeMapActivity extends MapActivity implements MapActivityImpl { +public class MapsforgeMapActivity extends MapActivity implements MapActivityImpl, FilteredActivity { private AbstractMap mapBase; @@ -121,4 +122,9 @@ public class MapsforgeMapActivity extends MapActivity implements MapActivityImpl public void goManual(View view) { mapBase.goManual(view); } + + @Override + public void showFilterMenu(View view) { + // do nothing, the filter bar only shows the global filter + } } diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java index 299bf30..294eb79 100644 --- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java +++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java @@ -31,7 +31,6 @@ public final class MapsforgeMapProvider extends AbstractMapProvider { public static final String MAPSFORGE_MAPNIK_ID = "MAPSFORGE_MAPNIK"; private boolean oldMap = false; private MapItemFactory mapItemFactory = new MapsforgeMapItemFactory(); - private static MapsforgeMapProvider instance; private MapsforgeMapProvider() { final Resources resources = cgeoapplication.getInstance().getResources(); @@ -42,11 +41,12 @@ public final class MapsforgeMapProvider extends AbstractMapProvider { updateOfflineMaps(); } + private static final class Holder { + private static final MapsforgeMapProvider INSTANCE = new MapsforgeMapProvider(); + } + public static MapsforgeMapProvider getInstance() { - if (instance == null) { - instance = new MapsforgeMapProvider(); - } - return instance; + return Holder.INSTANCE; } public static List<String> getOfflineMaps() { @@ -65,6 +65,7 @@ public final class MapsforgeMapProvider extends AbstractMapProvider { } } } + Collections.sort(mapFileList, String.CASE_INSENSITIVE_ORDER); return mapFileList; } catch (Exception e) { Log.e("Settings.getOfflineMaps: " + e); diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java index b6e31a2..dd7fb75 100644 --- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java +++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java @@ -29,6 +29,9 @@ public class MapsforgeOverlay extends Overlay implements OverlayImpl { break; case ScaleOverlay: overlayBase = new ScaleOverlay(activityIn, this); + break; + default: + throw new IllegalArgumentException(); } } diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapActivity024.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapActivity024.java index d45db9a..ed8a7bc 100644 --- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapActivity024.java +++ b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapActivity024.java @@ -1,5 +1,6 @@ package cgeo.geocaching.maps.mapsforge.v024; +import cgeo.geocaching.activity.FilteredActivity; import cgeo.geocaching.maps.AbstractMap; import cgeo.geocaching.maps.CGeoMap; import cgeo.geocaching.maps.interfaces.MapActivityImpl; @@ -12,7 +13,7 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; -public class MapsforgeMapActivity024 extends MapActivity implements MapActivityImpl { +public class MapsforgeMapActivity024 extends MapActivity implements MapActivityImpl, FilteredActivity { private AbstractMap mapBase; @@ -121,4 +122,9 @@ public class MapsforgeMapActivity024 extends MapActivity implements MapActivityI public void goManual(View view) { mapBase.goManual(view); } + + @Override + public void showFilterMenu(View view) { + // do nothing, the filter bar only shows the global filter + } } diff --git a/main/src/cgeo/geocaching/network/HtmlImage.java b/main/src/cgeo/geocaching/network/HtmlImage.java index d47afb9..e25eec5 100644 --- a/main/src/cgeo/geocaching/network/HtmlImage.java +++ b/main/src/cgeo/geocaching/network/HtmlImage.java @@ -3,6 +3,7 @@ package cgeo.geocaching.network; import cgeo.geocaching.R; import cgeo.geocaching.StoredList; import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.compatibility.Compatibility; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.files.LocalStorage; import cgeo.geocaching.utils.ImageHelper; @@ -12,15 +13,13 @@ import ch.boye.httpclientandroidlib.HttpResponse; import org.apache.commons.lang3.StringUtils; -import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Point; import android.graphics.drawable.BitmapDrawable; import android.net.Uri; import android.text.Html; -import android.view.Display; -import android.view.WindowManager; import java.io.File; import java.io.FileInputStream; @@ -66,9 +65,9 @@ public class HtmlImage implements Html.ImageGetter { bfOptions = new BitmapFactory.Options(); bfOptions.inTempStorage = new byte[16 * 1024]; - final Display display = ((WindowManager) cgeoapplication.getInstance().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); - this.maxWidth = display.getWidth() - 25; - this.maxHeight = display.getHeight() - 25; + Point displaySize = Compatibility.getDisplaySize(); + this.maxWidth = displaySize.x - 25; + this.maxHeight = displaySize.y - 25; this.resources = cgeoapplication.getInstance().getResources(); } diff --git a/main/src/cgeo/geocaching/network/Network.java b/main/src/cgeo/geocaching/network/Network.java index 72b325e..c3265fe 100644 --- a/main/src/cgeo/geocaching/network/Network.java +++ b/main/src/cgeo/geocaching/network/Network.java @@ -22,6 +22,7 @@ import ch.boye.httpclientandroidlib.client.methods.HttpGet; import ch.boye.httpclientandroidlib.client.methods.HttpPost; import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase; import ch.boye.httpclientandroidlib.client.params.ClientPNames; +import ch.boye.httpclientandroidlib.entity.StringEntity; import ch.boye.httpclientandroidlib.entity.mime.MultipartEntity; import ch.boye.httpclientandroidlib.entity.mime.content.FileBody; import ch.boye.httpclientandroidlib.entity.mime.content.StringBody; @@ -34,6 +35,7 @@ import ch.boye.httpclientandroidlib.params.HttpParams; import ch.boye.httpclientandroidlib.protocol.HttpContext; import ch.boye.httpclientandroidlib.util.EntityUtils; +import org.apache.commons.lang3.CharEncoding; import org.apache.commons.lang3.StringUtils; import org.json.JSONException; import org.json.JSONObject; @@ -43,11 +45,13 @@ import android.net.Uri; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; import java.net.URLEncoder; public abstract class Network { private static final int NB_DOWNLOAD_RETRIES = 4; + /** User agent id */ private final static String PC_USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:9.0.1) Gecko/20100101 Firefox/9.0.1"; /** Native user agent, taken from a Android 2.2 Nexus **/ @@ -58,7 +62,7 @@ public abstract class Network { private final static HttpParams clientParams = new BasicHttpParams(); static { - Network.clientParams.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, "UTF-8"); + Network.clientParams.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, CharEncoding.UTF_8); Network.clientParams.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 30000); Network.clientParams.setParameter(CoreConnectionPNames.SO_TIMEOUT, 30000); Network.clientParams.setParameter(ClientPNames.HANDLE_REDIRECTS, true); @@ -115,7 +119,6 @@ public abstract class Network { 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; } @@ -153,6 +156,27 @@ public abstract class Network { } /** + * POST HTTP request with Json POST DATA + * + * @param uri the URI to request + * @param json the json object to add to the POST request + * @return the HTTP response, or null in case of an encoding error params + */ + public static HttpResponse postJsonRequest(final String uri, final JSONObject json) { + HttpPost request = new HttpPost(uri); + request.addHeader("Content-Type", "application/json; charset=utf-8"); + if (json != null) { + try { + request.setEntity(new StringEntity(json.toString())); + } catch (UnsupportedEncodingException e) { + Log.e("postJsonRequest:JSON Entity: UnsupportedEncodingException"); + return null; + } + } + return doRepeatedRequests(request); + } + + /** * Multipart POST HTTP request * * @param uri the URI to request @@ -206,7 +230,7 @@ public abstract class Network { request = new HttpPost(uri); if (params != null) { try { - ((HttpPost) request).setEntity(new UrlEncodedFormEntity(params, "UTF-8")); + ((HttpPost) request).setEntity(new UrlEncodedFormEntity(params, CharEncoding.UTF_8)); } catch (final UnsupportedEncodingException e) { Log.e("request", e); return null; @@ -377,7 +401,7 @@ public abstract class Network { private static String getResponseDataNoError(final HttpResponse response, boolean replaceWhitespace) { try { - String data = EntityUtils.toString(response.getEntity(), "UTF-8"); + String data = EntityUtils.toString(response.getEntity(), CharEncoding.UTF_8); return replaceWhitespace ? BaseUtils.replaceWhitespace(data) : data; } catch (Exception e) { Log.e("getResponseData", e); @@ -397,7 +421,25 @@ public abstract class Network { } public static String rfc3986URLEncode(String text) { - return StringUtils.replace(URLEncoder.encode(text).replace("+", "%20"), "%7E", "~"); + return StringUtils.replace(Network.encode(text).replace("+", "%20"), "%7E", "~"); + } + + public static String decode(final String text) { + try { + return URLDecoder.decode(text, CharEncoding.UTF_8); + } catch (UnsupportedEncodingException e) { + Log.e("Network.decode", e); + } + return null; + } + + public static String encode(final String text) { + try { + return URLEncoder.encode(text, CharEncoding.UTF_8); + } catch (UnsupportedEncodingException e) { + Log.e("Network.encode", e); + } + return null; } } diff --git a/main/src/cgeo/geocaching/network/Parameters.java b/main/src/cgeo/geocaching/network/Parameters.java index 081a926..74f5531 100644 --- a/main/src/cgeo/geocaching/network/Parameters.java +++ b/main/src/cgeo/geocaching/network/Parameters.java @@ -4,6 +4,8 @@ import ch.boye.httpclientandroidlib.NameValuePair; import ch.boye.httpclientandroidlib.client.utils.URLEncodedUtils; import ch.boye.httpclientandroidlib.message.BasicNameValuePair; +import org.apache.commons.lang3.CharEncoding; + import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.Collections; @@ -24,7 +26,6 @@ public class Parameters extends ArrayList<NameValuePair> { * if the number of key/values is unbalanced */ public Parameters(final String... keyValues) { - super(); put(keyValues); } @@ -66,7 +67,7 @@ public class Parameters extends ArrayList<NameValuePair> { @Override public String toString() { - return URLEncodedUtils.format(this, "UTF-8"); + return URLEncodedUtils.format(this, CharEncoding.UTF_8); } /** diff --git a/main/src/cgeo/geocaching/network/StatusUpdater.java b/main/src/cgeo/geocaching/network/StatusUpdater.java index 8c3b9dc..1953e1d 100644 --- a/main/src/cgeo/geocaching/network/StatusUpdater.java +++ b/main/src/cgeo/geocaching/network/StatusUpdater.java @@ -31,7 +31,7 @@ public class StatusUpdater extends MemorySubject<StatusUpdater.Status> implement private void requestUpdate() { final JSONObject response = Network.requestJSON("http://status.cgeo.org/api/status.json", - new Parameters("version_code", "" + Version.getVersionCode(cgeoapplication.getInstance()), + new Parameters("version_code", String.valueOf(Version.getVersionCode(cgeoapplication.getInstance())), "version_name", Version.getVersionName(cgeoapplication.getInstance()), "locale", Locale.getDefault().toString())); if (response != null) { diff --git a/main/src/cgeo/geocaching/sorting/DistanceComparator.java b/main/src/cgeo/geocaching/sorting/DistanceComparator.java index d601433..781359a 100644 --- a/main/src/cgeo/geocaching/sorting/DistanceComparator.java +++ b/main/src/cgeo/geocaching/sorting/DistanceComparator.java @@ -11,8 +11,22 @@ import java.util.List; */ public class DistanceComparator extends AbstractCacheComparator { + final private Geopoint coords; + final private List<cgCache> list; + private boolean cachedDistances; + public DistanceComparator(final Geopoint coords, List<cgCache> list) { - // calculate all distances to avoid duplicate calculations during sorting + this.coords = coords; + this.list = list; + } + + /** + * calculate all distances only once to avoid costly re-calculation of the same distance during sorting + */ + private void calculateAllDistances() { + if (cachedDistances) { + return; + } for (cgCache cache : list) { if (cache.getCoords() != null) { cache.setDistance(coords.distanceTo(cache.getCoords())); @@ -21,6 +35,7 @@ public class DistanceComparator extends AbstractCacheComparator { cache.setDistance(null); } } + cachedDistances = true; } @Override @@ -30,6 +45,7 @@ public class DistanceComparator extends AbstractCacheComparator { @Override protected int compareCaches(final cgCache cache1, final cgCache cache2) { + calculateAllDistances(); if (cache1.getCoords() == null && cache2.getCoords() == null) { return 0; } diff --git a/main/src/cgeo/geocaching/sorting/FindsComparator.java b/main/src/cgeo/geocaching/sorting/FindsComparator.java index 6407b11..47e3844 100644 --- a/main/src/cgeo/geocaching/sorting/FindsComparator.java +++ b/main/src/cgeo/geocaching/sorting/FindsComparator.java @@ -1,13 +1,11 @@ package cgeo.geocaching.sorting; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.cgData; import cgeo.geocaching.enumerations.LogType; public class FindsComparator extends AbstractCacheComparator { - private final cgeoapplication app = cgeoapplication.getInstance(); - @Override protected boolean canCompare(cgCache cache1, cgCache cache2) { return cache1.getLogCounts() != null && cache2.getLogCounts() != null; @@ -20,9 +18,9 @@ public class FindsComparator extends AbstractCacheComparator { return finds2 - finds1; } - private int getFindsCount(cgCache cache) { + private static int getFindsCount(cgCache cache) { if (cache.getLogCounts().isEmpty()) { - cache.setLogCounts(app.loadLogCounts(cache.getGeocode())); + cache.setLogCounts(cgData.loadLogCounts(cache.getGeocode())); } Integer logged = cache.getLogCounts().get(LogType.FOUND_IT); if (logged != null) { diff --git a/main/src/cgeo/geocaching/sorting/InverseComparator.java b/main/src/cgeo/geocaching/sorting/InverseComparator.java new file mode 100644 index 0000000..d2fa085 --- /dev/null +++ b/main/src/cgeo/geocaching/sorting/InverseComparator.java @@ -0,0 +1,22 @@ +package cgeo.geocaching.sorting; + +import cgeo.geocaching.cgCache; + +/** + * comparator which inverses the sort order of the given other comparator + * + */ +public class InverseComparator implements CacheComparator { + + private final CacheComparator originalComparator; + + public InverseComparator(CacheComparator comparator) { + this.originalComparator = comparator; + } + + @Override + public int compare(cgCache lhs, cgCache rhs) { + return originalComparator.compare(rhs, lhs); + } + +} diff --git a/main/src/cgeo/geocaching/twitter/Twitter.java b/main/src/cgeo/geocaching/twitter/Twitter.java index c630cec..c86c633 100644 --- a/main/src/cgeo/geocaching/twitter/Twitter.java +++ b/main/src/cgeo/geocaching/twitter/Twitter.java @@ -2,6 +2,7 @@ package cgeo.geocaching.twitter; import cgeo.geocaching.Settings; import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgData; import cgeo.geocaching.cgTrackable; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.LoadFlags; @@ -55,7 +56,7 @@ public final class Twitter { } public static void postTweetCache(String geocode) { - final cgCache cache = cgeoapplication.getInstance().loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB); + final cgCache cache = cgData.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB); String status; final String url = cache.getUrl(); if (url.length() >= 100) { @@ -76,7 +77,7 @@ public final class Twitter { } public static void postTweetTrackable(String geocode) { - final cgTrackable trackable = cgeoapplication.getInstance().getTrackableByGeocode(geocode); + final cgTrackable trackable = cgData.loadTrackable(geocode); String name = trackable.getName(); if (name.length() > 82) { name = name.substring(0, 81) + '…'; diff --git a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java index 22ee0fb..96edebf 100644 --- a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java +++ b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java @@ -130,14 +130,13 @@ public class TwitterAuthorizationActivity extends AbstractActivity { } private void requestToken() { - final String host = "api.twitter.com"; - final String pathRequest = "/oauth/request_token"; - final String pathAuthorize = "/oauth/authorize"; - final String method = "GET"; int status = 0; try { final Parameters params = new Parameters(); + final String method = "GET"; + final String pathRequest = "/oauth/request_token"; + final String host = "api.twitter.com"; OAuth.signOAuth(host, pathRequest, method, true, params, null, null); final String line = Network.getResponseData(Network.getRequest("https://" + host + pathRequest, params)); @@ -157,6 +156,7 @@ public class TwitterAuthorizationActivity extends AbstractActivity { try { final Parameters paramsBrowser = new Parameters(); paramsBrowser.put("oauth_callback", "oob"); + final String pathAuthorize = "/oauth/authorize"; OAuth.signOAuth(host, pathAuthorize, "GET", true, paramsBrowser, OAtoken, OAtokenSecret); final String encodedParams = EntityUtils.toString(new UrlEncodedFormEntity(paramsBrowser)); startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://" + host + pathAuthorize + "?" + encodedParams))); @@ -174,15 +174,15 @@ public class TwitterAuthorizationActivity extends AbstractActivity { } private void changeToken() { - final String host = "api.twitter.com"; - final String path = "/oauth/access_token"; - final String method = "POST"; int status = 0; try { final Parameters params = new Parameters("oauth_verifier", pinEntry.getText().toString()); + final String method = "POST"; + final String path = "/oauth/access_token"; + final String host = "api.twitter.com"; OAuth.signOAuth(host, path, method, true, params, OAtoken, OAtokenSecret); final String line = StringUtils.defaultString(Network.getResponseData(Network.postRequest("https://" + host + path, params))); @@ -242,7 +242,7 @@ public class TwitterAuthorizationActivity extends AbstractActivity { @Override public void onClick(View arg0) { - if (((EditText) findViewById(R.id.pin)).getText().toString().length() == 0) { + if (StringUtils.isEmpty(((EditText) findViewById(R.id.pin)).getText().toString())) { helpDialog(res.getString(R.string.auth_dialog_pin_title), res.getString(R.string.auth_dialog_pin_message)); return; } diff --git a/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java b/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java new file mode 100644 index 0000000..333ef11 --- /dev/null +++ b/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java @@ -0,0 +1,32 @@ +package cgeo.geocaching.ui; + +import cgeo.geocaching.activity.AbstractViewPagerActivity.PageViewCreator; + +import android.view.View; + +/** + * View creator which destroys the created view on every {@link #notifyDataSetChanged()}. + * + * @param <ViewClass> + */ +public abstract class AbstractCachingPageViewCreator<ViewClass extends View> implements PageViewCreator { + + public ViewClass view; + + @Override + public final void notifyDataSetChanged() { + view = null; + } + + @Override + public final View getView() { + if (view == null) { + view = getDispatchedView(); + } + + return view; + } + + @Override + public abstract ViewClass getDispatchedView(); +} diff --git a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java index 2a83ddc..9745d63 100644 --- a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java +++ b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java @@ -35,7 +35,7 @@ public final class CacheDetailsCreator { } public TextView add(final int nameId, final CharSequence value) { - final RelativeLayout layout = (RelativeLayout) activity.getLayoutInflater().inflate(R.layout.cache_item, null); + final RelativeLayout layout = (RelativeLayout) activity.getLayoutInflater().inflate(R.layout.cache_layout, null); final TextView nameView = (TextView) layout.findViewById(R.id.name); nameView.setText(res.getString(nameId)); lastValueView = (TextView) layout.findViewById(R.id.value); @@ -56,16 +56,15 @@ public final class CacheDetailsCreator { nameView.setText(activity.getResources().getString(nameId)); lastValueView.setText(String.format("%.1f", value) + ' ' + activity.getResources().getString(R.string.cache_rating_of) + " 5"); - layoutStars.addView(createStarImages(value), 1); + createStarImages(layoutStars, value); + layoutStars.setVisibility(View.VISIBLE); parentView.addView(layout); return layout; } - private LinearLayout createStarImages(final float value) { + private void createStarImages(final ViewGroup starsContainer, final float value) { final LayoutInflater inflater = LayoutInflater.from(activity); - final LinearLayout starsContainer = new LinearLayout(activity); - starsContainer.setOrientation(LinearLayout.HORIZONTAL); for (int i = 0; i < 5; i++) { ImageView star = (ImageView) inflater.inflate(R.layout.star, null); @@ -78,8 +77,6 @@ public final class CacheDetailsCreator { } starsContainer.addView(star); } - - return starsContainer; } public void addCacheState(cgCache cache) { diff --git a/main/src/cgeo/geocaching/ui/CacheListAdapter.java b/main/src/cgeo/geocaching/ui/CacheListAdapter.java index 65d3fbc..efc95b8 100644 --- a/main/src/cgeo/geocaching/ui/CacheListAdapter.java +++ b/main/src/cgeo/geocaching/ui/CacheListAdapter.java @@ -12,6 +12,7 @@ import cgeo.geocaching.filter.IFilter; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.sorting.CacheComparator; import cgeo.geocaching.sorting.DistanceComparator; +import cgeo.geocaching.sorting.InverseComparator; import cgeo.geocaching.sorting.VisitComparator; import cgeo.geocaching.utils.AngleUtils; import cgeo.geocaching.utils.Log; @@ -43,6 +44,7 @@ import android.widget.TextView; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -64,6 +66,7 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { final private Resources res; /** Resulting list of caches */ final private List<cgCache> list; + private boolean inverseSort = false; private static final int SWIPE_MIN_DISTANCE = 60; private static final int SWIPE_MAX_OFF_PATH = 100; @@ -149,6 +152,14 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { * @param comparator */ public void setComparator(final CacheComparator comparator) { + // selecting the same sorting twice will toggle the order + if (cacheComparator != null && comparator != null && cacheComparator.getClass().equals(comparator.getClass())) { + inverseSort = !inverseSort; + } + else { + // always reset the inversion for a new sorting criteria + inverseSort = false; + } cacheComparator = comparator; forceSort(); } @@ -257,7 +268,7 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { updateSortByDistance(); } else { - Collections.sort(list, cacheComparator); + Collections.sort(list, getPotentialInversion(cacheComparator)); } notifyDataSetChanged(); @@ -292,7 +303,7 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { return; } final ArrayList<cgCache> oldList = new ArrayList<cgCache>(list); - Collections.sort(list, new DistanceComparator(coords, list)); + Collections.sort(list, getPotentialInversion(new DistanceComparator(coords, list))); // avoid an update if the list has not changed due to location update if (list.equals(oldList)) { @@ -302,6 +313,13 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { lastSort = System.currentTimeMillis(); } + private Comparator<? super cgCache> getPotentialInversion(final CacheComparator comparator) { + if (inverseSort) { + return new InverseComparator(comparator); + } + return comparator; + } + private boolean isSortedByDistance() { return cacheComparator == null || cacheComparator instanceof DistanceComparator; } @@ -390,17 +408,24 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { holder.logStatusMark.setVisibility(View.GONE); } - if (cache.getNameSp() == null) { - cache.setNameSp((new Spannable.Factory()).newSpannable(cache.getName())); - if (cache.isDisabled() || cache.isArchived()) { // strike - cache.getNameSp().setSpan(new StrikethroughSpan(), 0, cache.getNameSp().toString().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } - if (cache.isArchived()) { - cache.getNameSp().setSpan(new ForegroundColorSpan(res.getColor(R.color.archived_cache_color)), 0, cache.getNameSp().toString().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + Spannable spannable = null; + if (cache.isDisabled() || cache.isArchived()) { // strike + spannable = Spannable.Factory.getInstance().newSpannable(cache.getName()); + spannable.setSpan(new StrikethroughSpan(), 0, spannable.toString().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if (cache.isArchived()) { // red color + if (spannable == null) { + spannable = Spannable.Factory.getInstance().newSpannable(cache.getName()); } + spannable.setSpan(new ForegroundColorSpan(res.getColor(R.color.archived_cache_color)), 0, spannable.toString().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } - holder.text.setText(cache.getNameSp(), TextView.BufferType.SPANNABLE); + if (spannable != null) { + holder.text.setText(spannable, TextView.BufferType.SPANNABLE); + } + else { + holder.text.setText(cache.getName()); + } holder.text.setCompoundDrawablesWithIntrinsicBounds(getCacheIcon(cache), null, null, null); if (cache.getInventoryItems() > 0) { diff --git a/main/src/cgeo/geocaching/ui/CompassMiniView.java b/main/src/cgeo/geocaching/ui/CompassMiniView.java index 44fb8e2..da8f69e 100644 --- a/main/src/cgeo/geocaching/ui/CompassMiniView.java +++ b/main/src/cgeo/geocaching/ui/CompassMiniView.java @@ -97,17 +97,17 @@ final public class CompassMiniView extends View { targetCoords = point; } - protected void updateAzimuth(float azimuth) { + public void updateAzimuth(float azimuth) { this.azimuth = azimuth; updateDirection(); } - protected void updateHeading(float heading) { + public void updateHeading(float heading) { this.heading = heading; updateDirection(); } - protected void updateCurrentCoords(final Geopoint currentCoords) { + public void updateCurrentCoords(final Geopoint currentCoords) { if (currentCoords == null || targetCoords == null) { return; } diff --git a/main/src/cgeo/geocaching/ui/CompassView.java b/main/src/cgeo/geocaching/ui/CompassView.java index 048e280..0ef3a43 100644 --- a/main/src/cgeo/geocaching/ui/CompassView.java +++ b/main/src/cgeo/geocaching/ui/CompassView.java @@ -185,16 +185,13 @@ public class CompassView extends View { int canvasCenterX = (compassRoseWidth / 2) + ((getWidth() - compassRoseWidth) / 2); int canvasCenterY = (compassRoseHeight / 2) + ((getHeight() - compassRoseHeight) / 2); - int marginLeftTemp; - int marginTopTemp; - super.onDraw(canvas); canvas.save(); canvas.setDrawFilter(setfil); - marginLeftTemp = (getWidth() - compassUnderlayWidth) / 2; - marginTopTemp = (getHeight() - compassUnderlayHeight) / 2; + int marginLeftTemp = (getWidth() - compassUnderlayWidth) / 2; + int marginTopTemp = (getHeight() - compassUnderlayHeight) / 2; canvas.drawBitmap(compassUnderlay, marginLeftTemp, marginTopTemp, null); diff --git a/main/src/cgeo/geocaching/ui/EditorDialog.java b/main/src/cgeo/geocaching/ui/EditorDialog.java index 50b3e27..6dcf546 100644 --- a/main/src/cgeo/geocaching/ui/EditorDialog.java +++ b/main/src/cgeo/geocaching/ui/EditorDialog.java @@ -53,7 +53,7 @@ public class EditorDialog extends Dialog { @Override public void show() { super.show(); - getWindow().setLayout(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); + getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); } } diff --git a/main/src/cgeo/geocaching/ui/Formatter.java b/main/src/cgeo/geocaching/ui/Formatter.java index 53a7276..e006d57 100644 --- a/main/src/cgeo/geocaching/ui/Formatter.java +++ b/main/src/cgeo/geocaching/ui/Formatter.java @@ -153,7 +153,7 @@ public abstract class Formatter { public static String formatWaypointInfo(cgWaypoint waypoint) { final List<String> infos = new ArrayList<String>(3); - if (WaypointType.ALL_TYPES_EXCEPT_OWN.contains(waypoint.getWaypointType())) { + if (WaypointType.ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL.contains(waypoint.getWaypointType())) { infos.add(waypoint.getWaypointType().getL10n()); } if (cgWaypoint.PREFIX_OWN.equalsIgnoreCase(waypoint.getPrefix())) { diff --git a/main/src/cgeo/geocaching/ui/ImagesList.java b/main/src/cgeo/geocaching/ui/ImagesList.java index 3d6f95c..8313f2f 100644 --- a/main/src/cgeo/geocaching/ui/ImagesList.java +++ b/main/src/cgeo/geocaching/ui/ImagesList.java @@ -53,7 +53,7 @@ public class ImagesList { private final int titleResId; private final int loadingResId; - private ImageType(final int title, final int loading) { + ImageType(final int title, final int loading) { this.titleResId = title; this.loadingResId = loading; } @@ -95,9 +95,8 @@ public class ImagesList { progressDialog.setMax(count); progressDialog.show(); - LinearLayout rowView; for (final cgImage img : images) { - rowView = (LinearLayout) inflater.inflate(R.layout.cache_image_item, null); + LinearLayout rowView = (LinearLayout) inflater.inflate(R.layout.cache_image_item, null); if (StringUtils.isNotBlank(img.getTitle())) { ((TextView) rowView.findViewById(R.id.title)).setText(Html.fromHtml(img.getTitle())); @@ -179,10 +178,6 @@ public class ImagesList { bitmaps.clear(); } - public cgImage getImage(int id) { - return images.get(id); - } - public void onCreateContextMenu(ContextMenu menu, View v) { final Resources res = activity.getResources(); menu.setHeaderTitle(res.getString(R.string.cache_image)); diff --git a/main/src/cgeo/geocaching/ui/LoggingUI.java b/main/src/cgeo/geocaching/ui/LoggingUI.java index 0e048c3..eaa25ef 100644 --- a/main/src/cgeo/geocaching/ui/LoggingUI.java +++ b/main/src/cgeo/geocaching/ui/LoggingUI.java @@ -4,7 +4,7 @@ import cgeo.geocaching.LogEntry; import cgeo.geocaching.R; import cgeo.geocaching.Settings; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.cgData; import cgeo.geocaching.activity.IAbstractActivity; import cgeo.geocaching.enumerations.LogType; @@ -52,7 +52,7 @@ public class LoggingUI extends AbstractUIFactory { private final int stringId; - private SpecialLogType(final int stringId) { + SpecialLogType(final int stringId) { this.stringId = stringId; } @@ -94,7 +94,7 @@ public class LoggingUI extends AbstractUIFactory { } private static void showOfflineMenu(final cgCache cache, final Activity activity) { - final LogEntry currentLog = cgeoapplication.getInstance().loadLogOffline(cache.getGeocode()); + final LogEntry currentLog = cgData.loadLogOffline(cache.getGeocode()); final LogType currentLogType = currentLog == null ? null : currentLog.type; final List<LogType> logTypes = cache.getPossibleLogTypes(); @@ -123,7 +123,8 @@ public class LoggingUI extends AbstractUIFactory { break; case CLEAR_LOG: - cgeoapplication.getInstance().clearLogOffline(cache.getGeocode()); + cgData.clearLogOffline(cache.getGeocode()); + break; } } else { cache.logOffline(activity, logTypeEntry.logType); diff --git a/main/src/cgeo/geocaching/ui/WeakReferenceHandler.java b/main/src/cgeo/geocaching/ui/WeakReferenceHandler.java new file mode 100644 index 0000000..4724466 --- /dev/null +++ b/main/src/cgeo/geocaching/ui/WeakReferenceHandler.java @@ -0,0 +1,27 @@ +package cgeo.geocaching.ui; + +import android.app.Activity; +import android.os.Handler; + +import java.lang.ref.WeakReference; + +/** + * Standard handler implementation which uses a weak reference to its activity. This avoids that activities stay in + * memory due to references from the handler to the activity (see Android Lint warning "HandlerLeak") + * + * Create static private subclasses of this handler class in your activity. + * + * @param <ActivityType> + */ +public abstract class WeakReferenceHandler<ActivityType extends Activity> extends Handler { + + private final WeakReference<ActivityType> activityRef; + + protected WeakReferenceHandler(final ActivityType activity) { + this.activityRef = new WeakReference<ActivityType>(activity); + } + + protected ActivityType getActivity() { + return activityRef.get(); + } +} diff --git a/main/src/cgeo/geocaching/utils/AngleUtils.java b/main/src/cgeo/geocaching/utils/AngleUtils.java index e2b4a66..6e59a91 100644 --- a/main/src/cgeo/geocaching/utils/AngleUtils.java +++ b/main/src/cgeo/geocaching/utils/AngleUtils.java @@ -8,9 +8,11 @@ public class AngleUtils { /** * Return the angle to turn of to go from an angle to the other - * - * @param from the origin angle in degrees - * @param to the target angle in degreees + * + * @param from + * the origin angle in degrees + * @param to + * the target angle in degrees * @return a value in degrees, in the [-180, 180[ range */ public static float difference(final float from, final float to) { diff --git a/main/src/cgeo/geocaching/utils/CryptUtils.java b/main/src/cgeo/geocaching/utils/CryptUtils.java index f04327e..7a23156 100644 --- a/main/src/cgeo/geocaching/utils/CryptUtils.java +++ b/main/src/cgeo/geocaching/utils/CryptUtils.java @@ -46,16 +46,14 @@ public final class CryptUtils { boolean plaintext = false; final int length = text.length(); - int c; - int capitalized; for (int index = 0; index < length; index++) { - c = text.charAt(index); + int c = text.charAt(index); if (c == '[') { plaintext = true; } else if (c == ']') { plaintext = false; } else if (!plaintext) { - capitalized = c & 32; + int capitalized = c & 32; c &= ~capitalized; c = ((c >= 'A') && (c <= 'Z') ? ((c - 'A' + 13) % 26 + 'A') : c) | capitalized; @@ -116,16 +114,14 @@ public final class CryptUtils { boolean plaintext = false; final int length = span.length(); - int c; - int capitalized; for (int index = 0; index < length; index++) { - c = span.charAt(index); + int c = span.charAt(index); if (c == '[') { plaintext = true; } else if (c == ']') { plaintext = false; } else if (!plaintext) { - capitalized = c & 32; + int capitalized = c & 32; c &= ~capitalized; c = ((c >= 'A') && (c <= 'Z') ? ((c - 'A' + 13) % 26 + 'A') : c) | capitalized; diff --git a/main/src/cgeo/geocaching/utils/ImageHelper.java b/main/src/cgeo/geocaching/utils/ImageHelper.java index 4c18b06..98cad64 100644 --- a/main/src/cgeo/geocaching/utils/ImageHelper.java +++ b/main/src/cgeo/geocaching/utils/ImageHelper.java @@ -1,13 +1,12 @@ package cgeo.geocaching.utils; import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.compatibility.Compatibility; -import android.content.Context; import android.graphics.Bitmap; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; -import android.view.Display; -import android.view.WindowManager; public class ImageHelper { @@ -24,9 +23,9 @@ public class ImageHelper { */ public static BitmapDrawable scaleBitmapToFitDisplay(final Bitmap image) { final cgeoapplication app = cgeoapplication.getInstance(); - final Display display = ((WindowManager) app.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); - final int maxWidth = display.getWidth() - 25; - final int maxHeight = display.getHeight() - 25; + Point displaySize = Compatibility.getDisplaySize(); + final int maxWidth = displaySize.x - 25; + final int maxHeight = displaySize.y - 25; Bitmap result = image; int width = image.getWidth(); diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java index f0bc4f5..6122532 100644 --- a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java +++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java @@ -16,7 +16,7 @@ import java.util.Map; */ public abstract class LeastRecentlyUsedMap<K, V> extends LinkedHashMap<K, V> { - private static enum OperationModes { + private enum OperationModes { LRU_CACHE, BOUNDED } diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java index 98aba03..0df3289 100644 --- a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java +++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java @@ -120,7 +120,7 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E> */ @Override @SuppressWarnings("unchecked") - public Object clone() { + public Object clone() throws CloneNotSupportedException { try { synchronized (this) { final LeastRecentlyUsedSet<E> newSet = (LeastRecentlyUsedSet<E>) super.clone(); diff --git a/main/src/cgeo/geocaching/utils/PeriodicHandler.java b/main/src/cgeo/geocaching/utils/PeriodicHandler.java index 3f6c345..ac6b22a 100644 --- a/main/src/cgeo/geocaching/utils/PeriodicHandler.java +++ b/main/src/cgeo/geocaching/utils/PeriodicHandler.java @@ -26,7 +26,7 @@ abstract public class PeriodicHandler extends Handler { * @param period * The period in milliseconds. */ - public PeriodicHandler(final long period) { + protected PeriodicHandler(final long period) { this.period = period; } diff --git a/main/src/cgeo/geocaching/utils/TranslationUtils.java b/main/src/cgeo/geocaching/utils/TranslationUtils.java index a29c5a7..4d318f0 100644 --- a/main/src/cgeo/geocaching/utils/TranslationUtils.java +++ b/main/src/cgeo/geocaching/utils/TranslationUtils.java @@ -1,12 +1,11 @@ package cgeo.geocaching.utils; import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.network.Network; import android.content.Intent; import android.net.Uri; -import java.net.URLEncoder; - /** * Utilities used for translating */ @@ -30,7 +29,7 @@ public final class TranslationUtils { * @return URI ready to be parsed */ private static String buildTranslationURI(final String toLang, final String text) { - String content = URLEncoder.encode(text); + String content = Network.encode(text); // the app works better without the "+", the website works better with "+", therefore assume using the app if installed if (ProcessUtils.isInstalled(TRANSLATION_APP)) { content = content.replace("+", "%20"); diff --git a/main/src/com/viewpagerindicator/TitlePageIndicator.java b/main/src/com/viewpagerindicator/TitlePageIndicator.java index a181fed..94ac962 100644 --- a/main/src/com/viewpagerindicator/TitlePageIndicator.java +++ b/main/src/com/viewpagerindicator/TitlePageIndicator.java @@ -65,7 +65,7 @@ public class TitlePageIndicator extends View implements PageIndicator { public final int value; - private IndicatorStyle(int value) { + IndicatorStyle(int value) { this.value = value; } @@ -686,15 +686,13 @@ public class TitlePageIndicator extends View implements PageIndicator { * @return The width of the view, honoring constraints from measureSpec */ private int measureWidth(int measureSpec) { - int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode != MeasureSpec.EXACTLY) { throw new IllegalStateException(getClass().getSimpleName() + " can only be used in EXACTLY mode."); } - result = specSize; - return result; + return specSize; } /** diff --git a/main/src/gnu/android/app/appmanualclient/AppManualReaderClient.java b/main/src/gnu/android/app/appmanualclient/AppManualReaderClient.java index 28950b9..af4c03e 100644 --- a/main/src/gnu/android/app/appmanualclient/AppManualReaderClient.java +++ b/main/src/gnu/android/app/appmanualclient/AppManualReaderClient.java @@ -233,9 +233,8 @@ public class AppManualReaderClient { // manuals this doesn't matter, as the user then can choose which // one to use on a single or permanent basis. // - String logTag = "appmanualclient"; - for ( ;; ) { - Uri uri = Uri.parse(URI_SCHEME_APPMANUAL + "://" + manualIdentifier + while (true) { + Uri uri = Uri.parse(URI_SCHEME_APPMANUAL + "://" + manualIdentifier + localePath + "#topic='" + topic + "'"); // Note: we do not use a MIME type for this. intent.setData(uri); @@ -300,7 +299,8 @@ public class AppManualReaderClient { | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); } try { - if ( Log.isLoggable(logTag, Log.INFO) ) { + String logTag = "appmanualclient"; + if ( Log.isLoggable(logTag, Log.INFO) ) { Log.i(logTag, "Trying to activate manual: uri=" + uri.toString()); } diff --git a/main/src/org/openintents/intents/FileManagerIntents.java b/main/src/org/openintents/intents/FileManagerIntents.java new file mode 100644 index 0000000..8ff10c8 --- /dev/null +++ b/main/src/org/openintents/intents/FileManagerIntents.java @@ -0,0 +1,127 @@ +/*
+ * Copyright (C) 2008 OpenIntents.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.openintents.intents;
+
+/**
+ * Provides OpenIntents actions, extras, and categories used by providers.
+ * <p>These specifiers extend the standard Android specifiers.</p>
+ */
+public final class FileManagerIntents {
+
+ /**
+ * Activity Action: Pick a file through the file manager, or let user
+ * specify a custom file name.
+ * Data is the current file name or file name suggestion.
+ * Returns a new file name as file URI in data.
+ *
+ * <p>Constant Value: "org.openintents.action.PICK_FILE"</p>
+ */
+ public static final String ACTION_PICK_FILE = "org.openintents.action.PICK_FILE";
+
+ /**
+ * Activity Action: Pick a directory through the file manager, or let user
+ * specify a custom file name.
+ * Data is the current directory name or directory name suggestion.
+ * Returns a new directory name as file URI in data.
+ *
+ * <p>Constant Value: "org.openintents.action.PICK_DIRECTORY"</p>
+ */
+ public static final String ACTION_PICK_DIRECTORY = "org.openintents.action.PICK_DIRECTORY";
+
+ /**
+ * Activity Action: Move, copy or delete after select entries.
+ * Data is the current directory name or directory name suggestion.
+ *
+ * <p>Constant Value: "org.openintents.action.MULTI_SELECT"</p>
+ */
+ public static final String ACTION_MULTI_SELECT = "org.openintents.action.MULTI_SELECT";
+
+ public static final String ACTION_SEARCH_STARTED = "org.openintents.action.SEARCH_STARTED";
+
+ public static final String ACTION_SEARCH_FINISHED = "org.openintens.action.SEARCH_FINISHED";
+
+ /**
+ * The title to display.
+ *
+ * <p>This is shown in the title bar of the file manager.</p>
+ *
+ * <p>Constant Value: "org.openintents.extra.TITLE"</p>
+ */
+ public static final String EXTRA_TITLE = "org.openintents.extra.TITLE";
+
+ /**
+ * The text on the button to display.
+ *
+ * <p>Depending on the use, it makes sense to set this to "Open" or "Save".</p>
+ *
+ * <p>Constant Value: "org.openintents.extra.BUTTON_TEXT"</p>
+ */
+ public static final String EXTRA_BUTTON_TEXT = "org.openintents.extra.BUTTON_TEXT";
+
+ /**
+ * Flag indicating to show only writeable files and folders.
+ *
+ * <p>Constant Value: "org.openintents.extra.WRITEABLE_ONLY"</p>
+ */
+ public static final String EXTRA_WRITEABLE_ONLY = "org.openintents.extra.WRITEABLE_ONLY";
+
+ /**
+ * The path to prioritize in search. Usually denotes the path the user was on when the search was initiated.
+ *
+ * <p>Constant Value: "org.openintents.extra.SEARCH_INIT_PATH"</p>
+ */
+ public static final String EXTRA_SEARCH_INIT_PATH = "org.openintents.extra.SEARCH_INIT_PATH";
+
+ /**
+ * The search query as sent to SearchService.
+ *
+ * <p>Constant Value: "org.openintents.extra.SEARCH_QUERY"</p>
+ */
+ public static final String EXTRA_SEARCH_QUERY = "org.openintents.extra.SEARCH_QUERY";
+
+ /**
+ * <p>Constant Value: "org.openintents.extra.DIR_PATH"</p>
+ */
+ public static final String EXTRA_DIR_PATH = "org.openintents.extra.DIR_PATH";
+
+ /**
+ * Extension by which to filter.
+ *
+ * <p>Constant Value: "org.openintents.extra.FILTER_FILETYPE"</p>
+ */
+ public static final String EXTRA_FILTER_FILETYPE = "org.openintents.extra.FILTER_FILETYPE";
+
+ /**
+ * Mimetype by which to filter.
+ *
+ * <p>Constant Value: "org.openintents.extra.FILTER_MIMETYPE"</p>
+ */
+ public static final String EXTRA_FILTER_MIMETYPE = "org.openintents.extra.FILTER_MIMETYPE";
+
+ /**
+ * Only show directories.
+ *
+ * <p>Constant Value: "org.openintents.extra.DIRECTORIES_ONLY"</p>
+ */
+ public static final String EXTRA_DIRECTORIES_ONLY = "org.openintents.extra.DIRECTORIES_ONLY";
+
+ public static final String EXTRA_DIALOG_FILE_HOLDER = "org.openintents.extra.DIALOG_FILE";
+
+ public static final String EXTRA_IS_GET_CONTENT_INITIATED = "org.openintents.extra.ENABLE_ACTIONS";
+
+ public static final String EXTRA_FILENAME = "org.openintents.extra.FILENAME";
+}
|
