diff options
Diffstat (limited to 'main/src')
25 files changed, 538 insertions, 348 deletions
diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java index 528b2e2..a9c9dbf 100644 --- a/main/src/cgeo/geocaching/CacheDetailActivity.java +++ b/main/src/cgeo/geocaching/CacheDetailActivity.java @@ -65,6 +65,7 @@ import android.view.Menu; import android.view.MenuItem; import android.view.SubMenu; import android.view.View; +import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewParent; @@ -157,6 +158,13 @@ public class CacheDetailActivity extends AbstractActivity { // some views that must be available from everywhere // TODO: Reference can block GC? private TextView cacheDistanceView; + private Handler cacheChangeNotificationHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + notifyDataSetChanged(); + } + }; + public CacheDetailActivity() { // identifier for manual super("c:geolocation-cache-details"); @@ -262,6 +270,15 @@ public class CacheDetailActivity extends AbstractActivity { // nothing, we lost the window } + ImageView defaultNavigationImageView = (ImageView) findViewById(R.id.defaultNavigation); + defaultNavigationImageView.setOnLongClickListener(new OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + startDefaultNavigation2(); + return true; + } + }); + // initialize ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager); viewPagerAdapter = new ViewPagerAdapter(); @@ -314,7 +331,9 @@ public class CacheDetailActivity extends AbstractActivity { if (geolocation == null) { geolocation = app.startGeo(locationUpdater); } - + if (cache != null) { + cache.setChangeNotificationHandler(cacheChangeNotificationHandler); + } if (refreshOnResume) { notifyDataSetChanged(); refreshOnResume = false; @@ -336,6 +355,10 @@ public class CacheDetailActivity extends AbstractActivity { geolocation = app.removeGeo(); } + if (cache != null) { + cache.setChangeNotificationHandler(null); + } + super.onStop(); } @@ -840,6 +863,19 @@ public class CacheDetailActivity extends AbstractActivity { } /** + * Tries to navigate to the {@link cgCache} of this activity. + */ + private void startDefaultNavigation2() { + if (cache == null || cache.getCoords() == null) { + showToast(res.getString(R.string.err_location_unknown)); + return; + } + + //TODO: previously this used also the search argument "search". check if still needed + NavigationAppFactory.startDefaultNavigationApplication2(geolocation, this, cache, null, null); + } + + /** * Wrapper for the referenced method in the xml-layout. */ public void startDefaultNavigation(@SuppressWarnings("unused") View view) { @@ -858,7 +894,7 @@ public class CacheDetailActivity extends AbstractActivity { } /** - * Opens a dialog to do actions on an username + * Listener for clicks on username */ private class UserActionsClickListener implements View.OnClickListener { @@ -871,36 +907,65 @@ public class CacheDetailActivity extends AbstractActivity { } clickedItemText = ((TextView) view).getText().toString(); + showUserActionsDialog(clickedItemText); + } + } - final CharSequence[] items = {res.getString(R.string.user_menu_view_hidden), - res.getString(R.string.user_menu_view_found), - res.getString(R.string.user_menu_open_browser) - }; - - AlertDialog.Builder builder = new AlertDialog.Builder(CacheDetailActivity.this); - builder.setTitle(res.getString(R.string.user_menu_title) + " " + clickedItemText); - builder.setItems(items, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int item) { - switch (item) { - case 0: - cgeocaches.startActivityOwner(CacheDetailActivity.this, clickedItemText.toString()); - return; - case 1: - cgeocaches.startActivityUserName(CacheDetailActivity.this, clickedItemText.toString()); - return; - case 2: - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?u=" + URLEncoder.encode(clickedItemText.toString())))); - return; - default: - break; - } - } - }); - AlertDialog alert = builder.create(); - alert.show(); + /** + * Listener for clicks on owner name + */ + private class OwnerActionsClickListener implements View.OnClickListener { + + public void onClick(View view) { + if (view == null) { + return; + } + if (!cache.supportsUserActions()) { + return; + } + + // Use real owner name vice the one owner chose to display + if (StringUtils.isNotBlank(cache.getOwnerReal())) { + clickedItemText = cache.getOwnerReal(); + } else { + clickedItemText = ((TextView) view).getText().toString(); + } + showUserActionsDialog(clickedItemText); } } + /** + * Opens a dialog to do actions on an username + */ + private void showUserActionsDialog(final CharSequence name) { + final CharSequence[] items = { res.getString(R.string.user_menu_view_hidden), + res.getString(R.string.user_menu_view_found), + res.getString(R.string.user_menu_open_browser) + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(CacheDetailActivity.this); + builder.setTitle(res.getString(R.string.user_menu_title) + " " + name); + builder.setItems(items, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int item) { + switch (item) { + case 0: + cgeocaches.startActivityOwner(CacheDetailActivity.this, name.toString()); + return; + case 1: + 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())))); + return; + default: + break; + } + } + }); + AlertDialog alert = builder.create(); + alert.show(); + } + public static void startActivity(final Context context, final String geocode) { final Intent detailIntent = new Intent(context, CacheDetailActivity.class); detailIntent.putExtra("geocode", geocode.toUpperCase()); @@ -1394,10 +1459,10 @@ public class CacheDetailActivity extends AbstractActivity { TextView ownerView = addCacheDetail(R.string.cache_owner, ""); if (StringUtils.isNotBlank(cache.getOwner())) { ownerView.setText(Html.fromHtml(cache.getOwner()), TextView.BufferType.SPANNABLE); - } else if (StringUtils.isNotBlank(cache.getOwnerReal())) { + } else { // OwnerReal guaranteed to be not blank based on above ownerView.setText(Html.fromHtml(cache.getOwnerReal()), TextView.BufferType.SPANNABLE); } - ownerView.setOnClickListener(new UserActionsClickListener()); + ownerView.setOnClickListener(new OwnerActionsClickListener()); } // cache hidden diff --git a/main/src/cgeo/geocaching/GCConstants.java b/main/src/cgeo/geocaching/GCConstants.java index fe8c74f..d884380 100644 --- a/main/src/cgeo/geocaching/GCConstants.java +++ b/main/src/cgeo/geocaching/GCConstants.java @@ -63,8 +63,8 @@ public final class GCConstants { // Info box top-right public static final Pattern PATTERN_LOGIN_NAME = Pattern.compile("\"SignedInProfileLink\">([^<]+)</a>"); public static final Pattern PATTERN_MEMBER_STATUS = Pattern.compile("<span id=\"ctl00_litPMLevel\" style=\"display: block;\">([^<]+)</span>"); - /** Use replaceAll(",","") on the resulting string before converting to an int */ - public static final Pattern PATTERN_CACHES_FOUND = Pattern.compile("title=\"Caches Found\"[\\s\\w=\"/\\.]*/>\\s*([\\d,]+)"); + /** Use replaceAll("[,.]","") on the resulting string before converting to an int */ + public static final Pattern PATTERN_CACHES_FOUND = Pattern.compile("title=\"Caches Found\"[\\s\\w=\"/.]*/>\\s*([\\d,.]+)"); public static final Pattern PATTERN_AVATAR_IMAGE_PROFILE_PAGE = Pattern.compile("<img src=\"(http://img.geocaching.com/user/avatar/[0-9a-f-]+\\.jpg)\"[^>]*\\salt=\"Avatar\""); public static final Pattern PATTERN_LOGIN_NAME_LOGIN_PAGE = Pattern.compile("<span class=\"Success\">You are logged in as[^<]*<strong[^>]*>([^<]+)</strong>[^<]*</span>"); public static final Pattern PATTERN_CUSTOMDATE = Pattern.compile("<option selected=\"selected\" value=\"([ /Mdy-]+)\">"); @@ -92,6 +92,7 @@ public final class GCConstants { 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.+?src=\"/images/icons/([^.]+)\\.gif[^>]+> ([^<]+)</td>.+?guid.+?>([^<]+)</a>.+?(?:guid=([^\"]+)\">(<span class=\"Strike\">)?([^<]+)</.+?)?<td colspan=\"4\">(.+?)(?:<ul.+?ul>)?\\s*</td>\\s*</tr>"); + public final static Pattern PATTERN_TRACKABLE_LOG_IMAGES = Pattern.compile(".+?<li><a href=\"([^\"]+)\".+?LogImgTitle.+?>([^<]+)</"); /** * Patterns for parsing the result of a search (next) @@ -135,11 +136,16 @@ public final class GCConstants { public final static Pattern PATTERN_MAINTENANCE = Pattern.compile("<span id=\"ctl00_ContentBody_LogBookPanel1_lbConfirm\"[^>]*>([^<]*<font[^>]*>)?([^<]+)(</font>[^<]*)?</span>", Pattern.CASE_INSENSITIVE); public final static Pattern PATTERN_OK1 = Pattern.compile("<h2[^>]*>[^<]*<span id=\"ctl00_ContentBody_lbHeading\"[^>]*>[^<]*</span>[^<]*</h2>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); public final static Pattern PATTERN_OK2 = Pattern.compile("<div id=[\"|']ctl00_ContentBody_LogBookPanel1_ViewLogPanel[\"|']>", Pattern.CASE_INSENSITIVE); - public final static Pattern PATTERN_USERTOKEN = Pattern.compile("var userToken[^=]*=[^']*'([^']+)';", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); public final static Pattern PATTERN_VIEWSTATEFIELDCOUNT = Pattern.compile("id=\"__VIEWSTATEFIELDCOUNT\"[^(value)]+value=\"(\\d+)\"[^>]+>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); public final static Pattern PATTERN_VIEWSTATES = Pattern.compile("id=\"__VIEWSTATE(\\d*)\"[^(value)]+value=\"([^\"]+)\"[^>]+>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); public final static Pattern PATTERN_USERTOKEN2 = Pattern.compile("userToken\\s*=\\s*'([^']+)'"); + /** + * Patterns for GC and TB codes + */ + public final static Pattern PATTERN_GC_CODE = Pattern.compile("GC[0-9A-Z]*", Pattern.CASE_INSENSITIVE); + public final static Pattern PATTERN_TB_CODE = Pattern.compile("TB[0-9A-Z]*", Pattern.CASE_INSENSITIVE); + /** Live Map since 14.02.2012 */ public final static Pattern PATTERN_USERSESSION = Pattern.compile("UserSession\\('([^']+)'"); public final static Pattern PATTERN_SESSIONTOKEN = Pattern.compile("sessionToken:'([^']+)'"); diff --git a/main/src/cgeo/geocaching/Settings.java b/main/src/cgeo/geocaching/Settings.java index 4f9a240..af1ad0a 100644 --- a/main/src/cgeo/geocaching/Settings.java +++ b/main/src/cgeo/geocaching/Settings.java @@ -76,6 +76,7 @@ public final class Settings { private static final String KEY_LAST_DETAILS_PAGE = "lastdetailspage"; private static final String KEY_DEBUG_INFORMATIONS = "debuginfos"; private static final String KEY_DEFAULT_NAVIGATION_TOOL = "defaultNavigationTool"; + private static final String KEY_DEFAULT_NAVIGATION_TOOL_2 = "defaultNavigationTool2"; private final static int unitsMetric = 1; private final static int unitsImperial = 2; @@ -999,4 +1000,18 @@ public final class Settings { } }); } + + public static int getDefaultNavigationTool2() { + return sharedPrefs.getInt(KEY_DEFAULT_NAVIGATION_TOOL_2, 0); + } + + public static void setDefaultNavigationTool2(final int defaultNavigationTool) { + editSharedSettings(new PrefRunnable() { + + @Override + public void edit(Editor edit) { + edit.putInt(KEY_DEFAULT_NAVIGATION_TOOL_2, defaultNavigationTool); + } + }); + } } diff --git a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java index 53240bc..e2a1fc1 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java @@ -90,7 +90,7 @@ public final class NavigationAppFactory extends AbstractAppFactory { /** * Specialized way to handle selection of navigation tool.<br /> * A dialog is created for tool selection and the selected tool is started afterwards. - * + * * @param geo * @param activity * @param cache @@ -103,7 +103,7 @@ public final class NavigationAppFactory extends AbstractAppFactory { * should be <code>false</code> only when called from within the internal map * @param showDefaultNavigation * should be <code>false</code> by default - * + * * @see #showNavigationMenu(cgGeo, Activity, cgCache, cgWaypoint, Geopoint) */ public static void showNavigationMenu(final cgGeo geo, final Activity activity, @@ -297,8 +297,31 @@ public final class NavigationAppFactory extends AbstractAppFactory { } /** + * Starts the second default navigation tool if correctly set and installed or the compass app as default fallback. + * + * @param geo + * @param activity + * @param cache + * @param search + * @param waypoint + * @param destination + */ + public static void startDefaultNavigationApplication2(final cgGeo geo, Activity activity, cgCache cache, + cgWaypoint waypoint, final Geopoint destination) { + final NavigationApp app = getDefaultNavigationApplication2(activity); + + if (app != null) { + try { + app.invoke(geo, activity, cache, waypoint, destination); + } catch (Exception e) { + Log.e(Settings.tag, "NavigationAppFactory.startDefaultNavigationApplication2: " + e.toString()); + } + } + } + + /** * Returns the default navigation tool if correctly set and installed or the compass app as default fallback - * + * * @param activity * @return never <code>null</code> */ @@ -316,4 +339,24 @@ public final class NavigationAppFactory extends AbstractAppFactory { return NavigationAppsEnum.COMPASS.app; } + /** + * Returns the second default navigation tool if correctly set and installed or the compass app as default fallback + * + * @param activity + * @return never <code>null</code> + */ + public static NavigationApp getDefaultNavigationApplication2(Activity activity) { + final int defaultNavigationTool = Settings.getDefaultNavigationTool2(); + + final List<NavigationAppsEnum> installedNavigationApps = getInstalledNavigationApps(activity); + + for (NavigationAppsEnum navigationApp : installedNavigationApps) { + if (navigationApp.id == defaultNavigationTool) { + return navigationApp.app; + } + } + // second default navigation tool wasn't set already or couldn't be found (not installed any more for example) + return NavigationAppsEnum.COMPASS.app; + } + } diff --git a/main/src/cgeo/geocaching/cgBase.java b/main/src/cgeo/geocaching/cgBase.java index b05577b..3b057a7 100644 --- a/main/src/cgeo/geocaching/cgBase.java +++ b/main/src/cgeo/geocaching/cgBase.java @@ -19,7 +19,6 @@ import cgeo.geocaching.gcvote.GCVoteRating; import cgeo.geocaching.geopoint.DistanceParser; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter.Format; -import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.network.HtmlImage; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.twitter.Twitter; @@ -41,7 +40,6 @@ import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.cookie.Cookie; -import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.cookie.BasicClientCookie; @@ -79,7 +77,6 @@ import android.widget.LinearLayout; import java.io.File; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; @@ -370,7 +367,7 @@ public class cgBase { if (isActualLoginStatus()) { setActualUserName(BaseUtils.getMatch(page, GCConstants.PATTERN_LOGIN_NAME, true, "???")); setActualMemberStatus(BaseUtils.getMatch(page, GCConstants.PATTERN_MEMBER_STATUS, true, "???")); - setActualCachesFound(Integer.parseInt(BaseUtils.getMatch(page, GCConstants.PATTERN_CACHES_FOUND, true, "0").replaceAll(",", ""))); + setActualCachesFound(Integer.parseInt(BaseUtils.getMatch(page, GCConstants.PATTERN_CACHES_FOUND, true, "0").replaceAll("[,.]", ""))); return true; } @@ -695,101 +692,6 @@ public class cgBase { return searchResult; } - // TODO Valentine Remove with merge - @Deprecated - public static SearchResult parseMapJSON(final String uri, final String data) { - if (StringUtils.isEmpty(data)) { - Log.e(Settings.tag, "cgeoBase.parseMapJSON: No page given"); - return null; - } - - final SearchResult searchResult = new SearchResult(); - searchResult.setUrl(uri); - - try { - final JSONObject yoDawg = new JSONObject(data); - final String json = yoDawg.getString("d"); - - if (StringUtils.isBlank(json)) { - Log.e(Settings.tag, "cgeoBase.parseMapJSON: No JSON inside JSON"); - return null; - } - - final JSONObject dataJSON = new JSONObject(json); - final JSONObject extra = dataJSON.getJSONObject("cs"); - if (extra != null && extra.length() > 0) { - int count = extra.getInt("count"); - // currently unused: 'pm', true for premium members - // check login status - boolean li = extra.getBoolean("li"); - if (!li) { - searchResult.error = StatusCode.NOT_LOGGED_IN; - } - - if (count > 0 && extra.has("cc")) { - final JSONArray cachesData = extra.getJSONArray("cc"); - if (cachesData != null && cachesData.length() > 0) { - JSONObject oneCache = null; - for (int i = 0; i < count; i++) { - oneCache = cachesData.getJSONObject(i); - if (oneCache == null) { - break; - } - - final cgCache cacheToAdd = new cgCache(); - cacheToAdd.setDetailed(false); - // coords are reliable if we are logged in - cacheToAdd.setReliableLatLon(li); - cacheToAdd.setGeocode(oneCache.getString("gc")); - cacheToAdd.setCoords(new Geopoint(oneCache.getDouble("lat"), oneCache.getDouble("lon"))); - cacheToAdd.setName(oneCache.getString("nn")); - cacheToAdd.setFound(oneCache.getBoolean("f")); - cacheToAdd.setOwn(oneCache.getBoolean("o")); - cacheToAdd.setDisabled(!oneCache.getBoolean("ia")); - int ctid = oneCache.getInt("ctid"); - if (ctid == 2) { - cacheToAdd.setType(CacheType.TRADITIONAL); - } else if (ctid == 3) { - cacheToAdd.setType(CacheType.MULTI); - } else if (ctid == 4) { - cacheToAdd.setType(CacheType.VIRTUAL); - } else if (ctid == 5) { - cacheToAdd.setType(CacheType.LETTERBOX); - } else if (ctid == 6) { - cacheToAdd.setType(CacheType.EVENT); - } else if (ctid == 8) { - cacheToAdd.setType(CacheType.MYSTERY); - } else if (ctid == 11) { - cacheToAdd.setType(CacheType.WEBCAM); - } else if (ctid == 13) { - cacheToAdd.setType(CacheType.CITO); - } else if (ctid == 137) { - cacheToAdd.setType(CacheType.EARTH); - } else if (ctid == 453) { - cacheToAdd.setType(CacheType.MEGA_EVENT); - } else if (ctid == 1858) { - cacheToAdd.setType(CacheType.WHERIGO); - } else if (ctid == 3653) { - cacheToAdd.setType(CacheType.LOSTANDFOUND); - } else { - cacheToAdd.setType(CacheType.UNKNOWN); - } - - searchResult.addCache(cacheToAdd); - } - } - } else { - Log.w(Settings.tag, "There are no caches in viewport. Probably the viewport is too big"); - } - searchResult.totalCnt = searchResult.getGeocodes().size(); - } - } catch (Exception e) { - Log.e(Settings.tag, "cgBase.parseMapJSON", e); - } - - return searchResult; - } - public static SearchResult parseCache(final String page, final int listId, final CancellableHandler handler) { final SearchResult searchResult = parseCacheFromText(page, listId, handler); if (searchResult != null && !searchResult.getGeocodes().isEmpty()) { @@ -1426,7 +1328,7 @@ public class cgBase { Settings.setMemberStatus(BaseUtils.getMatch(profile, GCConstants.PATTERN_MEMBER_STATUS, true, null)); - setActualCachesFound(Integer.parseInt(BaseUtils.getMatch(profile, GCConstants.PATTERN_CACHES_FOUND, true, "-1").replaceAll(",", ""))); + setActualCachesFound(Integer.parseInt(BaseUtils.getMatch(profile, GCConstants.PATTERN_CACHES_FOUND, true, "-1").replaceAll("[,.]", ""))); final String avatarURL = BaseUtils.getMatch(profile, GCConstants.PATTERN_AVATAR_IMAGE_PROFILE_PAGE, false, null); if (null != avatarURL) { @@ -1598,11 +1500,26 @@ public class cgBase { logDone.cacheName = matcherLogs.group(6); } + // Apply the pattern for images in a trackable log entry against each full log (group(0)) + final Matcher matcherLogImages = GCConstants.PATTERN_TRACKABLE_LOG_IMAGES.matcher(matcherLogs.group(0)); + /* + * 1. Image URL + * 2. Image title + */ + while (matcherLogImages.find()) + { + final cgImage logImage = new cgImage(matcherLogImages.group(1), matcherLogImages.group(2)); + if (logDone.logImages == null) { + logDone.logImages = new ArrayList<cgImage>(); + } + logDone.logImages.add(logImage); + } + trackable.getLogs().add(logDone); } } catch (Exception e) { // failed to parse logs - Log.w(Settings.tag, "cgeoBase.parseCache: Failed to parse cache logs"); + Log.w(Settings.tag, "cgeoBase.parseCache: Failed to parse cache logs" + e.toString()); } // trackingcode @@ -1879,35 +1796,6 @@ public class cgBase { return searchByAny(thread, cacheType, false, listId, showCaptcha, params); } - // TODO Valentine Remove with merge - @Deprecated - public static SearchResult searchByViewport(final String userToken, final Viewport viewport) { - - String page = null; - - final String params = "{\"dto\":{\"data\":{\"c\":1,\"m\":\"\",\"d\":\"" + - viewport.getLatitudeMax() + "|" + viewport.getLatitudeMin() + "|" + - viewport.getLongitudeMax() + "|" + viewport.getLongitudeMin() + "\"},\"ut\":\"" + - StringUtils.defaultString(userToken) + "\"}}"; - - final String uri = "http://www.geocaching.com/map/default.aspx/MapAction"; - page = requestJSONgc(uri, params); - - if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.searchByViewport: No data from server"); - return null; - } - - final SearchResult searchResult = parseMapJSON(Uri.parse(uri).buildUpon().encodedQuery(params).build().toString(), page); - if (searchResult == null || CollectionUtils.isEmpty(searchResult.getGeocodes())) { - Log.e(Settings.tag, "cgeoBase.searchByViewport: No cache parsed for viewport " + viewport); - return null; - } - - final SearchResult search = searchResult.filterSearchResults(Settings.isExcludeDisabledCaches(), Settings.isExcludeMyCaches(), Settings.getCacheType(), StoredList.TEMPORARY_LIST_ID); - return search; - } - /** Request .png image for a tile. Ignore the image - just load it */ public static void requestMapTile(final String url, final String referer) { final HttpGet request = new HttpGet(url); @@ -1928,24 +1816,6 @@ public class cgBase { return getResponseData(request(request), false); } - // TODO Valentine Remove with merge - @Deprecated - public static String requestJSONgc(final String uri, final String params) { - final HttpPost request = new HttpPost("http://www.geocaching.com/map/default.aspx/MapAction"); - try { - request.setEntity(new StringEntity(params, HTTP.UTF_8)); - } catch (UnsupportedEncodingException e) { - Log.e(Settings.tag, "cgeoBase.searchByViewport", e); - } - - request.addHeader("Content-Type", "application/json; charset=UTF-8"); - request.addHeader("X-Requested-With", "XMLHttpRequest"); - request.addHeader("Accept", "application/json, text/javascript, */*; q=0.01"); - request.addHeader("Referer", uri); - String page = getResponseData(request(request)); - return page; - } - public static cgTrackable searchTrackable(final String geocode, final String guid, final String id) { if (StringUtils.isBlank(geocode) && StringUtils.isBlank(guid) && StringUtils.isBlank(id)) { Log.w(Settings.tag, "cgeoBase.searchTrackable: No geocode nor guid nor id given"); @@ -2917,29 +2787,6 @@ public class cgBase { return false; } - // TODO Valentine Remove with merge - @Deprecated - public static String getMapUserToken(final Handler noTokenHandler) { - final HttpResponse response = request("http://www.geocaching.com/map/default.aspx", null, false); - final String data = getResponseData(response); - String usertoken = null; - - if (StringUtils.isNotBlank(data)) { - final Matcher matcher = GCConstants.PATTERN_USERTOKEN.matcher(data); - while (matcher.find()) { - if (matcher.groupCount() > 0) { - usertoken = matcher.group(1); - } - } - } - - if (noTokenHandler != null && StringUtils.isBlank(usertoken)) { - noTokenHandler.sendEmptyMessage(0); - } - - return usertoken; - } - public static Double getElevation(final Geopoint coords) { try { final String uri = "http://maps.googleapis.com/maps/api/elevation/json"; diff --git a/main/src/cgeo/geocaching/cgCache.java b/main/src/cgeo/geocaching/cgCache.java index de3680e..f49dffe 100644 --- a/main/src/cgeo/geocaching/cgCache.java +++ b/main/src/cgeo/geocaching/cgCache.java @@ -24,6 +24,7 @@ import android.app.Activity; import android.content.Intent; import android.content.res.Resources; import android.net.Uri; +import android.os.Handler; import android.text.Spannable; import android.util.Log; @@ -102,6 +103,20 @@ public class cgCache implements ICache { private static final Pattern NUMBER_PATTERN = Pattern.compile("\\d+"); + private Handler changeNotificationHandler = null; + + public void setChangeNotificationHandler(Handler newNotificationHandler) { + changeNotificationHandler = newNotificationHandler; + } + + /** + * Sends a change notification to interested parties + */ + private void notifyChange() { + if (changeNotificationHandler != null) + changeNotificationHandler.sendEmptyMessage(0); + } + /** * Gather missing information from another cache object. * @@ -254,7 +269,13 @@ public class cgCache implements ICache { reliableLatLon = other.reliableLatLon; } - return isEqualTo(other); + boolean isEqual = isEqualTo(other); + + if (!isEqual) { + notifyChange(); + } + + return isEqual; } /** @@ -414,6 +435,8 @@ public class cgCache implements ICache { cgeoapplication app = (cgeoapplication) ((Activity) fromActivity).getApplication(); final boolean status = app.saveLogOffline(geocode, date.getTime(), logType, log); + notifyChange(); + Resources res = ((Activity) fromActivity).getResources(); if (status) { fromActivity.showToast(res.getString(R.string.info_log_saved)); diff --git a/main/src/cgeo/geocaching/cgeo.java b/main/src/cgeo/geocaching/cgeo.java index c012f3a..91cfaf7 100644 --- a/main/src/cgeo/geocaching/cgeo.java +++ b/main/src/cgeo/geocaching/cgeo.java @@ -15,6 +15,7 @@ import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import android.app.AlertDialog; +import android.app.SearchManager; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -52,6 +53,8 @@ public class cgeo extends AbstractActivity { private static final int SCAN_REQUEST_CODE = 1; private static final int MENU_OPEN_LIST = 100; + public static final int SEARCH_REQUEST_CODE = 2; + private int version = 0; private cgGeo geo = null; private UpdateLocationCallback geoUpdate = null; @@ -306,17 +309,29 @@ public class cgeo extends AbstractActivity { if (StringUtils.isBlank(scan)) { return; } - String host = "http://coord.info/"; - if (scan.toLowerCase().startsWith(host)) { - String geocode = scan.substring(host.length()).trim(); - CacheDetailActivity.startActivity(this, geocode); - } - else { - showToast(res.getString(R.string.unknown_scan)); - } + + Intent searchIntent = new Intent(this, cgeoadvsearch.class); + searchIntent.setAction(Intent.ACTION_SEARCH). + putExtra(SearchManager.QUERY, scan). + putExtra(cgeoadvsearch.EXTRAS_KEYWORDSEARCH, false); + startActivityForResult(searchIntent, SEARCH_REQUEST_CODE); + } else if (resultCode == RESULT_CANCELED) { // do nothing } + } else if (requestCode == SEARCH_REQUEST_CODE) { + // cgeoadvsearch activity returned without making a search + if (resultCode == RESULT_CANCELED) { + String query = intent.getStringExtra(SearchManager.QUERY); + if (query == null) { + query = ""; + } + new AlertDialog.Builder(this) + .setMessage(res.getString(R.string.unknown_scan) + "\n\n" + query) + .setPositiveButton(getString(android.R.string.ok), null) + .create() + .show(); + } } } diff --git a/main/src/cgeo/geocaching/cgeoadvsearch.java b/main/src/cgeo/geocaching/cgeoadvsearch.java index 754cbdb..7256bb3 100644 --- a/main/src/cgeo/geocaching/cgeoadvsearch.java +++ b/main/src/cgeo/geocaching/cgeoadvsearch.java @@ -4,6 +4,7 @@ import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter; import cgeo.geocaching.geopoint.GeopointParser; +import cgeo.geocaching.utils.BaseUtils; import cgeo.geocaching.utils.EditUtils; import org.apache.commons.lang3.StringUtils; @@ -22,10 +23,10 @@ import android.widget.AutoCompleteTextView; import android.widget.Button; import android.widget.EditText; -import java.util.regex.Pattern; - public class cgeoadvsearch extends AbstractActivity { + public static final String EXTRAS_KEYWORDSEARCH = "keywordsearch"; + private static final int MENU_SEARCH_OWN_CACHES = 1; private cgGeo geo = null; private UpdateLocationCallback geoUpdate = new update(); @@ -48,13 +49,17 @@ public class cgeoadvsearch extends AbstractActivity { Intent intent = getIntent(); if (Intent.ACTION_SEARCH.equals(intent.getAction())) { final String query = intent.getStringExtra(SearchManager.QUERY); - final boolean found = instantSearch(query); - - if (found) { - finish(); + final boolean keywordSearch = intent.getBooleanExtra(EXTRAS_KEYWORDSEARCH, true); - return; + if (instantSearch(query, keywordSearch)) { + setResult(RESULT_OK); + } else { + // send intent back so query string is known + setResult(RESULT_CANCELED, intent); } + finish(); + + return; } setTheme(); @@ -105,28 +110,39 @@ public class cgeoadvsearch extends AbstractActivity { super.onPause(); } - private boolean instantSearch(final String queryIn) { - final String query = queryIn.trim(); - + /** + * Performs a search for query either as geocode, trackable code or keyword + * + * @param query + * String to search for + * @param keywordSearch + * Set to true if keyword search should be performed if query isn't GC or TB + * @return true if a search was performed, else false + */ + private boolean instantSearch(final String query, final boolean keywordSearch) { try { - final Pattern gcCode = Pattern.compile("^GC[0-9A-Z]+$", Pattern.CASE_INSENSITIVE); - if (gcCode.matcher(query).find()) { // GC-code + String result = BaseUtils.getMatch(query, GCConstants.PATTERN_GC_CODE, true, 0, "", false); + if (StringUtils.isNotBlank(result)) { final Intent cachesIntent = new Intent(this, CacheDetailActivity.class); - cachesIntent.putExtra("geocode", query.toUpperCase()); + cachesIntent.putExtra("geocode", result.toUpperCase()); startActivity(cachesIntent); return true; } else { - final Pattern tbCode = Pattern.compile("^TB[0-9A-Z]+$", Pattern.CASE_INSENSITIVE); - if (tbCode.matcher(query).find()) { // TB-code + result = BaseUtils.getMatch(query, GCConstants.PATTERN_TB_CODE, true, 0, "", false); + if (StringUtils.isNotBlank(result)) { final Intent trackablesIntent = new Intent(this, cgeotrackable.class); - trackablesIntent.putExtra("geocode", query.toUpperCase()); + trackablesIntent.putExtra("geocode", result.toUpperCase()); startActivity(trackablesIntent); + return true; - } else { // keyword (fallback) - cgeocaches.startActivityKeyword(this, query); + } else if (keywordSearch) { // keyword fallback, if desired by caller + cgeocaches.startActivityKeyword(this, query.trim()); return true; + } else { + return false; } + } } catch (Exception e) { Log.w(Settings.tag, "cgeoadvsearch.instantSearch: " + e.toString()); diff --git a/main/src/cgeo/geocaching/cgeocaches.java b/main/src/cgeo/geocaching/cgeocaches.java index a7fe4ec..e6978ce 100644 --- a/main/src/cgeo/geocaching/cgeocaches.java +++ b/main/src/cgeo/geocaching/cgeocaches.java @@ -8,7 +8,6 @@ import cgeo.geocaching.apps.cachelist.CacheListAppFactory; import cgeo.geocaching.enumerations.CacheListType; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LoadFlags; -import cgeo.geocaching.enumerations.LoadFlags.LoadFlag; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.files.GPXImporter; @@ -79,7 +78,6 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; -import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -175,9 +173,7 @@ public class cgeocaches extends AbstractListActivity { setTitle(title + " [" + search.getCount() + "]"); cacheList.clear(); - EnumSet<LoadFlag> loadFlags = LoadFlags.LOAD_CACHE_OR_DB; - loadFlags.add(LoadFlag.LOAD_OFFLINE_LOG); - final Set<cgCache> caches = search.getCachesFromSearchResult(loadFlags); + final Set<cgCache> caches = search.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB); if (CollectionUtils.isNotEmpty(caches)) { cacheList.addAll(caches); Collections.sort(cacheList, gcComparator); @@ -566,7 +562,13 @@ public class cgeocaches extends AbstractListActivity { title = res.getString(R.string.stored_caches_button); } else { final StoredList list = app.getList(listId); - title = list.title; + // Check if list id is still valid + if (null == list) { + listId = StoredList.STANDARD_LIST_ID; + title = res.getString(R.string.stored_caches_button); + } else { + title = list.title; + } } setTitle(title); @@ -1800,7 +1802,7 @@ public class cgeocaches extends AbstractListActivity { @Override public void run() { - search = cgBase.searchByCoords(this, coords, cacheType, 0, Settings.isShowCaptcha()); + search = cgBase.searchByCoords(this, coords, cacheType, StoredList.TEMPORARY_LIST_ID, Settings.isShowCaptcha()); handler.sendMessage(new Message()); } diff --git a/main/src/cgeo/geocaching/cgeoinit.java b/main/src/cgeo/geocaching/cgeoinit.java index 5a601ac..0839f46 100644 --- a/main/src/cgeo/geocaching/cgeoinit.java +++ b/main/src/cgeo/geocaching/cgeoinit.java @@ -619,6 +619,50 @@ public class cgeoinit extends AbstractActivity { } }); + // 2nd Default navigation tool settings + Spinner defaultNavigationTool2Selector = (Spinner) findViewById(R.id.default_navigation_tool_2); + // final List<NavigationAppsEnum> apps = NavigationAppFactory.getInstalledNavigationApps(this); + ArrayAdapter<NavigationAppsEnum> navi2Adapter = new ArrayAdapter<NavigationAppsEnum>(this, android.R.layout.simple_spinner_item, apps) { + @Override + public View getView(int position, View convertView, ViewGroup parent) { + TextView textView = (TextView) super.getView(position, convertView, parent); + textView.setText(getItem(position).app.getName()); + return textView; + } + + @Override + public View getDropDownView(int position, View convertView, ViewGroup parent) { + TextView textView = (TextView) super.getDropDownView(position, convertView, parent); + textView.setText(getItem(position).app.getName()); + return textView; + } + }; + navi2Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + defaultNavigationTool2Selector.setAdapter(navi2Adapter); + int defaultNavigationTool2 = Settings.getDefaultNavigationTool2(); + int ordinal2 = 0; + for (int i = 0; i < apps.size(); i++) { + if (apps.get(i).id == defaultNavigationTool2) { + ordinal2 = i; + break; + } + } + defaultNavigationTool2Selector.setSelection(ordinal2); + defaultNavigationTool2Selector.setOnItemSelectedListener(new OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + NavigationAppsEnum item = (NavigationAppsEnum) parent.getItemAtPosition(position); + if (item != null) { + Settings.setDefaultNavigationTool2(item.id); + } + } + + @Override + public void onNothingSelected(AdapterView<?> arg0) { + // noop + } + }); + refreshBackupLabel(); } diff --git a/main/src/cgeo/geocaching/cgeopopup.java b/main/src/cgeo/geocaching/cgeopopup.java index 0d6195d..4898a40 100644 --- a/main/src/cgeo/geocaching/cgeopopup.java +++ b/main/src/cgeo/geocaching/cgeopopup.java @@ -26,6 +26,7 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; +import android.view.View.OnLongClickListener; import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; @@ -128,6 +129,16 @@ public class cgeopopup extends AbstractActivity { finish(); return; } + + ImageView defaultNavigationImageView = (ImageView) findViewById(R.id.defaultNavigation); + defaultNavigationImageView.setOnLongClickListener(new OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + startDefaultNavigation2(); + return true; + } + }); + } @Override @@ -632,6 +643,18 @@ public class cgeopopup extends AbstractActivity { finish(); } + /** + * Tries to navigate to the {@link cgCache} of this activity. + */ + private void startDefaultNavigation2() { + if (cache == null || cache.getCoords() == null) { + showToast(res.getString(R.string.cache_coordinates_no)); + return; + } + NavigationAppFactory.startDefaultNavigationApplication2(geo, this, cache, null, null); + finish(); + } + @Override public void goManual(View view) { super.goManual(view); diff --git a/main/src/cgeo/geocaching/cgeotrackable.java b/main/src/cgeo/geocaching/cgeotrackable.java index e40e04f..db533ce 100644 --- a/main/src/cgeo/geocaching/cgeotrackable.java +++ b/main/src/cgeo/geocaching/cgeotrackable.java @@ -4,6 +4,7 @@ import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.geopoint.HumanDistance; import cgeo.geocaching.network.HtmlImage; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import android.app.ProgressDialog; @@ -28,6 +29,7 @@ import android.widget.ScrollView; import android.widget.TextView; import java.net.URLEncoder; +import java.util.ArrayList; import java.util.Arrays; public class cgeotrackable extends AbstractActivity { @@ -441,7 +443,7 @@ public class cgeotrackable extends AbstractActivity { if (trackable != null && trackable.getLogs() != null) { for (cgLog log : trackable.getLogs()) { - rowView = (RelativeLayout) inflater.inflate(R.layout.trackable_logitem, null); + rowView = (RelativeLayout) inflater.inflate(R.layout.trackable_logs_item, null); if (log.date > 0) { ((TextView) rowView.findViewById(R.id.added)).setText(cgBase.formatShortDate(log.date)); @@ -468,7 +470,39 @@ public class cgeotrackable extends AbstractActivity { TextView logView = (TextView) rowView.findViewById(R.id.log); logView.setMovementMethod(LinkMovementMethod.getInstance()); - logView.setText(Html.fromHtml(log.log, new HtmlImage(cgeotrackable.this, null, false, 0, false), null), TextView.BufferType.SPANNABLE); + logView.setText(Html.fromHtml(log.log, new HtmlImage(cgeotrackable.this, null, false, StoredList.TEMPORARY_LIST_ID, false), null), TextView.BufferType.SPANNABLE); + + // add LogImages + LinearLayout logLayout = (LinearLayout) rowView.findViewById(R.id.log_layout); + + if (CollectionUtils.isNotEmpty(log.logImages)) { + + final ArrayList<cgImage> logImages = new ArrayList<cgImage>(log.logImages); + + final View.OnClickListener listener = new View.OnClickListener() { + @Override + public void onClick(View v) { + cgeoimages.startActivityLogImages(cgeotrackable.this, trackable.getGeocode(), logImages); + } + }; + + ArrayList<String> titles = new ArrayList<String>(); + for (int i_img_cnt = 0; i_img_cnt < log.logImages.size(); i_img_cnt++) { + String img_title = log.logImages.get(i_img_cnt).getTitle(); + if (!StringUtils.isBlank(img_title)) { + titles.add(img_title); + } + } + if (titles.isEmpty()) { + titles.add(res.getString(R.string.cache_log_image_default_title)); + } + + 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(StringUtils.join(titles.toArray(new String[titles.size()]), ", ")); + log_img_title.setOnClickListener(listener); + logLayout.addView(log_imgView); + } ((TextView) rowView.findViewById(R.id.author)).setOnClickListener(new userActions()); listView.addView(rowView); diff --git a/main/src/cgeo/geocaching/cgeowaypoint.java b/main/src/cgeo/geocaching/cgeowaypoint.java index 84eac46..7fbf14a 100644 --- a/main/src/cgeo/geocaching/cgeowaypoint.java +++ b/main/src/cgeo/geocaching/cgeowaypoint.java @@ -18,6 +18,7 @@ import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; import android.view.MenuItem; import android.view.View; +import android.view.View.OnLongClickListener; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; @@ -54,7 +55,7 @@ public class cgeowaypoint extends AbstractActivity { } else { final TextView identification = (TextView) findViewById(R.id.identification); final TextView coords = (TextView) findViewById(R.id.coordinates); - final ImageView compass = (ImageView) findViewById(R.id.compass); + final ImageView defaultNavigation = (ImageView) findViewById(R.id.defaultNavigation); final View separator = findViewById(R.id.separator); final View headline = findViewById(R.id.headline); @@ -76,11 +77,11 @@ public class cgeowaypoint extends AbstractActivity { if (waypoint.getCoords() != null) { coords.setText(Html.fromHtml(waypoint.getCoords().toString()), TextView.BufferType.SPANNABLE); - compass.setVisibility(View.VISIBLE); + defaultNavigation.setVisibility(View.VISIBLE); separator.setVisibility(View.VISIBLE); } else { coords.setText(res.getString(R.string.waypoint_unknown_coordinates)); - compass.setVisibility(View.GONE); + defaultNavigation.setVisibility(View.GONE); separator.setVisibility(View.GONE); } registerNavigationMenu(coords); @@ -163,6 +164,15 @@ public class cgeowaypoint extends AbstractActivity { waitDialog.setCancelable(true); (new loadWaypoint()).start(); + + ImageView defaultNavigationImageView = (ImageView) findViewById(R.id.defaultNavigation); + defaultNavigationImageView.setOnLongClickListener(new OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + startDefaultNavigation2(); + return true; + } + }); } @Override @@ -341,6 +351,17 @@ public class cgeowaypoint extends AbstractActivity { NavigationAppFactory.startDefaultNavigationApplication(geo, this, null, waypoint, null); } + /** + * Tries to navigate to the {@link cgCache} of this activity. + */ + private void startDefaultNavigation2() { + if (!navigationPossible()) { + return; + } + + NavigationAppFactory.startDefaultNavigationApplication2(geo, this, null, waypoint, null); + } + private boolean navigationPossible() { if (waypoint == null || waypoint.getCoords() == null) { showToast(res.getString(R.string.err_location_unknown)); diff --git a/main/src/cgeo/geocaching/connector/AbstractConnector.java b/main/src/cgeo/geocaching/connector/AbstractConnector.java index 3c0076a..ceaad5e 100644 --- a/main/src/cgeo/geocaching/connector/AbstractConnector.java +++ b/main/src/cgeo/geocaching/connector/AbstractConnector.java @@ -4,6 +4,7 @@ import cgeo.geocaching.SearchResult; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.utils.CancellableHandler; public abstract class AbstractConnector implements IConnector { @@ -53,6 +54,10 @@ public abstract class AbstractConnector implements IConnector { return null; } + public SearchResult searchByViewport(Viewport viewport, String tokens[]) { + return null; + } + protected static boolean isNumericId(final String string) { try { return Integer.parseInt(string) > 0; @@ -72,4 +77,9 @@ public abstract class AbstractConnector implements IConnector { // let every cache have reliable coordinates by default return true; } + + @Override + public String[] getTokens() { + return null; + } } diff --git a/main/src/cgeo/geocaching/connector/ConnectorFactory.java b/main/src/cgeo/geocaching/connector/ConnectorFactory.java index 39e6dee..471d43b 100644 --- a/main/src/cgeo/geocaching/connector/ConnectorFactory.java +++ b/main/src/cgeo/geocaching/connector/ConnectorFactory.java @@ -1,8 +1,11 @@ package cgeo.geocaching.connector; import cgeo.geocaching.ICache; +import cgeo.geocaching.SearchResult; import cgeo.geocaching.connector.opencaching.ApiOpenCachingConnector; import cgeo.geocaching.connector.opencaching.OpenCachingConnector; +import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.geopoint.Viewport; import org.apache.commons.lang3.StringUtils; @@ -62,4 +65,19 @@ public final class ConnectorFactory { private static boolean isInvalidGeocode(final String geocode) { return StringUtils.isBlank(geocode) || !Character.isLetterOrDigit(geocode.charAt(0)); } + + /** @see IConnector#searchByCoordinate */ + public static SearchResult searchByCoordinate(final Geopoint center) { + // We have only connector capable of doing a 'searchByCoordinate()' + // If there is a second connector the information has to be collected from all collectors + return GCConnector.getInstance().searchByCoordinate(center); + } + + /** @see IConnector#searchByViewport */ + public static SearchResult searchByViewport(final Viewport viewport, final String[] tokens) { + // We have only connector capable of doing a 'searchByViewport()' + // If there is a second connector the information has to be collected from all collectors + return GCConnector.getInstance().searchByViewport(viewport, tokens); + } + } diff --git a/main/src/cgeo/geocaching/connector/GCConnector.java b/main/src/cgeo/geocaching/connector/GCConnector.java index 2d6e67b..6b44f82 100644 --- a/main/src/cgeo/geocaching/connector/GCConnector.java +++ b/main/src/cgeo/geocaching/connector/GCConnector.java @@ -7,7 +7,10 @@ import cgeo.geocaching.Settings; import cgeo.geocaching.cgBase; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.connector.gc.GCBase; import cgeo.geocaching.enumerations.StatusCode; +import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.utils.CancellableHandler; @@ -133,6 +136,17 @@ public class GCConnector extends AbstractConnector { } @Override + public SearchResult searchByCoordinate(Geopoint center) { + // TODO Auto-generated method stub + return super.searchByCoordinate(center); + } + + @Override + public SearchResult searchByViewport(Viewport viewport, String[] tokens) { + return GCBase.searchByViewport(viewport, tokens); + } + + @Override public boolean isZippedGPXFile(final String fileName) { return gpxZipFilePattern.matcher(fileName).matches(); } @@ -141,4 +155,9 @@ public class GCConnector extends AbstractConnector { public boolean isReliableLatLon(boolean cacheHasReliableLatLon) { return cacheHasReliableLatLon; } + + @Override + public String[] getTokens() { + return GCBase.getTokens(); + } } diff --git a/main/src/cgeo/geocaching/connector/IConnector.java b/main/src/cgeo/geocaching/connector/IConnector.java index 21cdb75..bc772c9 100644 --- a/main/src/cgeo/geocaching/connector/IConnector.java +++ b/main/src/cgeo/geocaching/connector/IConnector.java @@ -4,6 +4,7 @@ import cgeo.geocaching.SearchResult; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.utils.CancellableHandler; public interface IConnector { @@ -86,6 +87,15 @@ public interface IConnector { public SearchResult searchByCoordinate(final Geopoint center); /** + * Search caches by viewport. + * + * @param viewport + * @param tokens + * @return + */ + public SearchResult searchByViewport(final Viewport viewport, final String[] tokens); + + /** * return true if this is a ZIP file containing a GPX file * * @param fileName @@ -101,4 +111,12 @@ public interface IConnector { * @return */ public boolean isReliableLatLon(boolean cacheHasReliableLatLon); + + /** + * Return required tokens for specific following actions + * + * @return + */ + public String[] getTokens(); + } diff --git a/main/src/cgeo/geocaching/connector/gc/GCBase.java b/main/src/cgeo/geocaching/connector/gc/GCBase.java index 72f5d55..eb7603b 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCBase.java +++ b/main/src/cgeo/geocaching/connector/gc/GCBase.java @@ -3,6 +3,7 @@ package cgeo.geocaching.connector.gc; import cgeo.geocaching.GCConstants; import cgeo.geocaching.SearchResult; import cgeo.geocaching.Settings; +import cgeo.geocaching.StoredList; import cgeo.geocaching.cgBase; import cgeo.geocaching.cgCache; import cgeo.geocaching.enumerations.CacheType; @@ -41,7 +42,6 @@ public class GCBase { private static final LeastRecentlyUsedCache<String, cgCache> liveMapCache = new LeastRecentlyUsedCache<String, cgCache>(2000); // JSON id, cache - // TODO Valentine move to connector before merge /** * @param viewport * @param zoomlevel @@ -54,6 +54,8 @@ public class GCBase { @SuppressWarnings("null") public static SearchResult searchByViewport(final Viewport viewport, final String[] tokens) { + Log.d(Settings.tag, "GCBase.searchByViewport" + viewport.toString()); + String referer = GCConstants.URL_LIVE_MAP; final SearchResult searchResult = new SearchResult(); @@ -66,28 +68,24 @@ public class GCBase { "?x=" + tile.getX() + // x tile "&y=" + tile.getY() + // y tile "&z=" + tile.getZoomlevel(); // zoom level - /* - * if (tokens != null) { - * url += "&k=" + tokens[0]; // user session - * url += "&st=" + tokens[1]; // session token - * } - * url += "&ep=1"; - * /* - * if (true || Settings.isExcludeMyCaches()) { - * url += "&hf=1"; // hide found - * url += "&hh=1"; // hide hidden - * } - * - * if (Settings.getCacheType() == CacheType.TRADITIONAL) { - * url += "&ect=9,5,3,6,453,13,1304,137,11,4,8,1858"; // 2 = tradi 3 = multi 8 = mystery - * } - * if (Settings.getCacheType() == CacheType.MULTI) { - * url += "&ect=9,5,2,6,453,13,1304,137,11,4,8,1858"; - * } - * if (Settings.getCacheType() == CacheType.MYSTERY) { - * url += "&ect=9,5,3,6,453,13,1304,137,11,4,2,1858"; - * } - */ + if (tokens != null) { + url += "&k=" + tokens[0]; // user session + url += "&st=" + tokens[1]; // session token + } + url += "&ep=1"; + if (Settings.isExcludeMyCaches()) { + url += "&hf=1"; // hide found + url += "&hh=1"; // hide hidden + } + if (Settings.getCacheType() == CacheType.TRADITIONAL) { + url += "&ect=9,5,3,6,453,13,1304,137,11,4,8,1858"; // 2 = tradi 3 = multi 8 = mystery + } + if (Settings.getCacheType() == CacheType.MULTI) { + url += "&ect=9,5,2,6,453,13,1304,137,11,4,8,1858"; + } + if (Settings.getCacheType() == CacheType.MYSTERY) { + url += "&ect=9,5,3,6,453,13,1304,137,11,4,2,1858"; + } if (tile.getZoomlevel() != 14) { url += "&_=" + String.valueOf(System.currentTimeMillis()); } @@ -107,6 +105,11 @@ public class GCBase { } } + if (Settings.isPremiumMember()) { + SearchResult search = cgBase.searchByCoords(null, viewport.getCenter(), Settings.getCacheType(), StoredList.TEMPORARY_LIST_ID, Settings.isShowCaptcha()); + searchResult.addGeocodes(search.getGeocodes()); + } + return searchResult; } @@ -149,7 +152,9 @@ public class GCBase { } /* - * // Optimization: the grid can get ignored. The keys are the grid position in the format x_y + * Optimization: the grid can get ignored. The keys are the grid position in the format x_y + * It's not used at the moment due to optimizations + * But maybe we need it some day... * * // attach all keys with the cache positions in the tile * Map<String, UTFGridPosition> keyPositions = new HashMap<String, UTFGridPosition>(); // JSON key, (x/y) in @@ -239,7 +244,9 @@ public class GCBase { */ protected static List<Tile> getTilesForViewport(final Viewport viewport) { List<Tile> tiles = new ArrayList<Tile>(); - tiles.add(new Tile(viewport.getCenter(), 14)); // precise coords for caches nearby + if (!Settings.isPremiumMember()) { + tiles.add(new Tile(viewport.getCenter(), 14)); // precise coords for caches nearby + } tiles.add(new Tile(viewport.getCenter(), 12)); // other caches around return tiles; } @@ -340,21 +347,6 @@ public class GCBase { return GCBase.gcidToGCCode(gcid); } - // TODO Valentine - /** Request further details in the live mapa for a given id */ - public void requestDetailsFromMap(@SuppressWarnings("unused") String id) { - /** - * URL http://www.geocaching.com/map/map.details?i=gEaR - * Response: {"status":"success","data":[{"name":"Spiel & Sport","gc":"GC211WG","g": - * "872d7eda-7cb9-40d5-890d-5b344bce7302" - * ,"disabled":false,"subrOnly":false,"li":false,"fp":"0","difficulty":{"text" - * :3.0,"value":"3"},"terrain":{"text" - * :2.0,"value":"2"},"hidden":"11/15/2009","container":{"text":"Regular","value" - * :"regular.gif"},"type":{"text":"Multi-cache" - * ,"value":3},"owner":{"text":"kai2707","value":"5c4b0915-5cec-4fa1-8afd-4b3ca67e004e"}}]} - */ - } - /** Get user session & session token from the Live Map. Needed for following requests */ public static String[] getTokens() { final HttpResponse response = cgBase.request(GCConstants.URL_LIVE_MAP, null, false); diff --git a/main/src/cgeo/geocaching/connector/gc/UTFGrid.java b/main/src/cgeo/geocaching/connector/gc/UTFGrid.java index 17f61da..cf490ec 100644 --- a/main/src/cgeo/geocaching/connector/gc/UTFGrid.java +++ b/main/src/cgeo/geocaching/connector/gc/UTFGrid.java @@ -12,7 +12,11 @@ public final class UTFGrid { public static final int GRID_MAXX = 63; public static final int GRID_MAXY = 63; - /** Convert a value from a JSON grid object into an id that can be used as an index */ + /** + * Convert a value from a JSON grid object into an id that can be used as an index + * It's not used at the moment due to optimizations. + * But maybe we need it some day... + */ public static short getUTFGridId(final char value) { short result = (short) value; if (result >= 93) { diff --git a/main/src/cgeo/geocaching/enumerations/CacheSize.java b/main/src/cgeo/geocaching/enumerations/CacheSize.java index c0de75b..9b0a559 100644 --- a/main/src/cgeo/geocaching/enumerations/CacheSize.java +++ b/main/src/cgeo/geocaching/enumerations/CacheSize.java @@ -20,7 +20,7 @@ public enum CacheSize { VIRTUAL("virtual", 0, R.string.cache_size_virtual), NOT_CHOSEN("not chosen", 0, R.string.cache_size_notchosen), OTHER("other", 0, R.string.cache_size_other), - UNKNOWN("unknown", 0, R.string.err_unknown); // CacheSize not init. yet + UNKNOWN("unknown", 0, R.string.cache_size_unknown); // CacheSize not init. yet public final String id; public final int comparable; diff --git a/main/src/cgeo/geocaching/enumerations/LoadFlags.java b/main/src/cgeo/geocaching/enumerations/LoadFlags.java index ac1e168..e55a4fc 100644 --- a/main/src/cgeo/geocaching/enumerations/LoadFlags.java +++ b/main/src/cgeo/geocaching/enumerations/LoadFlags.java @@ -24,9 +24,9 @@ public class LoadFlags { /** Retrieve cache from CacheCache only. Do not load from DB */ public final static EnumSet<LoadFlag> LOAD_CACHE_ONLY = EnumSet.of(LoadFlag.LOAD_CACHE_BEFORE); /** Retrieve cache from CacheCache first. If not found load from DB */ - public final static EnumSet<LoadFlag> LOAD_CACHE_OR_DB = EnumSet.of(LoadFlag.LOAD_CACHE_BEFORE, LoadFlag.LOAD_DB_MINIMAL); + public final static EnumSet<LoadFlag> LOAD_CACHE_OR_DB = EnumSet.of(LoadFlag.LOAD_CACHE_BEFORE, LoadFlag.LOAD_DB_MINIMAL, LoadFlag.LOAD_OFFLINE_LOG); /** Retrieve cache (minimalistic information including waypoints) from DB first. If not found load from CacheCache */ - public final static EnumSet<LoadFlag> LOAD_WAYPOINTS = EnumSet.of(LoadFlag.LOAD_CACHE_AFTER, LoadFlag.LOAD_DB_MINIMAL, LoadFlag.LOAD_WAYPOINTS); + public final static EnumSet<LoadFlag> LOAD_WAYPOINTS = EnumSet.of(LoadFlag.LOAD_CACHE_AFTER, LoadFlag.LOAD_DB_MINIMAL, LoadFlag.LOAD_WAYPOINTS, LoadFlag.LOAD_OFFLINE_LOG); /** Retrieve cache (all stored informations) from DB only. Do not load from CacheCache */ public final static EnumSet<LoadFlag> LOAD_ALL_DB_ONLY = EnumSet.range(LoadFlag.LOAD_DB_MINIMAL, LoadFlag.LOAD_OFFLINE_LOG); diff --git a/main/src/cgeo/geocaching/filter/SizeFilter.java b/main/src/cgeo/geocaching/filter/SizeFilter.java index 638a7c9..4f0d830 100644 --- a/main/src/cgeo/geocaching/filter/SizeFilter.java +++ b/main/src/cgeo/geocaching/filter/SizeFilter.java @@ -3,6 +3,8 @@ package cgeo.geocaching.filter; import cgeo.geocaching.cgCache; import cgeo.geocaching.enumerations.CacheSize; +import java.util.ArrayList; + public class SizeFilter extends AbstractFilter { private final CacheSize cacheSize; @@ -23,10 +25,12 @@ public class SizeFilter extends AbstractFilter { public static AbstractFilter[] getAllFilters() { final CacheSize[] cacheSizes = CacheSize.values(); - SizeFilter[] filters = new SizeFilter[cacheSizes.length]; - for (int i = 0; i < cacheSizes.length; i++) { - filters[i] = new SizeFilter(cacheSizes[i]); + ArrayList<SizeFilter> filters = new ArrayList<SizeFilter>(); + for (CacheSize cacheSize : cacheSizes) { + if (cacheSize != CacheSize.UNKNOWN) { + filters.add(new SizeFilter(cacheSize)); + } } - return filters; + return filters.toArray(new SizeFilter[filters.size()]); } } diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java index 434eb05..0038807 100644 --- a/main/src/cgeo/geocaching/maps/CGeoMap.java +++ b/main/src/cgeo/geocaching/maps/CGeoMap.java @@ -15,6 +15,7 @@ import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.cgeocaches; import cgeo.geocaching.activity.ActivityMixin; +import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.gc.GCBase; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LoadFlags; @@ -1266,8 +1267,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } if (tokens == null) { - // token = cgBase.getMapUserToken(noMapTokenHandler); tokens = GCBase.getTokens(); + if (noMapTokenHandler != null && tokens == null) { + noMapTokenHandler.sendEmptyMessage(0); + } } if (stop) { @@ -1276,7 +1279,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto final Viewport viewport = new Viewport(new Geopoint(latMin, lonMin), new Geopoint(latMax, lonMax)); // search = cgBase.searchByViewport(token, viewport); - search = GCBase.searchByViewport(viewport, tokens); + search = ConnectorFactory.searchByViewport(viewport, tokens); if (search != null) { downloaded = true; if (search.error == StatusCode.NOT_LOGGED_IN) { @@ -1846,12 +1849,13 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto int hashcode = new HashCodeBuilder() .append(cache.isReliableLatLon()) .append(cache.getType().id) - .append(cache.isDisabled()) + .append(cache.isDisabled() || cache.isArchived()) .append(cache.isOwn()) .append(cache.isFound()) .append(cache.hasUserModifiedCoords()) .append(cache.getPersonalNote()) .append(cache.isLogOffline()) + .append(cache.getListId() > 0) .toHashCode(); LayerDrawable ldFromCache = CGeoMap.overlaysCache.get(hashcode); @@ -1866,7 +1870,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto // background: disabled or not Drawable marker = getResources().getDrawable(R.drawable.marker); - if (cache.isDisabled()) { + if (cache.isDisabled() || cache.isArchived()) { marker = getResources().getDrawable(R.drawable.marker_disabled); } layers.add(marker); @@ -1883,6 +1887,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if ( cache.isOwn() ) { layers.add(getResources().getDrawable(R.drawable.marker_own)); insets.add(INSET_OWN[resolution]); + // if not, checked if stored + } else if (cache.getListId() > 0) { + layers.add(getResources().getDrawable(R.drawable.marker_stored)); + insets.add(INSET_OWN[resolution]); } // found if (cache.isFound()) { diff --git a/main/src/cgeo/geocaching/utils/BaseUtils.java b/main/src/cgeo/geocaching/utils/BaseUtils.java index 0d5e70e..44c35a1 100644 --- a/main/src/cgeo/geocaching/utils/BaseUtils.java +++ b/main/src/cgeo/geocaching/utils/BaseUtils.java @@ -31,33 +31,23 @@ public final class BaseUtils { * @return defaultValue or the n-th group if the pattern matches (trimed if wanted) */ public static String getMatch(final String data, final Pattern p, final boolean trim, final int group, final String defaultValue, final boolean last) { - String result = null; + if (data != null) { - boolean lastInternal = false; // Optimization 1: 'while (matcher.find())' returns the same result as 'mather.find()' (for the tested patterns so far) + String result = null; + final Matcher matcher = p.matcher(data); - final Matcher matcher = p.matcher(data); - - if (lastInternal) { - while (matcher.find()) { - // Optimization 2: 'matcher.find && matcher.groupCount() >= xx' can be shortened to 'matcher.find()' - // if (matcher.groupCount() >= group) { - result = matcher.group(group); - } - } else { - // Optimization 2: 'matcher.find && matcher.groupCount() >= xx' can be shortened to 'matcher.find()' - // if (matcher.find() && matcher.groupCount() >= group) { if (matcher.find()) { result = matcher.group(group); } - } - if (null != result) { - return trim ? new String(result).trim() : new String(result); - // Java copies the whole page String, when matching with regular expressions - // later this would block the garbage collector, as we only need tiny parts of the page - // see http://developer.android.com/reference/java/lang/String.html#backing_array - // Thus the creating of a new String via String constructor is necessary here!! + if (null != result) { + return trim ? new String(result).trim() : new String(result); + // Java copies the whole page String, when matching with regular expressions + // later this would block the garbage collector, as we only need tiny parts of the page + // see http://developer.android.com/reference/java/lang/String.html#backing_array + // Thus the creating of a new String via String constructor is necessary here!! - // And BTW: You cannot even see that effect in the debugger, but must use a separate memory profiler! + // And BTW: You cannot even see that effect in the debugger, but must use a separate memory profiler! + } } return defaultValue; } diff --git a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java index 8606649..bc9b448 100644 --- a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java +++ b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java @@ -1,16 +1,12 @@ package cgeo.geocaching.utils; +import cgeo.geocaching.GCConstants; import cgeo.geocaching.R; import cgeo.geocaching.Settings; import cgeo.geocaching.cgBase; import org.apache.commons.lang3.StringUtils; -import android.util.Log; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - /** * provides all the available templates for logging * @@ -131,29 +127,6 @@ public class LogTemplateProvider { return -1; } - int findCount = -1; - - try { - final Pattern findPattern = Pattern.compile("<strong><img.+?icon_smile.+?title=\"Caches Found\" /> ([,\\d]+)", Pattern.CASE_INSENSITIVE); - final Matcher findMatcher = findPattern.matcher(page); - if (findMatcher.find()) { - if (findMatcher.groupCount() > 0) { - String count = findMatcher.group(1); - - if (count != null) { - if (count.length() == 0) { - findCount = 0; - } else { - findCount = Integer.parseInt(count.replaceAll("[.,]", "")); - } - } - } - } - } catch (Exception e) { - Log.w(Settings.tag, "cgBase.parseFindCount: " + e.toString()); - } - - return findCount; + return Integer.parseInt(BaseUtils.getMatch(page, GCConstants.PATTERN_CACHES_FOUND, true, "-1").replaceAll("[,.]", "")); } - } |
