aboutsummaryrefslogtreecommitdiffstats
path: root/main/src
diff options
context:
space:
mode:
Diffstat (limited to 'main/src')
-rw-r--r--main/src/cgeo/calendar/CalendarAddon.java58
-rw-r--r--main/src/cgeo/calendar/ICalendar.java2
-rw-r--r--main/src/cgeo/contacts/IContacts.java2
-rw-r--r--main/src/cgeo/geocaching/AbstractPopupActivity.java2
-rw-r--r--main/src/cgeo/geocaching/CacheDetailActivity.java325
-rw-r--r--main/src/cgeo/geocaching/CacheListActivity.java181
-rw-r--r--main/src/cgeo/geocaching/CacheMenuHandler.java55
-rw-r--r--main/src/cgeo/geocaching/CachePopup.java6
-rw-r--r--main/src/cgeo/geocaching/CgeoApplication.java76
-rw-r--r--main/src/cgeo/geocaching/CompassActivity.java5
-rw-r--r--main/src/cgeo/geocaching/CreateShortcutActivity.java10
-rw-r--r--main/src/cgeo/geocaching/DataStore.java192
-rw-r--r--main/src/cgeo/geocaching/DirectionProvider.java90
-rw-r--r--main/src/cgeo/geocaching/EditWaypointActivity.java2
-rw-r--r--main/src/cgeo/geocaching/GeoDataProvider.java146
-rw-r--r--main/src/cgeo/geocaching/Geocache.java21
-rw-r--r--main/src/cgeo/geocaching/ImageSelectActivity.java3
-rw-r--r--main/src/cgeo/geocaching/Intents.java4
-rw-r--r--main/src/cgeo/geocaching/LogCacheActivity.java8
-rw-r--r--main/src/cgeo/geocaching/LogTrackableActivity.java4
-rw-r--r--main/src/cgeo/geocaching/MainActivity.java195
-rw-r--r--main/src/cgeo/geocaching/PocketQueryList.java137
-rw-r--r--main/src/cgeo/geocaching/SearchActivity.java80
-rw-r--r--main/src/cgeo/geocaching/SearchResult.java2
-rw-r--r--main/src/cgeo/geocaching/StaticMapsActivity.java1
-rw-r--r--main/src/cgeo/geocaching/StatusFragment.java129
-rw-r--r--main/src/cgeo/geocaching/TrackableActivity.java2
-rw-r--r--main/src/cgeo/geocaching/UsefulAppsActivity.java1
-rw-r--r--main/src/cgeo/geocaching/activity/AbstractListActivity.java23
-rw-r--r--main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java1
-rw-r--r--main/src/cgeo/geocaching/activity/ActivityMixin.java2
-rw-r--r--main/src/cgeo/geocaching/apps/AbstractLocusApp.java1
-rw-r--r--main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java2
-rw-r--r--main/src/cgeo/geocaching/concurrent/PriorityThreadFactory.java3
-rw-r--r--main/src/cgeo/geocaching/connector/AbstractConnector.java16
-rw-r--r--main/src/cgeo/geocaching/connector/ConnectorFactory.java40
-rw-r--r--main/src/cgeo/geocaching/connector/UserAction.java10
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECApi.java1
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECConnector.java2
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECLogin.java1
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCConnector.java31
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCLogin.java13
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCMap.java2
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCParser.java39
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OkapiClient.java41
-rw-r--r--main/src/cgeo/geocaching/connector/ox/OXGPXParser.java4
-rw-r--r--main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java1
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java4
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java27
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java8
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java4
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java17
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheAttribute.java8
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheListType.java31
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheSize.java37
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheType.java2
-rw-r--r--main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java2
-rw-r--r--main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java23
-rw-r--r--main/src/cgeo/geocaching/enumerations/StatusCode.java2
-rw-r--r--main/src/cgeo/geocaching/export/GpxExport.java2
-rw-r--r--main/src/cgeo/geocaching/files/LocalStorage.java9
-rw-r--r--main/src/cgeo/geocaching/files/SimpleDirChooser.java4
-rw-r--r--main/src/cgeo/geocaching/filter/DistanceFilter.java2
-rw-r--r--main/src/cgeo/geocaching/filter/FilterUserInterface.java13
-rw-r--r--main/src/cgeo/geocaching/filter/ModifiedFilter.java2
-rw-r--r--main/src/cgeo/geocaching/geopoint/Geopoint.java26
-rw-r--r--main/src/cgeo/geocaching/geopoint/GeopointParser.java36
-rw-r--r--main/src/cgeo/geocaching/geopoint/Viewport.java68
-rw-r--r--main/src/cgeo/geocaching/list/PseudoList.java6
-rw-r--r--main/src/cgeo/geocaching/list/StoredList.java40
-rw-r--r--main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java4
-rw-r--r--main/src/cgeo/geocaching/loaders/AddressGeocacheListLoader.java2
-rw-r--r--main/src/cgeo/geocaching/loaders/HistoryGeocacheListLoader.java2
-rw-r--r--main/src/cgeo/geocaching/loaders/NextPageGeocacheListLoader.java2
-rw-r--r--main/src/cgeo/geocaching/loaders/OfflineGeocacheListLoader.java4
-rw-r--r--main/src/cgeo/geocaching/maps/CGeoMap.java13
-rw-r--r--main/src/cgeo/geocaching/maps/MapProviderFactory.java2
-rw-r--r--main/src/cgeo/geocaching/maps/google/GoogleCacheOverlay.java5
-rw-r--r--main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java2
-rw-r--r--main/src/cgeo/geocaching/maps/google/GoogleMapView.java9
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/ItemizedOverlayImpl.java2
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java2
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java5
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java8
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java5
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java6
-rw-r--r--main/src/cgeo/geocaching/network/HtmlImage.java165
-rw-r--r--main/src/cgeo/geocaching/network/Network.java1
-rw-r--r--main/src/cgeo/geocaching/network/OAuth.java1
-rw-r--r--main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java1
-rw-r--r--main/src/cgeo/geocaching/network/StatusUpdater.java57
-rw-r--r--main/src/cgeo/geocaching/search/AutoCompleteAdapter.java71
-rw-r--r--main/src/cgeo/geocaching/search/SuggestionProvider.java57
-rw-r--r--main/src/cgeo/geocaching/settings/OAuthPreference.java4
-rw-r--r--main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java1
-rw-r--r--main/src/cgeo/geocaching/settings/Settings.java12
-rw-r--r--main/src/cgeo/geocaching/settings/SettingsActivity.java110
-rw-r--r--main/src/cgeo/geocaching/settings/TemplateTextPreference.java2
-rw-r--r--main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java35
-rw-r--r--main/src/cgeo/geocaching/sorting/CacheComparator.java4
-rw-r--r--main/src/cgeo/geocaching/sorting/ComparatorUserInterface.java9
-rw-r--r--main/src/cgeo/geocaching/sorting/DateComparator.java7
-rw-r--r--main/src/cgeo/geocaching/sorting/DifficultyComparator.java4
-rw-r--r--main/src/cgeo/geocaching/sorting/DistanceComparator.java5
-rw-r--r--main/src/cgeo/geocaching/sorting/FindsComparator.java4
-rw-r--r--main/src/cgeo/geocaching/sorting/GeocodeComparator.java13
-rw-r--r--main/src/cgeo/geocaching/sorting/InventoryComparator.java5
-rw-r--r--main/src/cgeo/geocaching/sorting/NameComparator.java4
-rw-r--r--main/src/cgeo/geocaching/sorting/PopularityComparator.java5
-rw-r--r--main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java5
-rw-r--r--main/src/cgeo/geocaching/sorting/RatingComparator.java5
-rw-r--r--main/src/cgeo/geocaching/sorting/SizeComparator.java4
-rw-r--r--main/src/cgeo/geocaching/sorting/StateComparator.java5
-rw-r--r--main/src/cgeo/geocaching/sorting/StorageTimeComparator.java5
-rw-r--r--main/src/cgeo/geocaching/sorting/TerrainComparator.java4
-rw-r--r--main/src/cgeo/geocaching/sorting/VisitComparator.java5
-rw-r--r--main/src/cgeo/geocaching/sorting/VoteComparator.java5
-rw-r--r--main/src/cgeo/geocaching/speech/SpeechService.java4
-rw-r--r--main/src/cgeo/geocaching/speech/TextFactory.java2
-rw-r--r--main/src/cgeo/geocaching/twitter/Twitter.java1
-rw-r--r--main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java1
-rw-r--r--main/src/cgeo/geocaching/ui/AnchorAwareLinkMovementMethod.java2
-rw-r--r--main/src/cgeo/geocaching/ui/CacheDetailsCreator.java21
-rw-r--r--main/src/cgeo/geocaching/ui/EditNoteDialog.java2
-rw-r--r--main/src/cgeo/geocaching/ui/ImagesList.java92
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java4
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/Dialogs.java21
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java13
-rw-r--r--main/src/cgeo/geocaching/utils/CancellableHandler.java16
-rw-r--r--main/src/cgeo/geocaching/utils/GeoDirHandler.java107
-rw-r--r--main/src/cgeo/geocaching/utils/IObserver.java22
-rw-r--r--main/src/cgeo/geocaching/utils/ISubject.java57
-rw-r--r--main/src/cgeo/geocaching/utils/ImageUtils.java2
-rw-r--r--main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java3
-rw-r--r--main/src/cgeo/geocaching/utils/LogTemplateProvider.java4
-rw-r--r--main/src/cgeo/geocaching/utils/MemorySubject.java45
-rw-r--r--main/src/cgeo/geocaching/utils/RunnableWithArgument.java7
-rw-r--r--main/src/cgeo/geocaching/utils/Subject.java76
-rw-r--r--main/src/cgeo/geocaching/utils/TextUtils.java1
139 files changed, 1757 insertions, 1779 deletions
diff --git a/main/src/cgeo/calendar/CalendarAddon.java b/main/src/cgeo/calendar/CalendarAddon.java
new file mode 100644
index 0000000..117fb9a
--- /dev/null
+++ b/main/src/cgeo/calendar/CalendarAddon.java
@@ -0,0 +1,58 @@
+package cgeo.calendar;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.R;
+import cgeo.geocaching.geopoint.GeopointFormatter;
+import cgeo.geocaching.network.Parameters;
+import cgeo.geocaching.ui.dialog.Dialogs;
+import cgeo.geocaching.utils.ProcessUtils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import android.app.Activity;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.Uri;
+
+import java.util.Date;
+
+public class CalendarAddon {
+ public static boolean isAvailable() {
+ return ProcessUtils.isIntentAvailable(ICalendar.INTENT, Uri.parse(ICalendar.URI_SCHEME + "://" + ICalendar.URI_HOST));
+ }
+
+ public static void addToCalendarWithIntent(final Activity activity, final Geocache cache) {
+ final Resources res = activity.getResources();
+ if (CalendarAddon.isAvailable()) {
+ final Date hiddenDate = cache.getHiddenDate();
+ final Parameters params = new Parameters(
+ ICalendar.PARAM_NAME, cache.getName(),
+ ICalendar.PARAM_NOTE, StringUtils.defaultString(cache.getPersonalNote()),
+ ICalendar.PARAM_HIDDEN_DATE, hiddenDate != null ? String.valueOf(hiddenDate.getTime()) : StringUtils.EMPTY,
+ ICalendar.PARAM_URL, StringUtils.defaultString(cache.getUrl()),
+ ICalendar.PARAM_COORDS, cache.getCoords() == null ? "" : cache.getCoords().format(GeopointFormatter.Format.LAT_LON_DECMINUTE_RAW),
+ ICalendar.PARAM_LOCATION, StringUtils.defaultString(cache.getLocation()),
+ ICalendar.PARAM_SHORT_DESC, StringUtils.defaultString(cache.getShortDescription()),
+ ICalendar.PARAM_START_TIME_MINUTES, StringUtils.defaultString(cache.guessEventTimeMinutes())
+ );
+
+ activity.startActivity(new Intent(ICalendar.INTENT,
+ Uri.parse(ICalendar.URI_SCHEME + "://" + ICalendar.URI_HOST + "?" + params.toString())));
+ } else {
+ // Inform user the calendar add-on is not installed and let them get it from Google Play
+ Dialogs.confirmYesNo(activity, R.string.addon_missing_title, new StringBuilder(res.getString(R.string.helper_calendar_missing))
+ .append(' ')
+ .append(res.getString(R.string.addon_download_prompt))
+ .toString(), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ final Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(ICalendar.CALENDAR_ADDON_URI));
+ activity.startActivity(intent);
+ }
+ });
+ }
+ }
+
+}
diff --git a/main/src/cgeo/calendar/ICalendar.java b/main/src/cgeo/calendar/ICalendar.java
index 933d248..6ecb6d5 100644
--- a/main/src/cgeo/calendar/ICalendar.java
+++ b/main/src/cgeo/calendar/ICalendar.java
@@ -14,6 +14,6 @@ public interface ICalendar {
static final String PARAM_NOTE = "note"; // personal note
static final String PARAM_NAME = "name"; // cache name
static final String PARAM_LOCATION = "location"; // cache location, or empty string
- static final String PARAM_COORDS = "coords"; // cache coords, or empty string
+ static final String PARAM_COORDS = "coords"; // cache coordinates, or empty string
static final String PARAM_START_TIME_MINUTES = "time"; // time of start
}
diff --git a/main/src/cgeo/contacts/IContacts.java b/main/src/cgeo/contacts/IContacts.java
index d46a5a4..d68b78a 100644
--- a/main/src/cgeo/contacts/IContacts.java
+++ b/main/src/cgeo/contacts/IContacts.java
@@ -1,8 +1,6 @@
package cgeo.contacts;
public interface IContacts {
- static final String CALENDAR_ADDON_URI = "market://details?id=cgeo.contacts";
-
static final String INTENT = "cgeo.contacts.FIND";
static final String URI_SCHEME = "find";
diff --git a/main/src/cgeo/geocaching/AbstractPopupActivity.java b/main/src/cgeo/geocaching/AbstractPopupActivity.java
index 5f24030..38e37da 100644
--- a/main/src/cgeo/geocaching/AbstractPopupActivity.java
+++ b/main/src/cgeo/geocaching/AbstractPopupActivity.java
@@ -40,7 +40,7 @@ public abstract class AbstractPopupActivity extends AbstractActivity implements
private final GeoDirHandler geoUpdate = new GeoDirHandler() {
@Override
- protected void updateGeoData(final IGeoData geo) {
+ public void updateGeoData(final IGeoData geo) {
try {
if (geo.getCoords() != null && cache != null && cache.getCoords() != null) {
cacheDistance.setText(Units.getDistanceFromKilometers(geo.getCoords().distanceTo(cache.getCoords())));
diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java
index 4068e38..6962317 100644
--- a/main/src/cgeo/geocaching/CacheDetailActivity.java
+++ b/main/src/cgeo/geocaching/CacheDetailActivity.java
@@ -3,6 +3,7 @@ package cgeo.geocaching;
import butterknife.ButterKnife;
import butterknife.InjectView;
+import cgeo.calendar.CalendarAddon;
import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.activity.AbstractViewPagerActivity;
import cgeo.geocaching.activity.Progress;
@@ -45,7 +46,6 @@ import cgeo.geocaching.utils.HtmlUtils;
import cgeo.geocaching.utils.ImageUtils;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.MatcherWrapper;
-import cgeo.geocaching.utils.RunnableWithArgument;
import cgeo.geocaching.utils.SimpleCancellableHandler;
import cgeo.geocaching.utils.SimpleHandler;
import cgeo.geocaching.utils.TextUtils;
@@ -57,6 +57,14 @@ 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 rx.Observable;
+import rx.Observable.OnSubscribeFunc;
+import rx.Observer;
+import rx.Subscription;
+import rx.android.observables.AndroidObservable;
+import rx.concurrency.Schedulers;
+import rx.subscriptions.Subscriptions;
+import rx.util.functions.Action1;
import android.R.color;
import android.app.AlertDialog;
@@ -80,7 +88,6 @@ import android.text.Editable;
import android.text.Html;
import android.text.Spannable;
import android.text.Spanned;
-import android.text.format.DateUtils;
import android.text.style.ForegroundColorSpan;
import android.text.style.StrikethroughSpan;
import android.text.style.StyleSpan;
@@ -109,7 +116,6 @@ import android.widget.TextView.BufferType;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Date;
import java.util.EnumSet;
import java.util.List;
import java.util.Locale;
@@ -176,24 +182,15 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
// set title in code, as the activity needs a hard coded title due to the intent filters
setTitle(res.getString(R.string.cache));
- String geocode = 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) {
- cache = search.getFirstCacheFromResult(LoadFlags.LOAD_ALL_DB_ONLY);
- if (cache != null && cache.getGeocode() != null) {
- geocode = cache.getGeocode();
- }
- }
-
// get parameters
final Bundle extras = getIntent().getExtras();
final Uri uri = getIntent().getData();
// try to get data from extras
String name = null;
+ String geocode = null;
String guid = null;
- if (geocode == null && extras != null) {
+ if (extras != null) {
geocode = extras.getString(Intents.EXTRA_GEOCODE);
name = extras.getString(Intents.EXTRA_NAME);
guid = extras.getString(Intents.EXTRA_GUID);
@@ -327,6 +324,14 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
@Override
+ public void onDestroy() {
+ if (imagesList != null) {
+ imagesList.removeAllViews();
+ }
+ super.onDestroy();
+ }
+
+ @Override
public void onStop() {
if (cache != null) {
cache.setChangeNotificationHandler(null);
@@ -382,6 +387,12 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
clickedItemText = ((TextView) view).getText();
buildDetailsContextMenu(menu, res.getString(R.string.cache_logs), false);
break;
+ case R.id.date: // event date
+ assert view instanceof TextView;
+ clickedItemText = ((TextView) view).getText();
+ buildDetailsContextMenu(menu, res.getString(R.string.cache_event), true);
+ menu.findItem(R.id.menu_calendar).setVisible(cache.canBeAddedToCalendar());
+ break;
case R.id.waypoint:
menu.setHeaderTitle(selectedWaypoint.getName() + " (" + res.getString(R.string.waypoint) + ")");
getMenuInflater().inflate(R.menu.waypoint_options, menu);
@@ -484,6 +495,9 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
new ResetCoordsThread(cache, handler, selectedWaypoint, true, false, progressDialog).start();
}
return true;
+ case R.id.menu_calendar:
+ CalendarAddon.addToCalendarWithIntent(this, cache);
+ return true;
default:
break;
}
@@ -542,20 +556,19 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
if (UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) {
updateStatusMsg((String) msg.obj);
} else {
- CacheDetailActivity activity = ((CacheDetailActivity) activityRef.get());
+ final CacheDetailActivity activity = ((CacheDetailActivity) activityRef.get());
if (activity == null) {
return;
}
- SearchResult search = activity.getSearch();
- if (search == null) {
+ if (activity.search == null) {
showToast(R.string.err_dwld_details_failed);
dismissProgress();
finishActivity();
return;
}
- if (search.getError() != null) {
- activity.showToast(activity.getResources().getString(R.string.err_dwld_details_failed) + " " + search.getError().getErrorString(activity.getResources()) + ".");
+ if (activity.search.getError() != null) {
+ activity.showToast(activity.getResources().getString(R.string.err_dwld_details_failed) + " " + activity.search.getError().getErrorString(activity.getResources()) + ".");
dismissProgress();
finishActivity();
return;
@@ -972,17 +985,10 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
ownerView.setOnClickListener(new OwnerActionsClickListener(cache));
}
- // cache hidden
- final Date hiddenDate = cache.getHiddenDate();
- if (hiddenDate != null) {
- final long time = hiddenDate.getTime();
- if (time > 0) {
- String dateString = Formatter.formatFullDate(time);
- if (cache.isEventCache()) {
- dateString = DateUtils.formatDateTime(CgeoApplication.getInstance().getBaseContext(), time, DateUtils.FORMAT_SHOW_WEEKDAY) + ", " + dateString;
- }
- details.add(cache.isEventCache() ? R.string.cache_event : R.string.cache_hidden, dateString);
- }
+ // hidden or event date
+ final TextView hiddenView = details.addHiddenDate(cache);
+ if (hiddenView != null) {
+ registerForContextMenu(hiddenView);
}
// cache location
@@ -1051,9 +1057,9 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
if (Settings.getChooseList()) {
// let user select list to store cache in
new StoredList.UserInterface(CacheDetailActivity.this).promptForListSelection(R.string.list_title,
- new RunnableWithArgument<Integer>() {
+ new Action1<Integer>() {
@Override
- public void run(final Integer selectedListId) {
+ public void call(final Integer selectedListId) {
storeCache(selectedListId, new StoreCacheHandler(CacheDetailActivity.this, progress));
}
}, true, StoredList.TEMPORARY_LIST_ID);
@@ -1302,9 +1308,9 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
@Override
public void onClick(View view) {
new StoredList.UserInterface(CacheDetailActivity.this).promptForListSelection(R.string.list_title,
- new RunnableWithArgument<Integer>() {
+ new Action1<Integer>() {
@Override
- public void run(final Integer selectedListId) {
+ public void call(final Integer selectedListId) {
switchListById(selectedListId);
}
}, true, cache.getListId());
@@ -1368,7 +1374,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
final LinearLayout layout = (LinearLayout) view.findViewById(R.id.favpoint_box);
final boolean supportsFavoritePoints = cache.supportsFavoritePoints();
layout.setVisibility(supportsFavoritePoints ? View.VISIBLE : View.GONE);
- if (!supportsFavoritePoints || cache.isOwner() || !Settings.isPremiumMember()) {
+ if (!supportsFavoritePoints || cache.isOwner() || !Settings.isGCPremiumMember()) {
return;
}
final Button buttonAdd = (Button) view.findViewById(R.id.add_to_favpoint);
@@ -1470,6 +1476,10 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
protected class DescriptionViewCreator extends AbstractCachingPageViewCreator<ScrollView> {
@InjectView(R.id.personalnote) protected TextView personalNoteView;
+ @InjectView(R.id.shortdesc) protected IndexOutOfBoundsAvoidingTextView shortDescView;
+ @InjectView(R.id.longdesc) protected IndexOutOfBoundsAvoidingTextView longDescView;
+ @InjectView(R.id.show_description) protected Button showDesc;
+ @InjectView(R.id.loading) protected View loadingView;
@Override
public ScrollView getDispatchedView() {
@@ -1483,7 +1493,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
// cache short description
if (StringUtils.isNotBlank(cache.getShortDescription())) {
- new LoadDescriptionTask(cache.getShortDescription(), view.findViewById(R.id.shortdesc), null, null).execute();
+ loadDescription(cache.getShortDescription(), shortDescView, null);
}
// long description
@@ -1491,7 +1501,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
if (Settings.isAutoLoadDescription()) {
loadLongDescription();
} else {
- final Button showDesc = (Button) view.findViewById(R.id.show_description);
showDesc.setVisibility(View.VISIBLE);
showDesc.setOnClickListener(new View.OnClickListener() {
@Override
@@ -1605,12 +1614,23 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
private void loadLongDescription() {
- final Button showDesc = (Button) view.findViewById(R.id.show_description);
showDesc.setVisibility(View.GONE);
showDesc.setOnClickListener(null);
view.findViewById(R.id.loading).setVisibility(View.VISIBLE);
- new LoadDescriptionTask(cache.getDescription(), view.findViewById(R.id.longdesc), view.findViewById(R.id.loading), view.findViewById(R.id.shortdesc)).execute();
+ final String longDescription = cache.getDescription();
+ loadDescription(longDescription, longDescView, loadingView);
+
+ // Hide the short description, if it is contained somewhere at the start of the long description.
+ if (shortDescView != null) {
+ final String shortDescription = cache.getShortDescription();
+ if (StringUtils.isNotBlank(shortDescription)) {
+ final int index = longDescription.indexOf(shortDescription);
+ if (index >= 0 && index < 200) {
+ shortDescView.setVisibility(View.GONE);
+ }
+ }
+ }
}
private void warnPersonalNoteNeedsStoring() {
@@ -1641,148 +1661,119 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
- /**
- * Loads the description in background. <br />
- * <br />
- * Params:
- * <ol>
- * <li>description string (String)</li>
- * <li>target description view (TextView)</li>
- * <li>loading indicator view (View, may be null)</li>
- * </ol>
- */
- private class LoadDescriptionTask extends AsyncTask<Object, Void, Void> {
- private final View loadingIndicatorView;
- private final IndexOutOfBoundsAvoidingTextView descriptionView;
- private final String descriptionString;
- private Spanned description;
- private final View shortDescView;
+ /**
+ * Load the description in the background.
+ * @param descriptionString the HTML description as retrieved from the connector
+ * @param descriptionView the view to fill
+ * @param loadingIndicatorView the loading indicator view, will be hidden when completed
+ */
+ private void loadDescription(final String descriptionString, final IndexOutOfBoundsAvoidingTextView descriptionView, final View loadingIndicatorView) {
+ // The producer produces successives (without then with images) versions of the description.
+ final Observable<Spanned> producer = Observable.create(new OnSubscribeFunc<Spanned>() {
+ @Override
+ public Subscription onSubscribe(final Observer<? super Spanned> observer) {
+ try {
+ // Fast preview: parse only HTML without loading any images
+ final HtmlImageCounter imageCounter = new HtmlImageCounter();
+ final UnknownTagsHandler unknownTagsHandler = new UnknownTagsHandler();
+ Spanned description = Html.fromHtml(descriptionString, imageCounter, unknownTagsHandler);
+ addWarning(unknownTagsHandler, description);
+ observer.onNext(description);
+
+ if (imageCounter.getImageCount() > 0) {
+ // Complete view: parse again with loading images - if necessary ! If there are any images causing problems the user can see at least the preview
+ description = Html.fromHtml(descriptionString, new HtmlImage(cache.getGeocode(), true, cache.getListId(), false), unknownTagsHandler);
+ addWarning(unknownTagsHandler, description);
+ observer.onNext(description);
+ }
- public LoadDescriptionTask(final String description, final View descriptionView, final View loadingIndicatorView, final View shortDescView) {
- assert descriptionView instanceof IndexOutOfBoundsAvoidingTextView;
- this.descriptionString = description;
- this.descriptionView = (IndexOutOfBoundsAvoidingTextView) descriptionView;
- this.loadingIndicatorView = loadingIndicatorView;
- this.shortDescView = shortDescView;
- }
+ observer.onCompleted();
+ } catch (final Exception e) {
+ Log.e("loadDescription", e);
+ observer.onError(e);
+ }
+ return Subscriptions.empty();
+ }
- @Override
- protected Void doInBackground(Object... params) {
- try {
- // Fast preview: parse only HTML without loading any images
- final HtmlImageCounter imageCounter = new HtmlImageCounter();
- final UnknownTagsHandler unknownTagsHandler = new UnknownTagsHandler();
- description = Html.fromHtml(descriptionString, imageCounter, unknownTagsHandler);
- publishProgress();
-
- boolean needsRefresh = false;
- if (imageCounter.getImageCount() > 0) {
- // Complete view: parse again with loading images - if necessary ! If there are any images causing problems the user can see at least the preview
- description = Html.fromHtml(descriptionString, new HtmlImage(cache.getGeocode(), true, cache.getListId(), false), unknownTagsHandler);
- needsRefresh = true;
- }
-
- // If description has an HTML construct which may be problematic to render, add a note at the end of the long description.
- // Technically, it may not be a table, but a pre, which has the same problems as a table, so the message is ok even though
- // sometimes technically incorrect.
- if (unknownTagsHandler.isProblematicDetected() && descriptionView != null) {
+ // If description has an HTML construct which may be problematic to render, add a note at the end of the long description.
+ // Technically, it may not be a table, but a pre, which has the same problems as a table, so the message is ok even though
+ // sometimes technically incorrect.
+ private void addWarning(final UnknownTagsHandler unknownTagsHandler, final Spanned description) {
+ if (unknownTagsHandler.isProblematicDetected()) {
final int startPos = description.length();
final IConnector connector = ConnectorFactory.getConnector(cache);
final Spanned tableNote = Html.fromHtml(res.getString(R.string.cache_description_table_note, "<a href=\"" + cache.getUrl() + "\">" + connector.getName() + "</a>"));
((Editable) description).append("\n\n").append(tableNote);
((Editable) description).setSpan(new StyleSpan(Typeface.ITALIC), startPos, description.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- needsRefresh = true;
- }
-
- if (needsRefresh) {
- publishProgress();
- }
- } catch (final Exception e) {
- Log.e("LoadDescriptionTask: ", e);
- }
- return null;
- }
-
- @Override
- protected void onProgressUpdate(Void... values) {
- if (description == null) {
- showToast(res.getString(R.string.err_load_descr_failed));
- return;
- }
- if (StringUtils.isNotBlank(descriptionString)) {
- try {
- descriptionView.setText(description, TextView.BufferType.SPANNABLE);
- } catch (final Exception e) {
- // On 4.1, there is sometimes a crash on measuring the layout: https://code.google.com/p/android/issues/detail?id=35412
- Log.e("Android bug setting text: ", e);
- // remove the formatting by converting to a simple string
- descriptionView.setText(description.toString());
}
- descriptionView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
- fixTextColor(descriptionView, descriptionString);
- descriptionView.setVisibility(View.VISIBLE);
- registerForContextMenu(descriptionView);
-
- hideDuplicatedShortDescription();
}
- }
+ });
- /**
- * Hide the short description, if it is contained somewhere at the start of the long description.
- */
- private void hideDuplicatedShortDescription() {
- if (shortDescView != null) {
- final String shortDescription = cache.getShortDescription();
- if (StringUtils.isNotBlank(shortDescription)) {
- final int index = descriptionString.indexOf(shortDescription);
- if (index >= 0 && index < 200) {
- shortDescView.setVisibility(View.GONE);
+ AndroidObservable.fromActivity(this, producer.subscribeOn(Schedulers.threadPoolForIO()))
+ .subscribe(new Observer<Spanned>() {
+ @Override
+ public void onCompleted() {
+ if (null != loadingIndicatorView) {
+ loadingIndicatorView.setVisibility(View.GONE);
+ }
}
- }
- }
- }
- @Override
- protected void onPostExecute(Void result) {
- if (null != loadingIndicatorView) {
- loadingIndicatorView.setVisibility(View.GONE);
- }
- }
+ @Override
+ public void onError(final Throwable throwable) {
+ showToast(res.getString(R.string.err_load_descr_failed));
+ }
- /**
- * Handle caches with black font color in dark skin and white font color in light skin
- * by changing background color of the view
- *
- * @param view
- * containing the text
- * @param text
- * to be checked
- */
- private void fixTextColor(final TextView view, final String text) {
- int backcolor;
- if (Settings.isLightSkin()) {
- backcolor = color.white;
-
- for (final Pattern pattern : LIGHT_COLOR_PATTERNS) {
- final MatcherWrapper matcher = new MatcherWrapper(pattern, text);
- if (matcher.find()) {
- view.setBackgroundResource(color.darker_gray);
- return;
+ @Override
+ public void onNext(final Spanned description) {
+ if (StringUtils.isNotBlank(descriptionString)) {
+ try {
+ descriptionView.setText(description, TextView.BufferType.SPANNABLE);
+ } catch (final Exception e) {
+ // On 4.1, there is sometimes a crash on measuring the layout: https://code.google.com/p/android/issues/detail?id=35412
+ Log.e("Android bug setting text: ", e);
+ // remove the formatting by converting to a simple string
+ descriptionView.setText(description.toString());
+ }
+ descriptionView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
+ fixTextColor(descriptionString);
+ descriptionView.setVisibility(View.VISIBLE);
+ registerForContextMenu(descriptionView);
+ }
}
- }
- } else {
- backcolor = color.black;
- for (final Pattern pattern : DARK_COLOR_PATTERNS) {
- final MatcherWrapper matcher = new MatcherWrapper(pattern, text);
- if (matcher.find()) {
- view.setBackgroundResource(color.darker_gray);
- return;
+ /**
+ * Handle caches with black font color in dark skin and white font color in light skin
+ * by changing background color of the view
+ *
+ * @param text
+ * to be checked
+ */
+ private void fixTextColor(final String text) {
+ int backcolor;
+ if (Settings.isLightSkin()) {
+ backcolor = color.white;
+
+ for (final Pattern pattern : LIGHT_COLOR_PATTERNS) {
+ final MatcherWrapper matcher = new MatcherWrapper(pattern, text);
+ if (matcher.find()) {
+ descriptionView.setBackgroundResource(color.darker_gray);
+ return;
+ }
+ }
+ } else {
+ backcolor = color.black;
+
+ for (final Pattern pattern : DARK_COLOR_PATTERNS) {
+ final MatcherWrapper matcher = new MatcherWrapper(pattern, text);
+ if (matcher.find()) {
+ descriptionView.setBackgroundResource(color.darker_gray);
+ return;
+ }
+ }
+ }
+ descriptionView.setBackgroundResource(backcolor);
}
- }
- }
- view.setBackgroundResource(backcolor);
- }
+ });
}
private class WaypointsViewCreator extends AbstractCachingPageViewCreator<ListView> {
@@ -2255,10 +2246,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
return cache;
}
- public SearchResult getSearch() {
- return search;
- }
-
private static class StoreCacheHandler extends SimpleCancellableHandler {
public StoreCacheHandler(CacheDetailActivity activity, Progress progress) {
diff --git a/main/src/cgeo/geocaching/CacheListActivity.java b/main/src/cgeo/geocaching/CacheListActivity.java
index cc8b178..b581411 100644
--- a/main/src/cgeo/geocaching/CacheListActivity.java
+++ b/main/src/cgeo/geocaching/CacheListActivity.java
@@ -18,11 +18,13 @@ import cgeo.geocaching.files.GPXImporter;
import cgeo.geocaching.filter.FilterUserInterface;
import cgeo.geocaching.filter.IFilter;
import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.list.PseudoList;
import cgeo.geocaching.list.StoredList;
import cgeo.geocaching.loaders.AbstractSearchLoader;
import cgeo.geocaching.loaders.AbstractSearchLoader.CacheListLoaderType;
import cgeo.geocaching.loaders.AddressGeocacheListLoader;
import cgeo.geocaching.loaders.CoordsGeocacheListLoader;
+import cgeo.geocaching.loaders.FinderGeocacheListLoader;
import cgeo.geocaching.loaders.HistoryGeocacheListLoader;
import cgeo.geocaching.loaders.KeywordGeocacheListLoader;
import cgeo.geocaching.loaders.NextPageGeocacheListLoader;
@@ -30,7 +32,6 @@ import cgeo.geocaching.loaders.OfflineGeocacheListLoader;
import cgeo.geocaching.loaders.OwnerGeocacheListLoader;
import cgeo.geocaching.loaders.PocketGeocacheListLoader;
import cgeo.geocaching.loaders.RemoveFromHistoryLoader;
-import cgeo.geocaching.loaders.FinderGeocacheListLoader;
import cgeo.geocaching.maps.CGeoMap;
import cgeo.geocaching.network.Cookies;
import cgeo.geocaching.network.Network;
@@ -43,10 +44,10 @@ import cgeo.geocaching.ui.LoggingUI;
import cgeo.geocaching.ui.WeakReferenceHandler;
import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.AsyncTaskWithProgress;
+import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.DateUtils;
import cgeo.geocaching.utils.GeoDirHandler;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.RunnableWithArgument;
import ch.boye.httpclientandroidlib.HttpResponse;
@@ -55,6 +56,8 @@ import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import rx.util.functions.Action1;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
@@ -93,7 +96,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
private static final int MAX_LIST_ITEMS = 1000;
private static final int MSG_DONE = -1;
- private static final int MSG_CANCEL = -99;
private static final int REQUEST_CODE_IMPORT_GPX = 1;
@@ -111,8 +113,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
private int detailTotal = 0;
private int detailProgress = 0;
private long detailProgressTime = 0L;
- private LoadDetailsThread threadDetails = null;
- private LoadFromWebThread threadWeb = null;
private int listId = StoredList.TEMPORARY_LIST_ID; // Only meaningful for the OFFLINE type
private final GeoDirHandler geoDirHandler = new GeoDirHandler() {
@@ -267,10 +267,10 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
}
- private final Handler loadDetailsHandler = new Handler() {
+ private final CancellableHandler loadDetailsHandler = new CancellableHandler() {
@Override
- public void handleMessage(Message msg) {
+ public void handleRegularMessage(Message msg) {
setAdapter();
if (msg.what > -1) {
@@ -287,10 +287,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
} else {
progress.setMessage(res.getString(R.string.caches_downloading) + " " + minutesRemaining + " " + res.getQuantityString(R.plurals.caches_eta_mins, minutesRemaining));
}
- } else if (msg.what == MSG_CANCEL) {
- if (threadDetails != null) {
- threadDetails.kill();
- }
} else {
if (search != null) {
final Set<Geocache> cacheListTmp = search.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB);
@@ -304,13 +300,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
showProgress(false);
progress.dismiss();
-
- if (!isPaused()) {
- // If the current activity has been paused, then we do not want to fiddle with the
- // GPS and direction states. If the activity later gets resumed, its onResume()
- // function will take care of turning the GPS back on.
- startGeoAndDir();
- }
}
}
};
@@ -318,9 +307,9 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
/**
* TODO Possibly parts should be a Thread not a Handler
*/
- private final Handler downloadFromWebHandler = new Handler() {
+ private final CancellableHandler downloadFromWebHandler = new CancellableHandler() {
@Override
- public void handleMessage(Message msg) {
+ public void handleRegularMessage(Message msg) {
setAdapter();
adapter.notifyDataSetChanged();
@@ -340,10 +329,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
progress.dismiss();
showToast(res.getString(R.string.sendToCgeo_no_registration));
finish();
- } else if (msg.what == MSG_CANCEL) {
- if (threadWeb != null) {
- threadWeb.kill();
- }
} else {
adapter.setSelectMode(false);
@@ -353,19 +338,17 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
}
};
- private final Handler clearOfflineLogsHandler = new Handler() {
+ private final CancellableHandler clearOfflineLogsHandler = new CancellableHandler() {
@Override
- public void handleMessage(Message msg) {
- if (msg.what != MSG_CANCEL) {
- adapter.setSelectMode(false);
+ public void handleRegularMessage(Message msg) {
+ adapter.setSelectMode(false);
- refreshCurrentList();
+ refreshCurrentList();
- replaceCacheListFromSearch();
+ replaceCacheListFromSearch();
- progress.dismiss();
- }
+ progress.dismiss();
}
};
@@ -402,7 +385,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
if (isInvokedFromAttachment()) {
type = CacheListType.OFFLINE;
if (coords == null) {
- coords = new Geopoint(0.0, 0.0);
+ coords = Geopoint.ZERO;
}
}
@@ -422,7 +405,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
prepareFilterBar();
- currentLoader = (AbstractSearchLoader) getSupportLoaderManager().initLoader(type.ordinal(), extras, this);
+ currentLoader = (AbstractSearchLoader) getSupportLoaderManager().initLoader(type.getLoaderId(), extras, this);
// init
if (CollectionUtils.isNotEmpty(cacheList)) {
@@ -458,10 +441,10 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
private void importGpxAttachement() {
- new StoredList.UserInterface(this).promptForListSelection(R.string.gpx_import_select_list_title, new RunnableWithArgument<Integer>() {
+ new StoredList.UserInterface(this).promptForListSelection(R.string.gpx_import_select_list_title, new Action1<Integer>() {
@Override
- public void run(Integer listId) {
+ public void call(Integer listId) {
new GPXImporter(CacheListActivity.this, listId, importGpxAttachementFinishedHandler).importGPX();
switchListById(listId);
}
@@ -472,12 +455,15 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
public void onResume() {
super.onResume();
- startGeoAndDir();
+ geoDirHandler.startGeo();
+ if (Settings.isLiveMap()) {
+ geoDirHandler.startDir();
+ }
adapter.setSelectMode(false);
setAdapterCurrentCoordinates(true);
- if (loadCachesHandler != null && search != null) {
+ if (search != null) {
replaceCacheListFromSearch();
loadCachesHandler.sendEmptyMessage(0);
}
@@ -503,8 +489,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
@Override
public void onPause() {
- removeGeoAndDir();
-
+ geoDirHandler.stopGeoAndDir();
super.onPause();
}
@@ -675,9 +660,9 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
return true;
case R.id.menu_sort:
final CacheComparator oldComparator = adapter.getCacheComparator();
- new ComparatorUserInterface(this).selectComparator(oldComparator, new RunnableWithArgument<CacheComparator>() {
+ new ComparatorUserInterface(this).selectComparator(oldComparator, new Action1<CacheComparator>() {
@Override
- public void run(CacheComparator selectedComparator) {
+ public void call(CacheComparator selectedComparator) {
// selecting the same sorting twice will toggle the order
if (selectedComparator != null && oldComparator != null && selectedComparator.getClass().equals(oldComparator.getClass())) {
adapter.toggleInverseSort();
@@ -728,7 +713,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
public void clearOfflineLogs() {
- progress.show(this, null, res.getString(R.string.caches_clear_offlinelogs_progress), true, clearOfflineLogsHandler.obtainMessage(MSG_CANCEL));
+ progress.show(this, null, res.getString(R.string.caches_clear_offlinelogs_progress), true, clearOfflineLogsHandler.cancelMessage());
new ClearOfflineLogsThread(clearOfflineLogsHandler).start();
}
@@ -737,13 +722,12 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
*/
@Override
public void showFilterMenu(final View view) {
- new FilterUserInterface(this).selectFilter(new RunnableWithArgument<IFilter>() {
+ new FilterUserInterface(this).selectFilter(new Action1<IFilter>() {
@Override
- public void run(IFilter selectedFilter) {
+ public void call(IFilter selectedFilter) {
if (selectedFilter != null) {
setFilter(selectedFilter);
- }
- else {
+ } else {
// clear filter
setFilter(null);
}
@@ -793,10 +777,10 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
private void moveCachesToOtherList() {
- new StoredList.UserInterface(this).promptForListSelection(R.string.cache_menu_move_list, new RunnableWithArgument<Integer>() {
+ new StoredList.UserInterface(this).promptForListSelection(R.string.cache_menu_move_list, new Action1<Integer>() {
@Override
- public void run(Integer newListId) {
+ public void call(Integer newListId) {
DataStore.moveToList(adapter.getCheckedOrAllCaches(), newListId);
adapter.setSelectMode(false);
@@ -850,10 +834,10 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
});
break;
case R.id.menu_move_to_list:
- new StoredList.UserInterface(this).promptForListSelection(R.string.cache_menu_move_list, new RunnableWithArgument<Integer>() {
+ new StoredList.UserInterface(this).promptForListSelection(R.string.cache_menu_move_list, new Action1<Integer>() {
@Override
- public void run(Integer newListId) {
+ public void call(Integer newListId) {
DataStore.moveToList(Collections.singletonList(cache), newListId);
adapter.setSelectMode(false);
refreshCurrentList();
@@ -960,7 +944,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
boolean enableMore = (type != CacheListType.OFFLINE && cacheList.size() < MAX_LIST_ITEMS);
if (enableMore && search != null) {
final int count = search.getTotalCountGC();
- enableMore = enableMore && count > 0 && cacheList.size() < count;
+ enableMore = count > 0 && cacheList.size() < count;
}
if (enableMore) {
@@ -973,17 +957,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
listFooter.setClickable(enableMore);
}
- private void startGeoAndDir() {
- geoDirHandler.startGeo();
- if (Settings.isLiveMap()) {
- geoDirHandler.startDir();
- }
- }
-
- private void removeGeoAndDir() {
- geoDirHandler.stopGeoAndDir();
- }
-
private void importGpx() {
GpxFileListActivity.startSubActivity(this, listId);
}
@@ -1002,7 +975,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
// provided to this method as a parameter. Pull that uri using "resultData.getData()"
if (data != null) {
final Uri uri = data.getData();
- new GPXImporter(CacheListActivity.this, listId, importGpxAttachementFinishedHandler).importGPX(uri, null, getDisplayName(uri));
+ new GPXImporter(this, listId, importGpxAttachementFinishedHandler).importGPX(uri, null, getDisplayName(uri));
}
}
@@ -1038,9 +1011,9 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
if (Settings.getChooseList() && type != CacheListType.OFFLINE) {
// let user select list to store cache in
new StoredList.UserInterface(this).promptForListSelection(R.string.list_title,
- new RunnableWithArgument<Integer>() {
+ new Action1<Integer>() {
@Override
- public void run(final Integer selectedListId) {
+ public void call(final Integer selectedListId) {
refreshStored(caches, selectedListId);
}
}, true, StoredList.TEMPORARY_LIST_ID, newListName);
@@ -1062,12 +1035,12 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
message = res.getString(R.string.caches_downloading) + " " + etaTime + " " + res.getQuantityString(R.plurals.caches_eta_mins, etaTime);
}
- progress.show(this, null, message, ProgressDialog.STYLE_HORIZONTAL, loadDetailsHandler.obtainMessage(MSG_CANCEL));
+ progress.show(this, null, message, ProgressDialog.STYLE_HORIZONTAL, loadDetailsHandler.cancelMessage());
progress.setMaxProgressAndReset(detailTotal);
detailProgressTime = System.currentTimeMillis();
- threadDetails = new LoadDetailsThread(loadDetailsHandler, caches, storeListId);
+ final LoadDetailsThread threadDetails = new LoadDetailsThread(loadDetailsHandler, caches, storeListId);
threadDetails.start();
}
@@ -1091,16 +1064,16 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
final Bundle b = new Bundle();
b.putStringArray(Intents.EXTRA_CACHELIST, geocodes);
- getSupportLoaderManager().initLoader(CacheListLoaderType.REMOVE_FROM_HISTORY.ordinal(), b, this);
+ getSupportLoaderManager().initLoader(CacheListLoaderType.REMOVE_FROM_HISTORY.getLoaderId(), b, this);
}
public void importWeb() {
detailProgress = 0;
showProgress(false);
- progress.show(this, null, res.getString(R.string.web_import_waiting), true, downloadFromWebHandler.obtainMessage(MSG_CANCEL));
+ progress.show(this, null, res.getString(R.string.web_import_waiting), true, downloadFromWebHandler.cancelMessage());
- threadWeb = new LoadFromWebThread(downloadFromWebHandler, listId);
+ final LoadFromWebThread threadWeb = new LoadFromWebThread(downloadFromWebHandler, listId);
threadWeb.start();
}
@@ -1127,26 +1100,20 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
private class LoadDetailsThread extends Thread {
- final private Handler handler;
+ final private CancellableHandler handler;
final private int listIdLD;
- private volatile boolean needToStop = false;
final private List<Geocache> caches;
- public LoadDetailsThread(Handler handlerIn, List<Geocache> caches, int listId) {
- handler = handlerIn;
+ public LoadDetailsThread(CancellableHandler handler, List<Geocache> caches, int listId) {
+ this.handler = handler;
this.caches = caches;
// in case of online lists, set the list id to the standard list
this.listIdLD = Math.max(listId, StoredList.STANDARD_LIST_ID);
}
- public void kill() {
- needToStop = true;
- }
-
@Override
public void run() {
- removeGeoAndDir();
// First refresh caches that do not yet have static maps to get them a chance to get a copy
// before the limit expires, unless we do not want to store offline maps.
final List<Geocache> allCaches = Settings.isStoreOfflineMaps() ?
@@ -1173,7 +1140,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
*/
private boolean refreshCache(Geocache cache) {
try {
- if (needToStop) {
+ if (handler.isCancelled()) {
throw new InterruptedException("Stopped storing process.");
}
detailProgress++;
@@ -1190,31 +1157,23 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
}
- private class LoadFromWebThread extends Thread {
+ private static class LoadFromWebThread extends Thread {
- final private Handler handler;
+ final private CancellableHandler handler;
final private int listIdLFW;
- private volatile boolean needToStop = false;
- public LoadFromWebThread(Handler handlerIn, int listId) {
- handler = handlerIn;
+ public LoadFromWebThread(CancellableHandler handler, int listId) {
+ this.handler = handler;
listIdLFW = StoredList.getConcreteList(listId);
}
- public void kill() {
- needToStop = true;
- }
-
@Override
public void run() {
-
- removeGeoAndDir();
-
int delay = -1;
int times = 0;
int ret = MSG_DONE;
- while (!needToStop && times < 3 * 60 / 5) { // maximum: 3 minutes, every 5 seconds
+ while (!handler.isCancelled() && times < 3 * 60 / 5) { // maximum: 3 minutes, every 5 seconds
//download new code
String deviceCode = Settings.getWebDeviceCode();
if (deviceCode == null) {
@@ -1238,7 +1197,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
//Server returned RG (registration) and this device no longer registered.
Settings.setWebNameCode(null, null);
ret = -3;
- needToStop = true;
+ handler.cancel();
break;
} else {
delay = 0;
@@ -1248,7 +1207,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
if (responseFromWeb == null || responseFromWeb.getStatusLine().getStatusCode() != 200) {
ret = -2;
- needToStop = true;
+ handler.cancel();
break;
}
@@ -1267,8 +1226,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
handler.sendEmptyMessage(ret);
-
- startGeoAndDir();
}
}
@@ -1283,9 +1240,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
@Override
protected Void doInBackgroundInternal(Geocache[] caches) {
- removeGeoAndDir();
DataStore.markDropped(Arrays.asList(caches));
- startGeoAndDir();
return null;
}
@@ -1328,7 +1283,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
showFooterLoadingCaches();
listFooter.setOnClickListener(null);
- getSupportLoaderManager().restartLoader(CacheListLoaderType.NEXT_PAGE.ordinal(), null, CacheListActivity.this);
+ getSupportLoaderManager().restartLoader(CacheListLoaderType.NEXT_PAGE.getLoaderId(), null, CacheListActivity.this);
}
}
@@ -1349,11 +1304,11 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
@NonNull
- private RunnableWithArgument<Integer> getListSwitchingRunnable() {
- return new RunnableWithArgument<Integer>() {
+ private Action1<Integer> getListSwitchingRunnable() {
+ return new Action1<Integer>() {
@Override
- public void run(final Integer selectedListId) {
+ public void call(final Integer selectedListId) {
switchListById(selectedListId);
}
};
@@ -1364,6 +1319,12 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
return;
}
+ if (id == PseudoList.HISTORY_LIST.id) {
+ CacheListActivity.startActivityHistory(this);
+ finish();
+ return;
+ }
+
final StoredList list = DataStore.getList(id);
if (list == null) {
return;
@@ -1378,7 +1339,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
showFooterLoadingCaches();
DataStore.moveToList(adapter.getCheckedCaches(), listId);
- currentLoader = (OfflineGeocacheListLoader) getSupportLoaderManager().initLoader(CacheListType.OFFLINE.ordinal(), new Bundle(), this);
+ currentLoader = (OfflineGeocacheListLoader) getSupportLoaderManager().initLoader(CacheListType.OFFLINE.getLoaderId(), new Bundle(), this);
currentLoader.reset();
((OfflineGeocacheListLoader) currentLoader).setListId(listId);
((OfflineGeocacheListLoader) currentLoader).setSearchCenter(coords);
@@ -1483,12 +1444,12 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
return true;
}
- public static void startActivityUserName(final Activity context, final String userName) {
+ public static void startActivityFinder(final Activity context, final String userName) {
if (!isValidUsername(context, userName)) {
return;
}
final Intent cachesIntent = new Intent(context, CacheListActivity.class);
- cachesIntent.putExtra(Intents.EXTRA_LIST_TYPE, CacheListType.USERNAME);
+ cachesIntent.putExtra(Intents.EXTRA_LIST_TYPE, CacheListType.FINDER);
cachesIntent.putExtra(Intents.EXTRA_USERNAME, userName);
context.startActivity(cachesIntent);
}
@@ -1606,6 +1567,9 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
} else {
final StoredList list = DataStore.getList(listId);
// list.id may be different if listId was not valid
+ if (list.id != listId) {
+ showToast(getString(R.string.list_not_available));
+ }
listId = list.id;
title = list.title;
}
@@ -1670,8 +1634,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
break;
case POCKET:
final String guid = extras.getString(Intents.EXTRA_POCKET_GUID);
- final String pocket_name = extras.getString(Intents.EXTRA_NAME);
- title = pocket_name;
+ title = extras.getString(Intents.EXTRA_NAME);
loader = new PocketGeocacheListLoader(app, guid);
break;
}
diff --git a/main/src/cgeo/geocaching/CacheMenuHandler.java b/main/src/cgeo/geocaching/CacheMenuHandler.java
index 84a08f5..ab11765 100644
--- a/main/src/cgeo/geocaching/CacheMenuHandler.java
+++ b/main/src/cgeo/geocaching/CacheMenuHandler.java
@@ -1,27 +1,17 @@
package cgeo.geocaching;
-import cgeo.calendar.ICalendar;
+import cgeo.calendar.CalendarAddon;
import cgeo.geocaching.apps.cache.navi.NavigationAppFactory;
-import cgeo.geocaching.geopoint.GeopointFormatter;
-import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.ui.AbstractUIFactory;
-import cgeo.geocaching.ui.dialog.Dialogs;
-import cgeo.geocaching.utils.ProcessUtils;
-
-import org.apache.commons.lang3.StringUtils;
import android.app.Activity;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.net.Uri;
import android.view.Menu;
import android.view.MenuItem;
-import java.util.Date;
-
/**
- * Shared menu handling for all activities having menu items related to a cache.
- *
+ * Shared menu handling for all activities having menu items related to a cache. <br>
+ * TODO: replace by a fragment
+ *
*/
public class CacheMenuHandler extends AbstractUIFactory {
@@ -58,7 +48,7 @@ public class CacheMenuHandler extends AbstractUIFactory {
cache.shareCache(activity, res);
return true;
case R.id.menu_calendar:
- addToCalendarWithIntent(activity, cache);
+ CalendarAddon.addToCalendarWithIntent(activity, cache);
return true;
default:
return false;
@@ -80,39 +70,4 @@ public class CacheMenuHandler extends AbstractUIFactory {
activity.getMenuInflater().inflate(R.menu.cache_options, menu);
onPrepareOptionsMenu(menu, cache);
}
-
- private static void addToCalendarWithIntent(final Activity activity, final Geocache cache) {
- final boolean calendarAddOnAvailable = ProcessUtils.isIntentAvailable(ICalendar.INTENT, Uri.parse(ICalendar.URI_SCHEME + "://" + ICalendar.URI_HOST));
-
- if (calendarAddOnAvailable) {
- final Date hiddenDate = cache.getHiddenDate();
- final Parameters params = new Parameters(
- ICalendar.PARAM_NAME, cache.getName(),
- ICalendar.PARAM_NOTE, StringUtils.defaultString(cache.getPersonalNote()),
- ICalendar.PARAM_HIDDEN_DATE, hiddenDate != null ? String.valueOf(hiddenDate.getTime()) : StringUtils.EMPTY,
- ICalendar.PARAM_URL, StringUtils.defaultString(cache.getUrl()),
- ICalendar.PARAM_COORDS, cache.getCoords() == null ? "" : cache.getCoords().format(GeopointFormatter.Format.LAT_LON_DECMINUTE_RAW),
- ICalendar.PARAM_LOCATION, StringUtils.defaultString(cache.getLocation()),
- ICalendar.PARAM_SHORT_DESC, StringUtils.defaultString(cache.getShortDescription()),
- ICalendar.PARAM_START_TIME_MINUTES, StringUtils.defaultString(cache.guessEventTimeMinutes())
- );
-
- activity.startActivity(new Intent(ICalendar.INTENT,
- Uri.parse(ICalendar.URI_SCHEME + "://" + ICalendar.URI_HOST + "?" + params.toString())));
- } else {
- // Inform user the calendar add-on is not installed and let them get it from Google Play
- Dialogs.confirmYesNo(activity, R.string.addon_missing_title, new StringBuilder(res.getString(R.string.helper_calendar_missing))
- .append(' ')
- .append(res.getString(R.string.addon_download_prompt))
- .toString(), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- final Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(ICalendar.CALENDAR_ADDON_URI));
- activity.startActivity(intent);
- }
- });
- }
- }
-
}
diff --git a/main/src/cgeo/geocaching/CachePopup.java b/main/src/cgeo/geocaching/CachePopup.java
index 9186497..5d04ab0 100644
--- a/main/src/cgeo/geocaching/CachePopup.java
+++ b/main/src/cgeo/geocaching/CachePopup.java
@@ -9,9 +9,9 @@ import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.CacheDetailsCreator;
import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.RunnableWithArgument;
import org.apache.commons.lang3.StringUtils;
+import rx.util.functions.Action1;
import android.content.Context;
import android.content.Intent;
@@ -110,9 +110,9 @@ public class CachePopup extends AbstractPopupActivity {
if (Settings.getChooseList()) {
// let user select list to store cache in
new StoredList.UserInterface(CachePopup.this).promptForListSelection(R.string.list_title,
- new RunnableWithArgument<Integer>() {
+ new Action1<Integer>() {
@Override
- public void run(final Integer selectedListId) {
+ public void call(final Integer selectedListId) {
storeCache(selectedListId);
}
}, true, StoredList.TEMPORARY_LIST_ID);
diff --git a/main/src/cgeo/geocaching/CgeoApplication.java b/main/src/cgeo/geocaching/CgeoApplication.java
index 2500d10..7bee97e 100644
--- a/main/src/cgeo/geocaching/CgeoApplication.java
+++ b/main/src/cgeo/geocaching/CgeoApplication.java
@@ -1,10 +1,10 @@
package cgeo.geocaching;
-import cgeo.geocaching.network.StatusUpdater;
import cgeo.geocaching.ui.dialog.Dialogs;
-import cgeo.geocaching.utils.IObserver;
import cgeo.geocaching.utils.Log;
+import rx.Observable;
+
import android.app.Activity;
import android.app.Application;
import android.app.ProgressDialog;
@@ -14,12 +14,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
public class CgeoApplication extends Application {
- private volatile GeoDataProvider geo;
- private volatile DirectionProvider dir;
+ private volatile Observable<IGeoData> geo;
+ private volatile Observable<Float> dir;
private boolean forceRelog = false; // c:geo needs to log into cache providers
public boolean showLoginToast = true; //login toast shown just once.
- private boolean liveMapHintShown = false; // livemap hint has been shown
- final private StatusUpdater statusUpdater = new StatusUpdater();
+ private boolean liveMapHintShownInThisSession = false; // livemap hint has been shown
private static CgeoApplication instance;
public CgeoApplication() {
@@ -35,26 +34,11 @@ public class CgeoApplication extends Application {
}
@Override
- public void onCreate() {
- new Thread(statusUpdater).start();
- }
-
- @Override
public void onLowMemory() {
Log.i("Cleaning applications cache.");
DataStore.removeAllFromCache();
}
- @Override
- public void onTerminate() {
- Log.d("Terminating c:geo…");
-
- DataStore.clean();
- DataStore.closeDb();
-
- super.onTerminate();
- }
-
/**
* Move the database to/from external cgdata in a new thread,
* showing a progress window
@@ -82,29 +66,11 @@ public class CgeoApplication extends Application {
}.start();
}
- /**
- * Register an observer to receive GeoData information.
- * <br/>
- * If there is a chance that no observers are registered before this
- * method is called, it is necessary to call it from a task implementing
- * a looper interface as the data provider will use listeners that
- * require a looper thread to run.
- *
- * @param observer a geodata observer
- */
- public void addGeoObserver(final IObserver<? super IGeoData> observer) {
- currentGeoObject().addObserver(observer);
- }
-
- public void deleteGeoObserver(final IObserver<? super IGeoData> observer) {
- currentGeoObject().deleteObserver(observer);
- }
-
- private GeoDataProvider currentGeoObject() {
+ public Observable<IGeoData> currentGeoObject() {
if (geo == null) {
synchronized(this) {
if (geo == null) {
- geo = new GeoDataProvider(this);
+ geo = GeoDataProvider.create(this);
}
}
}
@@ -112,22 +78,14 @@ public class CgeoApplication extends Application {
}
public IGeoData currentGeo() {
- return currentGeoObject().getMemory();
+ return currentGeoObject().first().toBlockingObservable().single();
}
- public void addDirectionObserver(final IObserver<? super Float> observer) {
- currentDirObject().addObserver(observer);
- }
-
- public void deleteDirectionObserver(final IObserver<? super Float> observer) {
- currentDirObject().deleteObserver(observer);
- }
-
- private DirectionProvider currentDirObject() {
+ public Observable<Float> currentDirObject() {
if (dir == null) {
synchronized(this) {
if (dir == null) {
- dir = new DirectionProvider(this);
+ dir = DirectionProvider.create(this);
}
}
}
@@ -135,19 +93,15 @@ public class CgeoApplication extends Application {
}
public Float currentDirection() {
- return currentDirObject().getMemory();
- }
-
- public StatusUpdater getStatusUpdater() {
- return statusUpdater;
+ return currentDirObject().first().toBlockingObservable().single();
}
- public boolean isLiveMapHintShown() {
- return liveMapHintShown;
+ public boolean isLiveMapHintShownInThisSession() {
+ return liveMapHintShownInThisSession;
}
- public void setLiveMapHintShown() {
- liveMapHintShown = true;
+ public void setLiveMapHintShownInThisSession() {
+ liveMapHintShownInThisSession = true;
}
/**
diff --git a/main/src/cgeo/geocaching/CompassActivity.java b/main/src/cgeo/geocaching/CompassActivity.java
index 8955afd..6fc2de1 100644
--- a/main/src/cgeo/geocaching/CompassActivity.java
+++ b/main/src/cgeo/geocaching/CompassActivity.java
@@ -150,12 +150,13 @@ public class CompassActivity extends AbstractActivity {
final CgeoApplication app = CgeoApplication.getInstance();
final IGeoData geo = app.currentGeo();
if (geo != null) {
- geoDirHandler.update(geo);
+ geoDirHandler.updateGeoData(geo);
}
final Float dir = app.currentDirection();
if (dir != null) {
- geoDirHandler.update(dir);
+ geoDirHandler.updateDirection(dir);
}
+
}
@Override
diff --git a/main/src/cgeo/geocaching/CreateShortcutActivity.java b/main/src/cgeo/geocaching/CreateShortcutActivity.java
index 7b91ba1..0b91da0 100644
--- a/main/src/cgeo/geocaching/CreateShortcutActivity.java
+++ b/main/src/cgeo/geocaching/CreateShortcutActivity.java
@@ -1,8 +1,10 @@
package cgeo.geocaching;
import cgeo.geocaching.activity.AbstractActivity;
+import cgeo.geocaching.list.PseudoList;
import cgeo.geocaching.list.StoredList;
-import cgeo.geocaching.utils.RunnableWithArgument;
+
+import rx.util.functions.Action1;
import android.content.Intent;
import android.content.Intent.ShortcutIconResource;
@@ -21,17 +23,17 @@ public class CreateShortcutActivity extends AbstractActivity {
}
private void promptForShortcut() {
- new StoredList.UserInterface(this).promptForListSelection(R.string.create_shortcut, new RunnableWithArgument<Integer>() {
+ new StoredList.UserInterface(this).promptForListSelection(R.string.create_shortcut, new Action1<Integer>() {
@Override
- public void run(final Integer listId) {
+ public void call(final Integer listId) {
final Intent shortcut = createShortcut(listId.intValue());
setResult(RESULT_OK, shortcut);
// finish activity to return the shortcut
finish();
}
- });
+ }, false, PseudoList.HISTORY_LIST.id);
}
protected Intent createShortcut(int listId) {
diff --git a/main/src/cgeo/geocaching/DataStore.java b/main/src/cgeo/geocaching/DataStore.java
index 6da1af8..11c5a9a 100644
--- a/main/src/cgeo/geocaching/DataStore.java
+++ b/main/src/cgeo/geocaching/DataStore.java
@@ -25,17 +25,20 @@ import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import android.app.SearchManager;
import android.content.ContentValues;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.DatabaseUtils;
+import android.database.MatrixCursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteDoneException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteStatement;
+import android.provider.BaseColumns;
import java.io.File;
import java.io.FilenameFilter;
@@ -811,12 +814,19 @@ public class DataStore {
/**
* Remove obsolete cache directories in c:geo private storage.
+ */
+ public static void removeObsoleteCacheDirectories() {
+ removeObsoleteCacheDirectories(database);
+ }
+
+ /**
+ * Remove obsolete cache directories in c:geo private storage.
*
* @param db
* the read-write database to use
*/
private static void removeObsoleteCacheDirectories(final SQLiteDatabase db) {
- final Pattern oldFilePattern = Pattern.compile("^[GC|TB|O][A-Z0-9]{4,7}$");
+ final Pattern oldFilePattern = Pattern.compile("^[GC|TB|EC|GK|O][A-Z0-9]{4,7}$");
final SQLiteStatement select = db.compileStatement("select count(*) from " + dbTableCaches + " where geocode = ?");
final File[] files = LocalStorage.getStorage().listFiles();
final ArrayList<File> toRemove = new ArrayList<File>(files.length);
@@ -868,28 +878,6 @@ public class DataStore {
db.execSQL("drop table if exists " + dbTableTrackables);
}
- public static String[] getRecentGeocodesForSearch() {
- init();
-
- try {
- long timestamp = System.currentTimeMillis() - DAYS_AFTER_CACHE_IS_DELETED;
- final Cursor cursor = database.query(
- dbTableCaches,
- new String[]{"geocode"},
- "(detailed = 1 and detailedupdate > ?) or reason > 0",
- new String[]{Long.toString(timestamp)},
- null,
- null,
- "detailedupdate desc",
- "100");
-
- return getFirstColumn(cursor);
- } catch (final Exception e) {
- Log.e("DataStore.allDetailedThere", e);
- return new String[0];
- }
- }
-
public static boolean isThere(String geocode, String guid, boolean detailed, boolean checkTime) {
init();
@@ -2302,11 +2290,6 @@ public class DataStore {
return new SearchResult(geocodes);
}
- /** delete caches from the DB store 3 days or more before */
- public static void clean() {
- clean(false);
- }
-
/**
* Remove caches with listId = 0
*
@@ -2355,6 +2338,8 @@ public class DataStore {
cursor.close();
+ geocodes = exceptCachesWithOfflineLog(geocodes);
+
if (!geocodes.isEmpty()) {
Log.d("Database clean: removing " + geocodes.size() + " geocaches from listId=0");
removeCaches(geocodes, LoadFlags.REMOVE_ALL);
@@ -2367,6 +2352,33 @@ public class DataStore {
databaseCleaned = true;
}
+ /**
+ * remove all geocodes from the given list of geocodes where an offline log exists
+ *
+ * @param geocodes
+ * @return
+ */
+ private static Set<String> exceptCachesWithOfflineLog(Set<String> geocodes) {
+ if (geocodes.isEmpty()) {
+ return geocodes;
+ }
+
+ init();
+ final Cursor cursor = database.query(
+ dbTableLogsOffline,
+ new String[] { "geocode" },
+ null,
+ null,
+ null,
+ null,
+ null);
+
+ final List<String> geocodesWithOfflineLog = Arrays.asList(getFirstColumn(cursor));
+
+ geocodes.removeAll(geocodesWithOfflineLog);
+ return geocodes;
+ }
+
public static void removeAllFromCache() {
// clean up CacheCache
cacheCache.removeAllFromCache();
@@ -2897,21 +2909,6 @@ public class DataStore {
return waypoints;
}
- public static String[] getTrackableCodes() {
- init();
-
- final Cursor cursor = database.query(
- dbTableTrackables,
- new String[] { "tbcode" },
- null,
- null,
- null,
- null,
- "updated DESC",
- "100");
- return getFirstColumn(cursor);
- }
-
/**
* Extract the first column of the cursor rows and close the cursor.
*
@@ -3098,4 +3095,113 @@ public class DataStore {
return missingFromSearch;
}
+ public static Cursor findSuggestions(final String searchTerm) {
+ // require 3 characters, otherwise there are to many results
+ if (StringUtils.length(searchTerm) < 3) {
+ return null;
+ }
+ init();
+ final MatrixCursor resultCursor = new MatrixCursor(new String[] {
+ BaseColumns._ID,
+ SearchManager.SUGGEST_COLUMN_TEXT_1,
+ SearchManager.SUGGEST_COLUMN_TEXT_2,
+ SearchManager.SUGGEST_COLUMN_INTENT_ACTION,
+ SearchManager.SUGGEST_COLUMN_QUERY
+ });
+ try {
+ final String selectionArg = getSuggestionArgument(searchTerm);
+ findCaches(resultCursor, selectionArg);
+ findTrackables(resultCursor, selectionArg);
+ } catch (final Exception e) {
+ Log.e("DataStore.loadBatchOfStoredGeocodes", e);
+ }
+ return resultCursor;
+ }
+
+ private static void findCaches(final MatrixCursor resultCursor, final String selectionArg) {
+ Cursor cursor = database.query(
+ dbTableCaches,
+ new String[] { "geocode", "name" },
+ "geocode IS NOT NULL AND geocode != '' AND (geocode LIKE ? OR name LIKE ?)",
+ new String[] { selectionArg, selectionArg },
+ null,
+ null,
+ "name");
+ while (cursor.moveToNext()) {
+ final String geocode = cursor.getString(0);
+ resultCursor.addRow(new String[] {
+ String.valueOf(resultCursor.getCount()),
+ cursor.getString(1),
+ geocode,
+ Intents.ACTION_GEOCACHE,
+ geocode
+ });
+ }
+ cursor.close();
+ }
+
+ private static String getSuggestionArgument(String input) {
+ return "%" + StringUtils.trim(input) + "%";
+ }
+
+ private static void findTrackables(final MatrixCursor resultCursor, final String selectionArg) {
+ Cursor cursor = database.query(
+ dbTableTrackables,
+ new String[] { "tbcode", "title" },
+ "tbcode IS NOT NULL AND tbcode != '' AND (tbcode LIKE ? OR title LIKE ?)",
+ new String[] { selectionArg, selectionArg },
+ null,
+ null,
+ "title");
+ while (cursor.moveToNext()) {
+ final String tbcode = cursor.getString(0);
+ resultCursor.addRow(new String[] {
+ String.valueOf(resultCursor.getCount()),
+ cursor.getString(1),
+ tbcode,
+ Intents.ACTION_TRACKABLE,
+ tbcode
+ });
+ }
+ cursor.close();
+ }
+
+ public static String[] getSuggestions(final String table, final String column, final String input) {
+ Cursor cursor = database.query(
+ true,
+ table,
+ new String[] { column },
+ column + " LIKE ?",
+ new String[] { getSuggestionArgument(input) },
+ null,
+ null,
+ column,
+ null);
+ return getFirstColumn(cursor);
+ }
+
+ public static String[] getSuggestionsOwnerName(String input) {
+ return getSuggestions(dbTableCaches, "owner", input);
+ }
+
+ public static String[] getSuggestionsTrackableCode(String input) {
+ return getSuggestions(dbTableTrackables, "tbcode", input);
+ }
+
+ public static String[] getSuggestionsFinderName(String input) {
+ return getSuggestions(dbTableLogs, "author", input);
+ }
+
+ public static String[] getSuggestionsGeocode(String input) {
+ return getSuggestions(dbTableCaches, "geocode", input);
+ }
+
+ public static String[] getSuggestionsKeyword(String input) {
+ return getSuggestions(dbTableCaches, "name", input);
+ }
+
+ public static String[] getSuggestionsAddress(String input) {
+ return getSuggestions(dbTableCaches, "location", input);
+ }
+
}
diff --git a/main/src/cgeo/geocaching/DirectionProvider.java b/main/src/cgeo/geocaching/DirectionProvider.java
index ae58fed..cc44155 100644
--- a/main/src/cgeo/geocaching/DirectionProvider.java
+++ b/main/src/cgeo/geocaching/DirectionProvider.java
@@ -1,9 +1,13 @@
package cgeo.geocaching;
import cgeo.geocaching.compatibility.Compatibility;
-import cgeo.geocaching.utils.MemorySubject;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import rx.Observable;
+import rx.Observable.OnSubscribeFunc;
+import rx.Observer;
+import rx.Subscription;
+import rx.observables.ConnectableObservable;
+import rx.subjects.BehaviorSubject;
import android.app.Activity;
import android.content.Context;
@@ -12,58 +16,61 @@ import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
-public class DirectionProvider extends MemorySubject<Float> implements SensorEventListener {
+public class DirectionProvider implements OnSubscribeFunc<Float> {
private final SensorManager sensorManager;
+ private final BehaviorSubject<Float> subject = BehaviorSubject.create(0.0f);
- // Previous values signaled to observers to avoid re-sending 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.
- private float previous = -1;
-
- public DirectionProvider(final Context context) {
- sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
-
+ static public Observable<Float> create(final Context context) {
+ return new DirectionProvider((SensorManager) context.getSystemService(Context.SENSOR_SERVICE)).worker.refCount();
}
- @Override
- protected void onFirstObserver() {
- @SuppressWarnings("deprecation")
- // This will be removed when using a new location service. Until then, it is okay to be used.
- final Sensor defaultSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
- sensorManager.registerListener(this, defaultSensor, SensorManager.SENSOR_DELAY_NORMAL);
+ private DirectionProvider(final SensorManager sensorManager) {
+ this.sensorManager = sensorManager;
}
@Override
- protected void onLastObserver() {
- sensorManager.unregisterListener(this);
+ public Subscription onSubscribe(final Observer<? super Float> observer) {
+ return subject.distinctUntilChanged().subscribe(observer);
}
- @Override
- public void onAccuracyChanged(final Sensor sensor, int accuracy) {
- /*
- * 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
- */
+ private final ConnectableObservable<Float> worker = new ConnectableObservable<Float>(this) {
+ @Override
+ public Subscription connect() {
+ @SuppressWarnings("deprecation")
+ // This will be removed when using a new location service. Until then, it is okay to be used.
+ final Sensor defaultSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
+ final SensorEventListener listener = new SensorEventListener() {
+ @Override
+ public void onSensorChanged(final SensorEvent event) {
+ subject.onNext(event.values[0]);
+ }
- //Log.i(Settings.tag, "Compass' accuracy is low (" + accuracy + ")");
- }
+ @Override
+ public void onAccuracyChanged(final Sensor sensor, final int accuracy) {
+ /*
+ * 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
+ */
- @Override
- @SuppressFBWarnings("FE_FLOATING_POINT_EQUALITY")
- public void onSensorChanged(final SensorEvent event) {
- final float direction = event.values[0];
- if (direction != previous) {
- notifyObservers(direction);
- previous = direction;
+ //Log.i(Settings.tag, "Compass' accuracy is low (" + accuracy + ")");
+ }
+ };
+
+ sensorManager.registerListener(listener, defaultSensor, SensorManager.SENSOR_DELAY_NORMAL);
+ return new Subscription() {
+ @Override
+ public void unsubscribe() {
+ sensorManager.unregisterListener(listener);
+ }
+ };
}
- }
+ };
/**
* Take the phone rotation (through a given activity) in account and adjust the direction.
@@ -72,6 +79,7 @@ public class DirectionProvider extends MemorySubject<Float> implements SensorEve
* @param direction the unadjusted direction in degrees, in the [0, 360[ range
* @return the adjusted direction in degrees, in the [0, 360[ range
*/
+
public static float getDirectionNow(final Activity activity, final float direction) {
return Compatibility.getDirectionNow(direction, activity);
}
diff --git a/main/src/cgeo/geocaching/EditWaypointActivity.java b/main/src/cgeo/geocaching/EditWaypointActivity.java
index 6d0f822..eee7505 100644
--- a/main/src/cgeo/geocaching/EditWaypointActivity.java
+++ b/main/src/cgeo/geocaching/EditWaypointActivity.java
@@ -110,12 +110,14 @@ public class EditWaypointActivity extends AbstractActivity {
buttonLon.setText(waypoint.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE));
}
waypointName.setText(Html.fromHtml(StringUtils.trimToEmpty(waypoint.getName())).toString());
+ Dialogs.moveCursorToEnd(waypointName);
if (TextUtils.containsHtml(waypoint.getNote())) {
note.setText(Html.fromHtml(StringUtils.trimToEmpty(waypoint.getNote())).toString());
}
else {
note.setText(StringUtils.trimToEmpty(waypoint.getNote()));
}
+ Dialogs.moveCursorToEnd(note);
}
final Geocache cache = DataStore.loadCache(geocode, LoadFlags.LOAD_CACHE_ONLY);
setCoordsModificationVisibility(ConnectorFactory.getConnector(geocode), cache);
diff --git a/main/src/cgeo/geocaching/GeoDataProvider.java b/main/src/cgeo/geocaching/GeoDataProvider.java
index 73aefce..c61b7e7 100644
--- a/main/src/cgeo/geocaching/GeoDataProvider.java
+++ b/main/src/cgeo/geocaching/GeoDataProvider.java
@@ -3,9 +3,14 @@ package cgeo.geocaching;
import cgeo.geocaching.enumerations.LocationProviderType;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.MemorySubject;
import org.apache.commons.lang3.StringUtils;
+import rx.Observable;
+import rx.Observable.OnSubscribeFunc;
+import rx.Observer;
+import rx.Subscription;
+import rx.observables.ConnectableObservable;
+import rx.subjects.BehaviorSubject;
import android.content.Context;
import android.location.GpsSatellite;
@@ -15,22 +20,14 @@ import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Provide information about the user location. This class should be instantiated only once per application.
- */
-class GeoDataProvider extends MemorySubject<IGeoData> {
+class GeoDataProvider implements OnSubscribeFunc<IGeoData> {
private static final String LAST_LOCATION_PSEUDO_PROVIDER = "last";
private final LocationManager geoManager;
- private final GpsStatus.Listener gpsStatusListener = new GpsStatusListener();
private final LocationData gpsLocation = new LocationData();
private final LocationData netLocation = new LocationData();
- private final Listener networkListener = new Listener(LocationManager.NETWORK_PROVIDER, netLocation);
- private final Listener gpsListener = new Listener(LocationManager.GPS_PROVIDER, gpsLocation);
- private final Unregisterer unregisterer = new Unregisterer();
+ private final BehaviorSubject<IGeoData> subject;
+
public boolean gpsEnabled = false;
public int satellitesVisible = 0;
public int satellitesFixed = 0;
@@ -111,51 +108,6 @@ class GeoDataProvider extends MemorySubject<IGeoData> {
}
}
- private class Unregisterer extends Thread {
-
- private boolean unregisterRequested = false;
- private final ArrayBlockingQueue<Boolean> queue = new ArrayBlockingQueue<Boolean>(1);
-
- public void cancelUnregister() {
- try {
- queue.put(false);
- } catch (final InterruptedException e) {
- // Do nothing
- }
- }
-
- public void lateUnregister() {
- try {
- queue.put(true);
- } catch (final InterruptedException e) {
- // Do nothing
- }
- }
-
- @Override
- public void run() {
- try {
- while (true) {
- if (unregisterRequested) {
- final Boolean element = queue.poll(2500, TimeUnit.MILLISECONDS);
- if (element == null) {
- // Timeout
- unregisterListeners();
- unregisterRequested = false;
- } else {
- unregisterRequested = element;
- }
- } else {
- unregisterRequested = queue.take();
- }
- }
- } catch (final InterruptedException e) {
- // Do nothing
- }
- }
-
- }
-
/**
* Build a new geo data provider object.
* <p/>
@@ -164,10 +116,50 @@ class GeoDataProvider extends MemorySubject<IGeoData> {
*
* @param context the context used to retrieve the system services
*/
- GeoDataProvider(final Context context) {
+ protected GeoDataProvider(final Context context) {
geoManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
- unregisterer.start();
+ subject = BehaviorSubject.create(findInitialLocation());
+ }
+
+ public static Observable<IGeoData> create(final Context context) {
+ final GeoDataProvider provider = new GeoDataProvider(context);
+ return provider.worker.refCount();
+ }
+ @Override
+ public Subscription onSubscribe(final Observer<? super IGeoData> observer) {
+ return subject.subscribe(observer);
+ }
+
+ final ConnectableObservable<IGeoData> worker = new ConnectableObservable<IGeoData>(this) {
+ @Override
+ public Subscription connect() {
+ final GpsStatus.Listener gpsStatusListener = new GpsStatusListener();
+ geoManager.addGpsStatusListener(gpsStatusListener);
+
+ final Listener networkListener = new Listener(LocationManager.NETWORK_PROVIDER, netLocation);
+ final Listener gpsListener = new Listener(LocationManager.GPS_PROVIDER, gpsLocation);
+
+ for (final Listener listener : new Listener[] { networkListener, gpsListener }) {
+ try {
+ geoManager.requestLocationUpdates(listener.locationProvider, 0, 0, listener);
+ } catch (final Exception e) {
+ Log.w("There is no location provider " + listener.locationProvider);
+ }
+ }
+
+ return new Subscription() {
+ @Override
+ public void unsubscribe() {
+ geoManager.removeUpdates(networkListener);
+ geoManager.removeUpdates(gpsListener);
+ geoManager.removeGpsStatusListener(gpsStatusListener);
+ }
+ };
+ }
+ };
+
+ private IGeoData findInitialLocation() {
final Location initialLocation = new Location(LAST_LOCATION_PSEUDO_PROVIDER);
try {
// Try to find a sensible initial location from the last locations known to Android.
@@ -195,45 +187,13 @@ class GeoDataProvider extends MemorySubject<IGeoData> {
}
// Start with an historical GeoData just in case someone queries it before we get
// a chance to get any information.
- notifyObservers(new GeoData(initialLocation, false, 0, 0));
+ return new GeoData(initialLocation, false, 0, 0);
}
private static void copyCoords(final Location target, final Location source) {
target.setLatitude(source.getLatitude());
target.setLongitude(source.getLongitude());
}
- private void registerListeners() {
- geoManager.addGpsStatusListener(gpsStatusListener);
-
- for (final Listener listener : new Listener[] { networkListener, gpsListener }) {
- try {
- geoManager.requestLocationUpdates(listener.locationProvider, 0, 0, listener);
- } catch (final Exception e) {
- Log.w("There is no location provider " + listener.locationProvider);
- }
- }
- }
-
- private synchronized void unregisterListeners() {
- // This method must be synchronized because it will be called asynchronously from the Unregisterer thread.
- // We check that no observers have been re-added to prevent a race condition.
- if (sizeObservers() == 0) {
- geoManager.removeUpdates(networkListener);
- geoManager.removeUpdates(gpsListener);
- geoManager.removeGpsStatusListener(gpsStatusListener);
- }
- }
-
- @Override
- protected void onFirstObserver() {
- unregisterer.cancelUnregister();
- registerListeners();
- }
-
- @Override
- protected void onLastObserver() {
- unregisterer.lateUnregister();
- }
private class Listener implements LocationListener {
private final String locationProvider;
@@ -336,7 +296,7 @@ class GeoDataProvider extends MemorySubject<IGeoData> {
// We do not necessarily get signalled when satellites go to 0/0.
final int visible = gpsLocation.isRecent() ? satellitesVisible : 0;
final IGeoData current = new GeoData(locationData.location, gpsEnabled, visible, satellitesFixed);
- notifyObservers(current);
+ subject.onNext(current);
}
}
diff --git a/main/src/cgeo/geocaching/Geocache.java b/main/src/cgeo/geocaching/Geocache.java
index 156c4b6..42b8f0a 100644
--- a/main/src/cgeo/geocaching/Geocache.java
+++ b/main/src/cgeo/geocaching/Geocache.java
@@ -817,13 +817,7 @@ public class Geocache implements ICache, IWaypoint {
}
public boolean showSize() {
- if (size == CacheSize.NOT_CHOSEN) {
- return false;
- }
- if (isEventCache() || isVirtual()) {
- return false;
- }
- return true;
+ return !(size == CacheSize.NOT_CHOSEN || isEventCache() || isVirtual());
}
public long getUpdated() {
@@ -1373,17 +1367,6 @@ public class Geocache implements ICache, IWaypoint {
}
/**
- * Retrieve a given waypoint.
- *
- * @param index
- * the index of the waypoint
- * @return waypoint or <code>null</code> if index is out of range
- */
- public Waypoint getWaypoint(final int index) {
- return index >= 0 && index < waypoints.size() ? waypoints.get(index) : null;
- }
-
- /**
* Lookup a waypoint by its id.
*
* @param id
@@ -1660,6 +1643,8 @@ public class Geocache implements ICache, IWaypoint {
StaticMapsProvider.downloadMaps(cache);
+ imgGetter.waitForBackgroundLoading(handler);
+
if (handler != null) {
handler.sendMessage(Message.obtain());
}
diff --git a/main/src/cgeo/geocaching/ImageSelectActivity.java b/main/src/cgeo/geocaching/ImageSelectActivity.java
index 9e0a37d..a9230c9 100644
--- a/main/src/cgeo/geocaching/ImageSelectActivity.java
+++ b/main/src/cgeo/geocaching/ImageSelectActivity.java
@@ -5,6 +5,7 @@ import butterknife.InjectView;
import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.ImageUtils;
import cgeo.geocaching.utils.Log;
@@ -103,10 +104,12 @@ public class ImageSelectActivity extends AbstractActivity {
if (StringUtils.isNotBlank(imageCaption)) {
captionView.setText(imageCaption);
+ Dialogs.moveCursorToEnd(captionView);
}
if (StringUtils.isNotBlank(imageDescription)) {
descriptionView.setText(imageDescription);
+ Dialogs.moveCursorToEnd(captionView);
}
scaleView.setSelection(scaleChoiceIndex);
diff --git a/main/src/cgeo/geocaching/Intents.java b/main/src/cgeo/geocaching/Intents.java
index d9d9829..5c969a1 100644
--- a/main/src/cgeo/geocaching/Intents.java
+++ b/main/src/cgeo/geocaching/Intents.java
@@ -29,4 +29,8 @@ public class Intents {
public static final String EXTRA_WAYPOINT_ID = PREFIX + "waypoint_id";
public static final String EXTRA_CACHELIST = PREFIX + "cache_list";
public static final String EXTRA_POCKET_GUID = PREFIX + "pocket_guid";
+
+ private static final String PREFIX_ACTION = "cgeo.geocaching.intent.action.";
+ public static final String ACTION_GEOCACHE = PREFIX_ACTION + "GEOCACHE";
+ public static final String ACTION_TRACKABLE = PREFIX_ACTION + "TRACKABLE";
}
diff --git a/main/src/cgeo/geocaching/LogCacheActivity.java b/main/src/cgeo/geocaching/LogCacheActivity.java
index f17a008..729ec60 100644
--- a/main/src/cgeo/geocaching/LogCacheActivity.java
+++ b/main/src/cgeo/geocaching/LogCacheActivity.java
@@ -13,6 +13,7 @@ import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.twitter.Twitter;
import cgeo.geocaching.ui.Formatter;
import cgeo.geocaching.ui.dialog.DateDialog;
+import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.AsyncTaskWithProgress;
import cgeo.geocaching.utils.DateUtils;
import cgeo.geocaching.utils.Log;
@@ -151,7 +152,7 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
final TextView actionButton = (TextView) inventoryItem.findViewById(R.id.action);
actionButton.setId(tb.id);
actionButtons.put(actionButton.getId(), tb);
- actionButton.setText(res.getString(tb.action.resourceId) + " â–¼");
+ actionButton.setText(tb.action.getLabel() + " â–¼");
actionButton.setOnClickListener(new View.OnClickListener() {
@Override
@@ -301,6 +302,7 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
final EditText logView = (EditText) findViewById(R.id.log);
if (StringUtils.isBlank(currentLogText()) && StringUtils.isNotBlank(text)) {
logView.setText(text);
+ Dialogs.moveCursorToEnd(logView);
}
tweetCheck.setChecked(true);
@@ -632,11 +634,11 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
alert.create().show();
}
- private String[] getTBLogTypes() {
+ private static String[] getTBLogTypes() {
final LogTypeTrackable[] logTypeValues = LogTypeTrackable.values();
String[] logTypes = new String[logTypeValues.length];
for (int i = 0; i < logTypes.length; i++) {
- logTypes[i] = res.getString(logTypeValues[i].resourceId);
+ logTypes[i] = logTypeValues[i].getLabel();
}
return logTypes;
}
diff --git a/main/src/cgeo/geocaching/LogTrackableActivity.java b/main/src/cgeo/geocaching/LogTrackableActivity.java
index 5246fa9..fabe391 100644
--- a/main/src/cgeo/geocaching/LogTrackableActivity.java
+++ b/main/src/cgeo/geocaching/LogTrackableActivity.java
@@ -3,8 +3,8 @@ package cgeo.geocaching;
import butterknife.ButterKnife;
import butterknife.InjectView;
-import cgeo.geocaching.connector.gc.GCParser;
import cgeo.geocaching.connector.gc.GCLogin;
+import cgeo.geocaching.connector.gc.GCParser;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.network.Network;
@@ -13,6 +13,7 @@ import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.twitter.Twitter;
import cgeo.geocaching.ui.Formatter;
import cgeo.geocaching.ui.dialog.DateDialog;
+import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.LogTemplateProvider.LogContext;
@@ -127,6 +128,7 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
if (StringUtils.isNotBlank(extras.getString(Intents.EXTRA_TRACKING_CODE))) {
trackingEditText.setText(extras.getString(Intents.EXTRA_TRACKING_CODE));
+ Dialogs.moveCursorToEnd(trackingEditText);
}
}
diff --git a/main/src/cgeo/geocaching/MainActivity.java b/main/src/cgeo/geocaching/MainActivity.java
index 924c66d..3ffc631 100644
--- a/main/src/cgeo/geocaching/MainActivity.java
+++ b/main/src/cgeo/geocaching/MainActivity.java
@@ -10,6 +10,7 @@ import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.Units;
+import cgeo.geocaching.list.PseudoList;
import cgeo.geocaching.list.StoredList;
import cgeo.geocaching.maps.CGeoMap;
import cgeo.geocaching.settings.Settings;
@@ -19,15 +20,22 @@ import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.DatabaseBackupUtils;
import cgeo.geocaching.utils.GeoDirHandler;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.RunnableWithArgument;
import cgeo.geocaching.utils.Version;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
-import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
+import rx.Observable;
+import rx.Observable.OnSubscribeFunc;
+import rx.Observer;
+import rx.Subscription;
+import rx.android.observables.AndroidObservable;
+import rx.concurrency.Schedulers;
+import rx.subscriptions.Subscriptions;
+import rx.util.functions.Action1;
+
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.SearchManager;
@@ -48,7 +56,6 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -77,8 +84,6 @@ public class MainActivity extends AbstractActivity {
private boolean cleanupRunning = false;
private int countBubbleCnt = 0;
private Geopoint addCoords = null;
- private List<Address> addresses = null;
- private boolean addressObtaining = false;
private boolean initialized = false;
private final UpdateLocation locationUpdater = new UpdateLocation();
@@ -104,7 +109,7 @@ public class MainActivity extends AbstractActivity {
if (conn.isLoggedIn()) {
userInfo.append(conn.getUserName());
if (conn.getCachesFound() >= 0) {
- userInfo.append(" (").append(String.valueOf(conn.getCachesFound())).append(')');
+ userInfo.append(" (").append(conn.getCachesFound()).append(')');
}
userInfo.append(Formatter.SEPARATOR);
}
@@ -115,40 +120,24 @@ public class MainActivity extends AbstractActivity {
}
};
- private Handler obtainAddressHandler = new Handler() {
-
- @Override
- public void handleMessage(final Message msg) {
- try {
- if (CollectionUtils.isNotEmpty(addresses)) {
- final Address address = addresses.get(0);
- final ArrayList<String> addressParts = new ArrayList<String>();
-
- final String countryName = address.getCountryName();
- if (countryName != null) {
- addressParts.add(countryName);
- }
- final String locality = address.getLocality();
- if (locality != null) {
- addressParts.add(locality);
- } else {
- final String adminArea = address.getAdminArea();
- if (adminArea != null) {
- addressParts.add(adminArea);
- }
- }
-
- addCoords = app.currentGeo().getCoords();
+ private static String formatAddress(final Address address) {
+ final ArrayList<String> addressParts = new ArrayList<String>();
- navLocation.setText(StringUtils.join(addressParts, ", "));
- }
- } catch (RuntimeException e) {
- // nothing
+ final String countryName = address.getCountryName();
+ if (countryName != null) {
+ addressParts.add(countryName);
+ }
+ final String locality = address.getLocality();
+ if (locality != null) {
+ addressParts.add(locality);
+ } else {
+ final String adminArea = address.getAdminArea();
+ if (adminArea != null) {
+ addressParts.add(adminArea);
}
-
- addresses = null;
}
- };
+ return StringUtils.join(addressParts, ", ");
+ }
private class SatellitesHandler extends GeoDirHandler {
@@ -285,7 +274,7 @@ public class MainActivity extends AbstractActivity {
@Override
public boolean onPrepareOptionsMenu(final Menu menu) {
super.onPrepareOptionsMenu(menu);
- menu.findItem(R.id.menu_pocket_queries).setVisible(Settings.isPremiumMember());
+ menu.findItem(R.id.menu_pocket_queries).setVisible(Settings.isGCPremiumMember());
return true;
}
@@ -309,13 +298,13 @@ public class MainActivity extends AbstractActivity {
startScannerApplication();
return true;
case R.id.menu_pocket_queries:
- if (!Settings.isPremiumMember()) {
+ if (!Settings.isGCPremiumMember()) {
return true;
}
- new PocketQueryList.UserInterface(MainActivity.this).promptForListSelection(new RunnableWithArgument<PocketQueryList>() {
+ PocketQueryList.promptForListSelection(this, new Action1<PocketQueryList>() {
@Override
- public void run(final PocketQueryList pql) {
+ public void call(final PocketQueryList pql) {
CacheListActivity.startActivityPocket(MainActivity.this, pql);
}
});
@@ -388,14 +377,14 @@ public class MainActivity extends AbstractActivity {
@Override
public boolean onLongClick(final View v) {
- new StoredList.UserInterface(MainActivity.this).promptForListSelection(R.string.list_title, new RunnableWithArgument<Integer>() {
+ new StoredList.UserInterface(MainActivity.this).promptForListSelection(R.string.list_title, new Action1<Integer>() {
@Override
- public void run(final Integer selectedListId) {
+ public void call(final Integer selectedListId) {
Settings.saveLastList(selectedListId);
CacheListActivity.startActivityOffline(MainActivity.this);
}
- });
+ }, false, PseudoList.HISTORY_LIST.id);
return true;
}
});
@@ -525,52 +514,61 @@ public class MainActivity extends AbstractActivity {
@Override
public void updateGeoData(final IGeoData geo) {
- try {
- if (geo.getCoords() != null) {
- if (!nearestView.isClickable()) {
- nearestView.setFocusable(true);
- nearestView.setClickable(true);
- nearestView.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(final View v) {
- cgeoFindNearest(v);
- }
- });
- nearestView.setBackgroundResource(R.drawable.main_nearby);
+ if (!nearestView.isClickable()) {
+ nearestView.setFocusable(true);
+ nearestView.setClickable(true);
+ nearestView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ cgeoFindNearest(v);
}
+ });
+ nearestView.setBackgroundResource(R.drawable.main_nearby);
+ }
- navType.setText(res.getString(geo.getLocationProvider().resourceId));
+ navType.setText(res.getString(geo.getLocationProvider().resourceId));
- if (geo.getAccuracy() >= 0) {
- int speed = Math.round(geo.getSpeed()) * 60 * 60 / 1000;
- navAccuracy.setText("±" + Units.getDistanceFromMeters(geo.getAccuracy()) + Formatter.SEPARATOR + Units.getSpeed(speed));
- } else {
- navAccuracy.setText(null);
- }
+ if (geo.getAccuracy() >= 0) {
+ int speed = Math.round(geo.getSpeed()) * 60 * 60 / 1000;
+ navAccuracy.setText("±" + Units.getDistanceFromMeters(geo.getAccuracy()) + Formatter.SEPARATOR + Units.getSpeed(speed));
+ } else {
+ navAccuracy.setText(null);
+ }
- if (Settings.isShowAddress()) {
- if (addCoords == null) {
- navLocation.setText(res.getString(R.string.loc_no_addr));
- }
- if (addCoords == null || (geo.getCoords().distanceTo(addCoords) > 0.5 && !addressObtaining)) {
- (new ObtainAddressThread()).start();
+ if (Settings.isShowAddress()) {
+ if (addCoords == null) {
+ navLocation.setText(R.string.loc_no_addr);
+ }
+ if (addCoords == null || (geo.getCoords().distanceTo(addCoords) > 0.5)) {
+ final Observable<String> address = Observable.create(new OnSubscribeFunc<String>() {
+ @Override
+ public Subscription onSubscribe(final Observer<? super String> observer) {
+ try {
+ addCoords = geo.getCoords();
+ final Geocoder geocoder = new Geocoder(MainActivity.this, Locale.getDefault());
+ final Geopoint coords = app.currentGeo().getCoords();
+ final List<Address> addresses = geocoder.getFromLocation(coords.getLatitude(), coords.getLongitude(), 1);
+ if (!addresses.isEmpty()) {
+ observer.onNext(formatAddress(addresses.get(0)));
+ }
+ observer.onCompleted();
+ } catch (final Exception e) {
+ observer.onError(e);
+ }
+ return Subscriptions.empty();
}
- } else {
- navLocation.setText(geo.getCoords().toString());
- }
- } else {
- if (nearestView.isClickable()) {
- nearestView.setFocusable(false);
- nearestView.setClickable(false);
- nearestView.setOnClickListener(null);
- nearestView.setBackgroundResource(R.drawable.main_nearby_disabled);
- }
- navType.setText(null);
- navAccuracy.setText(null);
- navLocation.setText(res.getString(R.string.loc_trying));
+ }).subscribeOn(Schedulers.threadPoolForIO());
+ AndroidObservable.fromActivity(MainActivity.this, address)
+ .onErrorResumeNext(Observable.from(geo.getCoords().toString()))
+ .subscribe(new Action1<String>() {
+ @Override
+ public void call(final String address) {
+ navLocation.setText(address);
+ }
+ });
}
- } catch (RuntimeException e) {
- Log.w("Failed to update location.");
+ } else {
+ navLocation.setText(geo.getCoords().toString());
}
}
}
@@ -714,35 +712,6 @@ public class MainActivity extends AbstractActivity {
}
}
- private class ObtainAddressThread extends Thread {
-
- public ObtainAddressThread() {
- setPriority(Thread.MIN_PRIORITY);
- }
-
- @Override
- public void run() {
- if (addressObtaining) {
- return;
- }
- addressObtaining = true;
-
- try {
- final Geocoder geocoder = new Geocoder(MainActivity.this, Locale.getDefault());
- final Geopoint coords = app.currentGeo().getCoords();
- addresses = geocoder.getFromLocation(coords.getLatitude(), coords.getLongitude(), 1);
- } catch (final IOException e) {
- Log.i("Failed to obtain address");
- } catch (final IllegalArgumentException e) {
- Log.w("ObtainAddressThread.run", e);
- }
-
- obtainAddressHandler.sendEmptyMessage(0);
-
- addressObtaining = false;
- }
- }
-
/**
* @param view
* unused here but needed since this method is referenced from XML layout
diff --git a/main/src/cgeo/geocaching/PocketQueryList.java b/main/src/cgeo/geocaching/PocketQueryList.java
index 9d1110d..6613441 100644
--- a/main/src/cgeo/geocaching/PocketQueryList.java
+++ b/main/src/cgeo/geocaching/PocketQueryList.java
@@ -2,15 +2,22 @@ package cgeo.geocaching;
import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.connector.gc.GCParser;
-import cgeo.geocaching.utils.RunnableWithArgument;
+
+import org.apache.commons.collections4.CollectionUtils;
+import rx.Observable;
+import rx.Observable.OnSubscribeFunc;
+import rx.Observer;
+import rx.Subscription;
+import rx.android.observables.AndroidObservable;
+import rx.concurrency.Schedulers;
+import rx.subscriptions.Subscriptions;
+import rx.util.functions.Action1;
import android.app.Activity;
import android.app.AlertDialog;
+import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
-import android.content.res.Resources;
-import android.os.Handler;
-import android.os.Message;
import java.util.List;
@@ -20,105 +27,63 @@ public final class PocketQueryList {
private final int maxCaches;
private final String name;
- public PocketQueryList(String guid, String name, int maxCaches) {
+ public PocketQueryList(final String guid, final String name, final int maxCaches) {
this.guid = guid;
this.name = name;
this.maxCaches = maxCaches;
}
- public static class UserInterface {
-
- List<PocketQueryList> pocketQueryList = null;
- RunnableWithArgument<PocketQueryList> runAfterwards;
-
- private Handler loadPocketQueryHandler = new Handler() {
-
- @Override
- public void handleMessage(Message msg) {
- if ((pocketQueryList == null) || (pocketQueryList.size() == 0)) {
- if (waitDialog != null) {
- waitDialog.dismiss();
- }
-
- ActivityMixin.showToast(activity, res.getString(R.string.warn_no_pocket_query_found));
-
- return;
- }
-
- if (waitDialog != null) {
- waitDialog.dismiss();
- }
-
- final CharSequence[] items = new CharSequence[pocketQueryList.size()];
-
- for (int i = 0; i < pocketQueryList.size(); i++) {
- PocketQueryList pq = pocketQueryList.get(i);
- items[i] = pq.name;
- }
+ public String getGuid() {
+ return guid;
+ }
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- builder.setTitle(res.getString(R.string.search_pocket_select));
- builder.setItems(items, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int itemId) {
- final PocketQueryList query = pocketQueryList.get(itemId);
- dialogInterface.dismiss();
- runAfterwards.run(query);
- }
- });
- builder.create().show();
+ public int getMaxCaches() {
+ return maxCaches;
+ }
- }
- };
+ public String getName() {
+ return name;
+ }
- private class LoadPocketQueryListThread extends Thread {
- final private Handler handler;
+ public static void promptForListSelection(final Activity activity, final Action1<PocketQueryList> runAfterwards) {
+ final Dialog waitDialog = ProgressDialog.show(activity, activity.getString(R.string.search_pocket_title), activity.getString(R.string.search_pocket_loading), true, true);
- public LoadPocketQueryListThread(Handler handlerIn) {
- handler = handlerIn;
+ AndroidObservable.fromActivity(activity, Observable.create(new OnSubscribeFunc<List<PocketQueryList>>() {
+ @Override
+ public Subscription onSubscribe(final Observer<? super List<PocketQueryList>> observer) {
+ observer.onNext(GCParser.searchPocketQueryList());
+ observer.onCompleted();
+ return Subscriptions.empty();
}
-
+ }).subscribeOn(Schedulers.threadPoolForIO())).subscribe(new Action1<List<PocketQueryList>>() {
@Override
- public void run() {
- pocketQueryList = GCParser.searchPocketQueryList();
- handler.sendMessage(Message.obtain());
+ public void call(final List<PocketQueryList> pocketQueryLists) {
+ waitDialog.dismiss();
+ selectFromPocketQueries(activity, pocketQueryLists, runAfterwards);
}
+ });
+ }
+ private static void selectFromPocketQueries(final Activity activity, final List<PocketQueryList> pocketQueryList, final Action1<PocketQueryList> runAfterwards) {
+ if (CollectionUtils.isEmpty(pocketQueryList)) {
+ ActivityMixin.showToast(activity, activity.getString(R.string.warn_no_pocket_query_found));
+ return;
}
- private final Activity activity;
- private final CgeoApplication app;
- private final Resources res;
- private ProgressDialog waitDialog = null;
-
- public UserInterface(final Activity activity) {
- this.activity = activity;
- app = CgeoApplication.getInstance();
- res = app.getResources();
- }
-
- public void promptForListSelection(final RunnableWithArgument<PocketQueryList> runAfterwards) {
+ final CharSequence[] items = new CharSequence[pocketQueryList.size()];
- this.runAfterwards = runAfterwards;
-
- waitDialog = ProgressDialog.show(activity, res.getString(R.string.search_pocket_title), res.getString(R.string.search_pocket_loading), true, true);
-
- LoadPocketQueryListThread thread = new LoadPocketQueryListThread(loadPocketQueryHandler);
- thread.start();
+ for (int i = 0; i < pocketQueryList.size(); i++) {
+ items[i] = pocketQueryList.get(i).name;
}
-
- }
-
- public String getGuid() {
- return guid;
- }
-
- public int getMaxCaches() {
- return maxCaches;
- }
-
- public String getName() {
- return name;
+ new AlertDialog.Builder(activity)
+ .setTitle(activity.getString(R.string.search_pocket_select))
+ .setItems(items, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(final DialogInterface dialogInterface, final int itemId) {
+ dialogInterface.dismiss();
+ runAfterwards.call(pocketQueryList.get(itemId));
+ }
+ }).create().show();
}
}
diff --git a/main/src/cgeo/geocaching/SearchActivity.java b/main/src/cgeo/geocaching/SearchActivity.java
index 0648073..7a90a49 100644
--- a/main/src/cgeo/geocaching/SearchActivity.java
+++ b/main/src/cgeo/geocaching/SearchActivity.java
@@ -10,6 +10,7 @@ import cgeo.geocaching.connector.capability.ISearchByGeocode;
import cgeo.geocaching.connector.trackable.TrackableConnector;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.GeopointFormatter;
+import cgeo.geocaching.search.AutoCompleteAdapter;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.dialog.CoordinatesInputDialog;
import cgeo.geocaching.ui.dialog.Dialogs;
@@ -17,6 +18,8 @@ import cgeo.geocaching.utils.EditUtils;
import org.apache.commons.lang3.StringUtils;
+import rx.util.functions.Func1;
+
import android.app.Activity;
import android.app.SearchManager;
import android.content.Intent;
@@ -26,10 +29,8 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
-import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
-import android.widget.EditText;
import java.util.Locale;
@@ -39,19 +40,19 @@ public class SearchActivity extends AbstractActivity {
@InjectView(R.id.buttonLongitude) protected Button buttonLongitude;
@InjectView(R.id.search_coordinates) protected Button buttonSearchCoords;
- @InjectView(R.id.address) protected EditText addressEditText;
+ @InjectView(R.id.address) protected AutoCompleteTextView addressEditText;
@InjectView(R.id.search_address) protected Button buttonSearchAddress;
@InjectView(R.id.geocode) protected AutoCompleteTextView geocodeEditText;
@InjectView(R.id.display_geocode) protected Button buttonSearchGeocode;
- @InjectView(R.id.keyword) protected EditText keywordEditText;
+ @InjectView(R.id.keyword) protected AutoCompleteTextView keywordEditText;
@InjectView(R.id.search_keyword) protected Button buttonSearchKeyword;
- @InjectView(R.id.finder) protected EditText finderNameEditText;
+ @InjectView(R.id.finder) protected AutoCompleteTextView finderNameEditText;
@InjectView(R.id.search_finder) protected Button buttonSearchFinder;
- @InjectView(R.id.owner) protected EditText ownerNameEditText;
+ @InjectView(R.id.owner) protected AutoCompleteTextView ownerNameEditText;
@InjectView(R.id.search_owner) protected Button buttonSearchOwner;
@InjectView(R.id.trackable) protected AutoCompleteTextView trackableEditText;
@@ -60,9 +61,23 @@ public class SearchActivity extends AbstractActivity {
@Override
public final void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ final Intent intent = getIntent();
+
+ // search suggestion for a cache
+ if (Intents.ACTION_GEOCACHE.equals(intent.getAction())) {
+ CacheDetailActivity.startActivity(this, intent.getStringExtra(SearchManager.QUERY));
+ finish();
+ return;
+ }
+
+ // search suggestion for a trackable
+ if (Intents.ACTION_TRACKABLE.equals(intent.getAction())) {
+ TrackableActivity.startActivity(this, null, intent.getStringExtra(SearchManager.QUERY), null);
+ finish();
+ return;
+ }
// search query
- final Intent intent = getIntent();
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
hideKeyboard();
final String query = intent.getStringExtra(SearchManager.QUERY);
@@ -173,6 +188,12 @@ public class SearchActivity extends AbstractActivity {
public void run() {
findByAddressFn();
}
+ }, new Func1<String, String[]>() {
+
+ @Override
+ public String[] call(final String input) {
+ return DataStore.getSuggestionsAddress(input);
+ }
});
setSearchAction(geocodeEditText, buttonSearchGeocode, new Runnable() {
@@ -181,8 +202,13 @@ public class SearchActivity extends AbstractActivity {
public void run() {
findByGeocodeFn();
}
+ }, new Func1<String, String[]>() {
+
+ @Override
+ public String[] call(final String input) {
+ return DataStore.getSuggestionsGeocode(input);
+ }
});
- addHistoryEntries(geocodeEditText, DataStore.getRecentGeocodesForSearch());
setSearchAction(keywordEditText, buttonSearchKeyword, new Runnable() {
@@ -190,6 +216,12 @@ public class SearchActivity extends AbstractActivity {
public void run() {
findByKeywordFn();
}
+ }, new Func1<String, String[]>() {
+
+ @Override
+ public String[] call(final String input) {
+ return DataStore.getSuggestionsKeyword(input);
+ }
});
setSearchAction(finderNameEditText, buttonSearchFinder, new Runnable() {
@@ -198,6 +230,12 @@ public class SearchActivity extends AbstractActivity {
public void run() {
findByFinderFn();
}
+ }, new Func1<String, String[]>() {
+
+ @Override
+ public String[] call(final String input) {
+ return DataStore.getSuggestionsFinderName(input);
+ }
});
setSearchAction(ownerNameEditText, buttonSearchOwner, new Runnable() {
@@ -206,6 +244,12 @@ public class SearchActivity extends AbstractActivity {
public void run() {
findByOwnerFn();
}
+ }, new Func1<String, String[]>() {
+
+ @Override
+ public String[] call(final String input) {
+ return DataStore.getSuggestionsOwnerName(input);
+ }
});
setSearchAction(trackableEditText, buttonSearchTrackable, new Runnable() {
@@ -214,12 +258,16 @@ public class SearchActivity extends AbstractActivity {
public void run() {
findTrackableFn();
}
+ }, new Func1<String, String[]>() {
+
+ @Override
+ public String[] call(final String input) {
+ return DataStore.getSuggestionsTrackableCode(input);
+ }
});
- addHistoryEntries(trackableEditText, DataStore.getTrackableCodes());
- disableSuggestions(trackableEditText);
}
- private static void setSearchAction(final EditText editText, final Button button, final Runnable runnable) {
+ private static void setSearchAction(final AutoCompleteTextView editText, final Button button, final Runnable runnable, final Func1<String, String[]> suggestionFunction) {
EditUtils.setActionListener(editText, runnable);
button.setOnClickListener(new View.OnClickListener() {
@Override
@@ -227,13 +275,7 @@ public class SearchActivity extends AbstractActivity {
runnable.run();
}
});
- }
-
- private void addHistoryEntries(final AutoCompleteTextView textView, final String[] entries) {
- if (entries != null) {
- final ArrayAdapter<String> historyAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, entries);
- textView.setAdapter(historyAdapter);
- }
+ editText.setAdapter(new AutoCompleteAdapter(editText.getContext(), android.R.layout.simple_dropdown_item_1line, suggestionFunction));
}
private class FindByCoordsAction implements OnClickListener {
@@ -305,7 +347,7 @@ public class SearchActivity extends AbstractActivity {
return;
}
- CacheListActivity.startActivityUserName(this, usernameText);
+ CacheListActivity.startActivityFinder(this, usernameText);
}
private void findByOwnerFn() {
diff --git a/main/src/cgeo/geocaching/SearchResult.java b/main/src/cgeo/geocaching/SearchResult.java
index 131a01c..46ac38e 100644
--- a/main/src/cgeo/geocaching/SearchResult.java
+++ b/main/src/cgeo/geocaching/SearchResult.java
@@ -10,6 +10,7 @@ import cgeo.geocaching.gcvote.GCVote;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -228,6 +229,7 @@ public class SearchResult implements Parcelable {
return result;
}
+ @Nullable
public Geocache getFirstCacheFromResult(final EnumSet<LoadFlag> loadFlags) {
return CollectionUtils.isNotEmpty(geocodes) ? DataStore.loadCache(geocodes.iterator().next(), loadFlags) : null;
}
diff --git a/main/src/cgeo/geocaching/StaticMapsActivity.java b/main/src/cgeo/geocaching/StaticMapsActivity.java
index 7811da5..f19ce29 100644
--- a/main/src/cgeo/geocaching/StaticMapsActivity.java
+++ b/main/src/cgeo/geocaching/StaticMapsActivity.java
@@ -8,7 +8,6 @@ import com.googlecode.androidannotations.annotations.EActivity;
import com.googlecode.androidannotations.annotations.Extra;
import com.googlecode.androidannotations.annotations.OptionsItem;
import com.googlecode.androidannotations.annotations.OptionsMenu;
-
import org.apache.commons.collections4.CollectionUtils;
import android.app.ProgressDialog;
diff --git a/main/src/cgeo/geocaching/StatusFragment.java b/main/src/cgeo/geocaching/StatusFragment.java
index 4f70f0e..a4b5973 100644
--- a/main/src/cgeo/geocaching/StatusFragment.java
+++ b/main/src/cgeo/geocaching/StatusFragment.java
@@ -1,15 +1,17 @@
package cgeo.geocaching;
+import cgeo.geocaching.network.StatusUpdater;
import cgeo.geocaching.network.StatusUpdater.Status;
-import cgeo.geocaching.utils.IObserver;
import cgeo.geocaching.utils.Log;
+import rx.Subscription;
+import rx.android.observables.AndroidObservable;
+import rx.util.functions.Action1;
+
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
@@ -20,91 +22,68 @@ import android.widget.TextView;
public class StatusFragment extends Fragment {
- private ViewGroup status;
- private ImageView statusIcon;
- private TextView statusMessage;
-
- final private StatusHandler statusHandler = new StatusHandler();
+ private Subscription statusSubscription;
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
- status = (ViewGroup) inflater.inflate(R.layout.status, container, false);
- statusIcon = (ImageView) status.findViewById(R.id.status_icon);
- statusMessage = (TextView) status.findViewById(R.id.status_message);
- return status;
- }
-
- @Override
- public void onResume() {
- super.onResume();
- CgeoApplication.getInstance().getStatusUpdater().addObserver(statusHandler);
- }
-
- @Override
- public void onPause() {
- CgeoApplication.getInstance().getStatusUpdater().deleteObserver(statusHandler);
- super.onPause();
- }
-
- private class StatusHandler extends Handler implements IObserver<Status> {
-
- @Override
- public void update(final Status data) {
- obtainMessage(0, data).sendToTarget();
- }
-
- @Override
- public void handleMessage(final Message msg) {
- final Status data = (Status) msg.obj;
- updateDisplay(data != null && data.message != null ? data : Status.defaultStatus());
- }
-
- private void updateDisplay(final Status data) {
-
- if (data == null) {
- status.setVisibility(View.INVISIBLE);
- return;
- }
-
- final Resources res = getResources();
- final String packageName = getActivity().getPackageName();
+ final ViewGroup statusGroup = (ViewGroup) inflater.inflate(R.layout.status, container, false);
+ final ImageView statusIcon = (ImageView) statusGroup.findViewById(R.id.status_icon);
+ final TextView statusMessage = (TextView) statusGroup.findViewById(R.id.status_message);
+ statusSubscription = AndroidObservable.fromFragment(this, StatusUpdater.latestStatus).subscribe(new Action1<Status>() {
+ @Override
+ public void call(final Status status) {
+ if (status == null) {
+ statusGroup.setVisibility(View.INVISIBLE);
+ return;
+ }
- if (data.icon != null) {
- final int iconId = res.getIdentifier(data.icon, "drawable", packageName);
- if (iconId != 0) {
- statusIcon.setImageResource(iconId);
- statusIcon.setVisibility(View.VISIBLE);
+ final Resources res = getResources();
+ final String packageName = getActivity().getPackageName();
+
+ if (status.icon != null) {
+ final int iconId = res.getIdentifier(status.icon, "drawable", packageName);
+ if (iconId != 0) {
+ statusIcon.setImageResource(iconId);
+ statusIcon.setVisibility(View.VISIBLE);
+ } else {
+ Log.w("StatusHandler: could not find icon corresponding to @drawable/" + status.icon);
+ statusIcon.setVisibility(View.GONE);
+ }
} else {
- Log.w("StatusHandler: could not find icon corresponding to @drawable/" + data.icon);
statusIcon.setVisibility(View.GONE);
}
- } else {
- statusIcon.setVisibility(View.GONE);
- }
- String message = data.message;
- if (data.messageId != null) {
- final int messageId = res.getIdentifier(data.messageId, "string", packageName);
- if (messageId != 0) {
- message = res.getString(messageId);
+ String message = status.message;
+ if (status.messageId != null) {
+ final int messageId = res.getIdentifier(status.messageId, "string", packageName);
+ if (messageId != 0) {
+ message = res.getString(messageId);
+ }
}
- }
- statusMessage.setText(message);
- status.setVisibility(View.VISIBLE);
+ statusMessage.setText(message);
+ statusGroup.setVisibility(View.VISIBLE);
- if (data.url != null) {
- status.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(final View v) {
- startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(data.url)));
- }
- });
- } else {
- status.setClickable(false);
+ if (status.url != null) {
+ statusGroup.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(status.url)));
+ }
+ });
+ } else {
+ statusGroup.setClickable(false);
+ }
}
- }
+ });
+ return statusGroup;
+ }
+ @Override
+ public void onDestroy() {
+ statusSubscription.unsubscribe();
+ super.onDestroy();
}
+
}
diff --git a/main/src/cgeo/geocaching/TrackableActivity.java b/main/src/cgeo/geocaching/TrackableActivity.java
index dcfd80a..34f546a 100644
--- a/main/src/cgeo/geocaching/TrackableActivity.java
+++ b/main/src/cgeo/geocaching/TrackableActivity.java
@@ -130,6 +130,8 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
// try to get data from URI
if (geocode == null && guid == null && id == null && uri != null) {
+ geocode = ConnectorFactory.getTrackableFromURL(uri.toString());
+
final String uriHost = uri.getHost().toLowerCase(Locale.US);
if (uriHost.contains("geocaching.com")) {
geocode = uri.getQueryParameter("tracker");
diff --git a/main/src/cgeo/geocaching/UsefulAppsActivity.java b/main/src/cgeo/geocaching/UsefulAppsActivity.java
index c70143f..39c527d 100644
--- a/main/src/cgeo/geocaching/UsefulAppsActivity.java
+++ b/main/src/cgeo/geocaching/UsefulAppsActivity.java
@@ -62,6 +62,7 @@ public class UsefulAppsActivity extends AbstractActivity {
private static final HelperApp[] HELPER_APPS = {
new HelperApp(R.string.helper_calendar_title, R.string.helper_calendar_description, R.drawable.cgeo, "cgeo.calendar"),
new HelperApp(R.string.helper_sendtocgeo_title, R.string.helper_sendtocgeo_description, R.drawable.cgeo, "http://send2.cgeo.org"),
+ new HelperApp(R.string.helper_contacts_title, R.string.helper_contacts_description, R.drawable.cgeo, "cgeo.contacts"),
new HelperApp(R.string.helper_pocketquery_title, R.string.helper_pocketquery_description, R.drawable.helper_pocketquery, "org.pquery"),
new HelperApp(R.string.helper_locus_title, R.string.helper_locus_description, R.drawable.helper_locus, "menion.android.locus"),
new HelperApp(R.string.helper_google_translate_title, R.string.helper_google_translate_description, R.drawable.helper_google_translate, "com.google.android.apps.translate"),
diff --git a/main/src/cgeo/geocaching/activity/AbstractListActivity.java b/main/src/cgeo/geocaching/activity/AbstractListActivity.java
index 2adae7a..a5d5c14 100644
--- a/main/src/cgeo/geocaching/activity/AbstractListActivity.java
+++ b/main/src/cgeo/geocaching/activity/AbstractListActivity.java
@@ -11,7 +11,6 @@ public abstract class AbstractListActivity extends FragmentListActivity implemen
IAbstractActivity {
private boolean keepScreenOn = false;
- private boolean paused = true;
protected CgeoApplication app = null;
protected Resources res = null;
@@ -85,26 +84,4 @@ public abstract class AbstractListActivity extends FragmentListActivity implemen
// initialize action bar title with activity title
ActivityMixin.setTitle(this, getTitle());
}
-
- @Override
- public void onResume() {
- paused = false;
- super.onResume();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- paused = true;
- }
-
- /**
- * Check if the current activity is paused. This must be called and acted
- * upon only from the UI thread.
- *
- * @return <code>true</code> if the current activity is paused
- */
- protected boolean isPaused() {
- return paused;
- }
}
diff --git a/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java b/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java
index c7d4507..6e2900d 100644
--- a/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java
+++ b/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java
@@ -5,7 +5,6 @@ import cgeo.geocaching.utils.Log;
import com.viewpagerindicator.TitlePageIndicator;
import com.viewpagerindicator.TitleProvider;
-
import org.apache.commons.lang3.tuple.Pair;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
diff --git a/main/src/cgeo/geocaching/activity/ActivityMixin.java b/main/src/cgeo/geocaching/activity/ActivityMixin.java
index c1a2678..bfd45da 100644
--- a/main/src/cgeo/geocaching/activity/ActivityMixin.java
+++ b/main/src/cgeo/geocaching/activity/ActivityMixin.java
@@ -125,6 +125,6 @@ public final class ActivityMixin {
editText.getText().replace(start, end, completeText);
int newCursor = moveCursor ? start + completeText.length() : start;
- editText.setSelection(newCursor, newCursor);
+ editText.setSelection(newCursor);
}
}
diff --git a/main/src/cgeo/geocaching/apps/AbstractLocusApp.java b/main/src/cgeo/geocaching/apps/AbstractLocusApp.java
index d6c2fe6..c26a24d 100644
--- a/main/src/cgeo/geocaching/apps/AbstractLocusApp.java
+++ b/main/src/cgeo/geocaching/apps/AbstractLocusApp.java
@@ -13,7 +13,6 @@ import menion.android.locus.addon.publiclib.geoData.Point;
import menion.android.locus.addon.publiclib.geoData.PointGeocachingData;
import menion.android.locus.addon.publiclib.geoData.PointGeocachingDataWaypoint;
import menion.android.locus.addon.publiclib.geoData.PointsData;
-
import org.apache.commons.lang3.time.FastDateFormat;
import android.app.Activity;
diff --git a/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java b/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java
index ac5809e..40c4d92 100644
--- a/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java
+++ b/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.apps.cachelist;
-import cgeo.geocaching.SearchResult;
import cgeo.geocaching.Geocache;
+import cgeo.geocaching.SearchResult;
import cgeo.geocaching.apps.App;
import android.app.Activity;
diff --git a/main/src/cgeo/geocaching/concurrent/PriorityThreadFactory.java b/main/src/cgeo/geocaching/concurrent/PriorityThreadFactory.java
index 76379de..0da198b 100644
--- a/main/src/cgeo/geocaching/concurrent/PriorityThreadFactory.java
+++ b/main/src/cgeo/geocaching/concurrent/PriorityThreadFactory.java
@@ -1,5 +1,7 @@
package cgeo.geocaching.concurrent;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.concurrent.ThreadFactory;
/**
@@ -12,6 +14,7 @@ public class PriorityThreadFactory implements ThreadFactory {
this.priority = priority;
}
+ @NonNull
@Override
public Thread newThread(Runnable r) {
Thread result = new Thread(r);
diff --git a/main/src/cgeo/geocaching/connector/AbstractConnector.java b/main/src/cgeo/geocaching/connector/AbstractConnector.java
index 53a3bcb..ca05439 100644
--- a/main/src/cgeo/geocaching/connector/AbstractConnector.java
+++ b/main/src/cgeo/geocaching/connector/AbstractConnector.java
@@ -16,10 +16,10 @@ import cgeo.geocaching.connector.capability.ISearchByViewPort;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.utils.RunnableWithArgument;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import rx.util.functions.Action1;
import java.util.ArrayList;
import java.util.Collection;
@@ -255,21 +255,21 @@ public abstract class AbstractConnector implements IConnector {
List<UserAction> actions = getDefaultUserActions();
if (this instanceof ISearchByOwner) {
- actions.add(new UserAction(R.string.user_menu_view_hidden, new RunnableWithArgument<UserAction.Context>() {
+ actions.add(new UserAction(R.string.user_menu_view_hidden, new Action1<Context>() {
@Override
- public void run(Context context) {
+ public void call(Context context) {
CacheListActivity.startActivityOwner(context.activity, context.userName);
}
}));
}
if (this instanceof ISearchByFinder) {
- actions.add(new UserAction(R.string.user_menu_view_found, new RunnableWithArgument<UserAction.Context>() {
+ actions.add(new UserAction(R.string.user_menu_view_found, new Action1<UserAction.Context>() {
@Override
- public void run(Context context) {
- CacheListActivity.startActivityUserName(context.activity, context.userName);
+ public void call(Context context) {
+ CacheListActivity.startActivityFinder(context.activity, context.userName);
}
}));
}
@@ -283,10 +283,10 @@ public abstract class AbstractConnector implements IConnector {
public List<UserAction> getDefaultUserActions() {
final ArrayList<UserAction> actions = new ArrayList<UserAction>();
if (ContactsAddon.isAvailable()) {
- actions.add(new UserAction(R.string.user_menu_open_contact, new RunnableWithArgument<UserAction.Context>() {
+ actions.add(new UserAction(R.string.user_menu_open_contact, new Action1<UserAction.Context>() {
@Override
- public void run(Context context) {
+ public void call(Context context) {
ContactsAddon.openContactCard(context.activity, context.userName);
}
}));
diff --git a/main/src/cgeo/geocaching/connector/ConnectorFactory.java b/main/src/cgeo/geocaching/connector/ConnectorFactory.java
index 0081951..68e3142 100644
--- a/main/src/cgeo/geocaching/connector/ConnectorFactory.java
+++ b/main/src/cgeo/geocaching/connector/ConnectorFactory.java
@@ -27,6 +27,10 @@ import cgeo.geocaching.geopoint.Viewport;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import rx.Observable;
+import rx.concurrency.Schedulers;
+import rx.util.functions.Func1;
+import rx.util.functions.Func2;
import java.util.ArrayList;
import java.util.Arrays;
@@ -176,14 +180,30 @@ public final class ConnectorFactory {
}
/** @see ISearchByViewPort#searchByViewport */
- public static SearchResult searchByViewport(final @NonNull Viewport viewport, final MapTokens tokens) {
- final SearchResult result = new SearchResult();
- for (final ISearchByViewPort connector : searchByViewPortConns) {
- if (connector.isActive()) {
- result.addSearchResult(connector.searchByViewport(viewport, tokens));
+ public static Observable<SearchResult> searchByViewport(final @NonNull Viewport viewport, final MapTokens tokens) {
+ return Observable.from(searchByViewPortConns).filter(new Func1<ISearchByViewPort, Boolean>() {
+ @Override
+ public Boolean call(final ISearchByViewPort connector) {
+ return connector.isActive();
}
- }
- return result;
+ }).parallel(new Func1<Observable<ISearchByViewPort>, Observable<SearchResult>>() {
+ @Override
+ public Observable<SearchResult> call(final Observable<ISearchByViewPort> connector) {
+ return connector.map(new Func1<ISearchByViewPort, SearchResult>() {
+ @Override
+ public SearchResult call(final ISearchByViewPort connector) {
+ return connector.searchByViewport(viewport, tokens);
+ }
+ });
+ }
+ }, Schedulers.threadPoolForIO()).reduce(new SearchResult(), new Func2<SearchResult, SearchResult, SearchResult>() {
+
+ @Override
+ public SearchResult call(final SearchResult result, final SearchResult searchResult) {
+ result.addSearchResult(searchResult);
+ return result;
+ }
+ });
}
public static String getGeocodeFromURL(final String url) {
@@ -200,6 +220,12 @@ public final class ConnectorFactory {
return TRACKABLE_CONNECTORS;
}
+ /**
+ * Get the geocode of a trackable from a URL.
+ *
+ * @param url
+ * @return {@code null} if the URL cannot be decoded
+ */
public static String getTrackableFromURL(final String url) {
if (url == null) {
return null;
diff --git a/main/src/cgeo/geocaching/connector/UserAction.java b/main/src/cgeo/geocaching/connector/UserAction.java
index d0c97bb..da03a95 100644
--- a/main/src/cgeo/geocaching/connector/UserAction.java
+++ b/main/src/cgeo/geocaching/connector/UserAction.java
@@ -1,8 +1,7 @@
package cgeo.geocaching.connector;
-import cgeo.geocaching.utils.RunnableWithArgument;
-
import org.eclipse.jdt.annotation.NonNull;
+import rx.util.functions.Action1;
import android.app.Activity;
@@ -19,14 +18,15 @@ public class UserAction {
}
public final int displayResourceId;
- private final @NonNull RunnableWithArgument<Context> runnable;
+ private final @NonNull
+ Action1<Context> runnable;
- public UserAction(int displayResourceId, final @NonNull RunnableWithArgument<UserAction.Context> runnable) {
+ public UserAction(int displayResourceId, final @NonNull Action1<Context> runnable) {
this.displayResourceId = displayResourceId;
this.runnable = runnable;
}
public void run(Context context) {
- runnable.run(context);
+ runnable.call(context);
}
}
diff --git a/main/src/cgeo/geocaching/connector/ec/ECApi.java b/main/src/cgeo/geocaching/connector/ec/ECApi.java
index 03fce4d..9d786ea 100644
--- a/main/src/cgeo/geocaching/connector/ec/ECApi.java
+++ b/main/src/cgeo/geocaching/connector/ec/ECApi.java
@@ -17,7 +17,6 @@ import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.FastDateFormat;
diff --git a/main/src/cgeo/geocaching/connector/ec/ECConnector.java b/main/src/cgeo/geocaching/connector/ec/ECConnector.java
index 6da076b..71716fe 100644
--- a/main/src/cgeo/geocaching/connector/ec/ECConnector.java
+++ b/main/src/cgeo/geocaching/connector/ec/ECConnector.java
@@ -140,7 +140,7 @@ public class ECConnector extends AbstractConnector implements ISearchByGeocode,
// invoke settings activity to insert login details
if (status == StatusCode.NO_LOGIN_INFO_STORED && fromActivity != null) {
- SettingsActivity.jumpToServicesPage(fromActivity);
+ SettingsActivity.openForScreen(R.string.preference_screen_ec, fromActivity);
}
}
return status == StatusCode.NO_ERROR;
diff --git a/main/src/cgeo/geocaching/connector/ec/ECLogin.java b/main/src/cgeo/geocaching/connector/ec/ECLogin.java
index 52bd423..012bdc9 100644
--- a/main/src/cgeo/geocaching/connector/ec/ECLogin.java
+++ b/main/src/cgeo/geocaching/connector/ec/ECLogin.java
@@ -10,7 +10,6 @@ import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.eclipse.jdt.annotation.Nullable;
diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
index e946748..a62b1f6 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
@@ -27,12 +27,12 @@ import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.settings.SettingsActivity;
import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.RunnableWithArgument;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import rx.util.functions.Action1;
import android.content.Context;
import android.content.Intent;
@@ -91,7 +91,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
@Override
public boolean supportsPersonalNote() {
- return Settings.isPremiumMember();
+ return Settings.isGCPremiumMember();
}
@Override
@@ -285,7 +285,22 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
@Override
protected String getCacheUrlPrefix() {
- return CACHE_URL_SHORT;
+ return null; // UNUSED
+ }
+
+ @Override
+ public String getGeocodeFromUrl(String url) {
+ // coord.info URLs
+ String code = StringUtils.substringAfterLast(url, "coord.info/");
+ if (code != null && canHandle(code)) {
+ return code;
+ }
+ // expanded geocaching.com URLs
+ code = StringUtils.substringBetween(url, "/geocache/", "_");
+ if (code != null && canHandle(code)) {
+ return code;
+ }
+ return null;
}
@Override
@@ -316,7 +331,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
// invoke settings activity to insert login details
if (status == StatusCode.NO_LOGIN_INFO_STORED && fromActivity != null) {
- SettingsActivity.jumpToServicesPage(fromActivity);
+ SettingsActivity.openForScreen(R.string.preference_screen_gc, fromActivity);
}
}
return status == StatusCode.NO_ERROR;
@@ -379,17 +394,17 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
public @NonNull
List<UserAction> getUserActions() {
List<UserAction> actions = super.getUserActions();
- actions.add(new UserAction(R.string.user_menu_open_browser, new RunnableWithArgument<UserAction.Context>() {
+ actions.add(new UserAction(R.string.user_menu_open_browser, new Action1<UserAction.Context>() {
@Override
- public void run(cgeo.geocaching.connector.UserAction.Context context) {
+ public void call(cgeo.geocaching.connector.UserAction.Context context) {
context.activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?u=" + Network.encode(context.userName))));
}
}));
- actions.add(new UserAction(R.string.user_menu_send_message, new RunnableWithArgument<UserAction.Context>() {
+ actions.add(new UserAction(R.string.user_menu_send_message, new Action1<UserAction.Context>() {
@Override
- public void run(cgeo.geocaching.connector.UserAction.Context context) {
+ public void call(cgeo.geocaching.connector.UserAction.Context context) {
context.activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/email/?u=" + Network.encode(context.userName))));
}
}));
diff --git a/main/src/cgeo/geocaching/connector/gc/GCLogin.java b/main/src/cgeo/geocaching/connector/gc/GCLogin.java
index a7cf6cf..92d488d 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCLogin.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCLogin.java
@@ -14,7 +14,6 @@ import cgeo.geocaching.utils.MatcherWrapper;
import cgeo.geocaching.utils.TextUtils;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
@@ -97,7 +96,7 @@ public class GCLogin extends AbstractLogin {
}
if (getLoginStatus(loginData)) {
- Log.i("Already logged in Geocaching.com as " + username + " (" + Settings.getMemberStatus() + ')');
+ Log.i("Already logged in Geocaching.com as " + username + " (" + Settings.getGCMemberStatus() + ')');
if (switchToEnglish(loginData) && retry) {
return login(false);
}
@@ -132,7 +131,7 @@ public class GCLogin extends AbstractLogin {
assert loginData != null; // Caught above
if (getLoginStatus(loginData)) {
- Log.i("Successfully logged in Geocaching.com as " + username + " (" + Settings.getMemberStatus() + ')');
+ Log.i("Successfully logged in Geocaching.com as " + username + " (" + Settings.getGCMemberStatus() + ')');
if (switchToEnglish(loginData) && retry) {
return login(false);
@@ -204,9 +203,9 @@ public class GCLogin extends AbstractLogin {
Log.e("getLoginStatus: bad cache count", e);
}
setActualCachesFound(cachesCount);
- Settings.setMemberStatus(TextUtils.getMatch(page, GCConstants.PATTERN_MEMBER_STATUS, true, null));
+ Settings.setGCMemberStatus(TextUtils.getMatch(page, GCConstants.PATTERN_MEMBER_STATUS, true, null));
if ( page.contains(GCConstants.MEMBER_STATUS_RENEW) ) {
- Settings.setMemberStatus(GCConstants.MEMBER_STATUS_PM);
+ Settings.setGCMemberStatus(GCConstants.MEMBER_STATUS_PM);
}
return true;
}
@@ -259,9 +258,9 @@ public class GCLogin extends AbstractLogin {
final String responseData = StringUtils.defaultString(Network.getResponseData(Network.getRequest("http://www.geocaching.com/my/")));
final String profile = TextUtils.replaceWhitespace(responseData);
- Settings.setMemberStatus(TextUtils.getMatch(profile, GCConstants.PATTERN_MEMBER_STATUS, true, null));
+ Settings.setGCMemberStatus(TextUtils.getMatch(profile, GCConstants.PATTERN_MEMBER_STATUS, true, null));
if (profile.contains(GCConstants.MEMBER_STATUS_RENEW)) {
- Settings.setMemberStatus(GCConstants.MEMBER_STATUS_PM);
+ Settings.setGCMemberStatus(GCConstants.MEMBER_STATUS_PM);
}
setActualCachesFound(Integer.parseInt(TextUtils.getMatch(profile, GCConstants.PATTERN_CACHES_FOUND, true, "-1").replaceAll("[,.]", "")));
diff --git a/main/src/cgeo/geocaching/connector/gc/GCMap.java b/main/src/cgeo/geocaching/connector/gc/GCMap.java
index 6c94150..2782b64 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCMap.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCMap.java
@@ -368,7 +368,7 @@ public class GCMap {
}
}
- if (strategy.flags.contains(StrategyFlag.SEARCH_NEARBY) && Settings.isPremiumMember()) {
+ if (strategy.flags.contains(StrategyFlag.SEARCH_NEARBY) && Settings.isGCPremiumMember()) {
final Geopoint center = viewport.getCenter();
if ((lastSearchViewport == null) || !lastSearchViewport.contains(center)) {
//FIXME We don't have a RecaptchaReceiver!?
diff --git a/main/src/cgeo/geocaching/connector/gc/GCParser.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java
index 62ccb14..70c3b2a 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCParser.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java
@@ -36,7 +36,6 @@ import cgeo.geocaching.utils.SynchronizedDateFormat;
import cgeo.geocaching.utils.TextUtils;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringEscapeUtils;
@@ -282,7 +281,7 @@ public abstract class GCParser {
recaptchaText = thread.getText();
}
- if (!cids.isEmpty() && (Settings.isPremiumMember() || showCaptcha) && ((thread == null || StringUtils.isBlank(thread.getChallenge())) || StringUtils.isNotBlank(recaptchaText))) {
+ if (!cids.isEmpty() && (Settings.isGCPremiumMember() || showCaptcha) && ((thread == null || StringUtils.isBlank(thread.getChallenge())) || StringUtils.isNotBlank(recaptchaText))) {
Log.i("Trying to get .loc for " + cids.size() + " caches");
try {
@@ -347,6 +346,9 @@ public abstract class GCParser {
// attention: parseCacheFromText already stores implicitly through searchResult.addCache
if (searchResult != null && !searchResult.getGeocodes().isEmpty()) {
final Geocache cache = searchResult.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB);
+ if (cache == null) {
+ return null;
+ }
getExtraOnlineInfo(cache, page, handler);
// too late: it is already stored through parseCacheFromText
cache.setDetailedUpdatedNow();
@@ -741,7 +743,7 @@ public abstract class GCParser {
cache.parseWaypointsFromNote();
// logs
- cache.setLogs(loadLogsFromDetails(page, cache, false, true));
+ cache.setLogs(getLogsFromDetails(page, false));
// last check for necessary cache conditions
if (StringUtils.isBlank(cache.getGeocode())) {
@@ -1380,8 +1382,7 @@ public abstract class GCParser {
}
private static boolean changeFavorite(final Geocache cache, final boolean add) {
- final String page = requestHtmlPage(cache.getGeocode(), null, "n", "0");
- final String userToken = TextUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, "");
+ final String userToken = getUserToken(cache);
if (StringUtils.isEmpty(userToken)) {
return false;
}
@@ -1400,6 +1401,11 @@ public abstract class GCParser {
return false;
}
+ private static String getUserToken(final Geocache cache) {
+ final String page = requestHtmlPage(cache.getGeocode(), null, "n", "0");
+ return TextUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, "");
+ }
+
/**
* Removes the cache from the favorites.
*
@@ -1613,19 +1619,20 @@ public abstract class GCParser {
}
/**
- * Load logs from a cache details page.
+ * Extract logs from a cache details page.
*
* @param page
* the text of the details page
- * @param cache
- * the cache object to put the logs in
* @param friends
- * retrieve friend logs
+ * return friends logs only (will require a network request)
+ * @return a list of log entries or <code>null</code> if the logs could not be retrieved
+ *
*/
- private static List<LogEntry> loadLogsFromDetails(final String page, final Geocache cache, final boolean friends, final boolean getDataFromPage) {
+ @Nullable
+ private static List<LogEntry> getLogsFromDetails(final String page, final boolean friends) {
String rawResponse;
- if (!getDataFromPage) {
+ if (friends) {
final MatcherWrapper userTokenMatcher = new MatcherWrapper(GCConstants.PATTERN_USERTOKEN, page);
if (!userTokenMatcher.find()) {
Log.e("GCParser.loadLogsFromDetails: unable to extract userToken");
@@ -1712,7 +1719,7 @@ public abstract class GCParser {
final JSONArray images = entry.getJSONArray("Images");
for (int i = 0; i < images.length(); i++) {
final JSONObject image = images.getJSONObject(i);
- final String url = "http://img.geocaching.com/cache/log/large/" + image.getString("FileName");
+ final String url = "http://imgcdn.geocaching.com/cache/log/large/" + image.getString("FileName");
final String title = TextUtils.removeControlCharacters(image.getString("Name"));
final Image logImage = new Image(url, title);
logDone.addLogImage(logImage);
@@ -1825,7 +1832,7 @@ public abstract class GCParser {
if (Settings.isFriendLogsWanted()) {
CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_logs);
final List<LogEntry> allLogs = cache.getLogs();
- final List<LogEntry> friendLogs = loadLogsFromDetails(page, cache, true, false);
+ final List<LogEntry> friendLogs = getLogsFromDetails(page, true);
if (friendLogs != null) {
for (final LogEntry log : friendLogs) {
if (allLogs.contains(log)) {
@@ -1860,8 +1867,7 @@ public abstract class GCParser {
}
public static boolean editModifiedCoordinates(Geocache cache, Geopoint wpt) {
- final String page = requestHtmlPage(cache.getGeocode(), null, "n", "0");
- final String userToken = TextUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, "");
+ final String userToken = getUserToken(cache);
if (StringUtils.isEmpty(userToken)) {
return false;
}
@@ -1896,8 +1902,7 @@ public abstract class GCParser {
}
public static boolean uploadPersonalNote(Geocache cache) {
- final String page = requestHtmlPage(cache.getGeocode(), null, "n", "0");
- final String userToken = TextUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, "");
+ final String userToken = getUserToken(cache);
if (StringUtils.isEmpty(userToken)) {
return false;
}
diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
index 2175935..c33a90e 100644
--- a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
+++ b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
@@ -75,7 +75,8 @@ final class OkapiClient {
private static final String CACHE_STATUS_ARCHIVED = "Archived";
private static final String CACHE_STATUS_DISABLED = "Temporarily unavailable";
private static final String CACHE_IS_FOUND = "is_found";
- private static final String CACHE_SIZE = "size";
+ private static final String CACHE_SIZE_DEPRECATED = "size";
+ private static final String CACHE_SIZE2 = "size2";
private static final String CACHE_VOTES = "rating_votes";
private static final String CACHE_NOTFOUNDS = "notfounds";
private static final String CACHE_FOUNDS = "founds";
@@ -112,7 +113,7 @@ final class OkapiClient {
// the several realms of possible fields for cache retrieval:
// Core: for livemap requests (L3 - only with level 3 auth)
// Additional: additional fields for full cache (L3 - only for level 3 auth, current - only for connectors with current api)
- private static final String SERVICE_CACHE_CORE_FIELDS = "code|name|location|type|status|difficulty|terrain|size|date_hidden";
+ private static final String SERVICE_CACHE_CORE_FIELDS = "code|name|location|type|status|difficulty|terrain|size|size2|date_hidden";
private static final String SERVICE_CACHE_CORE_L3_FIELDS = "is_found";
private static final String SERVICE_CACHE_ADDITIONAL_FIELDS = "owner|founds|notfounds|rating|rating_votes|recommendations|description|hint|images|latest_logs|alt_wpts|attrnames|req_passwd";
private static final String SERVICE_CACHE_ADDITIONAL_CURRENT_FIELDS = "gc_code|attribution_note|attr_acodes";
@@ -152,19 +153,14 @@ final class OkapiClient {
}
public static List<Geocache> getCachesByOwner(final String username, final OCApiConnector connector) {
- final Parameters params = new Parameters("search_method", METHOD_SEARCH_ALL);
- final Map<String, String> valueMap = new LinkedHashMap<String, String>();
- final @Nullable
- String uuid = getUserUUID(connector, username);
- if (StringUtils.isEmpty(uuid)) {
- return Collections.emptyList();
- }
- valueMap.put("owner_uuid", uuid);
-
- return requestCaches(connector, params, valueMap);
+ return getCachesByUser(username, connector, "owner_uuid");
}
public static List<Geocache> getCachesByFinder(final String username, final OCApiConnector connector) {
+ return getCachesByUser(username, connector, "found_by");
+ }
+
+ private static List<Geocache> getCachesByUser(final String username, final OCApiConnector connector, final String userRequestParam) {
final Parameters params = new Parameters("search_method", METHOD_SEARCH_ALL);
final Map<String, String> valueMap = new LinkedHashMap<String, String>();
final @Nullable
@@ -172,7 +168,7 @@ final class OkapiClient {
if (StringUtils.isEmpty(uuid)) {
return Collections.emptyList();
}
- valueMap.put("found_by", uuid);
+ valueMap.put(userRequestParam, uuid);
return requestCaches(connector, params, valueMap);
}
@@ -567,12 +563,25 @@ final class OkapiClient {
}
private static CacheSize getCacheSize(final JSONObject response) {
- if (response.isNull(CACHE_SIZE)) {
+ if (response.isNull(CACHE_SIZE2)) {
+ return getCacheSizeDeprecated(response);
+ }
+ try {
+ final String size = response.getString(CACHE_SIZE2);
+ return CacheSize.getById(size);
+ } catch (JSONException e) {
+ Log.e("OkapiClient.getCacheSize", e);
+ return getCacheSizeDeprecated(response);
+ }
+ }
+
+ private static CacheSize getCacheSizeDeprecated(final JSONObject response) {
+ if (response.isNull(CACHE_SIZE_DEPRECATED)) {
return CacheSize.NOT_CHOSEN;
}
double size = 0;
try {
- size = response.getDouble(CACHE_SIZE);
+ size = response.getDouble(CACHE_SIZE_DEPRECATED);
} catch (final JSONException e) {
Log.e("OkapiClient.getCacheSize", e);
}
@@ -586,7 +595,7 @@ final class OkapiClient {
case 4:
return CacheSize.LARGE;
case 5:
- return CacheSize.LARGE;
+ return CacheSize.VERY_LARGE;
default:
break;
}
diff --git a/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java b/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java
index f72b698..5f11a11 100644
--- a/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java
+++ b/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java
@@ -28,10 +28,10 @@ public class OXGPXParser extends GPX10Parser {
/**
* The short description of OX caches contains "title by owner, type(T/D/Awesomeness)". That is a lot of
* duplication.
- *
+ *
* @param cache
*/
private static void removeTitleFromShortDescription(final @NonNull Geocache cache) {
- cache.setShortDescription(StringUtils.substringAfterLast(cache.getShortDescription(), ","));
+ cache.setShortDescription(StringUtils.trim(StringUtils.substringAfterLast(cache.getShortDescription(), ",")));
}
}
diff --git a/main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java b/main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java
index 2defc52..0137af4 100644
--- a/main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java
+++ b/main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java
@@ -11,7 +11,6 @@ import cgeo.geocaching.utils.CryptUtils;
import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.collections4.CollectionUtils;
import org.eclipse.jdt.annotation.NonNull;
diff --git a/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java b/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java
index 69efddc..fb554b9 100644
--- a/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java
+++ b/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.connector.AbstractConnector;
import cgeo.geocaching.connector.UserAction;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import java.util.List;
@@ -15,7 +16,8 @@ public abstract class AbstractTrackableConnector implements TrackableConnector {
}
@Override
- public String getTrackableCodeFromUrl(@NonNull String url) {
+ public @Nullable
+ String getTrackableCodeFromUrl(@NonNull String url) {
return null;
}
diff --git a/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java b/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java
index 8387076..03052f9 100644
--- a/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java
+++ b/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java
@@ -4,6 +4,10 @@ import cgeo.geocaching.Trackable;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.utils.Log;
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
import java.util.regex.Pattern;
public class GeokretyConnector extends AbstractTrackableConnector {
@@ -29,7 +33,7 @@ public class GeokretyConnector extends AbstractTrackableConnector {
return GeokretyParser.parse(page);
}
- private static int getId(String geocode) {
+ protected static int getId(String geocode) {
try {
final String hex = geocode.substring(2);
return Integer.parseInt(hex, 16);
@@ -39,4 +43,25 @@ public class GeokretyConnector extends AbstractTrackableConnector {
return -1;
}
+ @Override
+ public @Nullable
+ String getTrackableCodeFromUrl(@NonNull String url) {
+ // http://geokrety.org/konkret.php?id=38545
+ String id = StringUtils.substringAfterLast(url, "konkret.php?id=");
+ if (StringUtils.isNumeric(id)) {
+ return geocode(Integer.parseInt(id));
+ }
+ return null;
+ }
+
+ /**
+ * Get geocode from geokrety id
+ *
+ * @param id
+ * @return
+ */
+ public static String geocode(final int id) {
+ return String.format("GK%04X", id);
+ }
+
}
diff --git a/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java b/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java
index ee8c8c0..0e64abd 100644
--- a/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java
+++ b/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java
@@ -37,8 +37,8 @@ public class GeokretyParser {
public void start(Attributes attributes) {
try {
final String kretyId = attributes.getValue("id");
- if (StringUtils.isNotBlank(kretyId)) {
- trackable.setGeocode(geocode(Integer.parseInt(kretyId)));
+ if (StringUtils.isNumeric(kretyId)) {
+ trackable.setGeocode(GeokretyConnector.geocode(Integer.parseInt(kretyId)));
}
final String distance = attributes.getValue("dist");
if (StringUtils.isNotBlank(distance)) {
@@ -88,8 +88,4 @@ public class GeokretyParser {
}
return null;
}
-
- protected static String geocode(final int id) {
- return String.format("GK%04X", id);
- }
}
diff --git a/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java b/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java
index 0990d96..6071b5f 100644
--- a/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java
+++ b/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.Trackable;
import cgeo.geocaching.connector.UserAction;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import java.util.List;
@@ -21,7 +22,8 @@ public interface TrackableConnector {
public Trackable searchTrackable(String geocode, String guid, String id);
- public String getTrackableCodeFromUrl(final @NonNull String url);
+ public @Nullable
+ String getTrackableCodeFromUrl(final @NonNull String url);
public @NonNull
List<UserAction> getUserActions();
diff --git a/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java b/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java
index dad285c..77848d7 100644
--- a/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java
+++ b/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java
@@ -7,6 +7,7 @@ import cgeo.geocaching.connector.gc.GCParser;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import java.util.List;
import java.util.regex.Pattern;
@@ -20,7 +21,7 @@ public class TravelBugConnector extends AbstractTrackableConnector {
@Override
public boolean canHandleTrackable(String geocode) {
- return TravelBugConnector.PATTERN_TB_CODE.matcher(geocode).matches();
+ return TravelBugConnector.PATTERN_TB_CODE.matcher(geocode).matches() && !StringUtils.startsWithIgnoreCase(geocode, "GC");
}
@Override
@@ -54,8 +55,18 @@ public class TravelBugConnector extends AbstractTrackableConnector {
}
@Override
- public String getTrackableCodeFromUrl(@NonNull String url) {
- return StringUtils.substringAfterLast(url, "?tracker=");
+ public @Nullable
+ String getTrackableCodeFromUrl(@NonNull String url) {
+ // coord.info URLs
+ String code = StringUtils.substringAfterLast(url, "coord.info/");
+ if (code != null && canHandleTrackable(code)) {
+ return code;
+ }
+ code = StringUtils.substringAfterLast(url, "?tracker=");
+ if (code != null && canHandleTrackable(code)) {
+ return code;
+ }
+ return null;
}
@Override
diff --git a/main/src/cgeo/geocaching/enumerations/CacheAttribute.java b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java
index 472bad5..0703c3c 100644
--- a/main/src/cgeo/geocaching/enumerations/CacheAttribute.java
+++ b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java
@@ -164,15 +164,11 @@ public enum CacheAttribute {
}
private final static Map<String, CacheAttribute> FIND_BY_GCRAWNAME;
- private final static SparseArray<CacheAttribute> FIND_BY_GCID = new SparseArray<CacheAttribute>();
private final static SparseArray<CacheAttribute> FIND_BY_OCACODE = new SparseArray<CacheAttribute>();
static {
final HashMap<String, CacheAttribute> mapGcRawNames = new HashMap<String, CacheAttribute>();
for (CacheAttribute attr : values()) {
mapGcRawNames.put(attr.rawName, attr);
- if (attr.gcid != NO_ID) {
- FIND_BY_GCID.put(attr.gcid, attr);
- }
if (attr.ocacode != NO_ID) {
FIND_BY_OCACODE.put(attr.ocacode, attr);
}
@@ -184,10 +180,6 @@ public enum CacheAttribute {
return rawName != null ? FIND_BY_GCRAWNAME.get(rawName) : null;
}
- public static CacheAttribute getByGcId(final int gcid) {
- return FIND_BY_GCID.get(gcid);
- }
-
public static CacheAttribute getByOcACode(final int ocAcode) {
return FIND_BY_OCACODE.get(ocAcode);
}
diff --git a/main/src/cgeo/geocaching/enumerations/CacheListType.java b/main/src/cgeo/geocaching/enumerations/CacheListType.java
index f482d5b..1fce282 100644
--- a/main/src/cgeo/geocaching/enumerations/CacheListType.java
+++ b/main/src/cgeo/geocaching/enumerations/CacheListType.java
@@ -1,23 +1,32 @@
package cgeo.geocaching.enumerations;
+import cgeo.geocaching.loaders.AbstractSearchLoader.CacheListLoaderType;
+
public enum CacheListType {
- OFFLINE(true),
- POCKET(false),
- HISTORY(true),
- NEAREST(false),
- COORDINATE(false),
- KEYWORD(false),
- ADDRESS(false),
- USERNAME(false),
- OWNER(false),
- MAP(false);
+ OFFLINE(true, CacheListLoaderType.OFFLINE),
+ POCKET(false, CacheListLoaderType.POCKET),
+ HISTORY(true, CacheListLoaderType.HISTORY),
+ NEAREST(false, CacheListLoaderType.NEAREST),
+ COORDINATE(false, CacheListLoaderType.COORDINATE),
+ KEYWORD(false, CacheListLoaderType.KEYWORD),
+ ADDRESS(false, CacheListLoaderType.ADDRESS),
+ FINDER(false, CacheListLoaderType.FINDER),
+ OWNER(false, CacheListLoaderType.OWNER),
+ MAP(false, CacheListLoaderType.MAP);
/**
* whether or not this list allows switching to another list
*/
public final boolean canSwitch;
- private CacheListType(final boolean canSwitch) {
+ public final CacheListLoaderType loaderType;
+
+ CacheListType(final boolean canSwitch, final CacheListLoaderType loaderType) {
this.canSwitch = canSwitch;
+ this.loaderType = loaderType;
+ }
+
+ public int getLoaderId() {
+ return loaderType.getLoaderId();
}
}
diff --git a/main/src/cgeo/geocaching/enumerations/CacheSize.java b/main/src/cgeo/geocaching/enumerations/CacheSize.java
index ee42c66..1255455 100644
--- a/main/src/cgeo/geocaching/enumerations/CacheSize.java
+++ b/main/src/cgeo/geocaching/enumerations/CacheSize.java
@@ -12,30 +12,38 @@ import java.util.Map;
* Enum listing cache sizes
*/
public enum CacheSize {
- MICRO("Micro", 1, R.string.cache_size_micro),
- SMALL("Small", 2, R.string.cache_size_small),
- REGULAR("Regular", 3, R.string.cache_size_regular),
- LARGE("Large", 4, R.string.cache_size_large),
- 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.cache_size_unknown); // CacheSize not init. yet
+ NANO("Nano", 0, R.string.cache_size_nano, "nano"), // used by OC only
+ MICRO("Micro", 1, R.string.cache_size_micro, "micro"),
+ SMALL("Small", 2, R.string.cache_size_small, "small"),
+ REGULAR("Regular", 3, R.string.cache_size_regular, "regular"),
+ LARGE("Large", 4, R.string.cache_size_large, "large"),
+ VERY_LARGE("Very large", 5, R.string.cache_size_very_large, "xlarge"), // used by OC only
+ NOT_CHOSEN("Not chosen", 6, R.string.cache_size_notchosen, ""),
+ VIRTUAL("Virtual", 7, R.string.cache_size_virtual, "none"),
+ OTHER("Other", 8, R.string.cache_size_other, "other"),
+ UNKNOWN("Unknown", -1, R.string.cache_size_unknown, ""); // CacheSize not init. yet
public final String id;
public final int comparable;
private final int stringId;
+ /**
+ * lookup for OC JSON requests (the numeric size is deprecated for OC)
+ */
+ private final String ocSize2;
- CacheSize(String id, int comparable, int stringId) {
+ CacheSize(final String id, final int comparable, final int stringId, final String ocSize2) {
this.id = id;
this.comparable = comparable;
this.stringId = stringId;
+ this.ocSize2 = ocSize2;
}
final private static Map<String, CacheSize> FIND_BY_ID;
static {
final HashMap<String, CacheSize> mapping = new HashMap<String, CacheSize>();
- for (CacheSize cs : values()) {
+ for (final CacheSize cs : values()) {
mapping.put(cs.id.toLowerCase(Locale.US), cs);
+ mapping.put(cs.ocSize2.toLowerCase(Locale.US), cs);
}
// add medium as additional string for Regular
mapping.put("medium", CacheSize.REGULAR);
@@ -61,21 +69,21 @@ public enum CacheSize {
/**
* Bad GPX files can contain the container size encoded as number.
- *
+ *
* @param id
* @return
*/
private static CacheSize getByNumber(final String id) {
try {
- int numerical = Integer.parseInt(id);
+ final int numerical = Integer.parseInt(id);
if (numerical != 0) {
- for (CacheSize size : CacheSize.values()) {
+ for (final CacheSize size : CacheSize.values()) {
if (size.comparable == numerical) {
return size;
}
}
}
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException e) {
// ignore, as this might be a number or not
}
return UNKNOWN;
@@ -85,4 +93,3 @@ public enum CacheSize {
return CgeoApplication.getInstance().getBaseContext().getResources().getString(stringId);
}
}
-
diff --git a/main/src/cgeo/geocaching/enumerations/CacheType.java b/main/src/cgeo/geocaching/enumerations/CacheType.java
index c952ba0..35fe7a1 100644
--- a/main/src/cgeo/geocaching/enumerations/CacheType.java
+++ b/main/src/cgeo/geocaching/enumerations/CacheType.java
@@ -1,8 +1,8 @@
package cgeo.geocaching.enumerations;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.ICache;
import cgeo.geocaching.R;
-import cgeo.geocaching.CgeoApplication;
import java.util.Collections;
import java.util.HashMap;
diff --git a/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java b/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java
index 710c3ba..5bcaf4a 100644
--- a/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java
+++ b/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.enumerations;
-import cgeo.geocaching.R;
import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.R;
import java.util.EnumSet;
diff --git a/main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java b/main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java
index 68a17a5..e008294 100644
--- a/main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java
+++ b/main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java
@@ -1,29 +1,22 @@
package cgeo.geocaching.enumerations;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
public enum LogTypeTrackable {
- DO_NOTHING(0, "", R.string.log_tb_nothing),
- VISITED(1, "_Visited", R.string.log_tb_visit),
- DROPPED_OFF(2, "_DroppedOff", R.string.log_tb_drop);
+ DO_NOTHING("", R.string.log_tb_nothing),
+ VISITED("_Visited", R.string.log_tb_visit),
+ DROPPED_OFF("_DroppedOff", R.string.log_tb_drop);
- final public int id;
final public String action;
- final public int resourceId;
+ final private int resourceId;
- LogTypeTrackable(int id, String action, int resourceId) {
- this.id = id;
+ LogTypeTrackable(String action, int resourceId) {
this.action = action;
this.resourceId = resourceId;
}
- public static LogTypeTrackable findById(int id) {
- for (LogTypeTrackable logType : values()) {
- if (logType.id == id) {
- return logType;
- }
- }
- return DO_NOTHING;
+ public String getLabel() {
+ return CgeoApplication.getInstance().getString(resourceId);
}
-
}
diff --git a/main/src/cgeo/geocaching/enumerations/StatusCode.java b/main/src/cgeo/geocaching/enumerations/StatusCode.java
index e1a1aaa..8bda371 100644
--- a/main/src/cgeo/geocaching/enumerations/StatusCode.java
+++ b/main/src/cgeo/geocaching/enumerations/StatusCode.java
@@ -6,7 +6,6 @@ import android.content.res.Resources;
public enum StatusCode {
- COMMUNICATION_NOT_STARTED(R.string.err_start),
NO_ERROR(R.string.err_none),
LOG_SAVED(R.string.info_log_saved),
LOGIN_PARSE_ERROR(R.string.err_parse),
@@ -24,7 +23,6 @@ public enum StatusCode {
LOG_POST_ERROR(R.string.err_log_post_failed),
LOG_POST_ERROR_EC(R.string.err_log_post_failed_ec),
NO_LOG_TEXT(R.string.warn_log_text_fill),
- NO_DATA_FROM_SERVER(R.string.err_log_failed_server),
NOT_LOGGED_IN(R.string.init_login_popup_failed),
LOGIMAGE_POST_ERROR(R.string.err_logimage_post_failed);
diff --git a/main/src/cgeo/geocaching/export/GpxExport.java b/main/src/cgeo/geocaching/export/GpxExport.java
index a2e0f93..08fca0b 100644
--- a/main/src/cgeo/geocaching/export/GpxExport.java
+++ b/main/src/cgeo/geocaching/export/GpxExport.java
@@ -1,8 +1,8 @@
package cgeo.geocaching.export;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
-import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.AsyncTaskWithProgress;
diff --git a/main/src/cgeo/geocaching/files/LocalStorage.java b/main/src/cgeo/geocaching/files/LocalStorage.java
index edbecf6..133f39a 100644
--- a/main/src/cgeo/geocaching/files/LocalStorage.java
+++ b/main/src/cgeo/geocaching/files/LocalStorage.java
@@ -7,7 +7,6 @@ import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.Header;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.Nullable;
@@ -122,7 +121,7 @@ public final class LocalStorage {
* the geocode
* @return the cache directory
*/
- public static File getStorageDir(final String geocode) {
+ public static File getStorageDir(@Nullable final String geocode) {
return storageDir(getStorage(), geocode);
}
@@ -134,11 +133,11 @@ public final class LocalStorage {
* the geocode
* @return the cache directory
*/
- private static File getStorageSecDir(final String geocode) {
+ private static File getStorageSecDir(@Nullable final String geocode) {
return storageDir(getStorageSec(), geocode);
}
- private static File storageDir(final File base, final String geocode) {
+ private static File storageDir(final File base, @Nullable final String geocode) {
return new File(base, StringUtils.defaultIfEmpty(geocode, "_others"));
}
@@ -155,7 +154,7 @@ public final class LocalStorage {
* true if an url was given, false if a file name was given
* @return the file
*/
- public static File getStorageFile(final String geocode, final String fileNameOrUrl, final boolean isUrl, final boolean createDirs) {
+ public static File getStorageFile(@Nullable final String geocode, final String fileNameOrUrl, final boolean isUrl, final boolean createDirs) {
return buildFile(getStorageDir(geocode), fileNameOrUrl, isUrl, createDirs);
}
diff --git a/main/src/cgeo/geocaching/files/SimpleDirChooser.java b/main/src/cgeo/geocaching/files/SimpleDirChooser.java
index 3e09cc4..e63c09f 100644
--- a/main/src/cgeo/geocaching/files/SimpleDirChooser.java
+++ b/main/src/cgeo/geocaching/files/SimpleDirChooser.java
@@ -89,9 +89,9 @@ public class SimpleDirChooser extends AbstractListActivity {
}
public void editPath() {
- AlertDialog.Builder builder = new AlertDialog.Builder(SimpleDirChooser.this);
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.simple_dir_chooser_current_path);
- final EditText input = new EditText(SimpleDirChooser.this);
+ final EditText input = new EditText(this);
input.setInputType(InputType.TYPE_CLASS_TEXT);
input.setText(currentDir.getPath());
builder.setView(input);
diff --git a/main/src/cgeo/geocaching/filter/DistanceFilter.java b/main/src/cgeo/geocaching/filter/DistanceFilter.java
index 54225d2..cddcf72 100644
--- a/main/src/cgeo/geocaching/filter/DistanceFilter.java
+++ b/main/src/cgeo/geocaching/filter/DistanceFilter.java
@@ -1,9 +1,9 @@
package cgeo.geocaching.filter;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.IGeoData;
import cgeo.geocaching.R;
-import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.geopoint.Geopoint;
import java.util.ArrayList;
diff --git a/main/src/cgeo/geocaching/filter/FilterUserInterface.java b/main/src/cgeo/geocaching/filter/FilterUserInterface.java
index d77341b..0033b9a 100644
--- a/main/src/cgeo/geocaching/filter/FilterUserInterface.java
+++ b/main/src/cgeo/geocaching/filter/FilterUserInterface.java
@@ -5,7 +5,8 @@ import cgeo.geocaching.R;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.RunnableWithArgument;
+
+import rx.util.functions.Action1;
import android.app.Activity;
import android.app.AlertDialog;
@@ -77,7 +78,7 @@ public final class FilterUserInterface {
registry.add(new FactoryEntry(res.getString(resourceId), factoryClass));
}
- public void selectFilter(final RunnableWithArgument<IFilter> runAfterwards) {
+ public void selectFilter(final Action1<IFilter> runAfterwards) {
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(R.string.caches_filter_title);
@@ -89,7 +90,7 @@ public final class FilterUserInterface {
FactoryEntry entry = adapter.getItem(itemIndex);
// reset?
if (entry.filterFactory == null) {
- runAfterwards.run(null);
+ runAfterwards.call(null);
}
else {
try {
@@ -105,10 +106,10 @@ public final class FilterUserInterface {
builder.create().show();
}
- private void selectFromFactory(final IFilterFactory factory, final String menuTitle, final RunnableWithArgument<IFilter> runAfterwards) {
+ private void selectFromFactory(final IFilterFactory factory, final String menuTitle, final Action1<IFilter> runAfterwards) {
final List<IFilter> filters = Collections.unmodifiableList(factory.getFilters());
if (filters.size() == 1) {
- runAfterwards.run(filters.get(0));
+ runAfterwards.call(filters.get(0));
return;
}
@@ -119,7 +120,7 @@ public final class FilterUserInterface {
builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int item) {
- runAfterwards.run(filters.get(item));
+ runAfterwards.call(filters.get(item));
}
});
diff --git a/main/src/cgeo/geocaching/filter/ModifiedFilter.java b/main/src/cgeo/geocaching/filter/ModifiedFilter.java
index d976b69..2ac088a 100644
--- a/main/src/cgeo/geocaching/filter/ModifiedFilter.java
+++ b/main/src/cgeo/geocaching/filter/ModifiedFilter.java
@@ -1,8 +1,8 @@
package cgeo.geocaching.filter;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
-import cgeo.geocaching.CgeoApplication;
import java.util.Collections;
import java.util.List;
diff --git a/main/src/cgeo/geocaching/geopoint/Geopoint.java b/main/src/cgeo/geocaching/geopoint/Geopoint.java
index f21df01..e91a93d 100644
--- a/main/src/cgeo/geocaching/geopoint/Geopoint.java
+++ b/main/src/cgeo/geocaching/geopoint/Geopoint.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.ICoordinates;
import cgeo.geocaching.R;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
import android.location.Location;
import android.os.Build;
@@ -11,10 +12,13 @@ import android.os.Parcel;
import android.os.Parcelable;
/**
- * Abstraction of geographic point.
+ * Abstraction of geographic point. This class is immutable.
*/
public final class Geopoint implements ICoordinates, Parcelable {
- public static final Geopoint ZERO = new Geopoint(0.0, 0.0);
+ /**
+ * Reusable default object
+ */
+ public static final @NonNull Geopoint ZERO = new Geopoint(0.0, 0.0);
private static final double DEG_TO_RAD = Math.PI / 180;
private static final double RAD_TO_DEG = 180 / Math.PI;
@@ -64,7 +68,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
* longitude string to parse
* @throws Geopoint.ParseException
* if any argument string cannot be parsed
- * @see GeopointParser#parse(String, String)
*/
public Geopoint(final String latText, final String lonText) {
this(GeopointParser.parseLatitude(latText), GeopointParser.parseLongitude(lonText));
@@ -273,19 +276,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
}
/**
- * Checks if given Geopoint is similar to this Geopoint with tolerance.
- *
- * @param gp
- * Geopoint to check
- * @param tolerance
- * tolerance in km
- * @return true if similar, false otherwise
- */
- public boolean isEqualTo(Geopoint gp, double tolerance) {
- return null != gp && distanceTo(gp) <= tolerance;
- }
-
- /**
* Returns formatted coordinates.
*
* @param format
@@ -300,7 +290,7 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Returns formatted coordinates with default format.
* Default format is decimalminutes, e.g. N 52° 36.123 E 010° 03.456
- *
+ *
* @return formatted coordinates
*/
@Override
@@ -365,7 +355,7 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get longitude character (E or W).
- *
+ *
* @return
*/
public char getLonDir() {
diff --git a/main/src/cgeo/geocaching/geopoint/GeopointParser.java b/main/src/cgeo/geocaching/geopoint/GeopointParser.java
index c043d6f..120e02e 100644
--- a/main/src/cgeo/geocaching/geopoint/GeopointParser.java
+++ b/main/src/cgeo/geocaching/geopoint/GeopointParser.java
@@ -70,37 +70,11 @@ class GeopointParser {
}
/**
- * Parses a pair of coordinates (latitude and longitude) out of a String.
- * Accepts following formats and combinations of it:
- * X DD
- * X DD°
- * X DD° MM
- * X DD° MM.MMM
- * X DD° MM SS
- *
- * as well as:
- * DD.DDDDDDD
- *
- * Both . and , are accepted, also variable count of spaces (also 0)
- *
- * @param latitude
- * the latitude string to parse
- * @param longitude
- * the longitude string to parse
- * @return an Geopoint with parsed latitude and longitude
- * @throws Geopoint.ParseException
- * if lat or lon could not be parsed
- */
- public static Geopoint parse(final String latitude, final String longitude) {
- final double lat = parseLatitude(latitude);
- final double lon = parseLongitude(longitude);
-
- return new Geopoint(lat, lon);
- }
-
- /*
- * (non JavaDoc)
- * Helper for coordinates-parsing.
+ * Helper for coordinates-parsing
+ *
+ * @param text
+ * @param latlon
+ * @return
*/
private static ResultWrapper parseHelper(final String text, final LatLon latlon) {
diff --git a/main/src/cgeo/geocaching/geopoint/Viewport.java b/main/src/cgeo/geocaching/geopoint/Viewport.java
index 9d55f69..ba0e040 100644
--- a/main/src/cgeo/geocaching/geopoint/Viewport.java
+++ b/main/src/cgeo/geocaching/geopoint/Viewport.java
@@ -5,16 +5,15 @@ import cgeo.geocaching.ICoordinates;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
-import java.util.Set;
+import java.util.Collection;
-
-public class Viewport {
+public final class Viewport {
public final @NonNull Geopoint center;
public final @NonNull Geopoint bottomLeft;
public final @NonNull Geopoint topRight;
- public Viewport(final ICoordinates point1, final ICoordinates point2) {
+ public Viewport(final @NonNull ICoordinates point1, final @NonNull ICoordinates point2) {
final Geopoint gp1 = point1.getCoords();
final Geopoint gp2 = point2.getCoords();
this.bottomLeft = new Geopoint(Math.min(gp1.getLatitude(), gp2.getLatitude()),
@@ -25,7 +24,7 @@ public class Viewport {
(gp1.getLongitude() + gp2.getLongitude()) / 2);
}
- public Viewport(final ICoordinates center, final double latSpan, final double lonSpan) {
+ public Viewport(final @NonNull ICoordinates center, final double latSpan, final double lonSpan) {
this.center = center.getCoords();
final double centerLat = this.center.getLatitude();
final double centerLon = this.center.getLongitude();
@@ -71,7 +70,7 @@ public class Viewport {
* the coordinates to check
* @return true if the point is contained in this viewport, false otherwise or if the point contains no coordinates
*/
- public boolean contains(final ICoordinates point) {
+ public boolean contains(final @NonNull ICoordinates point) {
final Geopoint coords = point.getCoords();
return coords != null
&& coords.getLongitudeE6() >= bottomLeft.getLongitudeE6()
@@ -87,12 +86,12 @@ public class Viewport {
/**
* Check whether another viewport is fully included into the current one.
- *
+ *
* @param vp
* the other viewport
- * @return true if the vp is fully included into this one, false otherwise
+ * @return true if the viewport is fully included into this one, false otherwise
*/
- public boolean includes(final Viewport vp) {
+ public boolean includes(final @NonNull Viewport vp) {
return contains(vp.bottomLeft) && contains(vp.topRight);
}
@@ -124,46 +123,37 @@ public class Viewport {
}
/**
- * Return a viewport that contains the current viewport as well as another point.
- *
- * @param point
- * the point we want in the viewport
- * @return either the same or an expanded viewport
- */
- public Viewport expand(final ICoordinates point) {
- if (contains(point)) {
- return this;
- }
-
- final Geopoint coords = point.getCoords();
- final double latitude = coords.getLatitude();
- final double longitude = coords.getLongitude();
- final double latMin = Math.min(getLatitudeMin(), latitude);
- final double latMax = Math.max(getLatitudeMax(), latitude);
- final double lonMin = Math.min(getLongitudeMin(), longitude);
- final double lonMax = Math.max(getLongitudeMax(), longitude);
- return new Viewport(new Geopoint(latMin, lonMin), new Geopoint(latMax, lonMax));
- }
-
- /**
* Return the smallest viewport containing all the given points.
*
* @param points
* a set of points. Point with null coordinates (or null themselves) will be ignored
* @return the smallest viewport containing the non-null coordinates, or null if no coordinates are non-null
*/
- static public Viewport containing(final Set<? extends ICoordinates> points) {
- Viewport viewport = null;
+ static public @Nullable
+ Viewport containing(final Collection<? extends ICoordinates> points) {
+ boolean valid = false;
+ double latMin = Double.MAX_VALUE;
+ double latMax = -Double.MAX_VALUE;
+ double lonMin = Double.MAX_VALUE;
+ double lonMax = -Double.MAX_VALUE;
for (final ICoordinates point : points) {
- if (point != null && point.getCoords() != null) {
- if (viewport == null) {
- viewport = new Viewport(point, point);
- } else {
- viewport = viewport.expand(point);
+ if (point != null) {
+ final Geopoint coords = point.getCoords();
+ if (coords != null) {
+ valid = true;
+ final double latitude = coords.getLatitude();
+ final double longitude = coords.getLongitude();
+ latMin = Math.min(latMin, latitude);
+ latMax = Math.max(latMax, latitude);
+ lonMin = Math.min(lonMin, longitude);
+ lonMax = Math.max(lonMax, longitude);
}
}
}
- return viewport;
+ if (!valid) {
+ return null;
+ }
+ return new Viewport(new Geopoint(latMin, lonMin), new Geopoint(latMax, lonMax));
}
@Override
diff --git a/main/src/cgeo/geocaching/list/PseudoList.java b/main/src/cgeo/geocaching/list/PseudoList.java
index 365d6fd..f2cc7ed 100644
--- a/main/src/cgeo/geocaching/list/PseudoList.java
+++ b/main/src/cgeo/geocaching/list/PseudoList.java
@@ -17,6 +17,12 @@ public class PseudoList extends AbstractList {
*/
public static final AbstractList NEW_LIST = new PseudoList(NEW_LIST_ID, R.string.list_menu_create);
+ private static final int HISTORY_LIST_ID = 4;
+ /**
+ * list entry to create a new list
+ */
+ public static final AbstractList HISTORY_LIST = new PseudoList(HISTORY_LIST_ID, R.string.menu_history);
+
/**
* private constructor to have all instances as constants in the class
*/
diff --git a/main/src/cgeo/geocaching/list/StoredList.java b/main/src/cgeo/geocaching/list/StoredList.java
index 8106073..ba8ce35 100644
--- a/main/src/cgeo/geocaching/list/StoredList.java
+++ b/main/src/cgeo/geocaching/list/StoredList.java
@@ -5,11 +5,12 @@ import cgeo.geocaching.DataStore;
import cgeo.geocaching.R;
import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.ui.dialog.Dialogs;
-import cgeo.geocaching.utils.RunnableWithArgument;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import rx.util.functions.Action1;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
@@ -67,15 +68,15 @@ public final class StoredList extends AbstractList {
res = app.getResources();
}
- public void promptForListSelection(final int titleId, @NonNull final RunnableWithArgument<Integer> runAfterwards) {
+ public void promptForListSelection(final int titleId, @NonNull final Action1<Integer> runAfterwards) {
promptForListSelection(titleId, runAfterwards, false, -1);
}
- public void promptForListSelection(final int titleId, @NonNull final RunnableWithArgument<Integer> runAfterwards, final boolean onlyConcreteLists, final int exceptListId) {
+ public void promptForListSelection(final int titleId, @NonNull final Action1<Integer> runAfterwards, final boolean onlyConcreteLists, final int exceptListId) {
promptForListSelection(titleId, runAfterwards, onlyConcreteLists, exceptListId, StringUtils.EMPTY);
}
- public void promptForListSelection(final int titleId, @NonNull final RunnableWithArgument<Integer> runAfterwards, final boolean onlyConcreteLists, final int exceptListId, final String newListName) {
+ public void promptForListSelection(final int titleId, @NonNull final Action1<Integer> runAfterwards, final boolean onlyConcreteLists, final int exceptListId, final String newListName) {
final List<AbstractList> lists = new ArrayList<AbstractList>();
lists.addAll(getSortedLists());
@@ -87,7 +88,12 @@ public final class StoredList extends AbstractList {
}
if (!onlyConcreteLists) {
- lists.add(PseudoList.ALL_LIST);
+ if (exceptListId != PseudoList.ALL_LIST.id) {
+ lists.add(PseudoList.ALL_LIST);
+ }
+ if (exceptListId != PseudoList.HISTORY_LIST.id) {
+ lists.add(PseudoList.HISTORY_LIST);
+ }
}
lists.add(PseudoList.NEW_LIST);
@@ -109,7 +115,7 @@ public final class StoredList extends AbstractList {
promptForListCreation(runAfterwards, newListName);
}
else {
- runAfterwards.run(lists.get(itemId).id);
+ runAfterwards.call(lists.get(itemId).id);
}
}
});
@@ -138,17 +144,17 @@ public final class StoredList extends AbstractList {
return lists;
}
- public void promptForListCreation(@NonNull final RunnableWithArgument<Integer> runAfterwards, String newListName) {
- handleListNameInput(newListName, R.string.list_dialog_create_title, R.string.list_dialog_create, new RunnableWithArgument<String>() {
+ public void promptForListCreation(@NonNull final Action1<Integer> runAfterwards, String newListName) {
+ handleListNameInput(newListName, R.string.list_dialog_create_title, R.string.list_dialog_create, new Action1<String>() {
@Override
- public void run(final String listName) {
+ public void call(final String listName) {
final int newId = DataStore.createList(listName);
new StoredList(newId, listName, 0);
if (newId >= DataStore.customListIdOffset) {
ActivityMixin.showToast(activity, res.getString(R.string.list_dialog_create_ok));
- runAfterwards.run(newId);
+ runAfterwards.call(newId);
} else {
ActivityMixin.showToast(activity, res.getString(R.string.list_dialog_create_err));
}
@@ -156,15 +162,15 @@ public final class StoredList extends AbstractList {
});
}
- private void handleListNameInput(final String defaultValue, int dialogTitle, int buttonTitle, final RunnableWithArgument<String> runnable) {
- Dialogs.input(activity, dialogTitle, defaultValue, buttonTitle, new RunnableWithArgument<String>() {
+ private void handleListNameInput(final String defaultValue, int dialogTitle, int buttonTitle, final Action1<String> runnable) {
+ Dialogs.input(activity, dialogTitle, defaultValue, buttonTitle, new Action1<String>() {
@Override
- public void run(final String input) {
+ public void call(final String input) {
// remove whitespaces added by autocompletion of Android keyboard
String listName = StringUtils.trim(input);
if (StringUtils.isNotBlank(listName)) {
- runnable.run(listName);
+ runnable.call(listName);
}
}
});
@@ -172,10 +178,10 @@ public final class StoredList extends AbstractList {
public void promptForListRename(final int listId, @NonNull final Runnable runAfterRename) {
final StoredList list = DataStore.getList(listId);
- handleListNameInput(list.title, R.string.list_dialog_rename_title, R.string.list_dialog_rename, new RunnableWithArgument<String>() {
+ handleListNameInput(list.title, R.string.list_dialog_rename_title, R.string.list_dialog_rename, new Action1<String>() {
@Override
- public void run(final String listName) {
+ public void call(final String listName) {
DataStore.renameList(listId, listName);
runAfterRename.run();
}
@@ -197,7 +203,7 @@ public final class StoredList extends AbstractList {
* Return the given list, if it is a concrete list. Return the default list otherwise.
*/
public static int getConcreteList(int listId) {
- if (listId == PseudoList.ALL_LIST.id || listId == TEMPORARY_LIST_ID) {
+ if (listId == PseudoList.ALL_LIST.id || listId == TEMPORARY_LIST_ID || listId == PseudoList.HISTORY_LIST.id) {
return STANDARD_LIST_ID;
}
return listId;
diff --git a/main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java b/main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java
index 7524b76..e3306f3 100644
--- a/main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java
+++ b/main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java
@@ -28,6 +28,10 @@ public abstract class AbstractSearchLoader extends AsyncTaskLoader<SearchResult>
MAP,
REMOVE_FROM_HISTORY,
NEXT_PAGE;
+
+ public int getLoaderId() {
+ return ordinal();
+ }
}
private Handler recaptchaHandler = null;
diff --git a/main/src/cgeo/geocaching/loaders/AddressGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/AddressGeocacheListLoader.java
index dd7c7a6..e1573c9 100644
--- a/main/src/cgeo/geocaching/loaders/AddressGeocacheListLoader.java
+++ b/main/src/cgeo/geocaching/loaders/AddressGeocacheListLoader.java
@@ -1,8 +1,8 @@
package cgeo.geocaching.loaders;
import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.connector.gc.GCParser;
+import cgeo.geocaching.settings.Settings;
import android.content.Context;
diff --git a/main/src/cgeo/geocaching/loaders/HistoryGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/HistoryGeocacheListLoader.java
index 605f461..fdb35f2 100644
--- a/main/src/cgeo/geocaching/loaders/HistoryGeocacheListLoader.java
+++ b/main/src/cgeo/geocaching/loaders/HistoryGeocacheListLoader.java
@@ -2,9 +2,9 @@ package cgeo.geocaching.loaders;
import cgeo.geocaching.DataStore;
import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.settings.Settings;
import android.content.Context;
diff --git a/main/src/cgeo/geocaching/loaders/NextPageGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/NextPageGeocacheListLoader.java
index 1104f83..05eac18 100644
--- a/main/src/cgeo/geocaching/loaders/NextPageGeocacheListLoader.java
+++ b/main/src/cgeo/geocaching/loaders/NextPageGeocacheListLoader.java
@@ -1,8 +1,8 @@
package cgeo.geocaching.loaders;
import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.connector.gc.GCParser;
+import cgeo.geocaching.settings.Settings;
import android.content.Context;
diff --git a/main/src/cgeo/geocaching/loaders/OfflineGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/OfflineGeocacheListLoader.java
index 5088484..b80a1b8 100644
--- a/main/src/cgeo/geocaching/loaders/OfflineGeocacheListLoader.java
+++ b/main/src/cgeo/geocaching/loaders/OfflineGeocacheListLoader.java
@@ -1,9 +1,9 @@
package cgeo.geocaching.loaders;
-import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.DataStore;
+import cgeo.geocaching.SearchResult;
import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.settings.Settings;
import android.content.Context;
diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java
index c98ba72..05b05be 100644
--- a/main/src/cgeo/geocaching/maps/CGeoMap.java
+++ b/main/src/cgeo/geocaching/maps/CGeoMap.java
@@ -38,12 +38,13 @@ import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.GeoDirHandler;
import cgeo.geocaching.utils.LeastRecentlyUsedSet;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.RunnableWithArgument;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.HashCodeBuilder;
+import rx.util.functions.Action1;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
@@ -466,7 +467,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
prepareFilterBar();
- if (!app.isLiveMapHintShown() && !Settings.getHideLiveMapHint()) {
+ if (!app.isLiveMapHintShownInThisSession() && !Settings.getHideLiveMapHint() && Settings.getLiveMapHintShowCount() <= 3) {
LiveMapInfoDialogBuilder.create(activity).show();
}
}
@@ -661,9 +662,9 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
if (Settings.getChooseList()) {
// let user select list to store cache in
new StoredList.UserInterface(activity).promptForListSelection(R.string.list_title,
- new RunnableWithArgument<Integer>() {
+ new Action1<Integer>() {
@Override
- public void run(final Integer selectedListId) {
+ public void call(final Integer selectedListId) {
storeCaches(geocodes, selectedListId);
}
}, true, StoredList.TEMPORARY_LIST_ID);
@@ -898,7 +899,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
private long timeLastPositionOverlayCalculation = 0;
@Override
- protected void updateGeoData(final IGeoData geo) {
+ public void updateGeoData(final IGeoData geo) {
if (geo.isPseudoLocation()) {
locationValid = false;
} else {
@@ -1182,7 +1183,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
}
}
}
- final SearchResult searchResult = ConnectorFactory.searchByViewport(viewport.resize(0.8), tokens);
+ final SearchResult searchResult = ConnectorFactory.searchByViewport(viewport.resize(0.8), tokens).toBlockingObservable().single();
downloaded = true;
Set<Geocache> result = searchResult.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB);
diff --git a/main/src/cgeo/geocaching/maps/MapProviderFactory.java b/main/src/cgeo/geocaching/maps/MapProviderFactory.java
index 2e43e19..b928a1e 100644
--- a/main/src/cgeo/geocaching/maps/MapProviderFactory.java
+++ b/main/src/cgeo/geocaching/maps/MapProviderFactory.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.maps;
-import cgeo.geocaching.R;
import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.R;
import cgeo.geocaching.maps.google.GoogleMapProvider;
import cgeo.geocaching.maps.interfaces.MapProvider;
import cgeo.geocaching.maps.interfaces.MapSource;
diff --git a/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlay.java b/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlay.java
index 3339650..d14c687 100644
--- a/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlay.java
+++ b/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlay.java
@@ -77,11 +77,6 @@ public class GoogleCacheOverlay extends ItemizedOverlay<GoogleCacheOverlayItem>
}
@Override
- public Drawable superBoundCenter(Drawable markerIn) {
- return ItemizedOverlay.boundCenter(markerIn);
- }
-
- @Override
public Drawable superBoundCenterBottom(Drawable marker) {
return ItemizedOverlay.boundCenterBottom(marker);
}
diff --git a/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java b/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java
index cb95b2c..38d7d96 100644
--- a/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java
+++ b/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.maps.google;
-import cgeo.geocaching.R;
import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.R;
import cgeo.geocaching.maps.AbstractMapProvider;
import cgeo.geocaching.maps.AbstractMapSource;
import cgeo.geocaching.maps.interfaces.MapItemFactory;
diff --git a/main/src/cgeo/geocaching/maps/google/GoogleMapView.java b/main/src/cgeo/geocaching/maps/google/GoogleMapView.java
index d02e3c2..471e061 100644
--- a/main/src/cgeo/geocaching/maps/google/GoogleMapView.java
+++ b/main/src/cgeo/geocaching/maps/google/GoogleMapView.java
@@ -11,13 +11,11 @@ import cgeo.geocaching.maps.interfaces.MapControllerImpl;
import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
import cgeo.geocaching.maps.interfaces.MapViewImpl;
import cgeo.geocaching.maps.interfaces.OnMapDragListener;
-import cgeo.geocaching.maps.interfaces.OverlayImpl;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
-import com.google.android.maps.Overlay;
import org.apache.commons.lang3.reflect.MethodUtils;
@@ -54,7 +52,7 @@ public class GoogleMapView extends MapView implements MapViewImpl {
}
@Override
- public void draw(Canvas canvas) {
+ public void draw(final Canvas canvas) {
try {
if (getMapZoomLevel() > 22) { // to avoid too close zoom level (mostly on Samsung Galaxy S series)
getController().setZoom(22);
@@ -102,11 +100,6 @@ public class GoogleMapView extends MapView implements MapViewImpl {
}
@Override
- public void addOverlay(OverlayImpl ovl) {
- getOverlays().add((Overlay) ovl);
- }
-
- @Override
public void clearOverlays() {
getOverlays().clear();
}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/ItemizedOverlayImpl.java b/main/src/cgeo/geocaching/maps/interfaces/ItemizedOverlayImpl.java
index 90c5b31..ee61f12 100644
--- a/main/src/cgeo/geocaching/maps/interfaces/ItemizedOverlayImpl.java
+++ b/main/src/cgeo/geocaching/maps/interfaces/ItemizedOverlayImpl.java
@@ -18,8 +18,6 @@ public interface ItemizedOverlayImpl extends OverlayImpl {
void superSetLastFocusedItemIndex(int i);
- Drawable superBoundCenter(Drawable markerIn);
-
Drawable superBoundCenterBottom(Drawable marker);
boolean superOnTap(int index);
diff --git a/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java b/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java
index cb7ddc6..c30f65f 100644
--- a/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java
+++ b/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java
@@ -22,8 +22,6 @@ public interface MapViewImpl {
void clearOverlays();
- void addOverlay(OverlayImpl ovl);
-
MapControllerImpl getMapController();
void destroyDrawingCache();
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java
index 9e14e36..b9e40d7 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java
@@ -70,11 +70,6 @@ public class MapsforgeCacheOverlay extends ItemizedOverlay<MapsforgeCacheOverlay
}
@Override
- public Drawable superBoundCenter(Drawable markerIn) {
- return ItemizedOverlay.boundCenter(markerIn);
- }
-
- @Override
public Drawable superBoundCenterBottom(Drawable marker) {
return ItemizedOverlay.boundCenterBottom(marker);
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java
index 78aa47d..e993548 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java
@@ -11,7 +11,6 @@ import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
import cgeo.geocaching.maps.interfaces.MapSource;
import cgeo.geocaching.maps.interfaces.MapViewImpl;
import cgeo.geocaching.maps.interfaces.OnMapDragListener;
-import cgeo.geocaching.maps.interfaces.OverlayImpl;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
@@ -86,11 +85,6 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
}
@Override
- public void addOverlay(OverlayImpl ovl) {
- getOverlays().add((Overlay) ovl);
- }
-
- @Override
public void clearOverlays() {
getOverlays().clear();
}
@@ -229,7 +223,7 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
@Override
public void setMapTheme() {
String customRenderTheme = Settings.getCustomRenderThemeFilePath();
- if (!StringUtils.isEmpty(customRenderTheme)) {
+ if (StringUtils.isNotEmpty(customRenderTheme)) {
try {
setRenderTheme(new File(customRenderTheme));
} catch (FileNotFoundException e) {
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java
index 30355fd..a8111ed 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java
@@ -70,11 +70,6 @@ public class MapsforgeCacheOverlay extends ItemizedOverlay<MapsforgeCacheOverlay
}
@Override
- public Drawable superBoundCenter(Drawable markerIn) {
- return ItemizedOverlay.boundCenter(markerIn);
- }
-
- @Override
public Drawable superBoundCenterBottom(Drawable marker) {
return ItemizedOverlay.boundCenterBottom(marker);
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java
index c741a31..6573304 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java
@@ -10,7 +10,6 @@ import cgeo.geocaching.maps.interfaces.MapControllerImpl;
import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
import cgeo.geocaching.maps.interfaces.MapViewImpl;
import cgeo.geocaching.maps.interfaces.OnMapDragListener;
-import cgeo.geocaching.maps.interfaces.OverlayImpl;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
@@ -77,11 +76,6 @@ public class MapsforgeMapView024 extends MapView implements MapViewImpl {
}
@Override
- public void addOverlay(OverlayImpl ovl) {
- getOverlays().add((Overlay) ovl);
- }
-
- @Override
public void clearOverlays() {
getOverlays().clear();
}
diff --git a/main/src/cgeo/geocaching/network/HtmlImage.java b/main/src/cgeo/geocaching/network/HtmlImage.java
index 0daa588..774dbf6 100644
--- a/main/src/cgeo/geocaching/network/HtmlImage.java
+++ b/main/src/cgeo/geocaching/network/HtmlImage.java
@@ -6,6 +6,7 @@ import cgeo.geocaching.compatibility.Compatibility;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.files.LocalStorage;
import cgeo.geocaching.list.StoredList;
+import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.FileUtils;
import cgeo.geocaching.utils.ImageUtils;
import cgeo.geocaching.utils.Log;
@@ -14,6 +15,17 @@ import ch.boye.httpclientandroidlib.HttpResponse;
import ch.boye.httpclientandroidlib.androidextra.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.Nullable;
+import rx.Observable;
+import rx.Observable.OnSubscribeFunc;
+import rx.Observer;
+import rx.Scheduler;
+import rx.Subscription;
+import rx.concurrency.Schedulers;
+import rx.subjects.PublishSubject;
+import rx.subscriptions.CompositeSubscription;
+import rx.subscriptions.Subscriptions;
+import rx.util.functions.Func1;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -31,6 +43,11 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
public class HtmlImage implements Html.ImageGetter {
@@ -64,6 +81,14 @@ public class HtmlImage implements Html.ImageGetter {
final private int maxHeight;
final private Resources resources;
+ // Background loading
+ final private PublishSubject<Observable<String>> loading = PublishSubject.create();
+ final Observable<String> waitForEnd = Observable.merge(loading).publish().refCount();
+ final CompositeSubscription subscription = new CompositeSubscription(waitForEnd.subscribe());
+ final private Scheduler downloadScheduler = Schedulers.executor(new ThreadPoolExecutor(5, 5, 5, TimeUnit.SECONDS,
+ new LinkedBlockingQueue<Runnable>()));
+ final private Set<String> downloading = new HashSet<String>();
+
public HtmlImage(final String geocode, final boolean returnErrorImage, final int listId, final boolean onlySave) {
this.geocode = geocode;
this.returnErrorImage = returnErrorImage;
@@ -80,60 +105,71 @@ public class HtmlImage implements Html.ImageGetter {
this.resources = CgeoApplication.getInstance().getResources();
}
+ @Nullable
@Override
public BitmapDrawable getDrawable(final String url) {
+ if (!onlySave) {
+ return loadDrawable(url);
+ } else {
+ synchronized(downloading) {
+ if (!downloading.contains(url)) {
+ loading.onNext(fetchDrawable(url).map(new Func1<BitmapDrawable, String>() {
+ @Override
+ public String call(final BitmapDrawable bitmapDrawable) {
+ return url;
+ }
+ }));
+ downloading.add(url);
+ }
+ return null;
+ }
+ }
+ }
+
+ public Observable<BitmapDrawable> fetchDrawable(final String url) {
+ return Observable.create(new OnSubscribeFunc<BitmapDrawable>() {
+ @Override
+ public Subscription onSubscribe(final Observer<? super BitmapDrawable> observer) {
+ if (!subscription.isUnsubscribed()) {
+ observer.onNext(loadDrawable(url));
+ }
+ observer.onCompleted();
+ return Subscriptions.empty();
+ }
+ }).subscribeOn(downloadScheduler);
+ }
+
+ public void waitForBackgroundLoading(@Nullable final CancellableHandler handler) {
+ if (handler != null) {
+ handler.unsubscribeIfCancelled(subscription);
+ }
+ loading.onCompleted();
+ waitForEnd.toBlockingObservable().lastOrDefault(null);
+ }
+
+ private BitmapDrawable loadDrawable(final String url) {
// Reject empty and counter images URL
if (StringUtils.isBlank(url) || isCounter(url)) {
- return new BitmapDrawable(resources, getTransparent1x1Image());
+ return getTransparent1x1Image(resources);
}
final boolean shared = url.contains("/images/icons/icon_");
final String pseudoGeocode = shared ? SHARED : geocode;
- Bitmap imagePre = loadImageFromStorage(url, pseudoGeocode, shared);
+ Bitmap image = loadImageFromStorage(url, pseudoGeocode, shared);
// Download image and save it to the cache
- if (imagePre == null) {
+ if (image == null) {
final File file = LocalStorage.getStorageFile(pseudoGeocode, url, true, true);
if (url.startsWith("data:image/")) {
if (url.contains(";base64,")) {
- // TODO: when we use SDK level 8 or above, we can use the streaming version of the base64
- // Android utilities.
- byte[] decoded = Base64.decode(StringUtils.substringAfter(url, ";base64,"), Base64.DEFAULT);
- OutputStream out = null;
- try {
- out = new FileOutputStream(file);
- out.write(decoded);
- } catch (final IOException e) {
- Log.e("HtmlImage.getDrawable: cannot write file for decoded inline image", e);
- return null;
- } finally {
- IOUtils.closeQuietly(out);
- }
+ saveBase64ToFile(url, file);
} else {
Log.e("HtmlImage.getDrawable: unable to decode non-base64 inline image");
return null;
}
} else {
- final String absoluteURL = makeAbsoluteURL(url);
-
- if (absoluteURL != null) {
- try {
- final HttpResponse httpResponse = Network.getRequest(absoluteURL, null, file);
- if (httpResponse != null) {
- final int statusCode = httpResponse.getStatusLine().getStatusCode();
- if (statusCode == 200) {
- LocalStorage.saveEntityToFile(httpResponse, file);
- } else if (statusCode == 304) {
- if (!file.setLastModified(System.currentTimeMillis())) {
- makeFreshCopy(file);
- }
- }
- }
- } catch (Exception e) {
- Log.e("HtmlImage.getDrawable (downloading from web)", e);
- }
- }
+ downloadOrRefreshCopy(url, file);
}
}
@@ -142,22 +178,56 @@ public class HtmlImage implements Html.ImageGetter {
}
// now load the newly downloaded image
- if (imagePre == null) {
- imagePre = loadImageFromStorage(url, pseudoGeocode, shared);
+ if (image == null) {
+ image = loadImageFromStorage(url, pseudoGeocode, shared);
}
// get image and return
- if (imagePre == null) {
+ if (image == null) {
Log.d("HtmlImage.getDrawable: Failed to obtain image");
- if (returnErrorImage) {
- imagePre = BitmapFactory.decodeResource(resources, R.drawable.image_not_loaded);
- } else {
- imagePre = getTransparent1x1Image();
+ return returnErrorImage
+ ? new BitmapDrawable(resources, BitmapFactory.decodeResource(resources, R.drawable.image_not_loaded))
+ : getTransparent1x1Image(resources);
+ }
+
+ return ImageUtils.scaleBitmapToFitDisplay(image);
+ }
+
+ private void downloadOrRefreshCopy(final String url, final File file) {
+ final String absoluteURL = makeAbsoluteURL(url);
+
+ if (absoluteURL != null) {
+ try {
+ final HttpResponse httpResponse = Network.getRequest(absoluteURL, null, file);
+ if (httpResponse != null) {
+ final int statusCode = httpResponse.getStatusLine().getStatusCode();
+ if (statusCode == 200) {
+ LocalStorage.saveEntityToFile(httpResponse, file);
+ } else if (statusCode == 304) {
+ if (!file.setLastModified(System.currentTimeMillis())) {
+ makeFreshCopy(file);
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.e("HtmlImage.downloadOrRefreshCopy", e);
}
}
+ }
- return imagePre != null ? ImageUtils.scaleBitmapToFitDisplay(imagePre) : null;
+ private static void saveBase64ToFile(final String url, final File file) {
+ // TODO: when we use SDK level 8 or above, we can use the streaming version of the base64
+ // Android utilities.
+ OutputStream out = null;
+ try {
+ out = new FileOutputStream(file);
+ out.write(Base64.decode(StringUtils.substringAfter(url, ";base64,"), Base64.DEFAULT));
+ } catch (final IOException e) {
+ Log.e("HtmlImage.saveBase64ToFile: cannot write file for decoded inline image", e);
+ } finally {
+ IOUtils.closeQuietly(out);
+ }
}
/**
@@ -180,10 +250,11 @@ public class HtmlImage implements Html.ImageGetter {
}
}
- private Bitmap getTransparent1x1Image() {
- return BitmapFactory.decodeResource(resources, R.drawable.image_no_placement);
+ private BitmapDrawable getTransparent1x1Image(final Resources res) {
+ return new BitmapDrawable(res, BitmapFactory.decodeResource(resources, R.drawable.image_no_placement));
}
+ @Nullable
private Bitmap loadImageFromStorage(final String url, final String pseudoGeocode, final boolean forceKeep) {
try {
final File file = LocalStorage.getStorageFile(pseudoGeocode, url, true, false);
@@ -194,11 +265,12 @@ public class HtmlImage implements Html.ImageGetter {
final File fileSec = LocalStorage.getStorageSecFile(pseudoGeocode, url, true);
return loadCachedImage(fileSec, forceKeep);
} catch (Exception e) {
- Log.w("HtmlImage.getDrawable (reading cache)", e);
+ Log.w("HtmlImage.loadImageFromStorage", e);
}
return null;
}
+ @Nullable
private String makeAbsoluteURL(final String url) {
// Check if uri is absolute or not, if not attach the connector hostname
// FIXME: that should also include the scheme
@@ -222,6 +294,7 @@ public class HtmlImage implements Html.ImageGetter {
return null;
}
+ @Nullable
private Bitmap loadCachedImage(final File file, final boolean forceKeep) {
if (file.exists()) {
if (listId >= StoredList.STANDARD_LIST_ID || file.lastModified() > (new Date().getTime() - (24 * 60 * 60 * 1000)) || forceKeep) {
diff --git a/main/src/cgeo/geocaching/network/Network.java b/main/src/cgeo/geocaching/network/Network.java
index e891d3b..b737fd2 100644
--- a/main/src/cgeo/geocaching/network/Network.java
+++ b/main/src/cgeo/geocaching/network/Network.java
@@ -34,7 +34,6 @@ import ch.boye.httpclientandroidlib.params.CoreProtocolPNames;
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.eclipse.jdt.annotation.Nullable;
diff --git a/main/src/cgeo/geocaching/network/OAuth.java b/main/src/cgeo/geocaching/network/OAuth.java
index c033660..1e22551 100644
--- a/main/src/cgeo/geocaching/network/OAuth.java
+++ b/main/src/cgeo/geocaching/network/OAuth.java
@@ -3,7 +3,6 @@ package cgeo.geocaching.network;
import cgeo.geocaching.utils.CryptUtils;
import ch.boye.httpclientandroidlib.NameValuePair;
-
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
diff --git a/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java b/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java
index 888cf77..fd6ccc6 100644
--- a/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java
+++ b/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java
@@ -10,7 +10,6 @@ import cgeo.geocaching.utils.MatcherWrapper;
import ch.boye.httpclientandroidlib.ParseException;
import ch.boye.httpclientandroidlib.client.entity.UrlEncodedFormEntity;
import ch.boye.httpclientandroidlib.util.EntityUtils;
-
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.eclipse.jdt.annotation.NonNull;
diff --git a/main/src/cgeo/geocaching/network/StatusUpdater.java b/main/src/cgeo/geocaching/network/StatusUpdater.java
index cb4c7f4..2d565bf 100644
--- a/main/src/cgeo/geocaching/network/StatusUpdater.java
+++ b/main/src/cgeo/geocaching/network/StatusUpdater.java
@@ -1,21 +1,22 @@
package cgeo.geocaching.network;
import cgeo.geocaching.CgeoApplication;
-import cgeo.geocaching.utils.MemorySubject;
-import cgeo.geocaching.utils.PeriodicHandler;
-import cgeo.geocaching.utils.PeriodicHandler.PeriodicHandlerListener;
import cgeo.geocaching.utils.Version;
import org.json.JSONException;
import org.json.JSONObject;
+import rx.Observable;
+import rx.concurrency.Schedulers;
+import rx.subjects.BehaviorSubject;
+import rx.util.functions.Func1;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
-import android.os.Looper;
import java.util.Locale;
+import java.util.concurrent.TimeUnit;
-public class StatusUpdater extends MemorySubject<StatusUpdater.Status> implements Runnable, PeriodicHandlerListener {
+public class StatusUpdater {
static public class Status {
final public String message;
@@ -30,24 +31,41 @@ public class StatusUpdater extends MemorySubject<StatusUpdater.Status> implement
this.url = url;
}
+ Status(final JSONObject response) {
+ message = get(response, "message");
+ messageId = get(response, "message_id");
+ icon = get(response, "icon");
+ url = get(response, "url");
+ }
+
final static public Status closeoutStatus =
new Status("", "status_closeout_warning", "attribute_abandonedbuilding", "http://faq.cgeo.org/#7_69");
- final static public Status defaultStatus() {
+ final static public Status defaultStatus(final Status upToDate) {
+ if (upToDate != null && upToDate.message != null) {
+ return upToDate;
+ }
return VERSION.SDK_INT < VERSION_CODES.ECLAIR_MR1 ? closeoutStatus : null;
}
}
- @Override
- public void onPeriodic() {
- final JSONObject response =
- Network.requestJSON("http://status.cgeo.org/api/status.json",
- new Parameters("version_code", String.valueOf(Version.getVersionCode(CgeoApplication.getInstance())),
- "version_name", Version.getVersionName(CgeoApplication.getInstance()),
- "locale", Locale.getDefault().toString()));
- if (response != null) {
- notifyObservers(new Status(get(response, "message"), get(response, "message_id"), get(response, "icon"), get(response, "url")));
- }
+ final static private Observable<Status> statusObservable =
+ Observable.interval(1800, TimeUnit.SECONDS).startWith(-1L).flatMap(new Func1<Long, Observable<Status>>() {
+ @Override
+ public Observable<Status> call(Long id) {
+ final JSONObject response =
+ Network.requestJSON("http://status.cgeo.org/api/status.json",
+ new Parameters("version_code", String.valueOf(Version.getVersionCode(CgeoApplication.getInstance())),
+ "version_name", Version.getVersionName(CgeoApplication.getInstance()),
+ "locale", Locale.getDefault().toString()));
+ return response != null ? Observable.from(Status.defaultStatus((new Status(response)))) : Observable.<Status>empty();
+ }
+ }).subscribeOn(Schedulers.threadPoolForIO());
+
+ final static public BehaviorSubject<Status> latestStatus = BehaviorSubject.create(Status.defaultStatus(null));
+
+ static {
+ statusObservable.subscribe(latestStatus);
}
private static String get(final JSONObject json, final String key) {
@@ -58,11 +76,4 @@ public class StatusUpdater extends MemorySubject<StatusUpdater.Status> implement
}
}
- @Override
- public void run() {
- Looper.prepare();
- new PeriodicHandler(1800000L, this).start();
- Looper.loop();
- }
-
}
diff --git a/main/src/cgeo/geocaching/search/AutoCompleteAdapter.java b/main/src/cgeo/geocaching/search/AutoCompleteAdapter.java
new file mode 100644
index 0000000..123469c
--- /dev/null
+++ b/main/src/cgeo/geocaching/search/AutoCompleteAdapter.java
@@ -0,0 +1,71 @@
+package cgeo.geocaching.search;
+
+import org.apache.commons.lang3.StringUtils;
+
+import rx.util.functions.Func1;
+
+import android.content.Context;
+import android.widget.ArrayAdapter;
+import android.widget.Filter;
+
+/**
+ * The standard auto completion only matches user input at word boundaries. Therefore searching "est" will not match
+ * "test". This adapter matches everywhere.
+ *
+ */
+public class AutoCompleteAdapter extends ArrayAdapter<String> {
+
+ private String[] suggestions;
+ private final Func1<String, String[]> suggestionFunction;
+
+ public AutoCompleteAdapter(Context context, int textViewResourceId, final Func1<String, String[]> suggestionFunction) {
+ super(context, textViewResourceId);
+ this.suggestionFunction = suggestionFunction;
+ }
+
+ @Override
+ public int getCount() {
+ return suggestions.length;
+ }
+
+ @Override
+ public String getItem(int index) {
+ return suggestions[index];
+ }
+
+ @Override
+ public Filter getFilter() {
+ Filter filter = new Filter() {
+
+ @Override
+ protected FilterResults performFiltering(CharSequence constraint) {
+ FilterResults filterResults = new FilterResults();
+ if (constraint == null) {
+ return filterResults;
+ }
+ String trimmed = StringUtils.trim(constraint.toString());
+ if (StringUtils.length(trimmed) >= 2) {
+ String[] newResults = suggestionFunction.call(trimmed);
+
+ // Assign the data to the FilterResults, but do not yet store in the global member.
+ // Otherwise we might invalidate the adapter and cause an IllegalStateException.
+ filterResults.values = newResults;
+ filterResults.count = newResults.length;
+ }
+ return filterResults;
+ }
+
+ @Override
+ protected void publishResults(CharSequence constraint, FilterResults filterResults) {
+ if (filterResults != null && filterResults.count > 0) {
+ suggestions = (String[]) filterResults.values;
+ notifyDataSetChanged();
+ }
+ else {
+ notifyDataSetInvalidated();
+ }
+ }
+ };
+ return filter;
+ }
+} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/search/SuggestionProvider.java b/main/src/cgeo/geocaching/search/SuggestionProvider.java
new file mode 100644
index 0000000..c0a7728
--- /dev/null
+++ b/main/src/cgeo/geocaching/search/SuggestionProvider.java
@@ -0,0 +1,57 @@
+package cgeo.geocaching.search;
+
+import cgeo.geocaching.DataStore;
+
+import org.apache.commons.lang3.StringUtils;
+
+import android.app.SearchManager;
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class SuggestionProvider extends ContentProvider {
+
+ private static Cursor lastCursor;
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public String getType(final Uri arg0) {
+ return SearchManager.SUGGEST_MIME_TYPE;
+ }
+
+ @Override
+ public Cursor query(final Uri uri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder) {
+ final String searchTerm = uri.getLastPathSegment();
+ // can be empty when deleting the query
+ if (StringUtils.equals(searchTerm, SearchManager.SUGGEST_URI_PATH_QUERY)) {
+ return lastCursor;
+ }
+ return getSuggestions(searchTerm);
+ }
+
+ private static Cursor getSuggestions(final String searchTerm) {
+ lastCursor = DataStore.findSuggestions(searchTerm);
+ return lastCursor;
+ }
+
+ @Override
+ public int delete(final Uri uri, final String selection, final String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Uri insert(final Uri uri, final ContentValues values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int update(final Uri uri, final ContentValues values, final String selection, final String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/settings/OAuthPreference.java b/main/src/cgeo/geocaching/settings/OAuthPreference.java
index 3550947..06982f5 100644
--- a/main/src/cgeo/geocaching/settings/OAuthPreference.java
+++ b/main/src/cgeo/geocaching/settings/OAuthPreference.java
@@ -23,8 +23,8 @@ public class OAuthPreference extends Preference {
OCPL(R.string.pref_fakekey_ocpl_authorization, OCPLAuthorizationActivity.class),
TWITTER(R.string.pref_fakekey_twitter_authorization, TwitterAuthorizationActivity.class);
- public int prefKeyId;
- public Class<?> authActivity;
+ public final int prefKeyId;
+ public final Class<?> authActivity;
OAuthActivityMapping(int prefKeyId, Class<?> clazz) {
this.prefKeyId = prefKeyId;
diff --git a/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java b/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java
index 3e838ab..2ca8df1 100644
--- a/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java
+++ b/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java
@@ -8,7 +8,6 @@ import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.lang3.StringUtils;
import android.app.ProgressDialog;
diff --git a/main/src/cgeo/geocaching/settings/Settings.java b/main/src/cgeo/geocaching/settings/Settings.java
index 0732866..ee97c13 100644
--- a/main/src/cgeo/geocaching/settings/Settings.java
+++ b/main/src/cgeo/geocaching/settings/Settings.java
@@ -313,16 +313,16 @@ public class Settings {
return getBoolean(R.string.pref_connectorOXActive, false);
}
- public static boolean isPremiumMember() {
+ public static boolean isGCPremiumMember() {
// Basic Member, Premium Member, ???
- return GCConstants.MEMBER_STATUS_PM.equalsIgnoreCase(Settings.getMemberStatus());
+ return GCConstants.MEMBER_STATUS_PM.equalsIgnoreCase(Settings.getGCMemberStatus());
}
- public static String getMemberStatus() {
+ public static String getGCMemberStatus() {
return getString(R.string.pref_memberstatus, "");
}
- public static boolean setMemberStatus(final String memberStatus) {
+ public static boolean setGCMemberStatus(final String memberStatus) {
if (StringUtils.isBlank(memberStatus)) {
return remove(R.string.pref_memberstatus);
}
@@ -478,7 +478,7 @@ public class Settings {
}
public static boolean getLoadDirImg() {
- return !isPremiumMember() && getBoolean(R.string.pref_loaddirectionimg, true);
+ return !isGCPremiumMember() && getBoolean(R.string.pref_loaddirectionimg, true);
}
public static void setGcCustomDate(final String format) {
@@ -506,7 +506,7 @@ public class Settings {
}
public static boolean isShowCaptcha() {
- return !isPremiumMember() && getBoolean(R.string.pref_showcaptcha, false);
+ return !isGCPremiumMember() && getBoolean(R.string.pref_showcaptcha, false);
}
public static boolean isExcludeDisabledCaches() {
diff --git a/main/src/cgeo/geocaching/settings/SettingsActivity.java b/main/src/cgeo/geocaching/settings/SettingsActivity.java
index 58acfc1..bcf6715 100644
--- a/main/src/cgeo/geocaching/settings/SettingsActivity.java
+++ b/main/src/cgeo/geocaching/settings/SettingsActivity.java
@@ -1,6 +1,7 @@
package cgeo.geocaching.settings;
import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.DataStore;
import cgeo.geocaching.Intents;
import cgeo.geocaching.R;
import cgeo.geocaching.SelectMapfileActivity;
@@ -19,8 +20,10 @@ import cgeo.geocaching.utils.Log;
import org.apache.commons.lang3.StringUtils;
import org.openintents.intents.FileManagerIntents;
+import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -52,8 +55,7 @@ import java.util.Locale;
*/
public class SettingsActivity extends PreferenceActivity {
- private static final String INTENT_GOTO = "GOTO";
- private static final int INTENT_GOTO_SERVICES = 1;
+ private static final String INTENT_OPEN_SCREEN = "OPEN_SCREEN";
/**
* Enumeration for directory choosers. This is how we can retrieve information about the
@@ -89,18 +91,21 @@ public class SettingsActivity extends PreferenceActivity {
initPreferences();
Intent intent = getIntent();
- int gotoPage = intent.getIntExtra(INTENT_GOTO, 0);
- if (gotoPage == INTENT_GOTO_SERVICES) {
- // start with services screen
- PreferenceScreen main = (PreferenceScreen) getPreference(R.string.pref_fakekey_main_screen);
- try {
- if (main != null) {
- int index = getPreference(R.string.pref_fakekey_services_screen).getOrder();
- main.onItemClick(null, null, index, 0);
- }
- } catch (RuntimeException e) {
- Log.e("could not open services preferences", e);
- }
+ openInitialScreen(intent.getIntExtra(INTENT_OPEN_SCREEN, 0));
+ }
+
+ private void openInitialScreen(int initialScreen) {
+ if (initialScreen == 0) {
+ return;
+ }
+ PreferenceScreen screen = (PreferenceScreen) getPreference(initialScreen);
+ if (screen == null) {
+ return;
+ }
+ try {
+ setPreferenceScreen(screen);
+ } catch (RuntimeException e) {
+ Log.e("could not open preferences " + initialScreen, e);
}
}
@@ -121,6 +126,7 @@ public class SettingsActivity extends PreferenceActivity {
initSend2CgeoPreferences();
initServicePreferences();
initNavigationMenuPreferences();
+ initMaintenanceButtons();
for (int k : new int[] { R.string.pref_username, R.string.pref_password,
R.string.pref_pass_vote, R.string.pref_signature,
@@ -141,9 +147,9 @@ public class SettingsActivity extends PreferenceActivity {
getPreference(appEnum.preferenceKey).setEnabled(true);
}
}
- getPreference(R.string.pref_fakekey_basicmembers_screen)
- .setEnabled(!Settings.isPremiumMember());
- redrawScreen(R.string.pref_fakekey_navigation_menu_screen);
+ getPreference(R.string.preference_screen_basicmembers)
+ .setEnabled(!Settings.isGCPremiumMember());
+ redrawScreen(R.string.preference_screen_navigation_menu);
}
private void initServicePreferences() {
@@ -310,6 +316,35 @@ public class SettingsActivity extends PreferenceActivity {
});
}
+ public void initMaintenanceButtons() {
+ Preference dirMaintenance = getPreference(R.string.pref_fakekey_preference_maintenance_directories);
+ dirMaintenance.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(final Preference preference) {
+ // disable the button, as the cleanup runs in background and should not be invoked a second time
+ preference.setEnabled(false);
+
+ Resources res = getResources();
+ final SettingsActivity activity = SettingsActivity.this;
+ final ProgressDialog dialog = ProgressDialog.show(activity, res.getString(R.string.init_maintenance), res.getString(R.string.init_maintenance_directories), true, false);
+ new Thread() {
+ @Override
+ public void run() {
+ DataStore.removeObsoleteCacheDirectories();
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ dialog.dismiss();
+ }
+ });
+ }
+ }.start();
+
+ return true;
+ }
+ });
+ }
+
private void initDbLocationPreference() {
Preference p = getPreference(R.string.pref_dbonsdcard);
p.setPersistent(false);
@@ -336,21 +371,29 @@ public class SettingsActivity extends PreferenceActivity {
}
void initBasicMemberPreferences() {
- getPreference(R.string.pref_fakekey_basicmembers_screen)
- .setEnabled(!Settings.isPremiumMember());
+ getPreference(R.string.preference_screen_basicmembers)
+ .setEnabled(!Settings.isGCPremiumMember());
getPreference(R.string.pref_loaddirectionimg)
- .setEnabled(!Settings.isPremiumMember());
+ .setEnabled(!Settings.isGCPremiumMember());
getPreference(R.string.pref_showcaptcha)
- .setEnabled(!Settings.isPremiumMember());
+ .setEnabled(!Settings.isGCPremiumMember());
- redrawScreen(R.string.pref_fakekey_services_screen);
+ redrawScreen(R.string.preference_screen_services);
}
- void redrawScreen(int key) {
- PreferenceScreen screen = (PreferenceScreen) getPreference(key);
- if (screen == null) {
+ /**
+ * Refresh a preference screen. Has no effect when called for a preference, that is not actually a preference
+ * screen.
+ *
+ * @param key
+ * Key of a preference screen.
+ */
+ void redrawScreen(final int key) {
+ final Preference preference = getPreference(key);
+ if (!(preference instanceof PreferenceScreen)) {
return;
}
+ final PreferenceScreen screen = (PreferenceScreen) preference;
ListAdapter adapter = screen.getRootAdapter();
if (adapter instanceof BaseAdapter) {
((BaseAdapter) adapter).notifyDataSetChanged();
@@ -399,9 +442,9 @@ public class SettingsActivity extends PreferenceActivity {
: R.string.settings_authorize));
}
- public static void jumpToServicesPage(final Context fromActivity) {
+ public static void openForScreen(final int preferenceScreenKey, final Context fromActivity) {
final Intent intent = new Intent(fromActivity, SettingsActivity.class);
- intent.putExtra(INTENT_GOTO, INTENT_GOTO_SERVICES);
+ intent.putExtra(INTENT_OPEN_SCREEN, preferenceScreenKey);
fromActivity.startActivity(intent);
}
@@ -445,15 +488,15 @@ public class SettingsActivity extends PreferenceActivity {
break;
case R.string.pref_fakekey_ocde_authorization:
setOCDEAuthTitle();
- redrawScreen(R.string.pref_fakekey_services_screen);
+ redrawScreen(R.string.preference_screen_ocde);
break;
case R.string.pref_fakekey_ocpl_authorization:
setOCPLAuthTitle();
- redrawScreen(R.string.pref_fakekey_services_screen);
+ redrawScreen(R.string.preference_screen_ocpl);
break;
case R.string.pref_fakekey_twitter_authorization:
setTwitterAuthTitle();
- redrawScreen(R.string.pref_fakekey_services_screen);
+ redrawScreen(R.string.preference_screen_twitter);
break;
default:
throw new IllegalArgumentException();
@@ -582,6 +625,13 @@ public class SettingsActivity extends PreferenceActivity {
preferenceActivity.addPreferencesFromResource(preferencesResId);
}
+ @SuppressWarnings("deprecation")
+ @Override
+ public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
+ // TODO replace with fragment based code
+ super.setPreferenceScreen(preferenceScreen);
+ }
+
private static boolean isPreference(final Preference preference, int preferenceKeyId) {
return getKey(preferenceKeyId).equals(preference.getKey());
}
diff --git a/main/src/cgeo/geocaching/settings/TemplateTextPreference.java b/main/src/cgeo/geocaching/settings/TemplateTextPreference.java
index a703231..667b02b 100644
--- a/main/src/cgeo/geocaching/settings/TemplateTextPreference.java
+++ b/main/src/cgeo/geocaching/settings/TemplateTextPreference.java
@@ -2,6 +2,7 @@ package cgeo.geocaching.settings;
import cgeo.geocaching.R;
import cgeo.geocaching.activity.ActivityMixin;
+import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.LogTemplateProvider;
import cgeo.geocaching.utils.LogTemplateProvider.LogTemplate;
@@ -49,6 +50,7 @@ public class TemplateTextPreference extends DialogPreference {
editText = (EditText) view.findViewById(R.id.signature_dialog_text);
editText.setText(getPersistedString(initialValue != null ? initialValue : StringUtils.EMPTY));
+ Dialogs.moveCursorToEnd(editText);
Button button = (Button) view.findViewById(R.id.signature_templates);
button.setOnClickListener(new View.OnClickListener() {
diff --git a/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java b/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java
index a1c04a4..2b171b4 100644
--- a/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java
+++ b/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java
@@ -3,6 +3,7 @@ package cgeo.geocaching.sorting;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.utils.Log;
+import org.apache.commons.lang3.StringUtils;
/**
* abstract super implementation for all cache comparators
@@ -13,25 +14,35 @@ public abstract class AbstractCacheComparator implements CacheComparator {
@Override
public final int compare(final Geocache cache1, final Geocache cache2) {
try {
- // first check that we have all necessary data for the comparison
- if (!canCompare(cache1, cache2)) {
- return 0;
+ final boolean canCompare1 = canCompare(cache1);
+ final boolean canCompare2 = canCompare(cache2);
+ if (!canCompare1) {
+ return canCompare2 ? 1 : fallbackToGeocode(cache1, cache2);
}
- return compareCaches(cache1, cache2);
- } catch (Exception e) {
+ return canCompare2 ? compareCaches(cache1, cache2) : -1;
+ } catch (final Exception e) {
Log.e("AbstractCacheComparator.compare", e);
+ // This may violate the Comparator interface if the exception is not systematic.
+ return fallbackToGeocode(cache1, cache2);
}
- return 0;
+ }
+
+ private static int fallbackToGeocode(final Geocache cache1, final Geocache cache2) {
+ return StringUtils.defaultString(cache1.getGeocode()).compareToIgnoreCase(StringUtils.defaultString(cache2.getGeocode()));
}
/**
- * Check necessary preconditions (like missing fields) before running the comparison itself
- *
- * @param cache1
- * @param cache2
- * @return
+ * Check necessary preconditions (like missing fields) before running the comparison itself.
+ * Caches not filling the conditions will be placed last, sorted by Geocode.
+ *
+ * The default returns <code>true</code> and can be overridden if needed in child classes.
+ *
+ * @param cache
+ * @return <code>true</code> if the cache holds the necessary data to be compared meaningfully
*/
- protected abstract boolean canCompare(final Geocache cache1, final Geocache cache2);
+ protected boolean canCompare(final Geocache cache) {
+ return true;
+ }
/**
* Compares two caches. Logging and exception handling is implemented outside this method already.
diff --git a/main/src/cgeo/geocaching/sorting/CacheComparator.java b/main/src/cgeo/geocaching/sorting/CacheComparator.java
index 7932729..b06a4b0 100644
--- a/main/src/cgeo/geocaching/sorting/CacheComparator.java
+++ b/main/src/cgeo/geocaching/sorting/CacheComparator.java
@@ -1,9 +1,9 @@
package cgeo.geocaching.sorting;
-import java.util.Comparator;
-
import cgeo.geocaching.Geocache;
+import java.util.Comparator;
+
public interface CacheComparator extends Comparator<Geocache> {
}
diff --git a/main/src/cgeo/geocaching/sorting/ComparatorUserInterface.java b/main/src/cgeo/geocaching/sorting/ComparatorUserInterface.java
index 99a535a..8cf3d9d 100644
--- a/main/src/cgeo/geocaching/sorting/ComparatorUserInterface.java
+++ b/main/src/cgeo/geocaching/sorting/ComparatorUserInterface.java
@@ -2,7 +2,8 @@ package cgeo.geocaching.sorting;
import cgeo.geocaching.R;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.RunnableWithArgument;
+
+import rx.util.functions.Action1;
import android.app.Activity;
import android.app.AlertDialog;
@@ -70,7 +71,7 @@ public class ComparatorUserInterface {
registry.add(new ComparatorEntry(res.getString(resourceId), comparatorClass));
}
- public void selectComparator(final CacheComparator current, final RunnableWithArgument<CacheComparator> runAfterwards) {
+ public void selectComparator(final CacheComparator current, final Action1<CacheComparator> runAfterwards) {
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(R.string.caches_sort_title);
@@ -85,11 +86,11 @@ public class ComparatorUserInterface {
ComparatorEntry entry = registry.get(itemIndex);
try {
if (entry.cacheComparator == null) {
- runAfterwards.run(null);
+ runAfterwards.call(null);
}
else {
CacheComparator comparator = entry.cacheComparator.newInstance();
- runAfterwards.run(comparator);
+ runAfterwards.call(comparator);
}
} catch (InstantiationException e) {
Log.e("selectComparator", e);
diff --git a/main/src/cgeo/geocaching/sorting/DateComparator.java b/main/src/cgeo/geocaching/sorting/DateComparator.java
index 091f6a4..9df70f9 100644
--- a/main/src/cgeo/geocaching/sorting/DateComparator.java
+++ b/main/src/cgeo/geocaching/sorting/DateComparator.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.sorting;
-import cgeo.geocaching.Geocache;
import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.Geocache;
import java.util.ArrayList;
import java.util.Date;
@@ -12,11 +12,6 @@ import java.util.Date;
public class DateComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache1, Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(Geocache cache1, Geocache cache2) {
final Date date1 = cache1.getHiddenDate();
final Date date2 = cache2.getHiddenDate();
diff --git a/main/src/cgeo/geocaching/sorting/DifficultyComparator.java b/main/src/cgeo/geocaching/sorting/DifficultyComparator.java
index 73d12fa..459f38d 100644
--- a/main/src/cgeo/geocaching/sorting/DifficultyComparator.java
+++ b/main/src/cgeo/geocaching/sorting/DifficultyComparator.java
@@ -9,8 +9,8 @@ import cgeo.geocaching.Geocache;
public class DifficultyComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache1, Geocache cache2) {
- return cache1.getDifficulty() != 0.0 && cache2.getDifficulty() != 0.0;
+ protected boolean canCompare(Geocache cache) {
+ return cache.getDifficulty() != 0.0;
}
@Override
diff --git a/main/src/cgeo/geocaching/sorting/DistanceComparator.java b/main/src/cgeo/geocaching/sorting/DistanceComparator.java
index 731e356..541ce48 100644
--- a/main/src/cgeo/geocaching/sorting/DistanceComparator.java
+++ b/main/src/cgeo/geocaching/sorting/DistanceComparator.java
@@ -36,11 +36,6 @@ public class DistanceComparator extends AbstractCacheComparator {
}
@Override
- protected boolean canCompare(Geocache cache1, Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
calculateAllDistances();
final Float distance1 = cache1.getDistance();
diff --git a/main/src/cgeo/geocaching/sorting/FindsComparator.java b/main/src/cgeo/geocaching/sorting/FindsComparator.java
index c889776..7f2ef50 100644
--- a/main/src/cgeo/geocaching/sorting/FindsComparator.java
+++ b/main/src/cgeo/geocaching/sorting/FindsComparator.java
@@ -5,8 +5,8 @@ import cgeo.geocaching.Geocache;
public class FindsComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache1, Geocache cache2) {
- return cache1.getLogCounts() != null && cache2.getLogCounts() != null;
+ protected boolean canCompare(Geocache cache) {
+ return cache.getLogCounts() != null;
}
@Override
diff --git a/main/src/cgeo/geocaching/sorting/GeocodeComparator.java b/main/src/cgeo/geocaching/sorting/GeocodeComparator.java
index fff26c6..e700f13 100644
--- a/main/src/cgeo/geocaching/sorting/GeocodeComparator.java
+++ b/main/src/cgeo/geocaching/sorting/GeocodeComparator.java
@@ -2,23 +2,20 @@ package cgeo.geocaching.sorting;
import cgeo.geocaching.Geocache;
-import org.apache.commons.lang3.StringUtils;
-
/**
* sorts caches by geo code, therefore effectively sorting by cache age
- *
+ *
*/
public class GeocodeComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache1, Geocache cache2) {
- return StringUtils.isNotBlank(cache1.getGeocode())
- && StringUtils.isNotBlank(cache2.getGeocode());
+ protected boolean canCompare(final Geocache cache) {
+ // This will fall back to geocode comparisons.
+ return false;
}
@Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
- final int lengthDiff = cache1.getGeocode().length() - cache2.getGeocode().length();
- return lengthDiff != 0 ? lengthDiff : cache1.getGeocode().compareToIgnoreCase(cache2.getGeocode());
+ throw new RuntimeException("should never be called");
}
}
diff --git a/main/src/cgeo/geocaching/sorting/InventoryComparator.java b/main/src/cgeo/geocaching/sorting/InventoryComparator.java
index 73ea2c5..9d19b64 100644
--- a/main/src/cgeo/geocaching/sorting/InventoryComparator.java
+++ b/main/src/cgeo/geocaching/sorting/InventoryComparator.java
@@ -8,11 +8,6 @@ import cgeo.geocaching.Geocache;
public class InventoryComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(final Geocache cache1, final Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
return cache2.getInventoryItems() - cache1.getInventoryItems();
}
diff --git a/main/src/cgeo/geocaching/sorting/NameComparator.java b/main/src/cgeo/geocaching/sorting/NameComparator.java
index b432ad0..2941b1c 100644
--- a/main/src/cgeo/geocaching/sorting/NameComparator.java
+++ b/main/src/cgeo/geocaching/sorting/NameComparator.java
@@ -11,8 +11,8 @@ import org.apache.commons.lang3.StringUtils;
public class NameComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache1, Geocache cache2) {
- return StringUtils.isNotBlank(cache1.getName()) && StringUtils.isNotBlank(cache2.getName());
+ protected boolean canCompare(Geocache cache) {
+ return StringUtils.isNotBlank(cache.getName());
}
@Override
diff --git a/main/src/cgeo/geocaching/sorting/PopularityComparator.java b/main/src/cgeo/geocaching/sorting/PopularityComparator.java
index e256654..2dbee68 100644
--- a/main/src/cgeo/geocaching/sorting/PopularityComparator.java
+++ b/main/src/cgeo/geocaching/sorting/PopularityComparator.java
@@ -9,11 +9,6 @@ import cgeo.geocaching.Geocache;
public class PopularityComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(final Geocache cache1, final Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
return cache2.getFavoritePoints() - cache1.getFavoritePoints();
}
diff --git a/main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java b/main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java
index f438762..1ed8e68 100644
--- a/main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java
+++ b/main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java
@@ -11,11 +11,6 @@ import cgeo.geocaching.Geocache;
public class PopularityRatioComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(final Geocache cache1, final Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
float ratio1 = 0.0f;
diff --git a/main/src/cgeo/geocaching/sorting/RatingComparator.java b/main/src/cgeo/geocaching/sorting/RatingComparator.java
index 72cf6c8..6f2c615 100644
--- a/main/src/cgeo/geocaching/sorting/RatingComparator.java
+++ b/main/src/cgeo/geocaching/sorting/RatingComparator.java
@@ -9,11 +9,6 @@ import cgeo.geocaching.Geocache;
public class RatingComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(final Geocache cache1, final Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
final float rating1 = cache1.getRating();
final float rating2 = cache2.getRating();
diff --git a/main/src/cgeo/geocaching/sorting/SizeComparator.java b/main/src/cgeo/geocaching/sorting/SizeComparator.java
index d128822..c8de586 100644
--- a/main/src/cgeo/geocaching/sorting/SizeComparator.java
+++ b/main/src/cgeo/geocaching/sorting/SizeComparator.java
@@ -9,8 +9,8 @@ import cgeo.geocaching.Geocache;
public class SizeComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache1, Geocache cache2) {
- return cache1.getSize() != null && cache2.getSize() != null;
+ protected boolean canCompare(Geocache cache) {
+ return cache.getSize() != null;
}
@Override
diff --git a/main/src/cgeo/geocaching/sorting/StateComparator.java b/main/src/cgeo/geocaching/sorting/StateComparator.java
index b99c3c0..9488bd9 100644
--- a/main/src/cgeo/geocaching/sorting/StateComparator.java
+++ b/main/src/cgeo/geocaching/sorting/StateComparator.java
@@ -9,11 +9,6 @@ import cgeo.geocaching.Geocache;
public class StateComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(final Geocache cache1, final Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
return getState(cache1) - getState(cache2);
}
diff --git a/main/src/cgeo/geocaching/sorting/StorageTimeComparator.java b/main/src/cgeo/geocaching/sorting/StorageTimeComparator.java
index 78ba742..b718d3b 100644
--- a/main/src/cgeo/geocaching/sorting/StorageTimeComparator.java
+++ b/main/src/cgeo/geocaching/sorting/StorageTimeComparator.java
@@ -5,11 +5,6 @@ import cgeo.geocaching.Geocache;
public class StorageTimeComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache1, Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(Geocache cache1, Geocache cache2) {
if (cache1.getUpdated() < cache2.getUpdated()) {
return -1;
diff --git a/main/src/cgeo/geocaching/sorting/TerrainComparator.java b/main/src/cgeo/geocaching/sorting/TerrainComparator.java
index be1e9bb..9bbb5f7 100644
--- a/main/src/cgeo/geocaching/sorting/TerrainComparator.java
+++ b/main/src/cgeo/geocaching/sorting/TerrainComparator.java
@@ -9,8 +9,8 @@ import cgeo.geocaching.Geocache;
public class TerrainComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(final Geocache cache1, final Geocache cache2) {
- return cache1.getTerrain() != 0.0 && cache2.getTerrain() != 0.0;
+ protected boolean canCompare(final Geocache cache) {
+ return cache.getTerrain() != 0.0;
}
@Override
diff --git a/main/src/cgeo/geocaching/sorting/VisitComparator.java b/main/src/cgeo/geocaching/sorting/VisitComparator.java
index 27d3170..1589a4c 100644
--- a/main/src/cgeo/geocaching/sorting/VisitComparator.java
+++ b/main/src/cgeo/geocaching/sorting/VisitComparator.java
@@ -9,11 +9,6 @@ import cgeo.geocaching.Geocache;
public class VisitComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(final Geocache cache1, final Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
return Long.valueOf(cache2.getVisitedDate()).compareTo(cache1.getVisitedDate());
}
diff --git a/main/src/cgeo/geocaching/sorting/VoteComparator.java b/main/src/cgeo/geocaching/sorting/VoteComparator.java
index dc0304b..cd4ad7e 100644
--- a/main/src/cgeo/geocaching/sorting/VoteComparator.java
+++ b/main/src/cgeo/geocaching/sorting/VoteComparator.java
@@ -8,11 +8,6 @@ import cgeo.geocaching.Geocache;
public class VoteComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache1, Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(Geocache cache1, Geocache cache2) {
// if there is no vote available, put that cache at the end of the list
return Float.compare(cache2.getMyVote(), cache1.getMyVote());
diff --git a/main/src/cgeo/geocaching/speech/SpeechService.java b/main/src/cgeo/geocaching/speech/SpeechService.java
index 2a72bbf..8c650c3 100644
--- a/main/src/cgeo/geocaching/speech/SpeechService.java
+++ b/main/src/cgeo/geocaching/speech/SpeechService.java
@@ -47,7 +47,7 @@ public class SpeechService extends Service implements OnInitListener {
GeoDirHandler geoHandler = new GeoDirHandler() {
@Override
- protected void updateDirection(float newDirection) {
+ public void updateDirection(float newDirection) {
if (CgeoApplication.getInstance().currentGeo().getSpeed() <= 5) {
direction = DirectionProvider.getDirectionNow(startingActivity, newDirection);
directionInitialized = true;
@@ -56,7 +56,7 @@ public class SpeechService extends Service implements OnInitListener {
}
@Override
- protected void updateGeoData(cgeo.geocaching.IGeoData newGeo) {
+ public void updateGeoData(cgeo.geocaching.IGeoData newGeo) {
position = newGeo.getCoords();
positionInitialized = true;
if (!Settings.isUseCompass() || newGeo.getSpeed() > 5) {
diff --git a/main/src/cgeo/geocaching/speech/TextFactory.java b/main/src/cgeo/geocaching/speech/TextFactory.java
index 2a3b6d7..eb780c6 100644
--- a/main/src/cgeo/geocaching/speech/TextFactory.java
+++ b/main/src/cgeo/geocaching/speech/TextFactory.java
@@ -2,9 +2,9 @@ package cgeo.geocaching.speech;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
-import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.IConversion;
+import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.AngleUtils;
import java.util.Locale;
diff --git a/main/src/cgeo/geocaching/twitter/Twitter.java b/main/src/cgeo/geocaching/twitter/Twitter.java
index 7213789..1caa2d4 100644
--- a/main/src/cgeo/geocaching/twitter/Twitter.java
+++ b/main/src/cgeo/geocaching/twitter/Twitter.java
@@ -17,7 +17,6 @@ import cgeo.geocaching.utils.LogTemplateProvider;
import cgeo.geocaching.utils.LogTemplateProvider.LogContext;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
diff --git a/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java b/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java
index ed5d182..0c67384 100644
--- a/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java
+++ b/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java
@@ -3,7 +3,6 @@ package cgeo.geocaching.ui;
import cgeo.geocaching.activity.AbstractViewPagerActivity.PageViewCreator;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
diff --git a/main/src/cgeo/geocaching/ui/AnchorAwareLinkMovementMethod.java b/main/src/cgeo/geocaching/ui/AnchorAwareLinkMovementMethod.java
index db82e5c..d4c2e10 100644
--- a/main/src/cgeo/geocaching/ui/AnchorAwareLinkMovementMethod.java
+++ b/main/src/cgeo/geocaching/ui/AnchorAwareLinkMovementMethod.java
@@ -8,7 +8,7 @@ import android.widget.TextView;
/**
* <code>LinkMovementMethod</code> with built-in suppression of errors for links, where the URL cannot be handled
* correctly by Android.
- *
+ *
*/
public class AnchorAwareLinkMovementMethod extends LinkMovementMethod {
diff --git a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
index 7fe77c4..5d8ebef 100644
--- a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
+++ b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
@@ -39,6 +39,11 @@ public final class CacheDetailsCreator {
parentView.removeAllViews();
}
+ /**
+ * @param nameId
+ * @param value
+ * @return the view containing the displayed string (i.e. the right side one from the pair of "label": "value")
+ */
public TextView add(final int nameId, final CharSequence value) {
final RelativeLayout layout = (RelativeLayout) activity.getLayoutInflater().inflate(R.layout.cache_information_item, null);
final TextView nameView = (TextView) layout.findViewById(R.id.name);
@@ -188,14 +193,24 @@ public final class CacheDetailsCreator {
if (!cache.isEventCache()) {
return;
}
+ addHiddenDate(cache);
+ }
+
+ public TextView addHiddenDate(final @NonNull Geocache cache) {
final Date hiddenDate = cache.getHiddenDate();
if (hiddenDate == null) {
- return;
+ return null;
}
final long time = hiddenDate.getTime();
if (time > 0) {
- final String dateString = DateUtils.formatDateTime(CgeoApplication.getInstance().getBaseContext(), time, DateUtils.FORMAT_SHOW_WEEKDAY) + ", " + Formatter.formatFullDate(time);
- add(R.string.cache_event, dateString);
+ String dateString = Formatter.formatFullDate(time);
+ if (cache.isEventCache()) {
+ dateString = DateUtils.formatDateTime(CgeoApplication.getInstance().getBaseContext(), time, DateUtils.FORMAT_SHOW_WEEKDAY) + ", " + dateString;
+ }
+ final TextView view = add(cache.isEventCache() ? R.string.cache_event : R.string.cache_hidden, dateString);
+ view.setId(R.id.date);
+ return view;
}
+ return null;
}
}
diff --git a/main/src/cgeo/geocaching/ui/EditNoteDialog.java b/main/src/cgeo/geocaching/ui/EditNoteDialog.java
index 2af1cb8..4bfa140 100644
--- a/main/src/cgeo/geocaching/ui/EditNoteDialog.java
+++ b/main/src/cgeo/geocaching/ui/EditNoteDialog.java
@@ -1,6 +1,7 @@
package cgeo.geocaching.ui;
import cgeo.geocaching.R;
+import cgeo.geocaching.ui.dialog.Dialogs;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -40,6 +41,7 @@ public class EditNoteDialog extends DialogFragment {
String initialNote = getArguments().getString(ARGUMENT_INITIAL_NOTE);
if (initialNote != null) {
mEditText.setText(initialNote);
+ Dialogs.moveCursorToEnd(mEditText);
getArguments().remove(ARGUMENT_INITIAL_NOTE);
}
diff --git a/main/src/cgeo/geocaching/ui/ImagesList.java b/main/src/cgeo/geocaching/ui/ImagesList.java
index 4eaf06d..f564583 100644
--- a/main/src/cgeo/geocaching/ui/ImagesList.java
+++ b/main/src/cgeo/geocaching/ui/ImagesList.java
@@ -9,6 +9,9 @@ import cgeo.geocaching.utils.Log;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
+import rx.android.concurrency.AndroidSchedulers;
+import rx.subscriptions.CompositeSubscription;
+import rx.util.functions.Action1;
import android.app.Activity;
import android.content.Intent;
@@ -18,7 +21,6 @@ import android.graphics.Bitmap.CompressFormat;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
-import android.os.AsyncTask;
import android.text.Html;
import android.util.SparseArray;
import android.view.ContextMenu;
@@ -41,11 +43,11 @@ public class ImagesList {
private BitmapDrawable currentDrawable;
private Image currentImage;
+ private CompositeSubscription subscriptions = new CompositeSubscription();
public enum ImageType {
LogImages(R.string.cache_log_images_title),
- SpoilerImages(R.string.cache_spoiler_images_title),
- AllImages(R.string.cache_images_title);
+ SpoilerImages(R.string.cache_spoiler_images_title);
private final int titleResId;
@@ -76,11 +78,13 @@ public class ImagesList {
}
public void loadImages(final View parentView, final List<Image> images, final boolean offline) {
-
imagesView = (LinearLayout) parentView.findViewById(R.id.spoiler_list);
+ final HtmlImage imgGetter = new HtmlImage(geocode, true, offline ? StoredList.STANDARD_LIST_ID : StoredList.TEMPORARY_LIST_ID, false);
+
for (final Image img : images) {
- LinearLayout rowView = (LinearLayout) inflater.inflate(R.layout.cache_image_item, null);
+ final LinearLayout rowView = (LinearLayout) inflater.inflate(R.layout.cache_image_item, null);
+ assert(rowView != null);
if (StringUtils.isNotBlank(img.getTitle())) {
((TextView) rowView.findViewById(R.id.title)).setText(Html.fromHtml(img.getTitle()));
@@ -93,66 +97,56 @@ public class ImagesList {
descView.setVisibility(View.VISIBLE);
}
- new AsyncImgLoader(rowView, img, offline).execute();
+ subscriptions.add(imgGetter.fetchDrawable(img.getUrl())
+ .observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<BitmapDrawable>() {
+ @Override
+ public void call(final BitmapDrawable image) {
+ display(image, img, rowView);
+ }
+ }));
+
imagesView.addView(rowView);
}
}
- private class AsyncImgLoader extends AsyncTask<Void, Void, BitmapDrawable> {
+ private void display(final BitmapDrawable image, final Image img, final LinearLayout view) {
+ if (image != null) {
+ bitmaps.add(image.getBitmap());
+ final ImageView imageView = (ImageView) inflater.inflate(R.layout.image_item, null);
+ assert(imageView != null);
- final private LinearLayout view;
- final private Image img;
- final boolean offline;
+ final Rect bounds = image.getBounds();
- public AsyncImgLoader(final LinearLayout view, final Image img, final boolean offline) {
- this.view = view;
- this.img = img;
- this.offline = offline;
- }
+ imageView.setImageResource(R.drawable.image_not_loaded);
+ imageView.setClickable(true);
+ imageView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ viewImageInStandardApp(image);
+ }
+ });
+ activity.registerForContextMenu(imageView);
+ imageView.setImageDrawable(image);
+ imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
+ imageView.setLayoutParams(new LayoutParams(bounds.width(), bounds.height()));
- @Override
- protected BitmapDrawable doInBackground(Void... params) {
- final HtmlImage imgGetter = new HtmlImage(geocode, true, offline ? StoredList.STANDARD_LIST_ID : StoredList.TEMPORARY_LIST_ID, false);
- return imgGetter.getDrawable(img.getUrl());
- }
+ view.findViewById(R.id.progress_bar).setVisibility(View.GONE);
+ view.addView(imageView);
- @Override
- protected void onPostExecute(final BitmapDrawable image) {
- if (image != null) {
- bitmaps.add(image.getBitmap());
- final ImageView imageView = (ImageView) inflater.inflate(R.layout.image_item, null);
-
- final Rect bounds = image.getBounds();
-
- imageView.setImageResource(R.drawable.image_not_loaded);
- imageView.setClickable(true);
- imageView.setOnClickListener(new View.OnClickListener() {
-
- @Override
- public void onClick(View arg0) {
- viewImageInStandardApp(image);
- }
- });
- activity.registerForContextMenu(imageView);
- imageView.setImageDrawable(image);
- imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
- imageView.setLayoutParams(new LayoutParams(bounds.width(), bounds.height()));
-
- view.findViewById(R.id.progress_bar).setVisibility(View.GONE);
- view.addView(imageView);
-
- imageView.setId(image.hashCode());
- images.put(imageView.getId(), img);
- }
+ imageView.setId(image.hashCode());
+ images.put(imageView.getId(), img);
}
}
public void removeAllViews() {
- imagesView.removeAllViews();
for (final Bitmap b : bitmaps) {
b.recycle();
}
bitmaps.clear();
+
+ // Stop loading images if some are still in progress
+ subscriptions.unsubscribe();
+ imagesView.removeAllViews();
}
public void onCreateContextMenu(ContextMenu menu, View v) {
diff --git a/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java b/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java
index 93f50e1..651ff6e 100644
--- a/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java
+++ b/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java
@@ -54,7 +54,7 @@ public class CoordinatesInputDialog extends NoTitleDialog {
} else if (geo != null && geo.getCoords() != null) {
this.gp = geo.getCoords();
} else {
- this.gp = new Geopoint(0.0, 0.0);
+ this.gp = Geopoint.ZERO;
}
}
@@ -396,7 +396,7 @@ public class CoordinatesInputDialog extends NoTitleDialog {
if (geo != null && geo.getCoords() != null) {
gp = geo.getCoords();
} else {
- gp = new Geopoint(0.0, 0.0);
+ gp = Geopoint.ZERO;
}
}
}
diff --git a/main/src/cgeo/geocaching/ui/dialog/Dialogs.java b/main/src/cgeo/geocaching/ui/dialog/Dialogs.java
index 865ba70..cbd5c94 100644
--- a/main/src/cgeo/geocaching/ui/dialog/Dialogs.java
+++ b/main/src/cgeo/geocaching/ui/dialog/Dialogs.java
@@ -1,11 +1,12 @@
package cgeo.geocaching.ui.dialog;
import cgeo.geocaching.CgeoApplication;
-import cgeo.geocaching.utils.RunnableWithArgument;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.Nullable;
+import rx.util.functions.Action1;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
@@ -298,7 +299,7 @@ public final class Dialogs {
/**
* Show a message dialog for input from the user. The okay button is only enabled on non empty input.
- *
+ *
* @param context
* activity owning the dialog
* @param title
@@ -310,7 +311,7 @@ public final class Dialogs {
* @param okayListener
* listener to be run on okay
*/
- public static void input(final Activity context, final int title, final String defaultValue, final int buttonTitle, final RunnableWithArgument<String> okayListener) {
+ public static void input(final Activity context, final int title, final String defaultValue, final int buttonTitle, final Action1<String> okayListener) {
final EditText input = new EditText(context);
input.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_CLASS_TEXT);
input.setText(defaultValue);
@@ -322,7 +323,7 @@ public final class Dialogs {
@Override
public void onClick(DialogInterface dialog, int which) {
- okayListener.run(input.getText().toString());
+ okayListener.call(input.getText().toString());
}
});
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@@ -357,8 +358,16 @@ public final class Dialogs {
dialog.show();
enableDialogButtonIfNotEmpty(dialog, defaultValue);
- // position cursor after text
- input.setSelection(input.getText().length());
+ moveCursorToEnd(input);
+ }
+
+ /**
+ * Move the cursor to the end of the input field.
+ *
+ * @param input
+ */
+ public static void moveCursorToEnd(final EditText input) {
+ input.setSelection(input.getText().length(), input.getText().length());
}
private static void enableDialogButtonIfNotEmpty(final AlertDialog dialog, final String input) {
diff --git a/main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java b/main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java
index 6ad59ec..c29f549 100644
--- a/main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java
+++ b/main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java
@@ -1,15 +1,14 @@
package cgeo.geocaching.ui.dialog;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
import cgeo.geocaching.settings.Settings;
-import cgeo.geocaching.CgeoApplication;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.view.ContextThemeWrapper;
import android.view.View;
-import android.widget.CheckBox;
public class LiveMapInfoDialogBuilder {
@@ -20,12 +19,7 @@ public class LiveMapInfoDialogBuilder {
final View layout = View.inflate(new ContextThemeWrapper(activity, R.style.dark), R.layout.livemapinfo, null);
builder.setView(layout);
- final CheckBox checkBoxHide = (CheckBox) layout.findViewById(R.id.live_map_hint_hide);
-
final int showCount = Settings.getLiveMapHintShowCount();
- if (showCount > 2) {
- checkBoxHide.setVisibility(View.VISIBLE);
- }
Settings.setLiveMapHintShowCount(showCount + 1);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@@ -33,10 +27,7 @@ public class LiveMapInfoDialogBuilder {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
- CgeoApplication.getInstance().setLiveMapHintShown();
- if (checkBoxHide.getVisibility() == View.VISIBLE && checkBoxHide.isChecked()) {
- Settings.setHideLiveHint(true);
- }
+ CgeoApplication.getInstance().setLiveMapHintShownInThisSession();
}
});
return builder.create();
diff --git a/main/src/cgeo/geocaching/utils/CancellableHandler.java b/main/src/cgeo/geocaching/utils/CancellableHandler.java
index cb4b9db..01fb568 100644
--- a/main/src/cgeo/geocaching/utils/CancellableHandler.java
+++ b/main/src/cgeo/geocaching/utils/CancellableHandler.java
@@ -2,6 +2,9 @@ package cgeo.geocaching.utils;
import cgeo.geocaching.CgeoApplication;
+import rx.Subscription;
+import rx.subscriptions.CompositeSubscription;
+
import android.os.Handler;
import android.os.Message;
@@ -13,6 +16,7 @@ public abstract class CancellableHandler extends Handler {
protected static final int UPDATE_LOAD_PROGRESS_DETAIL = 42186;
private volatile boolean cancelled = false;
+ private static CompositeSubscription subscriptions = new CompositeSubscription();
private static class CancelHolder {
final Object payload;
@@ -30,6 +34,7 @@ public abstract class CancellableHandler extends Handler {
if (message.obj instanceof CancelHolder) {
cancelled = true;
+ subscriptions.unsubscribe();
handleCancel(((CancelHolder) message.obj).payload);
} else {
handleRegularMessage(message);
@@ -37,6 +42,17 @@ public abstract class CancellableHandler extends Handler {
}
/**
+ * Add a subscription to the list of subscriptions to be subscribed at cancellation time.
+ */
+ final public void unsubscribeIfCancelled(final Subscription subscription) {
+ subscriptions.add(subscription);
+ if (cancelled) {
+ // Protect against race conditions
+ subscriptions.unsubscribe();
+ }
+ }
+
+ /**
* Handle a non-cancel message.<br>
* Subclasses must implement this to handle messages.
*
diff --git a/main/src/cgeo/geocaching/utils/GeoDirHandler.java b/main/src/cgeo/geocaching/utils/GeoDirHandler.java
index c85648b..b9c605b 100644
--- a/main/src/cgeo/geocaching/utils/GeoDirHandler.java
+++ b/main/src/cgeo/geocaching/utils/GeoDirHandler.java
@@ -4,12 +4,15 @@ import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.IGeoData;
import cgeo.geocaching.settings.Settings;
-import android.os.Handler;
-import android.os.Message;
+import rx.Observable;
+import rx.Subscription;
+import rx.android.concurrency.AndroidSchedulers;
+import rx.util.functions.Action1;
+
+import java.util.concurrent.TimeUnit;
/**
- * GeoData and Direction handler. Manipulating geodata and direction information
- * through a GeoDirHandler ensures that all listeners are registered from a {@link android.os.Looper} thread.
+ * GeoData and Direction handler.
* <p>
* To use this class, override at least one of {@link #updateDirection(float)} or {@link #updateGeoData(IGeoData)}. You
* need to start the handler using one of
@@ -21,47 +24,11 @@ import android.os.Message;
* A good place might be the {@code onResume} method of the Activity. Stop the Handler accordingly in {@code onPause}.
* </p>
*/
-public abstract class GeoDirHandler extends Handler implements IObserver<Object> {
-
- private static final int OBSERVABLE = 1 << 1;
- private static final int START_GEO = 1 << 2;
- private static final int START_DIR = 1 << 3;
- private static final int STOP_GEO = 1 << 4;
- private static final int STOP_DIR = 1 << 5;
-
+public abstract class GeoDirHandler {
private static final CgeoApplication app = CgeoApplication.getInstance();
- @Override
- final public void handleMessage(final Message message) {
- if ((message.what & START_GEO) != 0) {
- app.addGeoObserver(this);
- }
-
- if ((message.what & START_DIR) != 0) {
- app.addDirectionObserver(this);
- }
-
- if ((message.what & STOP_GEO) != 0) {
- app.deleteGeoObserver(this);
- }
-
- if ((message.what & STOP_DIR) != 0) {
- app.deleteDirectionObserver(this);
- }
-
- if ((message.what & OBSERVABLE) != 0) {
- if (message.obj instanceof IGeoData) {
- updateGeoData((IGeoData) message.obj);
- } else {
- updateDirection((Float) message.obj);
- }
- }
- }
-
- @Override
- final public void update(final Object o) {
- obtainMessage(OBSERVABLE, o).sendToTarget();
- }
+ private Subscription dirSubscription = null;
+ private Subscription geoSubscription = null;
/**
* Update method called when new IGeoData is available.
@@ -69,7 +36,7 @@ public abstract class GeoDirHandler extends Handler implements IObserver<Object>
* @param data
* the new data
*/
- protected void updateGeoData(final IGeoData data) {
+ public void updateGeoData(final IGeoData data) {
// Override this in children
}
@@ -79,24 +46,38 @@ public abstract class GeoDirHandler extends Handler implements IObserver<Object>
* @param direction
* the new direction
*/
- protected void updateDirection(final float direction) {
+ public void updateDirection(final float direction) {
// Override this in children
}
/**
* Register the current GeoDirHandler for GeoData information.
*/
- public void startGeo() {
- sendEmptyMessage(START_GEO);
+ public synchronized void startGeo() {
+ geoSubscription = app.currentGeoObject()
+ .subscribeOn(AndroidSchedulers.mainThread())
+ .subscribe(new Action1<IGeoData>() {
+ @Override
+ public void call(final IGeoData geoData) {
+ updateGeoData(geoData);
+ }
+ });
}
/**
* Register the current GeoDirHandler for direction information if the preferences
* allow it.
*/
- public void startDir() {
+ public synchronized void startDir() {
if (Settings.isUseCompass()) {
- sendEmptyMessage(START_DIR);
+ dirSubscription = app.currentDirObject()
+ .subscribeOn(AndroidSchedulers.mainThread())
+ .subscribe(new Action1<Float>() {
+ @Override
+ public void call(final Float direction) {
+ updateDirection(direction);
+ }
+ });
}
}
@@ -105,27 +86,43 @@ public abstract class GeoDirHandler extends Handler implements IObserver<Object>
* preferences allow it).
*/
public void startGeoAndDir() {
- sendEmptyMessage(START_GEO | (Settings.isUseCompass() ? START_DIR : 0));
+ startGeo();
+ startDir();
}
/**
* Unregister the current GeoDirHandler for GeoData information.
*/
- public void stopGeo() {
- sendEmptyMessage(STOP_GEO);
+ public synchronized void stopGeo() {
+ // Delay the unsubscription by 2.5 seconds, so that another activity has
+ // the time to subscribe and the GPS receiver will not be turned down.
+ if (geoSubscription != null) {
+ final Subscription subscription = geoSubscription;
+ geoSubscription = null;
+ Observable.interval(2500, TimeUnit.MILLISECONDS).take(1).subscribe(new Action1<Long>() {
+ @Override
+ public void call(final Long aLong) {
+ subscription.unsubscribe();
+ }
+ });
+ }
}
/**
* Unregister the current GeoDirHandler for direction information.
*/
- public void stopDir() {
- sendEmptyMessage(STOP_DIR);
+ public synchronized void stopDir() {
+ if (dirSubscription != null) {
+ dirSubscription.unsubscribe();
+ dirSubscription = null;
+ }
}
/**
* Unregister the current GeoDirHandler for GeoData and direction information.
*/
public void stopGeoAndDir() {
- sendEmptyMessage(STOP_GEO | STOP_DIR);
+ stopGeo();
+ stopDir();
}
}
diff --git a/main/src/cgeo/geocaching/utils/IObserver.java b/main/src/cgeo/geocaching/utils/IObserver.java
deleted file mode 100644
index bfcc798..0000000
--- a/main/src/cgeo/geocaching/utils/IObserver.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package cgeo.geocaching.utils;
-
-/**
- * Observer interface.
- * <p/>
- * An observer will receive updates about the observed object (implementing the {@link ISubject} interface) through its
- * {@link #update(Object)} method.
- *
- * @param <T>
- * the kind of data to observe
- */
-public interface IObserver<T> {
-
- /**
- * Called when an observed object has updated its data.
- *
- * @param data
- * the updated data
- */
- void update(final T data);
-
-}
diff --git a/main/src/cgeo/geocaching/utils/ISubject.java b/main/src/cgeo/geocaching/utils/ISubject.java
deleted file mode 100644
index c325db0..0000000
--- a/main/src/cgeo/geocaching/utils/ISubject.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package cgeo.geocaching.utils;
-
-/**
- * Interface for subjects objects. Those can be observed by objects implementing the {@link IObserver} interface.
- *
- * @param <T>
- * the kind of data to observe
- */
-
-public interface ISubject<T> {
-
- /**
- * Add an observer to the observers list.
- * <p/>
- * Observers will be notified with no particular order.
- *
- * @param observer
- * the observer to add
- * @return true if the observer has been added, false if it was present already
- */
- public boolean addObserver(final IObserver<? super T> observer);
-
- /**
- * Delete an observer from the observers list.
- *
- * @param observer
- * the observer to remove
- * @return true if the observer has been removed, false if it was not in the list of observers
- */
- public boolean deleteObserver(final IObserver<? super T> observer);
-
- /**
- * Number of observers currently observing the object.
- *
- * @return the number of observers
- */
- public int sizeObservers();
-
- /**
- * Notify all the observers that new data is available.
- * <p/>
- * The {@link IObserver#update(Object)} method of each observer will be called with no particular order.
- *
- * @param data
- * the updated data
- * @return true if at least one observer was notified, false if there were no observers
- */
- public boolean notifyObservers(final T data);
-
- /**
- * Clear the observers list.
- *
- * @return true if there were observers before calling this method, false if the observers list was empty
- */
- public boolean clearObservers();
-
-}
diff --git a/main/src/cgeo/geocaching/utils/ImageUtils.java b/main/src/cgeo/geocaching/utils/ImageUtils.java
index 73f322c..9f47ead 100644
--- a/main/src/cgeo/geocaching/utils/ImageUtils.java
+++ b/main/src/cgeo/geocaching/utils/ImageUtils.java
@@ -78,7 +78,7 @@ public final class ImageUtils {
* @return BitmapDrawable The scaled image
*/
@NonNull
- public static BitmapDrawable scaleBitmapTo(@NonNull final Bitmap image, final int maxWidth, final int maxHeight) {
+ private static BitmapDrawable scaleBitmapTo(@NonNull final Bitmap image, final int maxWidth, final int maxHeight) {
final CgeoApplication app = CgeoApplication.getInstance();
Bitmap result = image;
int width = image.getWidth();
diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
index 708dff0..259e94a 100644
--- a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
+++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
@@ -1,5 +1,7 @@
package cgeo.geocaching.utils;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
@@ -42,6 +44,7 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E>
*
* @see HashSet
*/
+ @NonNull
@Override
public Iterator<E> iterator() {
return map.keySet().iterator();
diff --git a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java
index 76fa0f7..5fa0982 100644
--- a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java
+++ b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java
@@ -47,10 +47,6 @@ public final class LogTemplateProvider {
this.logEntry = logEntry;
}
- public LogContext(final boolean offline) {
- this(null, null, offline);
- }
-
public LogContext(final Geocache cache, LogEntry logEntry, final boolean offline) {
this.cache = cache;
this.offline = offline;
diff --git a/main/src/cgeo/geocaching/utils/MemorySubject.java b/main/src/cgeo/geocaching/utils/MemorySubject.java
deleted file mode 100644
index c424528..0000000
--- a/main/src/cgeo/geocaching/utils/MemorySubject.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package cgeo.geocaching.utils;
-
-/**
- * Synchronized implementation of the {@link ISubject} interface with an added pull interface.
- *
- * @param <T>
- * the kind of data to observe
- */
-public class MemorySubject<T> extends Subject<T> {
-
- /**
- * The latest version of the observed data.
- * <p/>
- * A child class implementation may want to set this field from its constructors, in case early observers request
- * the data before it got a chance to get updated. Otherwise, <code>null</code> will be returned until updated
- * data is available.
- */
- private T memory;
-
- @Override
- public synchronized boolean addObserver(final IObserver<? super T> observer) {
- final boolean added = super.addObserver(observer);
- if (added && memory != null) {
- observer.update(memory);
- }
- return added;
- }
-
- @Override
- public synchronized boolean notifyObservers(final T data) {
- memory = data;
- return super.notifyObservers(data);
- }
-
- /**
- * Get the memorized version of the data.
- *
- * @return the initial data set by the subject (which may be <code>null</code>),
- * or the updated data if it is available
- */
- public synchronized T getMemory() {
- return memory;
- }
-
-}
diff --git a/main/src/cgeo/geocaching/utils/RunnableWithArgument.java b/main/src/cgeo/geocaching/utils/RunnableWithArgument.java
deleted file mode 100644
index 6137efd..0000000
--- a/main/src/cgeo/geocaching/utils/RunnableWithArgument.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package cgeo.geocaching.utils;
-
-public interface RunnableWithArgument<T> {
-
- abstract void run(final T argument);
-
-}
diff --git a/main/src/cgeo/geocaching/utils/Subject.java b/main/src/cgeo/geocaching/utils/Subject.java
deleted file mode 100644
index b1754cc..0000000
--- a/main/src/cgeo/geocaching/utils/Subject.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package cgeo.geocaching.utils;
-
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-/**
- * Synchronized implementation of the {@link ISubject} interface.
- *
- * @param <T>
- * the kind of data to observe
- */
-public class Subject<T> implements ISubject<T> {
-
- /**
- * Collection of observers.
- */
- protected final Set<IObserver<? super T>> observers = new LinkedHashSet<IObserver<? super T>>();
-
- @Override
- public synchronized boolean addObserver(final IObserver<? super T> observer) {
- final boolean added = observers.add(observer);
- if (added && observers.size() == 1) {
- onFirstObserver();
- }
- return added;
- }
-
- @Override
- public synchronized boolean deleteObserver(final IObserver<? super T> observer) {
- final boolean removed = observers.remove(observer);
- if (removed && observers.isEmpty()) {
- onLastObserver();
- }
- return removed;
- }
-
- @Override
- public synchronized boolean notifyObservers(final T arg) {
- final boolean nonEmpty = !observers.isEmpty();
- for (final IObserver<? super T> observer : observers) {
- observer.update(arg);
- }
- return nonEmpty;
- }
-
- @Override
- public synchronized int sizeObservers() {
- return observers.size();
- }
-
- @Override
- public synchronized boolean clearObservers() {
- final boolean nonEmpty = !observers.isEmpty();
- for (final IObserver<? super T> observer : observers) {
- deleteObserver(observer);
- }
- return nonEmpty;
- }
-
- /**
- * Method called when the collection of observers goes from empty to non-empty.
- * <p/>
- * The default implementation does nothing and may be overwritten by child classes.
- */
- protected void onFirstObserver() {
- }
-
- /**
- * Method called when the collection of observers goes from non-empty to empty.
- * <p/>
- * The default implementation does nothing and may be overwritten by child classes.
- */
- protected void onLastObserver() {
- }
-
-}
diff --git a/main/src/cgeo/geocaching/utils/TextUtils.java b/main/src/cgeo/geocaching/utils/TextUtils.java
index efbb2d7..c4e1128 100644
--- a/main/src/cgeo/geocaching/utils/TextUtils.java
+++ b/main/src/cgeo/geocaching/utils/TextUtils.java
@@ -4,7 +4,6 @@
package cgeo.geocaching.utils;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
import org.eclipse.jdt.annotation.Nullable;
import java.util.regex.Matcher;