aboutsummaryrefslogtreecommitdiffstats
path: root/main/src
diff options
context:
space:
mode:
Diffstat (limited to 'main/src')
-rw-r--r--main/src/cgeo/geocaching/AbstractPopupActivity.java6
-rw-r--r--main/src/cgeo/geocaching/CacheDetailActivity.java50
-rw-r--r--main/src/cgeo/geocaching/CacheListActivity.java61
-rw-r--r--main/src/cgeo/geocaching/CacheMenuHandler.java35
-rw-r--r--main/src/cgeo/geocaching/CachePopup.java29
-rw-r--r--main/src/cgeo/geocaching/CgeoApplication.java4
-rw-r--r--main/src/cgeo/geocaching/DirectionProvider.java3
-rw-r--r--main/src/cgeo/geocaching/EditWaypointActivity.java5
-rw-r--r--main/src/cgeo/geocaching/Geocache.java34
-rw-r--r--main/src/cgeo/geocaching/LogTrackableActivity.java8
-rw-r--r--main/src/cgeo/geocaching/MainActivity.java53
-rw-r--r--main/src/cgeo/geocaching/NavigateAnyPointActivity.java3
-rw-r--r--main/src/cgeo/geocaching/SearchActivity.java13
-rw-r--r--main/src/cgeo/geocaching/SearchResult.java59
-rw-r--r--main/src/cgeo/geocaching/UsefulAppsActivity.java8
-rw-r--r--main/src/cgeo/geocaching/Waypoint.java1
-rw-r--r--main/src/cgeo/geocaching/activity/AbstractActivity.java10
-rw-r--r--main/src/cgeo/geocaching/activity/AbstractListActivity.java10
-rw-r--r--main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java46
-rw-r--r--main/src/cgeo/geocaching/activity/ActivityMixin.java29
-rw-r--r--main/src/cgeo/geocaching/activity/IAbstractActivity.java2
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java38
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/PebbleApp.java44
-rw-r--r--main/src/cgeo/geocaching/connector/AbstractConnector.java62
-rw-r--r--main/src/cgeo/geocaching/connector/AbstractLoggingManager.java20
-rw-r--r--main/src/cgeo/geocaching/connector/AbstractLogin.java77
-rw-r--r--main/src/cgeo/geocaching/connector/ConnectorFactory.java75
-rw-r--r--main/src/cgeo/geocaching/connector/GeocachingAustraliaConnector.java5
-rw-r--r--main/src/cgeo/geocaching/connector/GeopeitusConnector.java5
-rw-r--r--main/src/cgeo/geocaching/connector/IConnector.java52
-rw-r--r--main/src/cgeo/geocaching/connector/NoLoggingManager.java7
-rw-r--r--main/src/cgeo/geocaching/connector/UnknownConnector.java5
-rw-r--r--main/src/cgeo/geocaching/connector/WaymarkingConnector.java5
-rw-r--r--main/src/cgeo/geocaching/connector/capability/ICredentials.java21
-rw-r--r--main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java5
-rw-r--r--main/src/cgeo/geocaching/connector/capability/ISearchByGeocode.java4
-rw-r--r--main/src/cgeo/geocaching/connector/capability/ISearchByKeyword.java10
-rw-r--r--main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java5
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECApi.java220
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECConnector.java232
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECConstants.java19
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECLoggingManager.java48
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECLogin.java138
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCConnector.java69
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java6
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCLogin.java (renamed from main/src/cgeo/geocaching/connector/gc/Login.java)134
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCMap.java10
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCParser.java89
-rw-r--r--main/src/cgeo/geocaching/connector/gc/MapTokens.java23
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCApiConnector.java8
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java11
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCConnector.java9
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java15
-rw-r--r--main/src/cgeo/geocaching/connector/ox/OXConnector.java55
-rw-r--r--main/src/cgeo/geocaching/connector/ox/OXGPXParser.java14
-rw-r--r--main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java47
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java6
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheAttribute.java8
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheSize.java24
-rw-r--r--main/src/cgeo/geocaching/enumerations/StatusCode.java2
-rw-r--r--main/src/cgeo/geocaching/export/FieldnoteExport.java12
-rw-r--r--main/src/cgeo/geocaching/files/GPXImporter.java9
-rw-r--r--main/src/cgeo/geocaching/files/GPXParser.java31
-rw-r--r--main/src/cgeo/geocaching/files/SimpleDirChooser.java25
-rw-r--r--main/src/cgeo/geocaching/filter/TerrainFilter.java2
-rw-r--r--main/src/cgeo/geocaching/gcvote/GCVote.java31
-rw-r--r--main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java9
-rw-r--r--main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java15
-rw-r--r--main/src/cgeo/geocaching/loaders/KeywordGeocacheListLoader.java15
-rw-r--r--main/src/cgeo/geocaching/maps/CGeoMap.java74
-rw-r--r--main/src/cgeo/geocaching/maps/PositionAndScaleOverlay.java73
-rw-r--r--main/src/cgeo/geocaching/maps/PositionDrawer.java (renamed from main/src/cgeo/geocaching/maps/PositionOverlay.java)70
-rw-r--r--main/src/cgeo/geocaching/maps/ScaleDrawer.java (renamed from main/src/cgeo/geocaching/maps/ScaleOverlay.java)30
-rw-r--r--main/src/cgeo/geocaching/maps/google/GoogleMapView.java30
-rw-r--r--main/src/cgeo/geocaching/maps/google/GoogleOverlay.java18
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java7
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/OverlayImpl.java5
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java17
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java19
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java19
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeOverlay.java19
-rw-r--r--main/src/cgeo/geocaching/settings/AbstractAttributeBasedPrefence.java54
-rw-r--r--main/src/cgeo/geocaching/settings/AbstractCheckCredentialsPreference.java116
-rw-r--r--main/src/cgeo/geocaching/settings/CapabilitiesPreference.java91
-rw-r--r--main/src/cgeo/geocaching/settings/CheckBoxWithPopupPreference.java26
-rw-r--r--main/src/cgeo/geocaching/settings/CheckECCredentialsPreference.java40
-rw-r--r--main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java107
-rw-r--r--main/src/cgeo/geocaching/settings/EditPasswordPreference.java16
-rw-r--r--main/src/cgeo/geocaching/settings/InfoPreference.java105
-rw-r--r--main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java8
-rw-r--r--main/src/cgeo/geocaching/settings/Settings.java51
-rw-r--r--main/src/cgeo/geocaching/settings/SettingsActivity.java27
-rw-r--r--main/src/cgeo/geocaching/settings/TemplateTextPreference.java2
-rw-r--r--main/src/cgeo/geocaching/settings/TextPreference.java45
-rw-r--r--main/src/cgeo/geocaching/settings/WpThresholdPreference.java3
-rw-r--r--main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java1
-rw-r--r--main/src/cgeo/geocaching/sorting/FindsComparator.java17
-rw-r--r--main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java17
-rw-r--r--main/src/cgeo/geocaching/ui/AbstractCachingListViewPageViewCreator.java57
-rw-r--r--main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java26
-rw-r--r--main/src/cgeo/geocaching/ui/AddressListAdapter.java5
-rw-r--r--main/src/cgeo/geocaching/ui/CacheDetailsCreator.java15
-rw-r--r--main/src/cgeo/geocaching/ui/CompassView.java6
-rw-r--r--main/src/cgeo/geocaching/ui/GPXListAdapter.java28
-rw-r--r--main/src/cgeo/geocaching/ui/UrlPopup.java40
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/Dialogs.java291
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/NoTitleDialog.java4
-rw-r--r--main/src/cgeo/geocaching/ui/logs/CacheLogsViewCreator.java4
-rw-r--r--main/src/cgeo/geocaching/ui/logs/LogsViewCreator.java4
-rw-r--r--main/src/cgeo/geocaching/utils/DatabaseBackupUtils.java12
-rw-r--r--main/src/cgeo/geocaching/utils/MatcherWrapper.java3
-rw-r--r--main/src/cgeo/geocaching/utils/TextUtils.java3
112 files changed, 2691 insertions, 1159 deletions
diff --git a/main/src/cgeo/geocaching/AbstractPopupActivity.java b/main/src/cgeo/geocaching/AbstractPopupActivity.java
index 5b9b509..5f24030 100644
--- a/main/src/cgeo/geocaching/AbstractPopupActivity.java
+++ b/main/src/cgeo/geocaching/AbstractPopupActivity.java
@@ -108,9 +108,6 @@ public abstract class AbstractPopupActivity extends AbstractActivity implements
}
@Override
- public abstract void navigateTo();
-
- @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// set theme
@@ -202,9 +199,6 @@ public abstract class AbstractPopupActivity extends AbstractActivity implements
return super.onTouchEvent(event);
}
- @Override
- public abstract void showNavigationMenu();
-
protected abstract void startDefaultNavigation2();
protected final void addCacheDetails() {
diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java
index b853949..079562e 100644
--- a/main/src/cgeo/geocaching/CacheDetailActivity.java
+++ b/main/src/cgeo/geocaching/CacheDetailActivity.java
@@ -35,6 +35,7 @@ import cgeo.geocaching.ui.IndexOutOfBoundsAvoidingTextView;
import cgeo.geocaching.ui.LoggingUI;
import cgeo.geocaching.ui.OwnerActionsClickListener;
import cgeo.geocaching.ui.WeakReferenceHandler;
+import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.ui.logs.CacheLogsViewCreator;
import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.ClipboardUtils;
@@ -382,7 +383,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
buildDetailsContextMenu(menu, res.getString(R.string.cache_logs), false);
break;
case R.id.waypoint:
- menu.setHeaderTitle(res.getString(R.string.waypoint));
+ menu.setHeaderTitle(selectedWaypoint.getName() + " (" + res.getString(R.string.waypoint) + ")");
getMenuInflater().inflate(R.menu.waypoint_options, menu);
final boolean isOriginalWaypoint = selectedWaypoint.getWaypointType().equals(WaypointType.ORIGINAL);
menu.findItem(R.id.menu_waypoint_reset_cache_coords).setVisible(isOriginalWaypoint);
@@ -1615,18 +1616,8 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
private void warnPersonalNoteNeedsStoring() {
- final AlertDialog.Builder builder = new AlertDialog.Builder(CacheDetailActivity.this);
- builder.setTitle(R.string.cache_personal_note_unstored);
- builder.setMessage(R.string.cache_personal_note_store);
- builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- // do nothing
- }
- });
-
- builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ Dialogs.confirm(CacheDetailActivity.this, R.string.cache_personal_note_unstored, R.string.cache_personal_note_store,
+ new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
@@ -1635,36 +1626,19 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
});
- final AlertDialog dialog = builder.create();
- dialog.setOwnerActivity(CacheDetailActivity.this);
- dialog.show();
}
private void warnPersonalNoteExceedsLimit() {
- final AlertDialog.Builder builder = new AlertDialog.Builder(CacheDetailActivity.this);
- builder.setTitle(R.string.cache_personal_note_limit);
- String lang = getString(R.string.cache_personal_note_truncation, GCConstants.PERSONAL_NOTE_MAX_CHARS);
- builder.setMessage(lang);
- builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- // do nothing
- }
- });
+ Dialogs.confirm(CacheDetailActivity.this, R.string.cache_personal_note_limit, getString(R.string.cache_personal_note_truncation, GCConstants.PERSONAL_NOTE_MAX_CHARS),
+ new DialogInterface.OnClickListener() {
- builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- uploadPersonalNote();
- }
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ uploadPersonalNote();
+ }
- });
- final AlertDialog dialog = builder.create();
- dialog.setOwnerActivity(CacheDetailActivity.this);
- dialog.show();
+ });
}
}
diff --git a/main/src/cgeo/geocaching/CacheListActivity.java b/main/src/cgeo/geocaching/CacheListActivity.java
index 8226f38..08d41d0 100644
--- a/main/src/cgeo/geocaching/CacheListActivity.java
+++ b/main/src/cgeo/geocaching/CacheListActivity.java
@@ -39,6 +39,7 @@ import cgeo.geocaching.sorting.ComparatorUserInterface;
import cgeo.geocaching.ui.CacheListAdapter;
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.DateUtils;
import cgeo.geocaching.utils.GeoDirHandler;
@@ -474,7 +475,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
// refresh standard list if it has changed (new caches downloaded)
if (type == CacheListType.OFFLINE && listId >= StoredList.STANDARD_LIST_ID && search != null) {
final SearchResult newSearch = DataStore.getBatchOfStoredCaches(coords, Settings.getCacheType(), listId);
- if (newSearch.getTotal() != search.getTotal()) {
+ if (newSearch.getTotalCountGC() != search.getTotalCountGC()) {
refreshCurrentList();
}
}
@@ -944,7 +945,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.getTotal();
+ final int count = search.getTotalCountGC();
enableMore = enableMore && count > 0 && cacheList.size() < count;
}
@@ -1027,27 +1028,15 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
public void removeFromHistoryCheck() {
- final AlertDialog.Builder dialog = new AlertDialog.Builder(this);
- dialog.setCancelable(true);
- dialog.setTitle(res.getString(R.string.caches_removing_from_history));
- dialog.setMessage((adapter != null && adapter.getCheckedCount() > 0) ? res.getString(R.string.cache_remove_from_history)
- : res.getString(R.string.cache_clear_history));
- dialog.setPositiveButton(getString(android.R.string.yes), new DialogInterface.OnClickListener() {
+ int message = (adapter != null && adapter.getCheckedCount() > 0) ? R.string.cache_remove_from_history
+ : R.string.cache_clear_history;
+ Dialogs.confirmYesNo(this, R.string.caches_removing_from_history, message, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
removeFromHistory();
dialog.cancel();
}
});
- dialog.setNegativeButton(getString(android.R.string.no), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- });
-
- final AlertDialog alert = dialog.create();
- alert.show();
}
public void removeFromHistory() {
@@ -1072,16 +1061,8 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
public void dropStored(final boolean removeListAfterwards) {
- final AlertDialog.Builder dialog = new AlertDialog.Builder(this);
- dialog.setCancelable(true);
- dialog.setTitle(res.getString(R.string.caches_drop_stored));
-
- if (adapter.getCheckedCount() > 0) {
- dialog.setMessage(res.getString(R.string.caches_drop_selected_ask));
- } else {
- dialog.setMessage(res.getString(R.string.caches_drop_all_ask));
- }
- dialog.setPositiveButton(getString(android.R.string.yes), new DialogInterface.OnClickListener() {
+ int message = (adapter.getCheckedCount() > 0) ? R.string.caches_drop_selected_ask : R.string.caches_drop_all_ask;
+ Dialogs.confirmYesNo(this, R.string.caches_drop_stored, message, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
@@ -1089,16 +1070,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
dialog.cancel();
}
});
- dialog.setNegativeButton(getString(android.R.string.no), new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- });
-
- final AlertDialog alert = dialog.create();
- alert.show();
}
public void dropSelected(boolean removeListAfterwards) {
@@ -1407,24 +1378,12 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
// ask him, if there are caches on the list
- final AlertDialog.Builder alert = new AlertDialog.Builder(this);
-
- alert.setTitle(R.string.list_dialog_remove_title);
- alert.setMessage(R.string.list_dialog_remove_description);
- alert.setPositiveButton(R.string.list_dialog_remove, new DialogInterface.OnClickListener() {
+ Dialogs.confirm(this, R.string.list_dialog_remove_title, R.string.list_dialog_remove_description, R.string.list_dialog_remove, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
removeListInternal();
}
});
- alert.setNegativeButton(res.getString(R.string.list_dialog_cancel), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int whichButton) {
- dialog.dismiss();
- }
- });
-
- alert.show();
}
/**
@@ -1631,7 +1590,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
if (coords != null) {
loader = new CoordsGeocacheListLoader(app, coords);
- }
+ }
else {
loader = new AddressGeocacheListLoader(app, address);
}
diff --git a/main/src/cgeo/geocaching/CacheMenuHandler.java b/main/src/cgeo/geocaching/CacheMenuHandler.java
index 887f6cf..84a08f5 100644
--- a/main/src/cgeo/geocaching/CacheMenuHandler.java
+++ b/main/src/cgeo/geocaching/CacheMenuHandler.java
@@ -5,12 +5,12 @@ 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.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
@@ -101,28 +101,17 @@ public class CacheMenuHandler extends AbstractUIFactory {
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
- new AlertDialog.Builder(activity)
- .setTitle(res.getString(R.string.addon_missing_title))
- .setMessage(new StringBuilder(res.getString(R.string.helper_calendar_missing))
- .append(' ')
- .append(res.getString(R.string.addon_download_prompt))
- .toString())
- .setPositiveButton(activity.getString(android.R.string.yes), 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);
- }
- })
- .setNegativeButton(activity.getString(android.R.string.no), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- })
- .create()
- .show();
+ 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 d88000f..9186497 100644
--- a/main/src/cgeo/geocaching/CachePopup.java
+++ b/main/src/cgeo/geocaching/CachePopup.java
@@ -26,6 +26,12 @@ public class CachePopup extends AbstractPopupActivity {
private final Progress progress = new Progress();
private class StoreCacheHandler extends CancellableHandler {
+ private final int progressMessage;
+
+ public StoreCacheHandler(final int progressMessage) {
+ this.progressMessage = progressMessage;
+ }
+
@Override
public void handleRegularMessage(Message msg) {
if (UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) {
@@ -36,7 +42,7 @@ public class CachePopup extends AbstractPopupActivity {
}
private void updateStatusMsg(final String msg) {
- progress.setMessage(res.getString(R.string.cache_dialog_offline_save_message)
+ progress.setMessage(res.getString(progressMessage)
+ "\n\n"
+ msg);
}
@@ -49,23 +55,6 @@ public class CachePopup extends AbstractPopupActivity {
}
}
- private class RefreshCacheHandler extends CancellableHandler {
- @Override
- public void handleRegularMessage(Message msg) {
- if (UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) {
- updateStatusMsg((String) msg.obj);
- } else {
- init();
- }
- }
-
- private void updateStatusMsg(final String msg) {
- progress.setMessage(res.getString(R.string.cache_dialog_refresh_message)
- + "\n\n"
- + msg);
- }
- }
-
public CachePopup() {
super(R.layout.popup);
}
@@ -133,7 +122,7 @@ public class CachePopup extends AbstractPopupActivity {
}
protected void storeCache(final int listId) {
- final StoreCacheHandler storeCacheHandler = new StoreCacheHandler();
+ final StoreCacheHandler storeCacheHandler = new StoreCacheHandler(R.string.cache_dialog_offline_save_message);
progress.show(CachePopup.this, res.getString(R.string.cache_dialog_offline_save_title), res.getString(R.string.cache_dialog_offline_save_message), true, storeCacheHandler.cancelMessage());
new StoreCacheThread(listId, storeCacheHandler).start();
}
@@ -168,7 +157,7 @@ public class CachePopup extends AbstractPopupActivity {
return;
}
- final RefreshCacheHandler refreshCacheHandler = new RefreshCacheHandler();
+ final StoreCacheHandler refreshCacheHandler = new StoreCacheHandler(R.string.cache_dialog_offline_save_message);
progress.show(CachePopup.this, res.getString(R.string.cache_dialog_refresh_title), res.getString(R.string.cache_dialog_refresh_message), true, refreshCacheHandler.cancelMessage());
new RefreshCacheThread(refreshCacheHandler).start();
}
diff --git a/main/src/cgeo/geocaching/CgeoApplication.java b/main/src/cgeo/geocaching/CgeoApplication.java
index 0af8117..3d2f758 100644
--- a/main/src/cgeo/geocaching/CgeoApplication.java
+++ b/main/src/cgeo/geocaching/CgeoApplication.java
@@ -1,7 +1,7 @@
package cgeo.geocaching;
-import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.network.StatusUpdater;
+import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.IObserver;
import cgeo.geocaching.utils.Log;
@@ -75,7 +75,7 @@ public class CgeoApplication extends Application {
dialog.dismiss();
boolean success = atomic.get();
String message = success ? res.getString(R.string.init_dbmove_success) : res.getString(R.string.init_dbmove_failed);
- ActivityMixin.helpDialog(fromActivity, res.getString(R.string.init_dbmove_dbmove), message);
+ Dialogs.message(fromActivity, R.string.init_dbmove_dbmove, message);
}
});
}
diff --git a/main/src/cgeo/geocaching/DirectionProvider.java b/main/src/cgeo/geocaching/DirectionProvider.java
index b4fb86c..ae58fed 100644
--- a/main/src/cgeo/geocaching/DirectionProvider.java
+++ b/main/src/cgeo/geocaching/DirectionProvider.java
@@ -3,6 +3,8 @@ package cgeo.geocaching;
import cgeo.geocaching.compatibility.Compatibility;
import cgeo.geocaching.utils.MemorySubject;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
@@ -54,6 +56,7 @@ public class DirectionProvider extends MemorySubject<Float> implements SensorEve
}
@Override
+ @SuppressFBWarnings("FE_FLOATING_POINT_EQUALITY")
public void onSensorChanged(final SensorEvent event) {
final float direction = event.values[0];
if (direction != previous) {
diff --git a/main/src/cgeo/geocaching/EditWaypointActivity.java b/main/src/cgeo/geocaching/EditWaypointActivity.java
index c31ad40..6d0f822 100644
--- a/main/src/cgeo/geocaching/EditWaypointActivity.java
+++ b/main/src/cgeo/geocaching/EditWaypointActivity.java
@@ -12,6 +12,7 @@ import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.GeopointFormatter;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.dialog.CoordinatesInputDialog;
+import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.GeoDirHandler;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.TextUtils;
@@ -331,7 +332,7 @@ public class EditWaypointActivity extends AbstractActivity {
if (StringUtils.isBlank(bearingText) && StringUtils.isBlank(distanceText)
&& StringUtils.isBlank(latText) && StringUtils.isBlank(lonText)) {
- helpDialog(res.getString(R.string.err_point_no_position_given_title), res.getString(R.string.err_point_no_position_given));
+ Dialogs.message(EditWaypointActivity.this, R.string.err_point_no_position_given_title, R.string.err_point_no_position_given);
return;
}
@@ -359,7 +360,7 @@ public class EditWaypointActivity extends AbstractActivity {
try {
bearing = Double.parseDouble(bearingText);
} catch (NumberFormatException e) {
- helpDialog(res.getString(R.string.err_point_bear_and_dist_title), res.getString(R.string.err_point_bear_and_dist));
+ Dialogs.message(EditWaypointActivity.this, R.string.err_point_bear_and_dist_title, R.string.err_point_bear_and_dist);
return;
}
diff --git a/main/src/cgeo/geocaching/Geocache.java b/main/src/cgeo/geocaching/Geocache.java
index c589e9b..6262792 100644
--- a/main/src/cgeo/geocaching/Geocache.java
+++ b/main/src/cgeo/geocaching/Geocache.java
@@ -32,6 +32,8 @@ import cgeo.geocaching.utils.LogTemplateProvider.LogContext;
import cgeo.geocaching.utils.MatcherWrapper;
import cgeo.geocaching.utils.UncertainProperty;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.lang3.BooleanUtils;
@@ -366,6 +368,7 @@ public class Geocache implements ICache, IWaypoint {
* the other cache to compare this one to
* @return true if both caches have the same content
*/
+ @SuppressFBWarnings("FE_FLOATING_POINT_EQUALITY")
private boolean isEqualTo(final Geocache other) {
return detailed == other.detailed &&
StringUtils.equalsIgnoreCase(geocode, other.geocode) &&
@@ -1578,7 +1581,7 @@ public class Geocache implements ICache, IWaypoint {
public static void storeCache(Geocache origCache, String geocode, int listId, boolean forceRedownload, CancellableHandler handler) {
try {
- Geocache cache;
+ Geocache cache = null;
// get cache details, they may not yet be complete
if (origCache != null) {
SearchResult search = null;
@@ -1593,9 +1596,9 @@ public class Geocache implements ICache, IWaypoint {
}
} else if (StringUtils.isNotBlank(geocode)) {
final SearchResult search = searchByGeocode(geocode, null, listId, forceRedownload, handler);
- cache = search.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB);
- } else {
- cache = null;
+ if (search != null) {
+ cache = search.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB);
+ }
}
if (cache == null) {
@@ -1710,7 +1713,7 @@ public class Geocache implements ICache, IWaypoint {
patterns.add(Pattern.compile("\\b(\\d{1,2})\\:(\\d\\d)\\b"));
if (StringUtils.isNotBlank(hourLocalized)) {
// 17 - 20 o'clock
- patterns.add(Pattern.compile("\\b(\\d{1,2})(?:\\.00)?" + "\\s*-\\s*" + "(?:\\d{1,2})(?:\\.00)?" + "\\s+" + Pattern.quote(hourLocalized), Pattern.CASE_INSENSITIVE));
+ patterns.add(Pattern.compile("\\b(\\d{1,2})(?:\\.00)?" + "\\s*(?:-|[a-z]+)\\s*" + "(?:\\d{1,2})(?:\\.00)?" + "\\s+" + Pattern.quote(hourLocalized), Pattern.CASE_INSENSITIVE));
// 12 o'clock, 12.00 o'clock
patterns.add(Pattern.compile("\\b(\\d{1,2})(?:\\.00)?\\s+" + Pattern.quote(hourLocalized), Pattern.CASE_INSENSITIVE));
}
@@ -1719,10 +1722,10 @@ public class Geocache implements ICache, IWaypoint {
final MatcherWrapper matcher = new MatcherWrapper(pattern, getDescription());
while (matcher.find()) {
try {
- final int hours = Integer.valueOf(matcher.group(1));
+ final int hours = Integer.parseInt(matcher.group(1));
int minutes = 0;
if (matcher.groupCount() >= 2) {
- minutes = Integer.valueOf(matcher.group(2));
+ minutes = Integer.parseInt(matcher.group(2));
}
if (hours >= 0 && hours < 24 && minutes >= 0 && minutes < 60) {
return String.valueOf(hours * 60 + minutes);
@@ -1810,4 +1813,21 @@ public class Geocache implements ICache, IWaypoint {
public String getWaypointPrefix(String name) {
return getConnector().getWaypointPrefix(name);
}
+
+ /**
+ * Get number of overall finds for a cache, or 0 if the number of finds is not known.
+ *
+ * @return
+ */
+ public int getFindsCount() {
+ if (getLogCounts().isEmpty()) {
+ setLogCounts(DataStore.loadLogCounts(getGeocode()));
+ }
+ Integer logged = getLogCounts().get(LogType.FOUND_IT);
+ if (logged != null) {
+ return logged;
+ }
+ return 0;
+ }
+
}
diff --git a/main/src/cgeo/geocaching/LogTrackableActivity.java b/main/src/cgeo/geocaching/LogTrackableActivity.java
index e549fdc..5246fa9 100644
--- a/main/src/cgeo/geocaching/LogTrackableActivity.java
+++ b/main/src/cgeo/geocaching/LogTrackableActivity.java
@@ -4,7 +4,7 @@ import butterknife.ButterKnife;
import butterknife.InjectView;
import cgeo.geocaching.connector.gc.GCParser;
-import cgeo.geocaching.connector.gc.Login;
+import cgeo.geocaching.connector.gc.GCLogin;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.network.Network;
@@ -76,7 +76,7 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
showToast(res.getString(R.string.info_log_type_changed));
}
- if (Login.isEmpty(viewstates)) {
+ if (GCLogin.isEmpty(viewstates)) {
if (attempts < 2) {
showToast(res.getString(R.string.err_log_load_data_again));
new LoadDataThread().start();
@@ -200,7 +200,7 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
possibleLogTypes = Trackable.getPossibleLogTypes();
}
- if (Login.isEmpty(viewstates)) {
+ if (GCLogin.isEmpty(viewstates)) {
buttonPost.setEnabled(false);
buttonPost.setOnTouchListener(null);
buttonPost.setOnClickListener(null);
@@ -294,7 +294,7 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
final String page = Network.getResponseData(Network.getRequest("http://www.geocaching.com/track/log.aspx", params));
- viewstates = Login.getViewstates(page);
+ viewstates = GCLogin.getViewstates(page);
final List<LogType> typesPre = GCParser.parseTypes(page);
if (CollectionUtils.isNotEmpty(typesPre)) {
diff --git a/main/src/cgeo/geocaching/MainActivity.java b/main/src/cgeo/geocaching/MainActivity.java
index 1d4c22c..d96b97c 100644
--- a/main/src/cgeo/geocaching/MainActivity.java
+++ b/main/src/cgeo/geocaching/MainActivity.java
@@ -15,10 +15,10 @@ import cgeo.geocaching.maps.CGeoMap;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.settings.SettingsActivity;
import cgeo.geocaching.ui.Formatter;
+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.ProcessUtils;
import cgeo.geocaching.utils.RunnableWithArgument;
import cgeo.geocaching.utils.Version;
@@ -27,7 +27,6 @@ import com.google.zxing.integration.android.IntentResult;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
-import org.eclipse.jdt.annotation.NonNull;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
@@ -72,7 +71,6 @@ public class MainActivity extends AbstractActivity {
@InjectView(R.id.offline_count) protected TextView countBubble;
@InjectView(R.id.info_area) protected LinearLayout infoArea;
- private static final String SCAN_INTENT = "com.google.zxing.client.android.SCAN";
public static final int SEARCH_REQUEST_CODE = 2;
private int version = 0;
@@ -268,7 +266,7 @@ public class MainActivity extends AbstractActivity {
@Override
public boolean onPrepareOptionsMenu(final Menu menu) {
super.onPrepareOptionsMenu(menu);
- menu.findItem(R.id.menu_scan).setEnabled(ProcessUtils.isIntentAvailable(SCAN_INTENT));
+ menu.findItem(R.id.menu_pocket_queries).setVisible(Settings.isPremiumMember());
return true;
}
@@ -291,6 +289,18 @@ public class MainActivity extends AbstractActivity {
case R.id.menu_scan:
startScannerApplication();
return true;
+ case R.id.menu_pocket_queries:
+ if (!Settings.isPremiumMember()) {
+ return true;
+ }
+ new PocketQueryList.UserInterface(MainActivity.this).promptForListSelection(new RunnableWithArgument<PocketQueryList>() {
+
+ @Override
+ public void run(final PocketQueryList pql) {
+ CacheListActivity.startActivityPocket(MainActivity.this, pql);
+ }
+ });
+ return true;
default:
return super.onOptionsItemSelected(item);
}
@@ -299,6 +309,11 @@ public class MainActivity extends AbstractActivity {
private void startScannerApplication() {
IntentIntegrator integrator = new IntentIntegrator(this);
+ // integrator dialog is English only, therefore localize it
+ integrator.setButtonYesByID(android.R.string.yes);
+ integrator.setButtonNoByID(android.R.string.no);
+ integrator.setTitleByID(R.string.menu_scan_geo);
+ integrator.setMessageByID(R.string.menu_scan_description);
integrator.initiateScan(IntentIntegrator.QR_CODE_TYPES);
}
@@ -318,11 +333,7 @@ public class MainActivity extends AbstractActivity {
if (query == null) {
query = "";
}
- new AlertDialog.Builder(this)
- .setMessage(res.getString(R.string.unknown_scan) + "\n\n" + query)
- .setPositiveButton(getString(android.R.string.ok), null)
- .create()
- .show();
+ Dialogs.message(this, res.getString(R.string.unknown_scan) + "\n\n" + query);
}
}
}
@@ -513,26 +524,6 @@ public class MainActivity extends AbstractActivity {
}
});
nearestView.setBackgroundResource(R.drawable.main_nearby);
-
- nearestView.setOnLongClickListener(new View.OnLongClickListener() {
-
- @Override
- public boolean onLongClick(View v) {
- if (!Settings.isPremiumMember()) {
- return true;
- }
- new PocketQueryList.UserInterface(MainActivity.this).promptForListSelection(new RunnableWithArgument<PocketQueryList>() {
-
- @Override
- public void run(final @NonNull PocketQueryList pql) {
- CacheListActivity.startActivityPocket(MainActivity.this, pql);
- }
- });
- return true;
- }
- });
- nearestView.setLongClickable(true);
-
}
navType.setText(res.getString(geo.getLocationProvider().resourceId));
@@ -665,10 +656,10 @@ public class MainActivity extends AbstractActivity {
int checks = 0;
while (!DataStore.isInitialized()) {
try {
- wait(500);
+ sleep(500);
checks++;
} catch (Exception e) {
- // nothing;
+ Log.e("MainActivity.CountBubbleUpdateThread.run", e);
}
if (checks > 10) {
diff --git a/main/src/cgeo/geocaching/NavigateAnyPointActivity.java b/main/src/cgeo/geocaching/NavigateAnyPointActivity.java
index c68c979..f24e86e 100644
--- a/main/src/cgeo/geocaching/NavigateAnyPointActivity.java
+++ b/main/src/cgeo/geocaching/NavigateAnyPointActivity.java
@@ -13,6 +13,7 @@ import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.AbstractViewHolder;
import cgeo.geocaching.ui.Formatter;
import cgeo.geocaching.ui.dialog.CoordinatesInputDialog;
+import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.GeoDirHandler;
import cgeo.geocaching.utils.Log;
@@ -518,7 +519,7 @@ public class NavigateAnyPointActivity extends AbstractActivity {
try {
bearing = Double.parseDouble(bearingText);
} catch (NumberFormatException e) {
- helpDialog(res.getString(R.string.err_point_bear_and_dist_title), res.getString(R.string.err_point_bear_and_dist));
+ Dialogs.message(this, R.string.err_point_bear_and_dist_title, R.string.err_point_bear_and_dist);
return null;
}
diff --git a/main/src/cgeo/geocaching/SearchActivity.java b/main/src/cgeo/geocaching/SearchActivity.java
index 334d99a..9952e18 100644
--- a/main/src/cgeo/geocaching/SearchActivity.java
+++ b/main/src/cgeo/geocaching/SearchActivity.java
@@ -12,6 +12,7 @@ import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.GeopointFormatter;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.dialog.CoordinatesInputDialog;
+import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.EditUtils;
import org.apache.commons.lang3.StringUtils;
@@ -276,7 +277,7 @@ public class SearchActivity extends AbstractActivity {
final String keyText = StringUtils.trim(keywordEditText.getText().toString());
if (StringUtils.isBlank(keyText)) {
- helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_keyword));
+ Dialogs.message(this, R.string.warn_search_help_title, R.string.warn_search_help_keyword);
return;
}
@@ -287,7 +288,7 @@ public class SearchActivity extends AbstractActivity {
final String addText = StringUtils.trim(addressEditText.getText().toString());
if (StringUtils.isBlank(addText)) {
- helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_address));
+ Dialogs.message(this, R.string.warn_search_help_title, R.string.warn_search_help_address);
return;
}
@@ -300,7 +301,7 @@ public class SearchActivity extends AbstractActivity {
final String usernameText = StringUtils.trim(userNameEditText.getText().toString());
if (StringUtils.isBlank(usernameText)) {
- helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_user));
+ Dialogs.message(this, R.string.warn_search_help_title, R.string.warn_search_help_user);
return;
}
@@ -315,7 +316,7 @@ public class SearchActivity extends AbstractActivity {
final String usernameText = StringUtils.trimToEmpty(userName);
if (StringUtils.isBlank(usernameText)) {
- helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_user));
+ Dialogs.message(this, R.string.warn_search_help_title, R.string.warn_search_help_user);
return;
}
@@ -326,7 +327,7 @@ public class SearchActivity extends AbstractActivity {
final String geocodeText = StringUtils.trim(geocodeEditText.getText().toString());
if (StringUtils.isBlank(geocodeText) || geocodeText.equalsIgnoreCase("GC")) {
- helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_gccode));
+ Dialogs.message(this, R.string.warn_search_help_title, R.string.warn_search_help_gccode);
return;
}
@@ -337,7 +338,7 @@ public class SearchActivity extends AbstractActivity {
final String trackableText = StringUtils.trim(trackableEditText.getText().toString());
if (StringUtils.isBlank(trackableText) || trackableText.equalsIgnoreCase("TB")) {
- helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_tb));
+ Dialogs.message(this, R.string.warn_search_help_title, R.string.warn_search_help_tb);
return;
}
diff --git a/main/src/cgeo/geocaching/SearchResult.java b/main/src/cgeo/geocaching/SearchResult.java
index 0bdf6c6..5d63a2d 100644
--- a/main/src/cgeo/geocaching/SearchResult.java
+++ b/main/src/cgeo/geocaching/SearchResult.java
@@ -1,6 +1,6 @@
package cgeo.geocaching;
-import cgeo.geocaching.connector.gc.Login;
+import cgeo.geocaching.connector.gc.GCLogin;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.enumerations.LoadFlags.LoadFlag;
@@ -28,7 +28,11 @@ public class SearchResult implements Parcelable {
private StatusCode error = null;
private String url = "";
public String[] viewstates = null;
- private int totalCnt = 0;
+ /**
+ * Overall number of search results matching our search on geocaching.com. If this number is higher than 20, we have
+ * to fetch multiple pages to get all caches.
+ */
+ private int totalCountGC = 0;
final public static Parcelable.Creator<SearchResult> CREATOR = new Parcelable.Creator<SearchResult>() {
@Override
@@ -60,20 +64,23 @@ public class SearchResult implements Parcelable {
error = searchResult.error;
url = searchResult.url;
viewstates = searchResult.viewstates;
- setTotal(searchResult.getTotal());
+ setTotalCountGC(searchResult.getTotalCountGC());
}
/**
* Build a search result from an existing collection of geocodes.
*
- * @param geocodes a non-null collection of geocodes
- * @param total the total number of geocodes (FIXME: what is the meaning of this number wrt to geocodes.size()?)
+ * @param geocodes
+ * a non-null collection of geocodes
+ * @param totalCountGC
+ * the total number of caches matching that search on geocaching.com (as we always get only the next 20
+ * from a web page)
*/
- public SearchResult(final Collection<String> geocodes, final int total) {
+ public SearchResult(final Collection<String> geocodes, final int totalCountGC) {
this.geocodes = new HashSet<String>(geocodes.size());
this.geocodes.addAll(geocodes);
this.filteredGeocodes = new HashSet<String>();
- this.setTotal(total);
+ this.setTotalCountGC(totalCountGC);
}
/**
@@ -99,7 +106,7 @@ public class SearchResult implements Parcelable {
viewstates = new String[length];
in.readStringArray(viewstates);
}
- setTotal(in.readInt());
+ setTotalCountGC(in.readInt());
}
/**
@@ -136,7 +143,7 @@ public class SearchResult implements Parcelable {
out.writeInt(viewstates.length);
out.writeStringArray(viewstates);
}
- out.writeInt(getTotal());
+ out.writeInt(getTotalCountGC());
}
@Override
@@ -173,19 +180,23 @@ public class SearchResult implements Parcelable {
}
public void setViewstates(String[] viewstates) {
- if (Login.isEmpty(viewstates)) {
+ if (GCLogin.isEmpty(viewstates)) {
return;
}
+ // lazy initialization of viewstates
+ if (this.viewstates == null) {
+ this.viewstates = new String[viewstates.length];
+ }
System.arraycopy(viewstates, 0, this.viewstates, 0, viewstates.length);
}
- public int getTotal() {
- return totalCnt;
+ public int getTotalCountGC() {
+ return totalCountGC;
}
- public void setTotal(int totalCnt) {
- this.totalCnt = totalCnt;
+ public void setTotalCountGC(int totalCountGC) {
+ this.totalCountGC = totalCountGC;
}
/**
@@ -214,7 +225,7 @@ public class SearchResult implements Parcelable {
}
}
// decrease maximum number of caches by filtered ones
- result.setTotal(result.getTotal() - excluded);
+ result.setTotalCountGC(result.getTotalCountGC() - excluded);
GCVote.loadRatings(cachesForVote);
return result;
}
@@ -268,12 +279,18 @@ public class SearchResult implements Parcelable {
}
public void addSearchResult(SearchResult other) {
- if (other != null) {
- addGeocodes(other.geocodes);
- addFilteredGeocodes(other.filteredGeocodes);
- if (StringUtils.isBlank(url)) {
- url = other.url;
- }
+ if (other == null) {
+ return;
+ }
+ addGeocodes(other.geocodes);
+ addFilteredGeocodes(other.filteredGeocodes);
+ if (StringUtils.isBlank(url)) {
+ url = other.url;
+ }
+ // copy the GC total search results number to be able to use "More caches" button
+ if (getTotalCountGC() == 0 && other.getTotalCountGC() != 0) {
+ setViewstates(other.getViewstates());
+ setTotalCountGC(other.getTotalCountGC());
}
}
diff --git a/main/src/cgeo/geocaching/UsefulAppsActivity.java b/main/src/cgeo/geocaching/UsefulAppsActivity.java
index c0f2d6f..c70143f 100644
--- a/main/src/cgeo/geocaching/UsefulAppsActivity.java
+++ b/main/src/cgeo/geocaching/UsefulAppsActivity.java
@@ -10,6 +10,7 @@ import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
+import android.text.Html;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
@@ -46,7 +47,9 @@ public class UsefulAppsActivity extends AbstractActivity {
private void installFromMarket(Activity activity) {
try {
- Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + packageName));
+ // allow also opening pure http URLs in addition to market packages
+ final String url = (packageName.startsWith("http:")) ? packageName : "market://details?id=" + packageName;
+ final Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
marketIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
activity.startActivity(marketIntent);
@@ -58,6 +61,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_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"),
@@ -92,7 +96,7 @@ public class UsefulAppsActivity extends AbstractActivity {
private void fillViewHolder(ViewHolder holder, HelperApp app) {
holder.title.setText(res.getString(app.titleId));
holder.image.setImageDrawable(res.getDrawable(app.iconId));
- holder.description.setText(res.getString(app.descriptionId));
+ holder.description.setText(Html.fromHtml(res.getString(app.descriptionId)));
}
});
diff --git a/main/src/cgeo/geocaching/Waypoint.java b/main/src/cgeo/geocaching/Waypoint.java
index dda83d9..47977bc 100644
--- a/main/src/cgeo/geocaching/Waypoint.java
+++ b/main/src/cgeo/geocaching/Waypoint.java
@@ -270,7 +270,6 @@ public class Waypoint implements IWaypoint {
/**
* Delegates the creation of the waypoint-id for gpx-export to the waypoint
*
- * @param prefix
* @return
*/
public String getGpxId() {
diff --git a/main/src/cgeo/geocaching/activity/AbstractActivity.java b/main/src/cgeo/geocaching/activity/AbstractActivity.java
index 1f44536..df21a8c 100644
--- a/main/src/cgeo/geocaching/activity/AbstractActivity.java
+++ b/main/src/cgeo/geocaching/activity/AbstractActivity.java
@@ -9,7 +9,6 @@ import cgeo.geocaching.settings.Settings;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
@@ -58,15 +57,6 @@ public abstract class AbstractActivity extends FragmentActivity implements IAbst
}
@Override
- public final void helpDialog(final String title, final String message) {
- ActivityMixin.helpDialog(this, title, message);
- }
-
- protected final void helpDialog(final String title, final String message, final Drawable icon) {
- ActivityMixin.helpDialog(this, title, message, icon);
- }
-
- @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initializeCommonFields();
diff --git a/main/src/cgeo/geocaching/activity/AbstractListActivity.java b/main/src/cgeo/geocaching/activity/AbstractListActivity.java
index d2bc0b4..a5d5c14 100644
--- a/main/src/cgeo/geocaching/activity/AbstractListActivity.java
+++ b/main/src/cgeo/geocaching/activity/AbstractListActivity.java
@@ -3,7 +3,6 @@ package cgeo.geocaching.activity;
import cgeo.geocaching.CgeoApplication;
import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.app.FragmentListActivity;
import android.view.View;
@@ -48,15 +47,6 @@ public abstract class AbstractListActivity extends FragmentListActivity implemen
}
@Override
- public final void helpDialog(final String title, final String message) {
- ActivityMixin.helpDialog(this, title, message, null);
- }
-
- public final void helpDialog(final String title, final String message, final Drawable icon) {
- ActivityMixin.helpDialog(this, title, message, icon);
- }
-
- @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initializeCommonFields();
diff --git a/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java b/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java
index 952726e..049fc7d 100644
--- a/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java
+++ b/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java
@@ -7,8 +7,11 @@ 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;
import android.app.Activity;
+import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
@@ -43,6 +46,10 @@ public abstract class AbstractViewPagerActivity<Page extends Enum<Page>> extends
private final Map<Page, PageViewCreator> viewCreators = new HashMap<Page, PageViewCreator>();
/**
+ * Store the states of the page views to be able to persist them when destroyed and reinstantiated again
+ */
+ private final Map<Page, Bundle> viewStates = new HashMap<Page, Bundle>();
+ /**
* The {@link ViewPager} for this activity.
*/
private ViewPager viewPager;
@@ -76,6 +83,17 @@ public abstract class AbstractViewPagerActivity<Page extends Enum<Page>> extends
* Handles changed data-sets.
*/
public void notifyDataSetChanged();
+
+ /**
+ * Gets state of the view
+ */
+ public @Nullable
+ Bundle getViewState();
+
+ /**
+ * Set the state of the view
+ */
+ public void setViewState(@NonNull Bundle state);
}
/**
@@ -93,6 +111,19 @@ public abstract class AbstractViewPagerActivity<Page extends Enum<Page>> extends
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
+
+ final Page page = pageOrder.get(position);
+
+ // Store the state of the view if the page supports it
+ PageViewCreator creator = viewCreators.get(page);
+ if (creator != null) {
+ @Nullable
+ Bundle state = creator.getViewState();
+ if (state != null) {
+ viewStates.put(page, state);
+ }
+ }
+
container.removeView((View) object);
}
@@ -107,6 +138,7 @@ public abstract class AbstractViewPagerActivity<Page extends Enum<Page>> extends
@Override
public Object instantiateItem(ViewGroup container, int position) {
+
final Page page = pageOrder.get(position);
PageViewCreator creator = viewCreators.get(page);
@@ -114,6 +146,7 @@ public abstract class AbstractViewPagerActivity<Page extends Enum<Page>> extends
if (null == creator && null != page) {
creator = AbstractViewPagerActivity.this.createViewCreator(page);
viewCreators.put(page, creator);
+ viewStates.put(page, new Bundle());
}
View view = null;
@@ -123,12 +156,18 @@ public abstract class AbstractViewPagerActivity<Page extends Enum<Page>> extends
// Result from getView() is maybe cached, but it should be valid because the
// creator should be informed about data-changes with notifyDataSetChanged()
view = creator.getView();
+
+ // Restore the state of the view if the page supports it
+ Bundle state = viewStates.get(page);
+ if (state != null) {
+ creator.setViewState(state);
+ }
+
container.addView(view, 0);
}
} catch (Exception e) {
Log.e("ViewPagerAdapter.instantiateItem ", e);
}
-
return view;
}
@@ -225,10 +264,15 @@ public abstract class AbstractViewPagerActivity<Page extends Enum<Page>> extends
protected abstract String getTitle(Page page);
protected final void reinitializeViewPager() {
+
// notify all creators that the data has changed
for (PageViewCreator creator : viewCreators.values()) {
creator.notifyDataSetChanged();
}
+ // reset the stored view states of all pages
+ for (Bundle state : viewStates.values()) {
+ state.clear();
+ }
pageOrder.clear();
final Pair<List<? extends Page>, Integer> pagesAndIndex = getOrderedPages();
diff --git a/main/src/cgeo/geocaching/activity/ActivityMixin.java b/main/src/cgeo/geocaching/activity/ActivityMixin.java
index 9b1e433..c1a2678 100644
--- a/main/src/cgeo/geocaching/activity/ActivityMixin.java
+++ b/main/src/cgeo/geocaching/activity/ActivityMixin.java
@@ -8,10 +8,7 @@ import cgeo.geocaching.settings.Settings;
import org.apache.commons.lang3.StringUtils;
import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
import android.content.Intent;
-import android.graphics.drawable.Drawable;
import android.os.Build;
import android.view.Gravity;
import android.view.View;
@@ -94,30 +91,6 @@ public final class ActivityMixin {
}
}
- public static void helpDialog(final Activity activity, final String title, final String message, final Drawable icon) {
- if (StringUtils.isBlank(message)) {
- return;
- }
-
- AlertDialog.Builder dialog = new AlertDialog.Builder(activity).setTitle(title).setMessage(message).setCancelable(true);
- dialog.setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- });
- if (icon != null) {
- dialog.setIcon(icon);
- }
-
- AlertDialog alert = dialog.create();
- alert.show();
- }
-
- public static void helpDialog(Activity activity, String title, String message) {
- helpDialog(activity, title, message, null);
- }
-
public static void keepScreenOn(final Activity abstractActivity, boolean keepScreenOn) {
if (keepScreenOn) {
abstractActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
@@ -130,7 +103,7 @@ public final class ActivityMixin {
/**
* insert text into the EditText at the current cursor position
- *
+ *
* @param editText
* @param insertText
* @param moveCursor
diff --git a/main/src/cgeo/geocaching/activity/IAbstractActivity.java b/main/src/cgeo/geocaching/activity/IAbstractActivity.java
index 61c218b..7ca2322 100644
--- a/main/src/cgeo/geocaching/activity/IAbstractActivity.java
+++ b/main/src/cgeo/geocaching/activity/IAbstractActivity.java
@@ -10,7 +10,5 @@ public interface IAbstractActivity {
public void showShortToast(String text);
- public void helpDialog(String title, String message);
-
public void invalidateOptionsMenuCompatible();
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java
index dd02bc1..bf0e776 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java
@@ -71,7 +71,8 @@ public final class NavigationAppFactory extends AbstractAppFactory {
CACHE_BEACON(new CacheBeaconApp(), 14, R.string.pref_navigation_menu_cache_beacon),
GCC(new GccApp(), 15, R.string.pref_navigation_menu_gcc),
- WHERE_YOU_GO(new WhereYouGoApp(), 16, R.string.pref_navigation_menu_where_you_go);
+ WHERE_YOU_GO(new WhereYouGoApp(), 16, R.string.pref_navigation_menu_where_you_go),
+ PEBBLE(new PebbleApp(), 17, R.string.pref_navigation_menu_pebble);
NavigationAppsEnum(final App app, final int id, final int preferenceKey) {
this.app = app;
@@ -142,8 +143,6 @@ public final class NavigationAppFactory extends AbstractAppFactory {
public static void showNavigationMenu(final Activity activity,
final Geocache cache, final Waypoint waypoint, final Geopoint destination,
final boolean showInternalMap, final boolean showDefaultNavigation) {
- final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- builder.setTitle(R.string.cache_menu_navigate);
final List<NavigationAppsEnum> items = new ArrayList<NavigationAppFactory.NavigationAppsEnum>();
final int defaultNavigationTool = Settings.getDefaultNavigationTool();
for (final NavigationAppsEnum navApp : getInstalledNavigationApps()) {
@@ -166,26 +165,25 @@ public final class NavigationAppFactory extends AbstractAppFactory {
}
}
}
+
+ if (items.size() == 1) {
+ invokeNavigation(activity, cache, waypoint, destination, items.get(0).app);
+ return;
+ }
+
/*
* Using an ArrayAdapter with list of NavigationAppsEnum items avoids
* handling between mapping list positions allows us to do dynamic filtering of the list based on use case.
*/
final ArrayAdapter<NavigationAppsEnum> adapter = new ArrayAdapter<NavigationAppsEnum>(activity, android.R.layout.select_dialog_item, items);
+ final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setTitle(R.string.cache_menu_navigate);
builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int item) {
final NavigationAppsEnum selectedItem = adapter.getItem(item);
- final App app = selectedItem.app;
- if (cache != null) {
- navigateCache(activity, cache, app);
- }
- else if (waypoint != null) {
- navigateWaypoint(activity, waypoint, app);
- }
- else {
- navigateGeopoint(activity, destination, app);
- }
+ invokeNavigation(activity, cache, waypoint, destination, selectedItem.app);
}
});
final AlertDialog alert = builder.create();
@@ -225,7 +223,7 @@ public final class NavigationAppFactory extends AbstractAppFactory {
/**
* Handles menu selections for menu entries created with
* {@link #showNavigationMenu(Activity, Geocache, Waypoint, Geopoint)}.
- *
+ *
* @param item
* @param activity
* @param cache
@@ -343,4 +341,16 @@ public final class NavigationAppFactory extends AbstractAppFactory {
return NavigationAppsEnum.COMPASS.app;
}
+ private static void invokeNavigation(final Activity activity, final Geocache cache, final Waypoint waypoint, final Geopoint destination, final App app) {
+ if (cache != null) {
+ navigateCache(activity, cache, app);
+ }
+ else if (waypoint != null) {
+ navigateWaypoint(activity, waypoint, app);
+ }
+ else {
+ navigateGeopoint(activity, destination, app);
+ }
+ }
+
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/PebbleApp.java b/main/src/cgeo/geocaching/apps/cache/navi/PebbleApp.java
new file mode 100644
index 0000000..8ba3bef
--- /dev/null
+++ b/main/src/cgeo/geocaching/apps/cache/navi/PebbleApp.java
@@ -0,0 +1,44 @@
+package cgeo.geocaching.apps.cache.navi;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.R;
+import cgeo.geocaching.geopoint.Geopoint;
+
+import android.app.Activity;
+import android.content.Intent;
+
+/**
+ * Application for communication with the Pebble watch.
+ *
+ */
+class PebbleApp extends AbstractPointNavigationApp {
+
+ private static final String INTENT = "com.webmajstr.pebble_gc.NAVIGATE_TO";
+ private static final String PACKAGE_NAME = "com.webmajstr.pebble_gc";
+
+ PebbleApp() {
+ super(getString(R.string.cache_menu_pebble), R.id.cache_app_pebble, INTENT, PACKAGE_NAME);
+ }
+
+ @Override
+ public void navigate(Activity activity, Geopoint point) {
+ final Intent pebbleIntent = new Intent(INTENT);
+ pebbleIntent.putExtra("latitude", point.getLatitude());
+ pebbleIntent.putExtra("longitude", point.getLongitude());
+ activity.startActivity(pebbleIntent);
+ }
+
+ @Override
+ public void navigate(Activity activity, Geocache cache) {
+ final Intent pebbleIntent = new Intent(INTENT);
+ pebbleIntent.putExtra("latitude", cache.getCoords().getLatitude());
+ pebbleIntent.putExtra("longitude", cache.getCoords().getLongitude());
+ pebbleIntent.putExtra("difficulty", cache.getDifficulty());
+ pebbleIntent.putExtra("terrain", cache.getTerrain());
+ pebbleIntent.putExtra("name", cache.getName());
+ pebbleIntent.putExtra("code", cache.getGeocode());
+ pebbleIntent.putExtra("size", cache.getSize().getL10n());
+ activity.startActivity(pebbleIntent);
+ }
+
+} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/connector/AbstractConnector.java b/main/src/cgeo/geocaching/connector/AbstractConnector.java
index b10366e..ffb1b1f 100644
--- a/main/src/cgeo/geocaching/connector/AbstractConnector.java
+++ b/main/src/cgeo/geocaching/connector/AbstractConnector.java
@@ -1,21 +1,28 @@
package cgeo.geocaching.connector;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.LogCacheActivity;
import cgeo.geocaching.R;
+import cgeo.geocaching.connector.capability.ISearchByCenter;
+import cgeo.geocaching.connector.capability.ISearchByGeocode;
+import cgeo.geocaching.connector.capability.ISearchByKeyword;
+import cgeo.geocaching.connector.capability.ISearchByViewPort;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.geopoint.Geopoint;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
public abstract class AbstractConnector implements IConnector {
@Override
- public boolean canHandle(String geocode) {
+ public boolean canHandle(@NonNull final String geocode) {
return false;
}
@@ -88,7 +95,7 @@ public abstract class AbstractConnector implements IConnector {
}
@Override
- public String getLicenseText(final Geocache cache) {
+ public String getLicenseText(final @NonNull Geocache cache) {
return null;
}
@@ -132,15 +139,12 @@ public abstract class AbstractConnector implements IConnector {
abstract protected String getCacheUrlPrefix();
@Override
- public String getLongCacheUrl(final Geocache cache) {
+ public String getLongCacheUrl(final @NonNull Geocache cache) {
return getCacheUrl(cache);
}
- /**
- * {@link IConnector}
- */
@Override
- public boolean isActivated() {
+ public boolean isActive() {
return false;
}
@@ -200,4 +204,48 @@ public abstract class AbstractConnector implements IConnector {
// Default: just return the name
return name;
}
+
+ @Override
+ public int getMaxTerrain() {
+ return 5;
+ }
+
+ @Override
+ public final Collection<String> getCapabilities() {
+ ArrayList<String> builder = new ArrayList<String>();
+ builder.add(capability(ISearchByViewPort.class, R.string.feature_search_live_map));
+ builder.add(capability(ISearchByKeyword.class, R.string.feature_search_keyword));
+ builder.add(capability(ISearchByCenter.class, R.string.feature_search_center));
+ builder.add(capability(ISearchByGeocode.class, R.string.feature_search_geocode));
+ if (supportsUserActions()) {
+ builder.add(feature(R.string.feature_search_user));
+ }
+ if (supportsLogging()) {
+ builder.add(feature(R.string.feature_online_logging));
+ }
+ if (supportsLogImages()) {
+ builder.add(feature(R.string.feature_log_images));
+ }
+ if (supportsPersonalNote()) {
+ builder.add(feature(R.string.feature_personal_notes));
+ }
+ if (supportsOwnCoordinates()) {
+ builder.add(feature(R.string.feature_own_coordinates));
+ }
+ if (supportsWatchList()) {
+ builder.add(feature(R.string.feature_watch_list));
+ }
+ return builder;
+ }
+
+ private String capability(Class<? extends IConnector> clazz, final int featureResourceId) {
+ if (clazz.isInstance(this)) {
+ return feature(featureResourceId);
+ }
+ return StringUtils.EMPTY;
+ }
+
+ private static String feature(int featureResourceId) {
+ return CgeoApplication.getInstance().getString(featureResourceId);
+ }
}
diff --git a/main/src/cgeo/geocaching/connector/AbstractLoggingManager.java b/main/src/cgeo/geocaching/connector/AbstractLoggingManager.java
new file mode 100644
index 0000000..9e702c4
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/AbstractLoggingManager.java
@@ -0,0 +1,20 @@
+package cgeo.geocaching.connector;
+
+import cgeo.geocaching.TrackableLog;
+
+import java.util.Collections;
+import java.util.List;
+
+public abstract class AbstractLoggingManager implements ILoggingManager {
+
+ @Override
+ public boolean hasLoaderError() {
+ return false;
+ }
+
+ @Override
+ public List<TrackableLog> getTrackables() {
+ return Collections.emptyList();
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/AbstractLogin.java b/main/src/cgeo/geocaching/connector/AbstractLogin.java
new file mode 100644
index 0000000..6527685
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/AbstractLogin.java
@@ -0,0 +1,77 @@
+package cgeo.geocaching.connector;
+
+import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.R;
+import cgeo.geocaching.enumerations.StatusCode;
+import cgeo.geocaching.network.Cookies;
+import cgeo.geocaching.settings.Settings;
+
+import org.apache.commons.lang3.StringUtils;
+
+public abstract class AbstractLogin {
+
+ /**
+ * {@code true} if logged in, {@code false} otherwise
+ */
+ private boolean actualLoginStatus = false;
+ private String actualUserName = StringUtils.EMPTY;
+ /**
+ * Number of caches found. An unknown number is signaled by the value -1, while 0 really indicates zero caches found
+ * by the user.
+ */
+ private int actualCachesFound = -1;
+ private String actualStatus = StringUtils.EMPTY;
+
+ public void setActualCachesFound(final int found) {
+ actualCachesFound = found;
+ }
+
+ public String getActualStatus() {
+ return actualStatus;
+ }
+
+ protected void setActualStatus(final String status) {
+ actualStatus = status;
+ }
+
+ public boolean isActualLoginStatus() {
+ return actualLoginStatus;
+ }
+
+ protected void setActualLoginStatus(boolean loginStatus) {
+ actualLoginStatus = loginStatus;
+ }
+
+ public String getActualUserName() {
+ return actualUserName;
+ }
+
+ protected void setActualUserName(String userName) {
+ actualUserName = userName;
+ }
+
+ public int getActualCachesFound() {
+ return actualCachesFound;
+ }
+
+ protected void resetLoginStatus() {
+ Cookies.clearCookies();
+ Settings.setCookieStore(null);
+
+ setActualLoginStatus(false);
+ }
+
+ protected void clearLoginInfo() {
+ resetLoginStatus();
+
+ setActualCachesFound(-1);
+ setActualStatus(CgeoApplication.getInstance().getString(R.string.err_login));
+ }
+
+ public StatusCode login() {
+ return login(true);
+ }
+
+ protected abstract StatusCode login(boolean retry);
+
+}
diff --git a/main/src/cgeo/geocaching/connector/ConnectorFactory.java b/main/src/cgeo/geocaching/connector/ConnectorFactory.java
index 83f8142..3df98e0 100644
--- a/main/src/cgeo/geocaching/connector/ConnectorFactory.java
+++ b/main/src/cgeo/geocaching/connector/ConnectorFactory.java
@@ -8,7 +8,9 @@ import cgeo.geocaching.connector.capability.ILogin;
import cgeo.geocaching.connector.capability.ISearchByCenter;
import cgeo.geocaching.connector.capability.ISearchByKeyword;
import cgeo.geocaching.connector.capability.ISearchByViewPort;
+import cgeo.geocaching.connector.ec.ECConnector;
import cgeo.geocaching.connector.gc.GCConnector;
+import cgeo.geocaching.connector.gc.MapTokens;
import cgeo.geocaching.connector.oc.OCApiConnector;
import cgeo.geocaching.connector.oc.OCApiConnector.ApiSupport;
import cgeo.geocaching.connector.oc.OCApiLiveConnector;
@@ -24,12 +26,16 @@ import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import java.util.List;
public final class ConnectorFactory {
private static final UnknownConnector UNKNOWN_CONNECTOR = new UnknownConnector();
- private static final IConnector[] CONNECTORS = new IConnector[] {
+ private static final Collection<IConnector> CONNECTORS = Collections.unmodifiableCollection(Arrays.asList(new IConnector[] {
GCConnector.getInstance(),
+ ECConnector.getInstance(),
new OCApiLiveConnector("opencaching.de", "www.opencaching.de", "OC", "CC BY-NC-ND, alle Logeinträge © jeweiliger Autor",
R.string.oc_de_okapi_consumer_key, R.string.oc_de_okapi_consumer_secret,
R.string.pref_connectorOCActive, R.string.pref_ocde_tokenpublic, R.string.pref_ocde_tokensecret, ApiSupport.current),
@@ -43,71 +49,54 @@ public final class ConnectorFactory {
new OCApiLiveConnector("opencaching.pl", "www.opencaching.pl", "OP", "CC BY-SA 3.0",
R.string.oc_pl_okapi_consumer_key, R.string.oc_pl_okapi_consumer_secret,
R.string.pref_connectorOCPLActive, R.string.pref_ocpl_tokenpublic, R.string.pref_ocpl_tokensecret, ApiSupport.current),
- new OCApiConnector("OpenCaching.US", "www.opencaching.us", "OU", "pTsYAYSXFcfcRQnYE6uA", "CC BY-NC-SA 2.5", ApiSupport.oldapi),
+ new OCApiConnector("OpenCaching.US", "www.opencaching.us", "OU", "pTsYAYSXFcfcRQnYE6uA", "CC BY-NC-SA 2.5", ApiSupport.current),
new OXConnector(),
new GeocachingAustraliaConnector(),
new GeopeitusConnector(),
new WaymarkingConnector(),
UNKNOWN_CONNECTOR // the unknown connector MUST be the last one
- };
+ }));
@NonNull public static final UnknownTrackableConnector UNKNOWN_TRACKABLE_CONNECTOR = new UnknownTrackableConnector();
- private static final TrackableConnector[] TRACKABLE_CONNECTORS = new TrackableConnector[] {
+ private static final Collection<TrackableConnector> TRACKABLE_CONNECTORS = Collections.unmodifiableCollection(Arrays.asList(new TrackableConnector[] {
new GeokretyConnector(), // GK must be first, as it overlaps with the secret codes of travel bugs
TravelBugConnector.getInstance(),
UNKNOWN_TRACKABLE_CONNECTOR // must be last
- };
+ }));
- private static final ISearchByViewPort[] searchByViewPortConns;
+ private static final Collection<ISearchByViewPort> searchByViewPortConns = getMatchingConnectors(ISearchByViewPort.class);
- private static final ISearchByCenter[] searchByCenterConns;
+ private static final Collection<ISearchByCenter> searchByCenterConns = getMatchingConnectors(ISearchByCenter.class);
- private static final ISearchByKeyword[] searchByKeywordConns;
+ private static final Collection<ISearchByKeyword> searchByKeywordConns = getMatchingConnectors(ISearchByKeyword.class);
- static {
- final List<ISearchByViewPort> vpConns = new ArrayList<ISearchByViewPort>();
- for (final IConnector conn : CONNECTORS) {
- if (conn instanceof ISearchByViewPort) {
- vpConns.add((ISearchByViewPort) conn);
- }
- }
- searchByViewPortConns = vpConns.toArray(new ISearchByViewPort[vpConns.size()]);
-
- final List<ISearchByCenter> centerConns = new ArrayList<ISearchByCenter>();
- for (final IConnector conn : CONNECTORS) {
- // GCConnector is handled specially, omit it here!
- if (conn instanceof ISearchByCenter && !(conn instanceof GCConnector)) {
- centerConns.add((ISearchByCenter) conn);
- }
- }
- searchByCenterConns = centerConns.toArray(new ISearchByCenter[centerConns.size()]);
-
- final List<ISearchByKeyword> keywordConns = new ArrayList<ISearchByKeyword>();
- for (final IConnector conn : CONNECTORS) {
- // GCConnector is handled specially, omit it here!
- if (conn instanceof ISearchByKeyword && !(conn instanceof GCConnector)) {
- keywordConns.add((ISearchByKeyword) conn);
+ @SuppressWarnings("unchecked")
+ private static <T extends IConnector> Collection<T> getMatchingConnectors(final Class<T> clazz) {
+ final List<T> matching = new ArrayList<T>();
+ for (final IConnector connector : CONNECTORS) {
+ if (clazz.isInstance(connector)) {
+ matching.add((T) connector);
}
}
- searchByKeywordConns = keywordConns.toArray(new ISearchByKeyword[keywordConns.size()]);
+ return Collections.unmodifiableCollection(matching);
}
- public static IConnector[] getConnectors() {
+ public static Collection<IConnector> getConnectors() {
return CONNECTORS;
}
- public static ISearchByCenter[] getSearchByCenterConnectors() {
+ public static Collection<ISearchByCenter> getSearchByCenterConnectors() {
return searchByCenterConns;
}
- public static ISearchByKeyword[] getSearchByKeywordConnectors() {
+ public static Collection<ISearchByKeyword> getSearchByKeywordConnectors() {
return searchByKeywordConns;
}
public static ILogin[] getActiveLiveConnectors() {
final List<ILogin> liveConns = new ArrayList<ILogin>();
for (final IConnector conn : CONNECTORS) {
- if (conn instanceof ILogin && conn.isActivated()) {
+ if (conn instanceof ILogin && conn.isActive()) {
liveConns.add((ILogin) conn);
}
}
@@ -147,6 +136,9 @@ public final class ConnectorFactory {
public static IConnector getConnector(final String geocodeInput) {
// this may come from user input
final String geocode = StringUtils.trim(geocodeInput);
+ if (geocode == null) {
+ return UNKNOWN_CONNECTOR;
+ }
if (isInvalidGeocode(geocode)) {
return UNKNOWN_CONNECTOR;
}
@@ -164,12 +156,11 @@ public final class ConnectorFactory {
}
/** @see ISearchByViewPort#searchByViewport */
- public static SearchResult searchByViewport(final Viewport viewport, final String[] tokens) {
-
+ public static SearchResult searchByViewport(final @NonNull Viewport viewport, final MapTokens tokens) {
final SearchResult result = new SearchResult();
- for (final ISearchByViewPort vpconn : searchByViewPortConns) {
- if (vpconn.isActivated()) {
- result.addSearchResult(vpconn.searchByViewport(viewport, tokens));
+ for (final ISearchByViewPort connector : searchByViewPortConns) {
+ if (connector.isActive()) {
+ result.addSearchResult(connector.searchByViewport(viewport, tokens));
}
}
return result;
@@ -185,7 +176,7 @@ public final class ConnectorFactory {
return null;
}
- public static TrackableConnector[] getTrackableConnectors() {
+ public static Collection<TrackableConnector> getTrackableConnectors() {
return TRACKABLE_CONNECTORS;
}
diff --git a/main/src/cgeo/geocaching/connector/GeocachingAustraliaConnector.java b/main/src/cgeo/geocaching/connector/GeocachingAustraliaConnector.java
index ac2fb37..3992013 100644
--- a/main/src/cgeo/geocaching/connector/GeocachingAustraliaConnector.java
+++ b/main/src/cgeo/geocaching/connector/GeocachingAustraliaConnector.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.Geocache;
import cgeo.geocaching.ICache;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
public class GeocachingAustraliaConnector extends AbstractConnector {
@@ -13,7 +14,7 @@ public class GeocachingAustraliaConnector extends AbstractConnector {
}
@Override
- public String getCacheUrl(final Geocache cache) {
+ public String getCacheUrl(final @NonNull Geocache cache) {
return getCacheUrlPrefix() + cache.getGeocode();
}
@@ -28,7 +29,7 @@ public class GeocachingAustraliaConnector extends AbstractConnector {
}
@Override
- public boolean canHandle(final String geocode) {
+ public boolean canHandle(final @NonNull String geocode) {
return (StringUtils.startsWithIgnoreCase(geocode, "GA") || StringUtils.startsWithIgnoreCase(geocode, "TP")) && isNumericId(geocode.substring(2));
}
diff --git a/main/src/cgeo/geocaching/connector/GeopeitusConnector.java b/main/src/cgeo/geocaching/connector/GeopeitusConnector.java
index 500f752..aa08485 100644
--- a/main/src/cgeo/geocaching/connector/GeopeitusConnector.java
+++ b/main/src/cgeo/geocaching/connector/GeopeitusConnector.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.Geocache;
import cgeo.geocaching.ICache;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
public class GeopeitusConnector extends AbstractConnector {
@@ -13,7 +14,7 @@ public class GeopeitusConnector extends AbstractConnector {
}
@Override
- public String getCacheUrl(final Geocache cache) {
+ public String getCacheUrl(final @NonNull Geocache cache) {
return getCacheUrlPrefix() + StringUtils.stripStart(cache.getGeocode().substring(2), "0");
}
@@ -28,7 +29,7 @@ public class GeopeitusConnector extends AbstractConnector {
}
@Override
- public boolean canHandle(String geocode) {
+ public boolean canHandle(@NonNull String geocode) {
return StringUtils.startsWith(geocode, "GE") && isNumericId(geocode.substring(2));
}
diff --git a/main/src/cgeo/geocaching/connector/IConnector.java b/main/src/cgeo/geocaching/connector/IConnector.java
index a96ee10..34922f5 100644
--- a/main/src/cgeo/geocaching/connector/IConnector.java
+++ b/main/src/cgeo/geocaching/connector/IConnector.java
@@ -6,6 +6,9 @@ import cgeo.geocaching.LogCacheActivity;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.geopoint.Geopoint;
+import org.eclipse.jdt.annotation.NonNull;
+
+import java.util.Collection;
import java.util.List;
public interface IConnector {
@@ -17,20 +20,21 @@ public interface IConnector {
public String getName();
/**
- * return true, if this connector is responsible for the given cache
+ * Check if this connector is responsible for the given geocode.
*
* @param geocode
- * @return
+ * geocode of a cache
+ * @return return {@code true}, if this connector is responsible for the cache
*/
- public boolean canHandle(final String geocode);
+ public boolean canHandle(final @NonNull String geocode);
/**
- * get browser URL for the given cache
+ * Get the browser URL for the given cache.
*
* @param cache
* @return
*/
- public String getCacheUrl(final Geocache cache);
+ public String getCacheUrl(final @NonNull Geocache cache);
/**
* get long browser URL for the given cache
@@ -38,7 +42,7 @@ public interface IConnector {
* @param cache
* @return
*/
- public String getLongCacheUrl(final Geocache cache);
+ public String getLongCacheUrl(final @NonNull Geocache cache);
/**
* enable/disable watchlist controls in cache details
@@ -92,19 +96,19 @@ public interface IConnector {
public ILoggingManager getLoggingManager(final LogCacheActivity activity, final Geocache cache);
/**
- * get host name of the connector server for dynamic loading of data
+ * Get host name of the connector server for dynamic loading of data.
*
* @return
*/
public String getHost();
/**
- * get cache data license text
+ * Get cache data license text. This is displayed somewhere near the cache details.
*
* @param cache
* @return
*/
- public String getLicenseText(final Geocache cache);
+ public String getLicenseText(final @NonNull Geocache cache);
/**
* enable/disable user actions in cache details
@@ -178,13 +182,13 @@ public interface IConnector {
public boolean uploadModifiedCoordinates(Geocache cache, Geopoint wpt);
/**
- * Return true if this connector is activated for online
- * interaction (download details, do searches, ...)
+ * Return {@code true} if this connector is active for online interaction (download details, do searches, ...). If
+ * this is {@code false}, the connector will still be used for already stored offline caches.
*
* @return
*/
- public boolean isActivated();
+ public boolean isActive();
/**
* Check if the current user is the owner of the given cache.
@@ -213,7 +217,7 @@ public interface IConnector {
public int getCacheMapMarkerId(boolean disabled);
/**
- * Get the list of <b>potentially</b> possible log types for a cache. Those may still be filter further during the
+ * Get the list of <b>potentially</b> possible log types for a cache. Those may still be filtered further during the
* actual logging activity.
*
* @param geocache
@@ -222,8 +226,8 @@ public interface IConnector {
public List<LogType> getPossibleLogTypes(Geocache geocache);
/**
- * Get the gpx id for a waypoint when exporting. For some connectors there is an inherent name logic,
- * for others its just the 'prefix'
+ * Get the GPX id for a waypoint when exporting. For some connectors there is an inherent name logic,
+ * for others its just the 'prefix'.
*
* @param prefix
* @return
@@ -231,10 +235,24 @@ public interface IConnector {
public String getWaypointGpxId(String prefix, String geocode);
/**
- * Get the 'prefix' (key) for a waypoint from the 'name' in the gpx file
- *
+ * Get the 'prefix' (key) for a waypoint from the 'name' in the GPX file
+ *
* @param name
* @return
*/
public String getWaypointPrefix(String name);
+
+ /**
+ * Get the maximum value for Terrain
+ *
+ * @return
+ */
+ public int getMaxTerrain();
+
+ /**
+ * Get a user readable collection of all online features of this connector.
+ *
+ * @return
+ */
+ public Collection<String> getCapabilities();
}
diff --git a/main/src/cgeo/geocaching/connector/NoLoggingManager.java b/main/src/cgeo/geocaching/connector/NoLoggingManager.java
index 04a73c1..e2e5d4c 100644
--- a/main/src/cgeo/geocaching/connector/NoLoggingManager.java
+++ b/main/src/cgeo/geocaching/connector/NoLoggingManager.java
@@ -11,7 +11,7 @@ import java.util.Calendar;
import java.util.Collections;
import java.util.List;
-public class NoLoggingManager implements ILoggingManager {
+public class NoLoggingManager extends AbstractLoggingManager {
@Override
public void init() {
@@ -34,11 +34,6 @@ public class NoLoggingManager implements ILoggingManager {
}
@Override
- public List<TrackableLog> getTrackables() {
- return Collections.emptyList();
- }
-
- @Override
public List<LogType> getPossibleLogTypes() {
return Collections.emptyList();
}
diff --git a/main/src/cgeo/geocaching/connector/UnknownConnector.java b/main/src/cgeo/geocaching/connector/UnknownConnector.java
index e9fecb9..05593d7 100644
--- a/main/src/cgeo/geocaching/connector/UnknownConnector.java
+++ b/main/src/cgeo/geocaching/connector/UnknownConnector.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.Geocache;
import cgeo.geocaching.ICache;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
public class UnknownConnector extends AbstractConnector {
@@ -13,7 +14,7 @@ public class UnknownConnector extends AbstractConnector {
}
@Override
- public String getCacheUrl(Geocache cache) {
+ public String getCacheUrl(@NonNull Geocache cache) {
return null; // we have no url for these caches
}
@@ -28,7 +29,7 @@ public class UnknownConnector extends AbstractConnector {
}
@Override
- public boolean canHandle(final String geocode) {
+ public boolean canHandle(final @NonNull String geocode) {
return StringUtils.isNotBlank(geocode);
}
diff --git a/main/src/cgeo/geocaching/connector/WaymarkingConnector.java b/main/src/cgeo/geocaching/connector/WaymarkingConnector.java
index f184f6e..282ee31 100644
--- a/main/src/cgeo/geocaching/connector/WaymarkingConnector.java
+++ b/main/src/cgeo/geocaching/connector/WaymarkingConnector.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.Geocache;
import cgeo.geocaching.ICache;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
public class WaymarkingConnector extends AbstractConnector {
@@ -13,7 +14,7 @@ public class WaymarkingConnector extends AbstractConnector {
}
@Override
- public String getCacheUrl(Geocache cache) {
+ public String getCacheUrl(@NonNull Geocache cache) {
return getCacheUrlPrefix() + cache.getGeocode();
}
@@ -34,7 +35,7 @@ public class WaymarkingConnector extends AbstractConnector {
}
@Override
- public boolean canHandle(String geocode) {
+ public boolean canHandle(@NonNull String geocode) {
return StringUtils.startsWith(geocode, "WM");
}
}
diff --git a/main/src/cgeo/geocaching/connector/capability/ICredentials.java b/main/src/cgeo/geocaching/connector/capability/ICredentials.java
new file mode 100644
index 0000000..2d5cd0b
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/capability/ICredentials.java
@@ -0,0 +1,21 @@
+package cgeo.geocaching.connector.capability;
+
+
+/**
+ * Marker interface for connectors which have user name and password as credentials.
+ *
+ */
+public interface ICredentials {
+ /**
+ * Get preference key of the user name.
+ *
+ */
+ public int getUsernamePreferenceKey();
+
+ /**
+ * Get preference key of the password.
+ *
+ */
+ public int getPasswordPreferenceKey();
+
+}
diff --git a/main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java b/main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java
index 91dd094..adc36c7 100644
--- a/main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java
+++ b/main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java
@@ -3,11 +3,14 @@ package cgeo.geocaching.connector.capability;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.connector.IConnector;
import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.loaders.RecaptchaReceiver;
+
+import org.eclipse.jdt.annotation.NonNull;
/**
* connector capability for online searching caches around a center coordinate, sorted by distance
*
*/
public interface ISearchByCenter extends IConnector {
- public SearchResult searchByCenter(final Geopoint center);
+ public SearchResult searchByCenter(final @NonNull Geopoint center, final @NonNull RecaptchaReceiver recaptchaReceiver);
}
diff --git a/main/src/cgeo/geocaching/connector/capability/ISearchByGeocode.java b/main/src/cgeo/geocaching/connector/capability/ISearchByGeocode.java
index 4c16049..7abc235 100644
--- a/main/src/cgeo/geocaching/connector/capability/ISearchByGeocode.java
+++ b/main/src/cgeo/geocaching/connector/capability/ISearchByGeocode.java
@@ -4,10 +4,12 @@ import cgeo.geocaching.SearchResult;
import cgeo.geocaching.connector.IConnector;
import cgeo.geocaching.utils.CancellableHandler;
+import org.eclipse.jdt.annotation.Nullable;
+
/**
* connector capability of searching online for a cache by geocode
*
*/
public interface ISearchByGeocode extends IConnector {
- public SearchResult searchByGeocode(final String geocode, final String guid, final CancellableHandler handler);
+ public SearchResult searchByGeocode(final @Nullable String geocode, final @Nullable String guid, final CancellableHandler handler);
}
diff --git a/main/src/cgeo/geocaching/connector/capability/ISearchByKeyword.java b/main/src/cgeo/geocaching/connector/capability/ISearchByKeyword.java
index 09b2423..9b3e6eb 100644
--- a/main/src/cgeo/geocaching/connector/capability/ISearchByKeyword.java
+++ b/main/src/cgeo/geocaching/connector/capability/ISearchByKeyword.java
@@ -2,11 +2,15 @@ package cgeo.geocaching.connector.capability;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.connector.IConnector;
+import cgeo.geocaching.loaders.RecaptchaReceiver;
+
+import org.eclipse.jdt.annotation.NonNull;
/**
- * connector capability of searching online for a cache by name
- *
+ * Connector capability of searching online for a cache by keyword.
+ *
*/
public interface ISearchByKeyword extends IConnector {
- public SearchResult searchByName(final String name);
+ // TODO: The recaptcha receiver is only needed for GC. Would be good to refactor this away from the generic interface.
+ public SearchResult searchByKeyword(final @NonNull String keyword, final @NonNull RecaptchaReceiver recaptchaReceiver);
}
diff --git a/main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java b/main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java
index 4954017..7981ba8 100644
--- a/main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java
+++ b/main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java
@@ -2,8 +2,11 @@ package cgeo.geocaching.connector.capability;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.connector.IConnector;
+import cgeo.geocaching.connector.gc.MapTokens;
import cgeo.geocaching.geopoint.Viewport;
+import org.eclipse.jdt.annotation.NonNull;
+
public interface ISearchByViewPort extends IConnector {
- public SearchResult searchByViewport(final Viewport viewport, final String[] tokens);
+ public SearchResult searchByViewport(final @NonNull Viewport viewport, final MapTokens tokens);
}
diff --git a/main/src/cgeo/geocaching/connector/ec/ECApi.java b/main/src/cgeo/geocaching/connector/ec/ECApi.java
new file mode 100644
index 0000000..f91bcdb
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/ec/ECApi.java
@@ -0,0 +1,220 @@
+package cgeo.geocaching.connector.ec;
+
+import cgeo.geocaching.DataStore;
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.connector.LogResult;
+import cgeo.geocaching.enumerations.CacheType;
+import cgeo.geocaching.enumerations.LoadFlags.SaveFlag;
+import cgeo.geocaching.enumerations.LogType;
+import cgeo.geocaching.enumerations.StatusCode;
+import cgeo.geocaching.files.GPX10Parser;
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.list.StoredList;
+import cgeo.geocaching.network.Network;
+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;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
+
+public class ECApi {
+
+ private static final String API_HOST = "http://extremcaching.com/exports/";
+
+ private static final FastDateFormat LOG_DATE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSSZ", TimeZone.getTimeZone("UTC"), Locale.US);
+
+ public static String cleanCode(String geocode) {
+ return geocode.replace("EC", "");
+ }
+
+ public static Geocache searchByGeoCode(final String geocode) {
+ final Parameters params = new Parameters("id", cleanCode(geocode), "cgeo", "1");
+ final HttpResponse response = apiRequest("gpx.php", params);
+
+ final Collection<Geocache> caches = importCachesFromGPXResponse(response);
+ if (CollectionUtils.isNotEmpty(caches)) {
+ return caches.iterator().next();
+ }
+ return null;
+ }
+
+ public static Collection<Geocache> searchByBBox(final Viewport viewport) {
+
+ if (viewport.getLatitudeSpan() == 0 || viewport.getLongitudeSpan() == 0) {
+ return Collections.emptyList();
+ }
+
+ final Parameters params = new Parameters("fnc", "bbox");
+ params.add("lat1", String.valueOf(viewport.getLatitudeMin()));
+ params.add("lat2", String.valueOf(viewport.getLatitudeMax()));
+ params.add("lon1", String.valueOf(viewport.getLongitudeMin()));
+ params.add("lon2", String.valueOf(viewport.getLongitudeMax()));
+ final HttpResponse response = apiRequest(params);
+
+ return importCachesFromJSON(response);
+ }
+
+
+ public static Collection<Geocache> searchByCenter(final Geopoint center) {
+
+ final Parameters params = new Parameters("fnc", "center");
+ params.add("distance", "20");
+ params.add("lat", String.valueOf(center.getLatitude()));
+ params.add("lon", String.valueOf(center.getLongitude()));
+ final HttpResponse response = apiRequest(params);
+
+ return importCachesFromJSON(response);
+ }
+
+ public static LogResult postLog(final Geocache cache, final LogType logType, final Calendar date, final String log) {
+ return postLog(cache, logType, date, log, false);
+ }
+
+ public static LogResult postLog(final Geocache cache, final LogType logType, final Calendar date, final String log, boolean isRetry) {
+ final Parameters params = new Parameters("cache_id", cache.getGeocode());
+ params.add("type", logType.type);
+ params.add("log", log);
+ params.add("date", LOG_DATE_FORMAT.format(date.getTime()));
+
+ final String uri = API_HOST + "log.php";
+ final HttpResponse response = Network.postRequest(uri, params);
+
+ if (response == null) {
+ return new LogResult(StatusCode.LOG_POST_ERROR_EC, "");
+ }
+ if (!isRetry && response.getStatusLine().getStatusCode() == 403) {
+ if (ECLogin.getInstance().login() == StatusCode.NO_ERROR) {
+ apiRequest(uri, params, true);
+ }
+ }
+ if (response.getStatusLine().getStatusCode() != 200) {
+ return new LogResult(StatusCode.LOG_POST_ERROR_EC, "");
+ }
+
+ final String data = Network.getResponseDataAlways(response);
+ if (!StringUtils.isBlank(data) && StringUtils.contains(data, "success")) {
+ final String uid = StringUtils.remove(data, "success:");
+ return new LogResult(StatusCode.NO_ERROR, uid);
+ }
+
+ return new LogResult(StatusCode.LOG_POST_ERROR_EC, "");
+ }
+
+
+ private static HttpResponse apiRequest(final Parameters params) {
+ return apiRequest("api.php", params, false);
+ }
+
+ private static HttpResponse apiRequest(final String uri, final Parameters params) {
+ return apiRequest(uri, params, false);
+ }
+
+ private static HttpResponse apiRequest(final String uri, final Parameters params, final boolean isRetry) {
+ final HttpResponse response = Network.getRequest(API_HOST + uri, params);
+
+ if (response == null) {
+ return null;
+ }
+ if (!isRetry && response.getStatusLine().getStatusCode() == 403) {
+ if (ECLogin.getInstance().login() == StatusCode.NO_ERROR) {
+ apiRequest(uri, params, true);
+ }
+ }
+ if (response.getStatusLine().getStatusCode() != 200) {
+ return null;
+ }
+ return response;
+ }
+
+ private static Collection<Geocache> importCachesFromGPXResponse(final HttpResponse response) {
+ if (response == null) {
+ return Collections.emptyList();
+ }
+
+ try {
+ return new GPX10Parser(StoredList.TEMPORARY_LIST_ID).parse(response.getEntity().getContent(), null);
+ } catch (Exception e) {
+ Log.e("Error importing gpx from extremcaching.com", e);
+ return Collections.emptyList();
+ }
+ }
+
+ private static List<Geocache> importCachesFromJSON(final HttpResponse response) {
+
+ if (response != null) {
+ try {
+ final String data = Network.getResponseDataAlways(response);
+ if (StringUtils.isBlank(data) || StringUtils.equals(data, "[]")) {
+ return Collections.emptyList();
+ }
+ final JSONArray json = new JSONArray(data);
+ final int len = json.length();
+ final List<Geocache> caches = new ArrayList<Geocache>(len);
+ for (int i = 0; i < len; i++) {
+ final Geocache cache = parseCache(json.getJSONObject(i));
+ if (cache != null) {
+ caches.add(cache);
+ }
+ }
+ return caches;
+ } catch (final JSONException e) {
+ Log.w("JSONResult", e);
+ }
+ }
+
+ return Collections.emptyList();
+
+ }
+
+ private static Geocache parseCache(final JSONObject response) {
+ final Geocache cache = new Geocache();
+ cache.setReliableLatLon(true);
+ try {
+ cache.setGeocode("EC" + response.getString("cache_id"));
+ cache.setName(response.getString("title"));
+ cache.setCoords(new Geopoint(response.getString("lat"), response.getString("lon")));
+ cache.setType(getCacheType(response.getString("type")));
+ cache.setDifficulty((float) response.getDouble("difficulty"));
+ cache.setTerrain((float) response.getDouble("terrain"));
+ cache.setFound(response.getInt("found") == 1 ? true : false);
+
+ DataStore.saveCache(cache, EnumSet.of(SaveFlag.SAVE_CACHE));
+ } catch (final JSONException e) {
+ Log.e("ECApi.parseCache", e);
+ return null;
+ }
+ return cache;
+ }
+
+ private static CacheType getCacheType(final String cacheType) {
+ if (cacheType.equalsIgnoreCase("Tradi")) {
+ return CacheType.TRADITIONAL;
+ }
+ if (cacheType.equalsIgnoreCase("Multi")) {
+ return CacheType.MULTI;
+ }
+ if (cacheType.equalsIgnoreCase("Event")) {
+ return CacheType.EVENT;
+ }
+ if (cacheType.equalsIgnoreCase("Mystery")) {
+ return CacheType.MYSTERY;
+ }
+ return CacheType.UNKNOWN;
+ }
+}
diff --git a/main/src/cgeo/geocaching/connector/ec/ECConnector.java b/main/src/cgeo/geocaching/connector/ec/ECConnector.java
new file mode 100644
index 0000000..3c66d7d
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/ec/ECConnector.java
@@ -0,0 +1,232 @@
+package cgeo.geocaching.connector.ec;
+
+import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.ICache;
+import cgeo.geocaching.LogCacheActivity;
+import cgeo.geocaching.R;
+import cgeo.geocaching.SearchResult;
+import cgeo.geocaching.connector.AbstractConnector;
+import cgeo.geocaching.connector.ILoggingManager;
+import cgeo.geocaching.connector.capability.ICredentials;
+import cgeo.geocaching.connector.capability.ILogin;
+import cgeo.geocaching.connector.capability.ISearchByCenter;
+import cgeo.geocaching.connector.capability.ISearchByGeocode;
+import cgeo.geocaching.connector.capability.ISearchByViewPort;
+import cgeo.geocaching.connector.gc.MapTokens;
+import cgeo.geocaching.enumerations.LogType;
+import cgeo.geocaching.enumerations.StatusCode;
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.loaders.RecaptchaReceiver;
+import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.settings.SettingsActivity;
+import cgeo.geocaching.utils.CancellableHandler;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+import android.content.Context;
+import android.os.Handler;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class ECConnector extends AbstractConnector implements ISearchByGeocode, ISearchByCenter, ISearchByViewPort, ILogin, ICredentials {
+
+ private static final String CACHE_URL = "http://extremcaching.com/index.php/output-2/";
+
+ /**
+ * Pattern for EC codes
+ */
+ private final static Pattern PATTERN_EC_CODE = Pattern.compile("EC[0-9]+", Pattern.CASE_INSENSITIVE);
+
+ private ECConnector() {
+ // singleton
+ }
+
+ /**
+ * initialization on demand holder pattern
+ */
+ private static class Holder {
+ private static final @NonNull ECConnector INSTANCE = new ECConnector();
+ }
+
+ public static @NonNull
+ ECConnector getInstance() {
+ return Holder.INSTANCE;
+ }
+
+ @Override
+ public boolean canHandle(@NonNull String geocode) {
+ return ECConnector.PATTERN_EC_CODE.matcher(geocode).matches();
+ }
+
+ @Override
+ public String getCacheUrl(@NonNull Geocache cache) {
+ return CACHE_URL + cache.getGeocode().replace("EC", "");
+ }
+
+ @Override
+ public String getName() {
+ return "extremcaching.com";
+ }
+
+ @Override
+ public String getHost() {
+ return "extremcaching.com";
+ }
+
+ @Override
+ public SearchResult searchByGeocode(final @Nullable String geocode, final @Nullable String guid, final CancellableHandler handler) {
+ if (geocode == null) {
+ return null;
+ }
+ CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_loadpage);
+
+ final Geocache cache = ECApi.searchByGeoCode(geocode);
+
+ return cache != null ? new SearchResult(cache) : null;
+ }
+
+ @Override
+ public SearchResult searchByViewport(@NonNull Viewport viewport, final MapTokens tokens) {
+ final Collection<Geocache> caches = ECApi.searchByBBox(viewport);
+ if (caches == null) {
+ return null;
+ }
+ final SearchResult searchResult = new SearchResult(caches);
+ return searchResult.filterSearchResults(false, false, Settings.getCacheType());
+ }
+
+ @Override
+ public SearchResult searchByCenter(@NonNull Geopoint center, final @NonNull RecaptchaReceiver recaptchaReceiver) {
+ final Collection<Geocache> caches = ECApi.searchByCenter(center);
+ if (caches == null) {
+ return null;
+ }
+ final SearchResult searchResult = new SearchResult(caches);
+ return searchResult.filterSearchResults(false, false, Settings.getCacheType());
+ }
+
+ @Override
+ public boolean isOwner(final ICache cache) {
+ return false;
+ }
+
+ @Override
+ protected String getCacheUrlPrefix() {
+ return CACHE_URL;
+ }
+
+ @Override
+ public boolean isActive() {
+ return Settings.isECConnectorActive();
+ }
+
+ @Override
+ public boolean login(Handler handler, Context fromActivity) {
+ // login
+ final StatusCode status = ECLogin.getInstance().login();
+
+ if (status == StatusCode.NO_ERROR) {
+ CgeoApplication.getInstance().checkLogin = false;
+ }
+
+ if (CgeoApplication.getInstance().showLoginToast && handler != null) {
+ handler.sendMessage(handler.obtainMessage(0, status));
+ CgeoApplication.getInstance().showLoginToast = false;
+
+ // invoke settings activity to insert login details
+ if (status == StatusCode.NO_LOGIN_INFO_STORED && fromActivity != null) {
+ SettingsActivity.jumpToServicesPage(fromActivity);
+ }
+ }
+ return status == StatusCode.NO_ERROR;
+ }
+
+ @Override
+ public String getUserName() {
+ return ECLogin.getInstance().getActualUserName();
+ }
+
+ @Override
+ public int getCachesFound() {
+ return ECLogin.getInstance().getActualCachesFound();
+ }
+
+ @Override
+ public String getLoginStatusString() {
+ return ECLogin.getInstance().getActualStatus();
+ }
+
+ @Override
+ public boolean isLoggedIn() {
+ return ECLogin.getInstance().isActualLoginStatus();
+ }
+
+ @Override
+ public int getCacheMapMarkerId(boolean disabled) {
+ final String icons = Settings.getECIconSet();
+ if (StringUtils.equals(icons, "1")) {
+ return disabled ? R.drawable.marker_disabled_other : R.drawable.marker_other;
+ }
+ return disabled ? R.drawable.marker_disabled_oc : R.drawable.marker_oc;
+ }
+
+ @Override
+ public String getLicenseText(final @NonNull Geocache cache) {
+ // NOT TO BE TRANSLATED
+ return "© " + cache.getOwnerDisplayName() + ", <a href=\"" + getCacheUrl(cache) + "\">" + getName() + "</a>, CC BY-NC-ND 3.0, alle Logeinträge © jeweiliger Autor";
+ }
+
+ @Override
+ public boolean supportsLogging() {
+ return true;
+ }
+
+ @Override
+ public boolean canLog(Geocache cache) {
+ return true;
+ }
+
+ @Override
+ public ILoggingManager getLoggingManager(final LogCacheActivity activity, final Geocache cache) {
+ return new ECLoggingManager(activity, this, cache);
+ }
+
+ @Override
+ public List<LogType> getPossibleLogTypes(Geocache geocache) {
+ final List<LogType> logTypes = new ArrayList<LogType>();
+ if (geocache.isEventCache()) {
+ logTypes.add(LogType.WILL_ATTEND);
+ logTypes.add(LogType.ATTENDED);
+ } else {
+ logTypes.add(LogType.FOUND_IT);
+ }
+ if (!geocache.isEventCache()) {
+ logTypes.add(LogType.DIDNT_FIND_IT);
+ }
+ logTypes.add(LogType.NOTE);
+ return logTypes;
+ }
+
+ @Override
+ public int getMaxTerrain() {
+ return 7;
+ }
+
+ @Override
+ public int getUsernamePreferenceKey() {
+ return R.string.pref_ecusername;
+ }
+
+ @Override
+ public int getPasswordPreferenceKey() {
+ return R.string.pref_ecpassword;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/ec/ECConstants.java b/main/src/cgeo/geocaching/connector/ec/ECConstants.java
new file mode 100644
index 0000000..7c02d8e
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/ec/ECConstants.java
@@ -0,0 +1,19 @@
+package cgeo.geocaching.connector.ec;
+
+import java.util.regex.Pattern;
+
+/**
+ * For further information about patterns have a look at
+ * http://download.oracle.com/javase/1.4.2/docs/api/java/util/regex/Pattern.html
+ */
+public final class ECConstants {
+
+ public static final Pattern PATTERN_LOGIN_NAME = Pattern.compile("\"mod_login_greetingfrontpage-teaser\">Hallo, ([^<]+)</span>");
+ public static final Pattern PATTERN_LOGIN_SECURITY = Pattern.compile("<input type=\"hidden\" name=\"return\" value=\"(.*)\" />[^<]*<input type=\"hidden\" name=\"(.*)\" value=\"1\" />");
+ public static final Pattern PATTERN_CACHES_FOUND = Pattern.compile("Gefundene Caches.*?>([0-9]+)<");
+
+ private ECConstants() {
+ // this class shall not have instances
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/ec/ECLoggingManager.java b/main/src/cgeo/geocaching/connector/ec/ECLoggingManager.java
new file mode 100644
index 0000000..ded2d71
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/ec/ECLoggingManager.java
@@ -0,0 +1,48 @@
+package cgeo.geocaching.connector.ec;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.LogCacheActivity;
+import cgeo.geocaching.TrackableLog;
+import cgeo.geocaching.connector.AbstractLoggingManager;
+import cgeo.geocaching.connector.ImageResult;
+import cgeo.geocaching.connector.LogResult;
+import cgeo.geocaching.enumerations.LogType;
+
+import android.net.Uri;
+
+import java.util.Calendar;
+import java.util.List;
+
+public class ECLoggingManager extends AbstractLoggingManager {
+
+ private final ECConnector connector;
+ private final Geocache cache;
+ private LogCacheActivity activity;
+
+ public ECLoggingManager(final LogCacheActivity activity, final ECConnector connector, final Geocache cache) {
+ this.connector = connector;
+ this.cache = cache;
+ this.activity = activity;
+ }
+
+ @Override
+ public final void init() {
+ activity.onLoadFinished();
+ }
+
+ @Override
+ public final LogResult postLog(final Geocache cache, final LogType logType, final Calendar date, final String log, final String logPassword, final List<TrackableLog> trackableLogs) {
+ return ECApi.postLog(cache, logType, date, log);
+ }
+
+ @Override
+ public final ImageResult postLogImage(final String logId, final String imageCaption, final String imageDescription, final Uri imageUri) {
+ return null;
+ }
+
+ @Override
+ public List<LogType> getPossibleLogTypes() {
+ return connector.getPossibleLogTypes(cache);
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/ec/ECLogin.java b/main/src/cgeo/geocaching/connector/ec/ECLogin.java
new file mode 100644
index 0000000..089688e
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/ec/ECLogin.java
@@ -0,0 +1,138 @@
+package cgeo.geocaching.connector.ec;
+
+import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.R;
+import cgeo.geocaching.connector.AbstractLogin;
+import cgeo.geocaching.enumerations.StatusCode;
+import cgeo.geocaching.network.Cookies;
+import cgeo.geocaching.network.Network;
+import cgeo.geocaching.network.Parameters;
+import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.TextUtils;
+
+import ch.boye.httpclientandroidlib.HttpResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.eclipse.jdt.annotation.Nullable;
+
+import java.util.regex.Matcher;
+
+public class ECLogin extends AbstractLogin {
+
+ private ECLogin() {
+ // singleton
+ }
+
+ private static class SingletonHolder {
+ private static ECLogin INSTANCE = new ECLogin();
+ }
+
+ public static ECLogin getInstance() {
+ return SingletonHolder.INSTANCE;
+ }
+
+ @Override
+ protected StatusCode login(boolean retry) {
+ final ImmutablePair<String, String> login = Settings.getCredentials(ECConnector.getInstance());
+
+ if (StringUtils.isEmpty(login.left) || StringUtils.isEmpty(login.right)) {
+ clearLoginInfo();
+ Log.e("ECLogin.login: No login information stored");
+ return StatusCode.NO_LOGIN_INFO_STORED;
+ }
+
+ setActualStatus(CgeoApplication.getInstance().getString(R.string.init_login_popup_working));
+ HttpResponse loginResponse = Network.getRequest("https://extremcaching.com/community/profil1");
+ String loginData = Network.getResponseData(loginResponse);
+
+ if (StringUtils.isBlank(loginData)) {
+ Log.e("ECLogin.login: Failed to retrieve login page (1st)");
+ return StatusCode.CONNECTION_FAILED_EC; // no login page
+ }
+
+ if (getLoginStatus(loginData)) {
+ Log.i("Already logged in Extremcaching.com as " + login.left);
+ return StatusCode.NO_ERROR; // logged in
+ }
+
+ final Parameters params = new Parameters(
+ "username", login.left,
+ "password", login.right,
+ "remember", "yes");
+
+ Matcher m = ECConstants.PATTERN_LOGIN_SECURITY.matcher(loginData);
+ if (m.find() && m.groupCount() == 2) {
+ params.add("return", m.group(1));
+ params.add(m.group(2), "1");
+ } else {
+ Log.e("ECLogin.login security tokens in login form not found");
+ return StatusCode.COMMUNICATION_ERROR;
+ }
+
+ loginResponse = Network.postRequest("http://extremcaching.com/component/users/?task=user.login", params);
+ loginData = Network.getResponseData(loginResponse);
+
+ if (StringUtils.isBlank(loginData)) {
+ Log.e("ECLogin.login: Failed to retrieve login page (2nd)");
+ return StatusCode.COMMUNICATION_ERROR; // no login page
+ }
+ assert loginData != null; // Caught above
+
+ if (getLoginStatus(loginData)) {
+ Log.i("Successfully logged in Extremcaching.com as " + login.left);
+
+ Settings.setCookieStore(Cookies.dumpCookieStore());
+
+ return StatusCode.NO_ERROR; // logged in
+ }
+
+ if (loginData.contains("Benutzername und Passwort falsch")) { // Yes, it's hardcoded in German (translation is done using Javascript and Google Translate)
+ Log.i("Failed to log in Extremcaching.com as " + login.left + " because of wrong username/password");
+ return StatusCode.WRONG_LOGIN_DATA; // wrong login
+ }
+
+ Log.i("Failed to log in Extremcaching.com as " + login.left + " for some unknown reason");
+ if (retry) {
+ return login(false);
+ }
+
+ return StatusCode.UNKNOWN_ERROR; // can't login
+ }
+
+
+ /**
+ * Check if the user has been logged in when he retrieved the data.
+ *
+ * @param page
+ * @return <code>true</code> if user is logged in, <code>false</code> otherwise
+ */
+ public boolean getLoginStatus(@Nullable final String page) {
+ if (StringUtils.isBlank(page)) {
+ Log.e("ECLogin.getLoginStatus: No page given");
+ return false;
+ }
+ assert page != null;
+
+ setActualStatus(CgeoApplication.getInstance().getString(R.string.init_login_popup_ok));
+
+ // on every page except login page
+ setActualLoginStatus(TextUtils.matches(page, ECConstants.PATTERN_LOGIN_NAME));
+ if (isActualLoginStatus()) {
+ setActualUserName(TextUtils.getMatch(page, ECConstants.PATTERN_LOGIN_NAME, true, "???"));
+ int cachesCount = 0;
+ try {
+ cachesCount = Integer.parseInt(TextUtils.getMatch(page, ECConstants.PATTERN_CACHES_FOUND, true, "0"));
+ } catch (final NumberFormatException e) {
+ Log.e("ECLogin.getLoginStatus: bad cache count", e);
+ }
+ setActualCachesFound(cachesCount);
+ return true;
+ }
+
+ setActualStatus(CgeoApplication.getInstance().getString(R.string.init_login_popup_failed));
+ return false;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
index 6a61405..4349d5d 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
@@ -9,13 +9,16 @@ import cgeo.geocaching.R;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.connector.AbstractConnector;
import cgeo.geocaching.connector.ILoggingManager;
+import cgeo.geocaching.connector.capability.ICredentials;
import cgeo.geocaching.connector.capability.ILogin;
import cgeo.geocaching.connector.capability.ISearchByCenter;
import cgeo.geocaching.connector.capability.ISearchByGeocode;
+import cgeo.geocaching.connector.capability.ISearchByKeyword;
import cgeo.geocaching.connector.capability.ISearchByViewPort;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.loaders.RecaptchaReceiver;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.settings.SettingsActivity;
import cgeo.geocaching.utils.CancellableHandler;
@@ -23,13 +26,15 @@ import cgeo.geocaching.utils.Log;
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 android.content.Context;
import android.os.Handler;
import java.util.regex.Pattern;
-public class GCConnector extends AbstractConnector implements ISearchByGeocode, ISearchByCenter, ISearchByViewPort, ILogin {
+public class GCConnector extends AbstractConnector implements ISearchByGeocode, ISearchByCenter, ISearchByViewPort, ISearchByKeyword, ILogin, ICredentials {
private static final String CACHE_URL_SHORT = "http://coord.info/";
// Double slash is used to force open in browser
@@ -53,28 +58,26 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
* initialization on demand holder pattern
*/
private static class Holder {
- private static final GCConnector INSTANCE = new GCConnector();
+ private static final @NonNull GCConnector INSTANCE = new GCConnector();
}
- public static GCConnector getInstance() {
+ public static @NonNull
+ GCConnector getInstance() {
return Holder.INSTANCE;
}
@Override
- public boolean canHandle(String geocode) {
- if (geocode == null) {
- return false;
- }
+ public boolean canHandle(@NonNull String geocode) {
return GCConnector.PATTERN_GC_CODE.matcher(geocode).matches();
}
@Override
- public String getLongCacheUrl(Geocache cache) {
+ public String getLongCacheUrl(@NonNull Geocache cache) {
return CACHE_URL_LONG + cache.getGeocode();
}
@Override
- public String getCacheUrl(Geocache cache) {
+ public String getCacheUrl(@NonNull Geocache cache) {
return CACHE_URL_SHORT + cache.getGeocode();
}
@@ -129,7 +132,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public SearchResult searchByGeocode(final String geocode, final String guid, final CancellableHandler handler) {
+ public SearchResult searchByGeocode(final @Nullable String geocode, final @Nullable String guid, final CancellableHandler handler) {
CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_loadpage);
@@ -166,7 +169,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public SearchResult searchByViewport(Viewport viewport, String[] tokens) {
+ public SearchResult searchByViewport(@NonNull Viewport viewport, final MapTokens tokens) {
return GCMap.searchByViewport(viewport, tokens);
}
@@ -209,8 +212,9 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
*
* This must not be called from the UI thread.
*
- * @param cache the cache to add
- * @return <code>true</code> if the cache was sucessfully added, <code>false</code> otherwise
+ * @param cache
+ * the cache to add
+ * @return <code>true</code> if the cache was successfully added, <code>false</code> otherwise
*/
public static boolean addToFavorites(Geocache cache) {
@@ -226,8 +230,9 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
*
* This must not be called from the UI thread.
*
- * @param cache the cache to add
- * @return <code>true</code> if the cache was sucessfully added, <code>false</code> otherwise
+ * @param cache
+ * the cache to add
+ * @return <code>true</code> if the cache was successfully added, <code>false</code> otherwise
*/
public static boolean removeFromFavorites(Geocache cache) {
@@ -266,9 +271,8 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public SearchResult searchByCenter(Geopoint center) {
- // TODO make search by coordinate use this method. currently it is just a marker that this connector supports search by center
- return null;
+ public SearchResult searchByCenter(@NonNull Geopoint center, final @NonNull RecaptchaReceiver recaptchaReceiver) {
+ return GCParser.searchByCoords(center, Settings.getCacheType(), Settings.isShowCaptcha(), recaptchaReceiver);
}
@Override
@@ -282,7 +286,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public boolean isActivated() {
+ public boolean isActive() {
return Settings.isGCConnectorActive();
}
@@ -297,11 +301,11 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
@Override
public boolean login(Handler handler, Context fromActivity) {
// login
- final StatusCode status = Login.login();
+ final StatusCode status = GCLogin.getInstance().login();
if (status == StatusCode.NO_ERROR) {
CgeoApplication.getInstance().checkLogin = false;
- Login.detectGcCustomDate();
+ GCLogin.detectGcCustomDate();
}
if (CgeoApplication.getInstance().showLoginToast && handler != null) {
@@ -318,22 +322,22 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
@Override
public String getUserName() {
- return Login.getActualUserName();
+ return GCLogin.getInstance().getActualUserName();
}
@Override
public int getCachesFound() {
- return Login.getActualCachesFound();
+ return GCLogin.getInstance().getActualCachesFound();
}
@Override
public String getLoginStatusString() {
- return Login.getActualStatus();
+ return GCLogin.getInstance().getActualStatus();
}
@Override
public boolean isLoggedIn() {
- return Login.isActualLoginStatus();
+ return GCLogin.getInstance().isActualLoginStatus();
}
@Override
@@ -353,4 +357,19 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
return prefix;
}
+
+ @Override
+ public SearchResult searchByKeyword(@NonNull String keyword, final @NonNull RecaptchaReceiver recaptchaReceiver) {
+ return GCParser.searchByKeyword(keyword, Settings.getCacheType(), Settings.isShowCaptcha(), recaptchaReceiver);
+ }
+
+ @Override
+ public int getUsernamePreferenceKey() {
+ return R.string.pref_username;
+ }
+
+ @Override
+ public int getPasswordPreferenceKey() {
+ return R.string.pref_password;
+ }
}
diff --git a/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java b/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java
index 8bed2ea..06d6411 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java
@@ -5,7 +5,7 @@ import cgeo.geocaching.LogCacheActivity;
import cgeo.geocaching.R;
import cgeo.geocaching.TrackableLog;
import cgeo.geocaching.activity.ActivityMixin;
-import cgeo.geocaching.connector.ILoggingManager;
+import cgeo.geocaching.connector.AbstractLoggingManager;
import cgeo.geocaching.connector.ImageResult;
import cgeo.geocaching.connector.LogResult;
import cgeo.geocaching.enumerations.LogType;
@@ -28,7 +28,7 @@ import java.util.Calendar;
import java.util.Collections;
import java.util.List;
-public class GCLoggingManager implements ILoggingManager, LoaderManager.LoaderCallbacks<String> {
+public class GCLoggingManager extends AbstractLoggingManager implements LoaderManager.LoaderCallbacks<String> {
private final LogCacheActivity activity;
private final Geocache cache;
@@ -60,7 +60,7 @@ public class GCLoggingManager implements ILoggingManager, LoaderManager.LoaderCa
hasLoaderError = true;
} else {
- viewstates = Login.getViewstates(page);
+ viewstates = GCLogin.getViewstates(page);
trackables = GCParser.parseTrackableLog(page);
possibleLogTypes = GCParser.parseTypes(page);
diff --git a/main/src/cgeo/geocaching/connector/gc/Login.java b/main/src/cgeo/geocaching/connector/gc/GCLogin.java
index beb49f1..e072c8f 100644
--- a/main/src/cgeo/geocaching/connector/gc/Login.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCLogin.java
@@ -2,6 +2,7 @@ package cgeo.geocaching.connector.gc;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
+import cgeo.geocaching.connector.AbstractLogin;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.network.Cookies;
import cgeo.geocaching.network.HtmlImage;
@@ -13,6 +14,7 @@ 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;
@@ -29,18 +31,12 @@ import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
-public abstract class Login {
+public class GCLogin extends AbstractLogin {
private static final String DEFAULT_CUSTOM_DATE_FORMAT = "MM/dd/yyyy";
private final static String ENGLISH = "<a href=\"#\">English&#9660;</a>";
- // false = not logged in
- private static boolean actualLoginStatus = false;
- private static String actualUserName = StringUtils.EMPTY;
- private static int actualCachesFound = -1;
- private static String actualStatus = StringUtils.EMPTY;
-
private final static Map<String, SimpleDateFormat> GC_CUSTOM_DATE_FORMATS;
public static final String LANGUAGE_CHANGE_URI = "http://www.geocaching.com/my/souvenirs.aspx";
@@ -64,20 +60,31 @@ public abstract class Login {
GC_CUSTOM_DATE_FORMATS = Collections.unmodifiableMap(map);
}
- public static StatusCode login() {
- return login(true);
+ private GCLogin() {
+ // singleton
}
- private static StatusCode login(boolean retry) {
- final ImmutablePair<String, String> login = Settings.getGcLogin();
+ public static GCLogin getInstance() {
+ return SingletonHolder.INSTANCE;
+ }
+
+ private static class SingletonHolder {
+ private static final GCLogin INSTANCE = new GCLogin();
+ }
- if (StringUtils.isEmpty(login.left) || StringUtils.isEmpty(login.right)) {
+ @Override
+ protected StatusCode login(boolean retry) {
+ final ImmutablePair<String, String> credentials = Settings.getGcCredentials();
+ final String username = credentials.left;
+ final String password = credentials.right;
+
+ if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
clearLoginInfo();
Log.e("Login.login: No login information stored");
return StatusCode.NO_LOGIN_INFO_STORED;
}
- Login.setActualStatus(CgeoApplication.getInstance().getString(R.string.init_login_popup_working));
+ setActualStatus(CgeoApplication.getInstance().getString(R.string.init_login_popup_working));
HttpResponse loginResponse = Network.getRequest("https://www.geocaching.com/login/default.aspx");
String loginData = Network.getResponseData(loginResponse);
if (loginResponse != null && loginResponse.getStatusLine().getStatusCode() == 503 && TextUtils.matches(loginData, GCConstants.PATTERN_MAINTENANCE)) {
@@ -86,12 +93,12 @@ public abstract class Login {
if (StringUtils.isBlank(loginData)) {
Log.e("Login.login: Failed to retrieve login page (1st)");
- return StatusCode.CONNECTION_FAILED; // no loginpage
+ return StatusCode.CONNECTION_FAILED; // no login page
}
- if (Login.getLoginStatus(loginData)) {
- Log.i("Already logged in Geocaching.com as " + login.left + " (" + Settings.getMemberStatus() + ')');
- Login.switchToEnglish(loginData);
+ if (getLoginStatus(loginData)) {
+ Log.i("Already logged in Geocaching.com as " + username + " (" + Settings.getMemberStatus() + ')');
+ switchToEnglish(loginData);
return StatusCode.NO_ERROR; // logged in
}
@@ -101,16 +108,16 @@ public abstract class Login {
final Parameters params = new Parameters(
"__EVENTTARGET", "",
"__EVENTARGUMENT", "",
- "ctl00$ContentBody$tbUsername", login.left,
- "ctl00$ContentBody$tbPassword", login.right,
+ "ctl00$ContentBody$tbUsername", username,
+ "ctl00$ContentBody$tbPassword", password,
"ctl00$ContentBody$cbRememberMe", "on",
"ctl00$ContentBody$btnSignIn", "Login");
- final String[] viewstates = Login.getViewstates(loginData);
+ final String[] viewstates = GCLogin.getViewstates(loginData);
if (isEmpty(viewstates)) {
Log.e("Login.login: Failed to find viewstates");
return StatusCode.LOGIN_PARSE_ERROR; // no viewstates
}
- Login.putViewstates(params, viewstates);
+ GCLogin.putViewstates(params, viewstates);
loginResponse = Network.postRequest("https://www.geocaching.com/login/default.aspx", params);
loginData = Network.getResponseData(loginResponse);
@@ -122,35 +129,35 @@ public abstract class Login {
}
assert loginData != null; // Caught above
- if (Login.getLoginStatus(loginData)) {
- Log.i("Successfully logged in Geocaching.com as " + login.left + " (" + Settings.getMemberStatus() + ')');
+ if (getLoginStatus(loginData)) {
+ Log.i("Successfully logged in Geocaching.com as " + username + " (" + Settings.getMemberStatus() + ')');
- Login.switchToEnglish(loginData);
+ switchToEnglish(loginData);
Settings.setCookieStore(Cookies.dumpCookieStore());
return StatusCode.NO_ERROR; // logged in
}
if (loginData.contains("Your username/password combination does not match.")) {
- Log.i("Failed to log in Geocaching.com as " + login.left + " because of wrong username/password");
+ Log.i("Failed to log in Geocaching.com as " + username + " because of wrong username/password");
return StatusCode.WRONG_LOGIN_DATA; // wrong login
}
if (loginData.contains("You must validate your account before you can log in.")) {
- Log.i("Failed to log in Geocaching.com as " + login.left + " because account needs to be validated first");
+ Log.i("Failed to log in Geocaching.com as " + username + " because account needs to be validated first");
return StatusCode.UNVALIDATED_ACCOUNT;
}
- Log.i("Failed to log in Geocaching.com as " + login.left + " for some unknown reason");
+ Log.i("Failed to log in Geocaching.com as " + username + " for some unknown reason");
if (retry) {
- Login.switchToEnglish(loginData);
+ switchToEnglish(loginData);
return login(false);
}
return StatusCode.UNKNOWN_ERROR; // can't login
}
- public static StatusCode logout() {
+ public StatusCode logout() {
final HttpResponse logoutResponse = Network.getRequest("https://www.geocaching.com/login/default.aspx?RESET=Y&redir=http%3a%2f%2fwww.geocaching.com%2fdefault.aspx%3f");
final String logoutData = Network.getResponseData(logoutResponse);
if (logoutResponse != null && logoutResponse.getStatusLine().getStatusCode() == 503 && TextUtils.matches(logoutData, GCConstants.PATTERN_MAINTENANCE)) {
@@ -162,51 +169,6 @@ public abstract class Login {
return StatusCode.NO_ERROR;
}
- private static void resetLoginStatus() {
- Cookies.clearCookies();
- Settings.setCookieStore(null);
-
- setActualLoginStatus(false);
- }
-
- private static void clearLoginInfo() {
- resetLoginStatus();
-
- setActualCachesFound(-1);
- setActualStatus(CgeoApplication.getInstance().getString(R.string.err_login));
- }
-
- static void setActualCachesFound(final int found) {
- actualCachesFound = found;
- }
-
- public static String getActualStatus() {
- return actualStatus;
- }
-
- private static void setActualStatus(final String status) {
- actualStatus = status;
- }
-
- public static boolean isActualLoginStatus() {
- return actualLoginStatus;
- }
-
- private static void setActualLoginStatus(boolean loginStatus) {
- actualLoginStatus = loginStatus;
- }
-
- public static String getActualUserName() {
- return actualUserName;
- }
-
- private static void setActualUserName(String userName) {
- actualUserName = userName;
- }
-
- public static int getActualCachesFound() {
- return actualCachesFound;
- }
/**
* Check if the user has been logged in when he retrieved the data.
@@ -214,7 +176,7 @@ public abstract class Login {
* @param page
* @return <code>true</code> if user is logged in, <code>false</code> otherwise
*/
- public static boolean getLoginStatus(@Nullable final String page) {
+ public boolean getLoginStatus(@Nullable final String page) {
if (StringUtils.isBlank(page)) {
Log.e("Login.checkLogin: No page given");
return false;
@@ -253,7 +215,7 @@ public abstract class Login {
return false;
}
- private static void switchToEnglish(String previousPage) {
+ private void switchToEnglish(String previousPage) {
if (previousPage != null && previousPage.contains(ENGLISH)) {
Log.i("Geocaching.com language already set to English");
// get find count
@@ -267,7 +229,7 @@ public abstract class Login {
final Parameters params = new Parameters(
"__EVENTTARGET", "ctl00$uxLocaleList$uxLocaleList$ctl00$uxLocaleItem", // switch to english
"__EVENTARGUMENT", "");
- Login.transferViewstates(page, params);
+ GCLogin.transferViewstates(page, params);
final HttpResponse response = Network.postRequest(LANGUAGE_CHANGE_URI, params, new Parameters("Referer", LANGUAGE_CHANGE_URI));
if (Network.isSuccess(response)) {
Log.i("changed language on geocaching.com to English");
@@ -277,7 +239,7 @@ public abstract class Login {
}
}
- public static BitmapDrawable downloadAvatarAndGetMemberStatus() {
+ public BitmapDrawable downloadAvatarAndGetMemberStatus() {
try {
final String responseData = StringUtils.defaultString(Network.getResponseData(Network.getRequest("http://www.geocaching.com/my/")));
final String profile = TextUtils.replaceWhitespace(responseData);
@@ -455,7 +417,7 @@ public abstract class Login {
* @param uri
* @return
*/
- public static String postRequestLogged(final String uri, final Parameters params) {
+ public String postRequestLogged(final String uri, final Parameters params) {
final String data = Network.getResponseData(Network.postRequest(uri, params));
if (getLoginStatus(data)) {
@@ -478,7 +440,7 @@ public abstract class Login {
* @return
*/
@Nullable
- public static String getRequestLogged(@NonNull final String uri, @Nullable final Parameters params) {
+ public String getRequestLogged(@NonNull final String uri, @Nullable final Parameters params) {
final HttpResponse response = Network.getRequest(uri, params);
final String data = Network.getResponseData(response, canRemoveWhitespace(uri));
@@ -506,12 +468,18 @@ public abstract class Login {
return !StringUtils.contains(uri, "cache_details");
}
- /** Get user session & session token from the Live Map. Needed for following requests */
- public static String[] getMapTokens() {
+ /**
+ * Get user session & session token from the Live Map. Needed for following requests.
+ *
+ * @return first is user session, second is session token
+ */
+ public static @NonNull
+ MapTokens getMapTokens() {
final HttpResponse response = Network.getRequest(GCConstants.URL_LIVE_MAP);
final String data = Network.getResponseData(response);
final String userSession = TextUtils.getMatch(data, GCConstants.PATTERN_USERSESSION, "");
final String sessionToken = TextUtils.getMatch(data, GCConstants.PATTERN_SESSIONTOKEN, "");
- return new String[] { userSession, sessionToken };
+ return new MapTokens(userSession, sessionToken);
}
+
}
diff --git a/main/src/cgeo/geocaching/connector/gc/GCMap.java b/main/src/cgeo/geocaching/connector/gc/GCMap.java
index e2c7dfa..aabeb56 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCMap.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCMap.java
@@ -1,9 +1,9 @@
package cgeo.geocaching.connector.gc;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.DataStore;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.enumerations.CacheSize;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy;
@@ -85,7 +85,7 @@ public class GCMap {
cache.setDifficulty(Float.parseFloat(difficultyObj.getString("text"))); // 3.5
JSONObject terrainObj = dataObject.getJSONObject("terrain");
cache.setTerrain(Float.parseFloat(terrainObj.getString("text"))); // 1.5
- cache.setHidden(Login.parseGcCustomDate(dataObject.getString("hidden"), "MM/dd/yyyy")); // 7/23/2001
+ cache.setHidden(GCLogin.parseGcCustomDate(dataObject.getString("hidden"), "MM/dd/yyyy")); // 7/23/2001
JSONObject containerObj = dataObject.getJSONObject("container");
cache.setSize(CacheSize.getById(containerObj.getString("text"))); // Regular
JSONObject typeObj = dataObject.getJSONObject("type");
@@ -254,7 +254,7 @@ public class GCMap {
* Live map tokens
* @return
*/
- public static SearchResult searchByViewport(final Viewport viewport, final String[] tokens) {
+ public static SearchResult searchByViewport(final Viewport viewport, final MapTokens tokens) {
int speed = (int) CgeoApplication.getInstance().currentGeo().getSpeed() * 60 * 60 / 1000; // in km/h
Strategy strategy = Settings.getLiveMapStrategy();
if (strategy == Strategy.AUTO) {
@@ -284,7 +284,7 @@ public class GCMap {
* Strategy for data retrieval and parsing, @see Strategy
* @return
*/
- private static SearchResult searchByViewport(final Viewport viewport, final String[] tokens, Strategy strategy) {
+ private static SearchResult searchByViewport(final Viewport viewport, final MapTokens tokens, Strategy strategy) {
Log.d("GCMap.searchByViewport" + viewport.toString());
final SearchResult searchResult = new SearchResult();
@@ -310,7 +310,7 @@ public class GCMap {
"ep", "1",
"app", "cgeo");
if (tokens != null) {
- params.put("k", tokens[0], "st", tokens[1]);
+ params.put("k", tokens.getUserSession(), "st", tokens.getSessionToken());
}
if (Settings.isExcludeMyCaches()) { // works only for PM
params.put("hf", "1", "hh", "1"); // hide found, hide hidden
diff --git a/main/src/cgeo/geocaching/connector/gc/GCParser.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java
index 4f5d293..f05bc04 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCParser.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java
@@ -79,7 +79,7 @@ public abstract class GCParser {
final SearchResult searchResult = new SearchResult();
searchResult.setUrl(url);
- searchResult.viewstates = Login.getViewstates(page);
+ searchResult.viewstates = GCLogin.getViewstates(page);
// recaptcha
if (showCaptcha) {
@@ -203,7 +203,7 @@ public abstract class GCParser {
final String dateHidden = TextUtils.getMatch(row, GCConstants.PATTERN_SEARCH_HIDDEN_DATE, false, 1, null, false);
if (StringUtils.isNotBlank(dateHidden)) {
try {
- Date date = Login.parseGcCustomDate(dateHidden);
+ Date date = GCLogin.parseGcCustomDate(dateHidden);
if (date != null) {
cache.setHidden(date);
}
@@ -268,7 +268,7 @@ public abstract class GCParser {
try {
final String result = TextUtils.getMatch(page, GCConstants.PATTERN_SEARCH_TOTALCOUNT, false, 1, null, true);
if (null != result) {
- searchResult.setTotal(Integer.parseInt(result) - excludedCaches);
+ searchResult.setTotalCountGC(Integer.parseInt(result) - excludedCaches);
}
} catch (final NumberFormatException e) {
Log.w("GCParser.parseSearch: Failed to parse cache count");
@@ -276,10 +276,7 @@ public abstract class GCParser {
String recaptchaText = null;
if (thread != null && StringUtils.isNotBlank(thread.getChallenge())) {
- if (thread.getText() == null) {
- thread.waitForUser();
- }
-
+ thread.waitForUser();
recaptchaText = thread.getText();
}
@@ -465,13 +462,13 @@ public abstract class GCParser {
try {
String hiddenString = TextUtils.getMatch(tableInside, GCConstants.PATTERN_HIDDEN, true, null);
if (StringUtils.isNotBlank(hiddenString)) {
- cache.setHidden(Login.parseGcCustomDate(hiddenString));
+ cache.setHidden(GCLogin.parseGcCustomDate(hiddenString));
}
if (cache.getHiddenDate() == null) {
// event date
hiddenString = TextUtils.getMatch(tableInside, GCConstants.PATTERN_HIDDENEVENT, true, null);
if (StringUtils.isNotBlank(hiddenString)) {
- cache.setHidden(Login.parseGcCustomDate(hiddenString));
+ cache.setHidden(GCLogin.parseGcCustomDate(hiddenString));
}
}
} catch (final ParseException e) {
@@ -497,7 +494,7 @@ public abstract class GCParser {
try {
final String foundDateString = TextUtils.getMatch(page, GCConstants.PATTERN_FOUND_DATE, true, null);
if (StringUtils.isNotBlank(foundDateString)) {
- cache.setVisitedDate(Login.parseGcCustomDate(foundDateString).getTime());
+ cache.setVisitedDate(GCLogin.parseGcCustomDate(foundDateString).getTime());
}
} catch (final ParseException e) {
// failed to parse cache found date
@@ -775,7 +772,7 @@ public abstract class GCParser {
return search;
}
- if (Login.isEmpty(viewstates)) {
+ if (GCLogin.isEmpty(viewstates)) {
Log.e("GCParser.searchByNextPage: No viewstate given");
return search;
}
@@ -786,10 +783,10 @@ public abstract class GCParser {
final Parameters params = new Parameters(
"__EVENTTARGET", "ctl00$ContentBody$pgrBottom$ctl08",
"__EVENTARGUMENT", "");
- Login.putViewstates(params, viewstates);
+ GCLogin.putViewstates(params, viewstates);
- final String page = Login.postRequestLogged(uri, params);
- if (!Login.getLoginStatus(page)) {
+ final String page = GCLogin.getInstance().postRequestLogged(uri, params);
+ if (!GCLogin.getInstance().getLoginStatus(page)) {
Log.e("GCParser.postLogTrackable: Can not log in geocaching");
return search;
}
@@ -853,7 +850,7 @@ public abstract class GCParser {
final String uri = "http://www.geocaching.com/seek/nearest.aspx";
final String fullUri = uri + "?" + addFToParams(params, my, true);
- final String page = Login.getRequestLogged(uri, addFToParams(params, my, true));
+ final String page = GCLogin.getInstance().getRequestLogged(uri, addFToParams(params, my, true));
if (StringUtils.isBlank(page)) {
Log.e("GCParser.searchByAny: No data from server");
@@ -869,17 +866,17 @@ public abstract class GCParser {
final SearchResult search = searchResult.filterSearchResults(Settings.isExcludeDisabledCaches(), false, cacheType);
- Login.getLoginStatus(page);
+ GCLogin.getInstance().getLoginStatus(page);
return search;
}
- public static SearchResult searchByCoords(final Geopoint coords, final CacheType cacheType, final boolean showCaptcha, RecaptchaReceiver recaptchaReceiver) {
+ public static SearchResult searchByCoords(final @NonNull Geopoint coords, final CacheType cacheType, final boolean showCaptcha, RecaptchaReceiver recaptchaReceiver) {
final Parameters params = new Parameters("lat", Double.toString(coords.getLatitude()), "lng", Double.toString(coords.getLongitude()));
return searchByAny(cacheType, false, showCaptcha, params, recaptchaReceiver);
}
- public static SearchResult searchByKeyword(final String keyword, final CacheType cacheType, final boolean showCaptcha, RecaptchaReceiver recaptchaReceiver) {
+ public static SearchResult searchByKeyword(final @NonNull String keyword, final CacheType cacheType, final boolean showCaptcha, RecaptchaReceiver recaptchaReceiver) {
if (StringUtils.isBlank(keyword)) {
Log.e("GCParser.searchByKeyword: No keyword given");
return null;
@@ -890,7 +887,7 @@ public abstract class GCParser {
}
private static boolean isSearchForMyCaches(final String userName) {
- if (userName.equalsIgnoreCase(Settings.getGcLogin().left)) {
+ if (userName.equalsIgnoreCase(Settings.getGcCredentials().left)) {
Log.i("Overriding users choice because of self search, downloading all caches.");
return true;
}
@@ -976,7 +973,7 @@ public abstract class GCParser {
params.put("id", id);
}
- final String page = Login.getRequestLogged("http://www.geocaching.com/track/details.aspx", params);
+ final String page = GCLogin.getInstance().getRequestLogged("http://www.geocaching.com/track/details.aspx", params);
if (StringUtils.isBlank(page)) {
Log.e("GCParser.searchTrackable: No data from server");
@@ -997,7 +994,7 @@ public abstract class GCParser {
final Parameters params = new Parameters();
- final String page = Login.getRequestLogged("http://www.geocaching.com/pocket/default.aspx", params);
+ final String page = GCLogin.getInstance().getRequestLogged("http://www.geocaching.com/pocket/default.aspx", params);
if (StringUtils.isBlank(page)) {
Log.e("GCParser.searchPocketQueryList: No data from server");
@@ -1043,7 +1040,7 @@ public abstract class GCParser {
public static ImmutablePair<StatusCode, String> postLog(final String geocode, final String cacheid, final String[] viewstates,
final LogType logType, final int year, final int month, final int day,
final String log, final List<TrackableLog> trackables) {
- if (Login.isEmpty(viewstates)) {
+ if (GCLogin.isEmpty(viewstates)) {
Log.e("GCParser.postLog: No viewstate given");
return new ImmutablePair<StatusCode, String>(StatusCode.LOG_POST_ERROR, "");
}
@@ -1064,7 +1061,7 @@ public abstract class GCParser {
"__EVENTARGUMENT", "",
"__LASTFOCUS", "",
"ctl00$ContentBody$LogBookPanel1$ddLogType", Integer.toString(logType.id),
- "ctl00$ContentBody$LogBookPanel1$uxDateVisited", Login.getCustomGcDateFormat().format(new GregorianCalendar(year, month - 1, day).getTime()),
+ "ctl00$ContentBody$LogBookPanel1$uxDateVisited", GCLogin.getCustomGcDateFormat().format(new GregorianCalendar(year, month - 1, day).getTime()),
"ctl00$ContentBody$LogBookPanel1$uxDateVisited$Month", Integer.toString(month),
"ctl00$ContentBody$LogBookPanel1$uxDateVisited$Day", Integer.toString(day),
"ctl00$ContentBody$LogBookPanel1$uxDateVisited$Year", Integer.toString(year),
@@ -1077,7 +1074,7 @@ public abstract class GCParser {
"ctl00$ContentBody$LogBookPanel1$btnSubmitLog", "Submit Log Entry",
"ctl00$ContentBody$LogBookPanel1$uxLogCreationSource", "Old",
"ctl00$ContentBody$uxVistOtherListingGC", "");
- Login.putViewstates(params, viewstates);
+ GCLogin.putViewstates(params, viewstates);
if (trackables != null && !trackables.isEmpty()) { // we have some trackables to proceed
final StringBuilder hdnSelected = new StringBuilder();
@@ -1094,8 +1091,8 @@ public abstract class GCParser {
}
final String uri = new Uri.Builder().scheme("http").authority("www.geocaching.com").path("/seek/log.aspx").encodedQuery("ID=" + cacheid).build().toString();
- String page = Login.postRequestLogged(uri, params);
- if (!Login.getLoginStatus(page)) {
+ String page = GCLogin.getInstance().postRequestLogged(uri, params);
+ if (!GCLogin.getInstance().getLoginStatus(page)) {
Log.e("GCParser.postLog: Cannot log in geocaching");
return new ImmutablePair<StatusCode, String>(StatusCode.NOT_LOGGED_IN, "");
}
@@ -1106,15 +1103,15 @@ public abstract class GCParser {
try {
if (matcher.find() && matcher.groupCount() > 0) {
- final String[] viewstatesConfirm = Login.getViewstates(page);
+ final String[] viewstatesConfirm = GCLogin.getViewstates(page);
- if (Login.isEmpty(viewstatesConfirm)) {
+ if (GCLogin.isEmpty(viewstatesConfirm)) {
Log.e("GCParser.postLog: No viewstate for confirm log");
return new ImmutablePair<StatusCode, String>(StatusCode.LOG_POST_ERROR, "");
}
params.clear();
- Login.putViewstates(params, viewstatesConfirm);
+ GCLogin.putViewstates(params, viewstatesConfirm);
params.put("__EVENTTARGET", "");
params.put("__EVENTARGUMENT", "");
params.put("__LASTFOCUS", "");
@@ -1159,10 +1156,10 @@ public abstract class GCParser {
DataStore.saveVisitDate(geocode);
}
- Login.getLoginStatus(page);
+ GCLogin.getInstance().getLoginStatus(page);
// the log-successful-page contains still the old value
- if (Login.getActualCachesFound() >= 0) {
- Login.setActualCachesFound(Login.getActualCachesFound() + 1);
+ if (GCLogin.getInstance().getActualCachesFound() >= 0) {
+ GCLogin.getInstance().setActualCachesFound(GCLogin.getInstance().getActualCachesFound() + 1);
}
final String logID = TextUtils.getMatch(page, GCConstants.PATTERN_LOG_IMAGE_UPLOAD, "");
@@ -1193,14 +1190,14 @@ public abstract class GCParser {
public static ImmutablePair<StatusCode, String> uploadLogImage(final String logId, final String caption, final String description, final Uri imageUri) {
final String uri = new Uri.Builder().scheme("http").authority("www.geocaching.com").path("/seek/upload.aspx").encodedQuery("LID=" + logId).build().toString();
- final String page = Login.getRequestLogged(uri, null);
+ final String page = GCLogin.getInstance().getRequestLogged(uri, null);
if (StringUtils.isBlank(page)) {
Log.e("GCParser.uploadLogImage: No data from server");
return new ImmutablePair<StatusCode, String>(StatusCode.UNKNOWN_ERROR, null);
}
assert page != null;
- final String[] viewstates = Login.getViewstates(page);
+ final String[] viewstates = GCLogin.getViewstates(page);
final Parameters uploadParams = new Parameters(
"__EVENTTARGET", "",
@@ -1208,7 +1205,7 @@ public abstract class GCParser {
"ctl00$ContentBody$ImageUploadControl1$uxFileCaption", caption,
"ctl00$ContentBody$ImageUploadControl1$uxFileDesc", description,
"ctl00$ContentBody$ImageUploadControl1$uxUpload", "Upload");
- Login.putViewstates(uploadParams, viewstates);
+ GCLogin.putViewstates(uploadParams, viewstates);
final File image = new File(imageUri.getPath());
final String response = Network.getResponseData(Network.postRequest(uri, uploadParams, "ctl00$ContentBody$ImageUploadControl1$uxFileUpload", "image/jpeg", image));
@@ -1232,7 +1229,7 @@ public abstract class GCParser {
*/
public static StatusCode postLogTrackable(final String tbid, final String trackingCode, final String[] viewstates,
final LogType logType, final int year, final int month, final int day, final String log) {
- if (Login.isEmpty(viewstates)) {
+ if (GCLogin.isEmpty(viewstates)) {
Log.e("GCParser.postLogTrackable: No viewstate given");
return StatusCode.LOG_POST_ERROR;
}
@@ -1253,13 +1250,13 @@ public abstract class GCParser {
"__LASTFOCUS", "",
"ctl00$ContentBody$LogBookPanel1$ddLogType", Integer.toString(logType.id),
"ctl00$ContentBody$LogBookPanel1$tbCode", trackingCode);
- Login.putViewstates(params, viewstates);
+ GCLogin.putViewstates(params, viewstates);
if (currentDate.get(Calendar.YEAR) == year && (currentDate.get(Calendar.MONTH) + 1) == month && currentDate.get(Calendar.DATE) == day) {
params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged", "");
params.put("ctl00$ContentBody$LogBookPanel1$uxDateVisited", "");
} else {
params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged", Integer.toString(month) + "/" + Integer.toString(day) + "/" + Integer.toString(year));
- params.put("ctl00$ContentBody$LogBookPanel1$uxDateVisited", Login.getCustomGcDateFormat().format(new GregorianCalendar(year, month - 1, day).getTime()));
+ params.put("ctl00$ContentBody$LogBookPanel1$uxDateVisited", GCLogin.getCustomGcDateFormat().format(new GregorianCalendar(year, month - 1, day).getTime()));
}
params.put(
"ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Day", Integer.toString(day),
@@ -1275,8 +1272,8 @@ public abstract class GCParser {
"ctl00$ContentBody$uxVistOtherListingGC", "");
final String uri = new Uri.Builder().scheme("http").authority("www.geocaching.com").path("/track/log.aspx").encodedQuery("wid=" + tbid).build().toString();
- final String page = Login.postRequestLogged(uri, params);
- if (!Login.getLoginStatus(page)) {
+ final String page = GCLogin.getInstance().postRequestLogged(uri, params);
+ if (!GCLogin.getInstance().getLoginStatus(page)) {
Log.e("GCParser.postLogTrackable: Cannot log in geocaching");
return StatusCode.NOT_LOGGED_IN;
}
@@ -1305,7 +1302,7 @@ public abstract class GCParser {
*/
static boolean addToWatchlist(final Geocache cache) {
final String uri = "http://www.geocaching.com/my/watchlist.aspx?w=" + cache.getCacheId();
- final String page = Login.postRequestLogged(uri, null);
+ final String page = GCLogin.getInstance().postRequestLogged(uri, null);
if (StringUtils.isBlank(page)) {
Log.e("GCParser.addToWatchlist: No data from server");
@@ -1331,7 +1328,7 @@ public abstract class GCParser {
*/
static boolean removeFromWatchlist(final Geocache cache) {
final String uri = "http://www.geocaching.com/my/watchlist.aspx?ds=1&action=rem&id=" + cache.getCacheId();
- String page = Login.postRequestLogged(uri, null);
+ String page = GCLogin.getInstance().postRequestLogged(uri, null);
if (StringUtils.isBlank(page)) {
Log.e("GCParser.removeFromWatchlist: No data from server");
@@ -1343,7 +1340,7 @@ public abstract class GCParser {
"__EVENTTARGET", "",
"__EVENTARGUMENT", "",
"ctl00$ContentBody$btnYes", "Yes");
- Login.transferViewstates(page, params);
+ GCLogin.transferViewstates(page, params);
page = Network.getResponseData(Network.postRequest(uri, params));
final boolean guidOnPage = cache.isGuidContainedInPage(page);
@@ -1367,7 +1364,7 @@ public abstract class GCParser {
params.put("log", log);
params.put("numlogs", numlogs);
- return Login.getRequestLogged("http://www.geocaching.com/seek/cache_details.aspx", params);
+ return GCLogin.getInstance().getRequestLogged("http://www.geocaching.com/seek/cache_details.aspx", params);
}
/**
@@ -1563,7 +1560,7 @@ public abstract class GCParser {
while (matcherLogs.find()) {
long date = 0;
try {
- date = Login.parseGcCustomDate(matcherLogs.group(2)).getTime();
+ date = GCLogin.parseGcCustomDate(matcherLogs.group(2)).getTime();
} catch (final ParseException e) {
}
@@ -1694,7 +1691,7 @@ public abstract class GCParser {
long date = 0;
try {
- date = Login.parseGcCustomDate(entry.getString("Visited")).getTime();
+ date = GCLogin.parseGcCustomDate(entry.getString("Visited")).getTime();
} catch (final ParseException e) {
Log.e("GCParser.loadLogsFromDetails: failed to parse log date.");
}
diff --git a/main/src/cgeo/geocaching/connector/gc/MapTokens.java b/main/src/cgeo/geocaching/connector/gc/MapTokens.java
new file mode 100644
index 0000000..78ce4cb
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/gc/MapTokens.java
@@ -0,0 +1,23 @@
+package cgeo.geocaching.connector.gc;
+
+import android.util.Pair;
+
+/**
+ * Wrapper type to make map tokens more type safe than with a String array.
+ *
+ */
+public final class MapTokens extends Pair<String, String> {
+
+ public MapTokens(String userSession, String sessionToken) {
+ super(userSession, sessionToken);
+ }
+
+ public String getUserSession() {
+ return first;
+ }
+
+ public String getSessionToken() {
+ return second;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java b/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java
index d43d06b..46e4c96 100644
--- a/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java
+++ b/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java
@@ -8,6 +8,8 @@ import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.CryptUtils;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
public class OCApiConnector extends OCConnector implements ISearchByGeocode {
@@ -41,13 +43,13 @@ public class OCApiConnector extends OCConnector implements ISearchByGeocode {
}
@Override
- public String getLicenseText(final Geocache cache) {
+ public String getLicenseText(final @NonNull Geocache cache) {
// NOT TO BE TRANSLATED
return "© " + cache.getOwnerDisplayName() + ", <a href=\"" + getCacheUrl(cache) + "\">" + getName() + "</a>, " + licenseString;
}
@Override
- public SearchResult searchByGeocode(final String geocode, final String guid, final CancellableHandler handler) {
+ public SearchResult searchByGeocode(final @Nullable String geocode, final @Nullable String guid, final CancellableHandler handler) {
final Geocache cache = OkapiClient.getCache(geocode);
if (cache == null) {
return null;
@@ -56,7 +58,7 @@ public class OCApiConnector extends OCConnector implements ISearchByGeocode {
}
@Override
- public boolean isActivated() {
+ public boolean isActive() {
// currently always active, but only for details download
return true;
}
diff --git a/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java b/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java
index b1b9088..b45f809 100644
--- a/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java
+++ b/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java
@@ -10,13 +10,16 @@ import cgeo.geocaching.connector.capability.ILogin;
import cgeo.geocaching.connector.capability.ISearchByCenter;
import cgeo.geocaching.connector.capability.ISearchByKeyword;
import cgeo.geocaching.connector.capability.ISearchByViewPort;
+import cgeo.geocaching.connector.gc.MapTokens;
import cgeo.geocaching.connector.oc.UserInfo.UserInfoStatus;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.loaders.RecaptchaReceiver;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.CryptUtils;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
import android.content.Context;
import android.os.Handler;
@@ -39,17 +42,17 @@ public class OCApiLiveConnector extends OCApiConnector implements ISearchByCente
}
@Override
- public boolean isActivated() {
+ public boolean isActive() {
return Settings.isOCConnectorActive(isActivePrefKeyId);
}
@Override
- public SearchResult searchByViewport(Viewport viewport, String[] tokens) {
+ public SearchResult searchByViewport(@NonNull Viewport viewport, MapTokens tokens) {
return new SearchResult(OkapiClient.getCachesBBox(viewport, this));
}
@Override
- public SearchResult searchByCenter(Geopoint center) {
+ public SearchResult searchByCenter(@NonNull Geopoint center, final @NonNull RecaptchaReceiver recaptchaReceiver) {
return new SearchResult(OkapiClient.getCachesAround(center, this));
}
@@ -155,7 +158,7 @@ public class OCApiLiveConnector extends OCApiConnector implements ISearchByCente
}
@Override
- public SearchResult searchByName(final String name) {
+ public SearchResult searchByKeyword(final @NonNull String name, final @NonNull RecaptchaReceiver recaptchaReceiver) {
final Geopoint currentPos = CgeoApplication.getInstance().currentGeo().getCoords();
return new SearchResult(OkapiClient.getCachesNamed(currentPos, name, this));
}
diff --git a/main/src/cgeo/geocaching/connector/oc/OCConnector.java b/main/src/cgeo/geocaching/connector/oc/OCConnector.java
index b5c62ea..1ba88d5 100644
--- a/main/src/cgeo/geocaching/connector/oc/OCConnector.java
+++ b/main/src/cgeo/geocaching/connector/oc/OCConnector.java
@@ -6,6 +6,8 @@ import cgeo.geocaching.R;
import cgeo.geocaching.connector.AbstractConnector;
import cgeo.geocaching.enumerations.LogType;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
@@ -27,10 +29,7 @@ public class OCConnector extends AbstractConnector {
}
@Override
- public boolean canHandle(String geocode) {
- if (geocode == null) {
- return false;
- }
+ public boolean canHandle(@NonNull String geocode) {
return codePattern.matcher(geocode).matches();
}
@@ -40,7 +39,7 @@ public class OCConnector extends AbstractConnector {
}
@Override
- public String getCacheUrl(Geocache cache) {
+ public String getCacheUrl(@NonNull Geocache cache) {
return getCacheUrlPrefix() + cache.getGeocode();
}
diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java b/main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java
index c6be3cb..6836e6f 100644
--- a/main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java
+++ b/main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java
@@ -3,7 +3,7 @@ package cgeo.geocaching.connector.oc;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.LogCacheActivity;
import cgeo.geocaching.TrackableLog;
-import cgeo.geocaching.connector.ILoggingManager;
+import cgeo.geocaching.connector.AbstractLoggingManager;
import cgeo.geocaching.connector.ImageResult;
import cgeo.geocaching.connector.LogResult;
import cgeo.geocaching.enumerations.LogType;
@@ -12,10 +12,9 @@ import cgeo.geocaching.enumerations.StatusCode;
import android.net.Uri;
import java.util.Calendar;
-import java.util.Collections;
import java.util.List;
-public class OkapiLoggingManager implements ILoggingManager {
+public class OkapiLoggingManager extends AbstractLoggingManager {
private final OCApiLiveConnector connector;
private final Geocache cache;
@@ -45,16 +44,6 @@ public class OkapiLoggingManager implements ILoggingManager {
}
@Override
- public final boolean hasLoaderError() {
- return false;
- }
-
- @Override
- public final List<TrackableLog> getTrackables() {
- return Collections.emptyList();
- }
-
- @Override
public List<LogType> getPossibleLogTypes() {
return connector.getPossibleLogTypes(cache);
}
diff --git a/main/src/cgeo/geocaching/connector/ox/OXConnector.java b/main/src/cgeo/geocaching/connector/ox/OXConnector.java
index af33bb6..7d4cf7f 100644
--- a/main/src/cgeo/geocaching/connector/ox/OXConnector.java
+++ b/main/src/cgeo/geocaching/connector/ox/OXConnector.java
@@ -3,13 +3,21 @@ package cgeo.geocaching.connector.ox;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.ICache;
import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.connector.AbstractConnector;
import cgeo.geocaching.connector.capability.ISearchByCenter;
import cgeo.geocaching.connector.capability.ISearchByGeocode;
+import cgeo.geocaching.connector.capability.ISearchByKeyword;
+import cgeo.geocaching.connector.capability.ISearchByViewPort;
+import cgeo.geocaching.connector.gc.MapTokens;
import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.loaders.RecaptchaReceiver;
+import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.CancellableHandler;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
import java.util.Collection;
import java.util.regex.Pattern;
@@ -17,17 +25,17 @@ import java.util.regex.Pattern;
* connector for OpenCaching.com
*
*/
-public class OXConnector extends AbstractConnector implements ISearchByCenter, ISearchByGeocode {
+public class OXConnector extends AbstractConnector implements ISearchByCenter, ISearchByGeocode, ISearchByViewPort, ISearchByKeyword {
private static final Pattern PATTERN_GEOCODE = Pattern.compile("OX[A-Z0-9]+", Pattern.CASE_INSENSITIVE);
@Override
- public boolean canHandle(String geocode) {
+ public boolean canHandle(@NonNull String geocode) {
return PATTERN_GEOCODE.matcher(geocode).matches();
}
@Override
- public String getCacheUrl(Geocache cache) {
+ public String getCacheUrl(@NonNull Geocache cache) {
return getCacheUrlPrefix() + cache.getGeocode();
}
@@ -42,9 +50,9 @@ public class OXConnector extends AbstractConnector implements ISearchByCenter, I
}
@Override
- public String getLicenseText(Geocache cache) {
+ public String getLicenseText(@NonNull Geocache cache) {
// NOT TO BE TRANSLATED
- return "<a href=\"" + getCacheUrl(cache) + "\">" + getName() + "</a> data licensed under the Creative Commons BY-SA 3.0 License";
+ return "<a href=\"" + getCacheUrl(cache) + "\">" + getName() + "</a> data licensed under the Creative Commons CC-BY-SA 3.0 License";
}
@Override
@@ -53,7 +61,10 @@ public class OXConnector extends AbstractConnector implements ISearchByCenter, I
}
@Override
- public SearchResult searchByGeocode(String geocode, String guid, CancellableHandler handler) {
+ public SearchResult searchByGeocode(final @Nullable String geocode, final @Nullable String guid, final CancellableHandler handler) {
+ if (geocode == null) {
+ return null;
+ }
final Geocache cache = OpenCachingApi.searchByGeoCode(geocode);
if (cache == null) {
return null;
@@ -63,16 +74,34 @@ public class OXConnector extends AbstractConnector implements ISearchByCenter, I
}
@Override
- public SearchResult searchByCenter(Geopoint center) {
- Collection<Geocache> caches = OpenCachingApi.searchByCenter(center);
- if (caches == null) {
- return null;
- }
- return new SearchResult(caches);
+ public SearchResult searchByCenter(@NonNull Geopoint center, final @NonNull RecaptchaReceiver recaptchaReceiver) {
+ return createSearchResult(OpenCachingApi.searchByCenter(center));
}
@Override
protected String getCacheUrlPrefix() {
return "http://www.opencaching.com/#!geocache/";
}
+
+ @Override
+ public SearchResult searchByViewport(@NonNull Viewport viewport, final MapTokens tokens) {
+ return createSearchResult(OpenCachingApi.searchByBoundingBox(viewport));
+ }
+
+ @Override
+ public boolean isActive() {
+ return Settings.isOXConnectorActive();
+ }
+
+ @Override
+ public SearchResult searchByKeyword(final @NonNull String name, final @NonNull RecaptchaReceiver recaptchaReceiver) {
+ return createSearchResult(OpenCachingApi.searchByKeyword(name));
+ }
+
+ private static SearchResult createSearchResult(Collection<Geocache> caches) {
+ if (caches == null) {
+ return null;
+ }
+ return new SearchResult(caches);
+ }
}
diff --git a/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java b/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java
index f40a3e8..f72b698 100644
--- a/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java
+++ b/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java
@@ -3,6 +3,9 @@ package cgeo.geocaching.connector.ox;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.files.GPX10Parser;
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+
public class OXGPXParser extends GPX10Parser {
private final boolean isDetailed;
@@ -19,5 +22,16 @@ public class OXGPXParser extends GPX10Parser {
cache.setDetailedUpdate(cache.getUpdated());
cache.setDetailed(true);
}
+ removeTitleFromShortDescription(cache);
+ }
+
+ /**
+ * 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(), ","));
}
}
diff --git a/main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java b/main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java
index 9d1dfc7..2defc52 100644
--- a/main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java
+++ b/main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java
@@ -3,6 +3,7 @@ package cgeo.geocaching.connector.ox;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.GeopointFormatter;
+import cgeo.geocaching.geopoint.Viewport;
import cgeo.geocaching.list.StoredList;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
@@ -12,19 +13,20 @@ import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.HttpResponse;
import org.apache.commons.collections4.CollectionUtils;
+import org.eclipse.jdt.annotation.NonNull;
import java.util.Collection;
import java.util.Collections;
public class OpenCachingApi {
+ private static final String API_URL_CACHES_GPX = "http://www.opencaching.com/api/geocache.gpx";
private static final String DEV_KEY = CryptUtils.rot13("PtqQnHo9RUTht3Np");
- public static Geocache searchByGeoCode(final String geocode) {
- final HttpResponse response = Network.getRequest("http://www.opencaching.com/api/geocache/" + geocode + ".gpx",
+ public static Geocache searchByGeoCode(final @NonNull String geocode) {
+ final HttpResponse response = getRequest("http://www.opencaching.com/api/geocache/" + geocode + ".gpx",
new Parameters(
- "Authorization", DEV_KEY,
- "log_limit", "30",
+ "log_limit", "50",
"hint", "true",
"description", "html"));
final Collection<Geocache> caches = importCachesFromResponse(response, true);
@@ -34,13 +36,18 @@ public class OpenCachingApi {
return null;
}
+ private static HttpResponse getRequest(String string, Parameters parameters) {
+ parameters.add("Authorization", DEV_KEY);
+ return Network.getRequest(string, parameters);
+ }
+
private static Collection<Geocache> importCachesFromResponse(final HttpResponse response, final boolean isDetailed) {
if (response == null) {
return Collections.emptyList();
}
Collection<Geocache> caches;
try {
- caches = new OXGPXParser(StoredList.STANDARD_LIST_ID, isDetailed).parse(response.getEntity().getContent(), null);
+ caches = new OXGPXParser(StoredList.TEMPORARY_LIST_ID, isDetailed).parse(response.getEntity().getContent(), null);
} catch (Exception e) {
Log.e("Error importing from OpenCaching.com", e);
return Collections.emptyList();
@@ -48,17 +55,39 @@ public class OpenCachingApi {
return caches;
}
- public static Collection<Geocache> searchByCenter(final Geopoint center) {
- final HttpResponse response = Network.getRequest("http://www.opencaching.com/api/geocache/.gpx",
+ public static Collection<Geocache> searchByCenter(final @NonNull Geopoint center) {
+ final HttpResponse response = getRequest(API_URL_CACHES_GPX,
new Parameters(
- "Authorization", DEV_KEY,
"log_limit", "0",
"hint", "false",
"description", "none",
- "limit", "10",
+ "limit", "20",
"center", center.format(GeopointFormatter.Format.LAT_LON_DECDEGREE_COMMA)));
return importCachesFromResponse(response, false);
}
+ public static Collection<Geocache> searchByBoundingBox(final @NonNull Viewport viewport) {
+ final String bbox = viewport.bottomLeft.format(GeopointFormatter.Format.LAT_LON_DECDEGREE_COMMA) + "," + viewport.topRight.format(GeopointFormatter.Format.LAT_LON_DECDEGREE_COMMA);
+ final HttpResponse response = getRequest(API_URL_CACHES_GPX,
+ new Parameters(
+ "log_limit", "0",
+ "hint", "false",
+ "description", "none",
+ "limit", "100",
+ "bbox", bbox));
+ return importCachesFromResponse(response, false);
+ }
+
+ public static Collection<Geocache> searchByKeyword(final @NonNull String name) {
+ final HttpResponse response = getRequest(API_URL_CACHES_GPX,
+ new Parameters(
+ "log_limit", "5",
+ "hint", "false",
+ "description", "none",
+ "limit", "100",
+ "name", name));
+ return importCachesFromResponse(response, false);
+ }
+
}
diff --git a/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java b/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java
index 67180b3..9cb5dc5 100644
--- a/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java
+++ b/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java
@@ -37,15 +37,15 @@ public class GeokretyParser {
try {
final int indexId = attributes.getIndex("id");
if (indexId > -1) {
- trackable.setGeocode(geocode(Integer.valueOf(attributes.getValue("id"))));
+ trackable.setGeocode(geocode(Integer.parseInt(attributes.getValue("id"))));
}
final int indexDist = attributes.getIndex("dist");
if (indexDist > -1) {
- trackable.setDistance(Float.valueOf(attributes.getValue("dist")));
+ trackable.setDistance(Float.parseFloat(attributes.getValue("dist")));
}
final int indexType = attributes.getIndex("type");
if (indexType > -1) {
- trackable.setType(getType(Integer.valueOf(attributes.getValue("type"))));
+ trackable.setType(getType(Integer.parseInt(attributes.getValue("type"))));
}
final int indexWaypoint = attributes.getIndex("waypoint");
if (indexWaypoint > -1) {
diff --git a/main/src/cgeo/geocaching/enumerations/CacheAttribute.java b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java
index 31fc023..4ace4a8 100644
--- a/main/src/cgeo/geocaching/enumerations/CacheAttribute.java
+++ b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java
@@ -79,7 +79,7 @@ public enum CacheAttribute {
STROLLER(41, -1, "stroller", R.drawable.attribute_stroller, R.string.attribute_stroller_yes, R.string.attribute_stroller_no),
FUEL(58, -1, "fuel", R.drawable.attribute_fuel, R.string.attribute_fuel_yes, R.string.attribute_fuel_no),
FOOD(59, -1, "food", R.drawable.attribute_food, R.string.attribute_food_yes, R.string.attribute_food_no),
- OC_ONLY(-1, -1, "oc_only", R.drawable.attribute_oc_only, R.string.attribute_oc_only_yes, R.string.attribute_oc_only_no),
+ OC_ONLY(-1, 1, "oc_only", R.drawable.attribute_oc_only, R.string.attribute_oc_only_yes, R.string.attribute_oc_only_no),
LINK_ONLY(-1, -1, "link_only", R.drawable.attribute_link_only, R.string.attribute_link_only_yes, R.string.attribute_link_only_no),
LETTERBOX(-1, 4, "letterbox", R.drawable.attribute_letterbox, R.string.attribute_letterbox_yes, R.string.attribute_letterbox_no),
RAILWAY(-1, 60, "railway", R.drawable.attribute_railway, R.string.attribute_railway_yes, R.string.attribute_railway_no),
@@ -109,7 +109,11 @@ public enum CacheAttribute {
OTHER_CACHE(-1, 13, "other_cache", R.drawable.attribute_other_cache, R.string.attribute_other_cache_yes, R.string.attribute_other_cache_no),
ASK_OWNER(-1, 17, "ask_owner", R.drawable.attribute_ask_owner, R.string.attribute_ask_owner_yes, R.string.attribute_ask_owner_no),
UNKNOWN(-1, -1, "unknown", R.drawable.attribute_unknown, R.string.attribute_unknown_yes, R.string.attribute_unknown_no),
- GEOTOUR(67, -1, "geotour", R.drawable.attribute_geotour, R.string.attribute_geotour_yes, R.string.attribute_geotour_no);
+ GEOTOUR(67, -1, "geotour", R.drawable.attribute_geotour, R.string.attribute_geotour_yes, R.string.attribute_geotour_no),
+ KIDS_2(-1, 70, "kids_2", R.drawable.attribute_kids_2, R.string.attribute_kids_2_yes, R.string.attribute_kids_2_no),
+ HISTORIC_SITE(-1, 29, "historic_site", R.drawable.attribute_historic_site, R.string.attribute_historic_site_yes, R.string.attribute_historic_site_no),
+ MAGNETIC(-1, 6, "magnetic", R.drawable.attribute_magnetic, R.string.attribute_magnetic_yes, R.string.attribute_magnetic_no),
+ USB_CACHE(-1, 10, "usb_cache", R.drawable.attribute_usb_cache, R.string.attribute_usb_cache_yes, R.string.attribute_usb_cache_no);
// THIS LIST IS GENERATED: don't change anything here but read
// project/attributes/readme.txt
diff --git a/main/src/cgeo/geocaching/enumerations/CacheSize.java b/main/src/cgeo/geocaching/enumerations/CacheSize.java
index a6f8df3..ee42c66 100644
--- a/main/src/cgeo/geocaching/enumerations/CacheSize.java
+++ b/main/src/cgeo/geocaching/enumerations/CacheSize.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.enumerations;
-import cgeo.geocaching.R;
import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.R;
import java.util.Collections;
import java.util.HashMap;
@@ -56,6 +56,28 @@ public enum CacheSize {
if (resultNormalized != null) {
return resultNormalized;
}
+ return getByNumber(id);
+ }
+
+ /**
+ * 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);
+ if (numerical != 0) {
+ for (CacheSize size : CacheSize.values()) {
+ if (size.comparable == numerical) {
+ return size;
+ }
+ }
+ }
+ } catch (NumberFormatException e) {
+ // ignore, as this might be a number or not
+ }
return UNKNOWN;
}
diff --git a/main/src/cgeo/geocaching/enumerations/StatusCode.java b/main/src/cgeo/geocaching/enumerations/StatusCode.java
index 102b9e9..e1a1aaa 100644
--- a/main/src/cgeo/geocaching/enumerations/StatusCode.java
+++ b/main/src/cgeo/geocaching/enumerations/StatusCode.java
@@ -11,6 +11,7 @@ public enum StatusCode {
LOG_SAVED(R.string.info_log_saved),
LOGIN_PARSE_ERROR(R.string.err_parse),
CONNECTION_FAILED(R.string.err_server),
+ CONNECTION_FAILED_EC(R.string.err_server_ec),
NO_LOGIN_INFO_STORED(R.string.err_login),
UNKNOWN_ERROR(R.string.err_unknown),
COMMUNICATION_ERROR(R.string.err_comm),
@@ -21,6 +22,7 @@ public enum StatusCode {
PREMIUM_ONLY(R.string.err_premium_only),
MAINTENANCE(R.string.err_maintenance),
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),
diff --git a/main/src/cgeo/geocaching/export/FieldnoteExport.java b/main/src/cgeo/geocaching/export/FieldnoteExport.java
index 1ae97f3..4da480a 100644
--- a/main/src/cgeo/geocaching/export/FieldnoteExport.java
+++ b/main/src/cgeo/geocaching/export/FieldnoteExport.java
@@ -5,7 +5,7 @@ import cgeo.geocaching.Geocache;
import cgeo.geocaching.LogEntry;
import cgeo.geocaching.R;
import cgeo.geocaching.activity.ActivityMixin;
-import cgeo.geocaching.connector.gc.Login;
+import cgeo.geocaching.connector.gc.GCLogin;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
@@ -175,30 +175,30 @@ class FieldnoteExport extends AbstractExport {
if (upload) {
publishProgress(STATUS_UPLOAD);
- if (!Login.isActualLoginStatus()) {
+ if (!GCLogin.getInstance().isActualLoginStatus()) {
// no need to upload (possibly large file) if we're not logged in
- final StatusCode loginState = Login.login();
+ final StatusCode loginState = GCLogin.getInstance().login();
if (loginState != StatusCode.NO_ERROR) {
Log.e("FieldnoteExport.ExportTask upload: Login failed");
}
}
final String uri = "http://www.geocaching.com/my/uploadfieldnotes.aspx";
- final String page = Login.getRequestLogged(uri, null);
+ final String page = GCLogin.getInstance().getRequestLogged(uri, null);
if (StringUtils.isBlank(page)) {
Log.e("FieldnoteExport.ExportTask get page: No data from server");
return false;
}
- final String[] viewstates = Login.getViewstates(page);
+ final String[] viewstates = GCLogin.getViewstates(page);
final Parameters uploadParams = new Parameters(
"__EVENTTARGET", "",
"__EVENTARGUMENT", "",
"ctl00$ContentBody$btnUpload", "Upload Field Note");
- Login.putViewstates(uploadParams, viewstates);
+ GCLogin.putViewstates(uploadParams, viewstates);
Network.getResponseData(Network.postRequest(uri, uploadParams, "ctl00$ContentBody$FieldNoteLoader", "text/plain", exportFile));
diff --git a/main/src/cgeo/geocaching/files/GPXImporter.java b/main/src/cgeo/geocaching/files/GPXImporter.java
index bf0aa72..07ef285 100644
--- a/main/src/cgeo/geocaching/files/GPXImporter.java
+++ b/main/src/cgeo/geocaching/files/GPXImporter.java
@@ -1,14 +1,15 @@
package cgeo.geocaching.files;
+import cgeo.geocaching.DataStore;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.StaticMapsProvider;
-import cgeo.geocaching.DataStore;
import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.activity.Progress;
import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.Log;
@@ -417,19 +418,19 @@ public class GPXImporter {
progressHandler.cancel();
final StringBuilder bufferSkipped = new StringBuilder(20);
bufferSkipped.append(res.getString(R.string.gpx_import_static_maps_skipped)).append(", ").append(msg.arg1).append(' ').append(res.getString(R.string.gpx_import_caches_imported));
- ActivityMixin.helpDialog(fromActivity, res.getString(R.string.gpx_import_title_caches_imported), bufferSkipped.toString());
+ Dialogs.message(fromActivity, R.string.gpx_import_title_caches_imported, bufferSkipped.toString());
importFinished();
break;
case IMPORT_STEP_FINISHED:
progress.dismiss();
- ActivityMixin.helpDialog(fromActivity, res.getString(R.string.gpx_import_title_caches_imported), msg.arg1 + " " + res.getString(R.string.gpx_import_caches_imported));
+ Dialogs.message(fromActivity, R.string.gpx_import_title_caches_imported, msg.arg1 + " " + res.getString(R.string.gpx_import_caches_imported));
importFinished();
break;
case IMPORT_STEP_FINISHED_WITH_ERROR:
progress.dismiss();
- ActivityMixin.helpDialog(fromActivity, res.getString(R.string.gpx_import_title_caches_import_failed), res.getString(msg.arg1) + "\n\n" + msg.obj);
+ Dialogs.message(fromActivity, R.string.gpx_import_title_caches_import_failed, res.getString(msg.arg1) + "\n\n" + msg.obj);
importFinished();
break;
diff --git a/main/src/cgeo/geocaching/files/GPXParser.java b/main/src/cgeo/geocaching/files/GPXParser.java
index 3e96291..d26a48c 100644
--- a/main/src/cgeo/geocaching/files/GPXParser.java
+++ b/main/src/cgeo/geocaching/files/GPXParser.java
@@ -104,6 +104,10 @@ public abstract class GPXParser extends FileParser {
*/
private final Set<String> result = new HashSet<String>(100);
private ProgressInputStream progressStream;
+ /**
+ * URL contained in the header of the GPX file. Used to guess where the file is coming from.
+ */
+ protected String scriptUrl;
private final class UserDataListener implements EndTextElementListener {
private final int index;
@@ -265,6 +269,14 @@ public abstract class GPXParser extends FileParser {
final RootElement root = new RootElement(namespace, "gpx");
final Element waypoint = root.getChild(namespace, "wpt");
+ root.getChild(namespace, "url").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String body) {
+ scriptUrl = body;
+ }
+ });
+
// waypoint - attributes
waypoint.setStartElementListener(new StartElementListener() {
@@ -338,7 +350,12 @@ public abstract class GPXParser extends FileParser {
if (cache.getName().length() > 2 || StringUtils.isNotBlank(parentCacheCode)) {
if (StringUtils.isBlank(parentCacheCode)) {
- parentCacheCode = "GC" + cache.getName().substring(2).toUpperCase(Locale.US);
+ if (StringUtils.containsIgnoreCase(scriptUrl, "extremcaching")) {
+ parentCacheCode = cache.getName().substring(2);
+ }
+ else {
+ parentCacheCode = "GC" + cache.getName().substring(2).toUpperCase(Locale.US);
+ }
}
// lookup cache for waypoint in already parsed caches
final Geocache cacheForWaypoint = DataStore.loadCache(parentCacheCode, LoadFlags.LOAD_CACHE_OR_DB);
@@ -382,14 +399,19 @@ public abstract class GPXParser extends FileParser {
}
});
- // waypoint.getName()
+ // waypoint.name
waypoint.getChild(namespace, "name").setEndTextElementListener(new EndTextElementListener() {
@Override
public void end(String body) {
name = body;
- final String content = body.trim();
+ String content = body.trim();
+
+ // extremcaching.com manipulates the GC code by adding GC in front of ECxxx
+ if (StringUtils.startsWithIgnoreCase(content, "GCEC") && StringUtils.containsIgnoreCase(scriptUrl, "extremcaching")) {
+ content = content.substring(2);
+ }
cache.setName(content);
findGeoCode(cache.getName());
@@ -834,6 +856,9 @@ public abstract class GPXParser extends FileParser {
}
/**
+ * Overwrite this method in a GPX parser sub class to modify the {@link Geocache}, after it has been fully parsed
+ * from the GPX file and before it gets stored.
+ *
* @param cache
* currently imported cache
*/
diff --git a/main/src/cgeo/geocaching/files/SimpleDirChooser.java b/main/src/cgeo/geocaching/files/SimpleDirChooser.java
index 3f6182c..3e09cc4 100644
--- a/main/src/cgeo/geocaching/files/SimpleDirChooser.java
+++ b/main/src/cgeo/geocaching/files/SimpleDirChooser.java
@@ -29,6 +29,7 @@ import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
/**
@@ -141,7 +142,7 @@ public class SimpleDirChooser extends AbstractListActivity {
}
} catch (RuntimeException e) {
}
- Collections.sort(listDirs);
+ Collections.sort(listDirs, Option.NAME_COMPARATOR);
if (dir.getParent() != null) {
listDirs.add(0, new Option(PARENT_DIR, dir.getParent(), false));
}
@@ -247,15 +248,21 @@ public class SimpleDirChooser extends AbstractListActivity {
}
}
- /**
- * Note: this class has a natural ordering that is inconsistent with equals.
- */
- public static class Option implements Comparable<Option> {
+ public static class Option {
private final String name;
private final String path;
private boolean checked = false;
private boolean writeable = false;
+ private static Comparator<Option> NAME_COMPARATOR = new Comparator<SimpleDirChooser.Option>() {
+
+ @Override
+ public int compare(Option lhs, Option rhs) {
+ return String.CASE_INSENSITIVE_ORDER.compare(lhs.name, rhs.name);
+ }
+
+ };
+
public Option(String name, String path, boolean writeable) {
this.name = name;
this.path = path;
@@ -281,14 +288,6 @@ public class SimpleDirChooser extends AbstractListActivity {
public boolean isWriteable() {
return writeable;
}
-
- @Override
- public int compareTo(Option other) {
- if (other != null && this.name != null) {
- return String.CASE_INSENSITIVE_ORDER.compare(this.name, other.getName());
- }
- throw new IllegalArgumentException("");
- }
}
public static class DirOnlyFilenameFilter implements FilenameFilter {
diff --git a/main/src/cgeo/geocaching/filter/TerrainFilter.java b/main/src/cgeo/geocaching/filter/TerrainFilter.java
index d74f954..f14313c 100644
--- a/main/src/cgeo/geocaching/filter/TerrainFilter.java
+++ b/main/src/cgeo/geocaching/filter/TerrainFilter.java
@@ -20,7 +20,7 @@ class TerrainFilter extends AbstractRangeFilter {
public static class Factory implements IFilterFactory {
private static final int TERRAIN_MIN = 1;
- private static final int TERRAIN_MAX = 5;
+ private static final int TERRAIN_MAX = 7;
@Override
public List<IFilter> getFilters() {
diff --git a/main/src/cgeo/geocaching/gcvote/GCVote.java b/main/src/cgeo/geocaching/gcvote/GCVote.java
index b245aa9..fd4b914 100644
--- a/main/src/cgeo/geocaching/gcvote/GCVote.java
+++ b/main/src/cgeo/geocaching/gcvote/GCVote.java
@@ -11,8 +11,10 @@ import cgeo.geocaching.utils.MatcherWrapper;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.eclipse.jdt.annotation.NonNull;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -219,19 +221,12 @@ public final class GCVote {
return result != null && result.trim().equalsIgnoreCase("ok");
}
- public static void loadRatings(final ArrayList<Geocache> caches) {
+ public static void loadRatings(final @NonNull ArrayList<Geocache> caches) {
if (!Settings.isRatingWanted()) {
return;
}
- final ArrayList<String> geocodes = new ArrayList<String>(caches.size());
- for (final Geocache cache : caches) {
- String geocode = cache.getGeocode();
- if (StringUtils.isNotBlank(geocode)) {
- geocodes.add(geocode);
- }
- }
-
+ final ArrayList<String> geocodes = getVotableGeocodes(caches);
if (geocodes.isEmpty()) {
return;
}
@@ -256,6 +251,24 @@ public final class GCVote {
}
}
+ /**
+ * Get geocodes of all the caches, which can be used with GCVote. Non-GC caches will be filtered out.
+ *
+ * @param caches
+ * @return
+ */
+ private static @NonNull
+ ArrayList<String> getVotableGeocodes(final @NonNull Collection<Geocache> caches) {
+ final ArrayList<String> geocodes = new ArrayList<String>(caches.size());
+ for (final Geocache cache : caches) {
+ String geocode = cache.getGeocode();
+ if (StringUtils.isNotBlank(geocode) && cache.supportsGCVote()) {
+ geocodes.add(geocode);
+ }
+ }
+ return geocodes;
+ }
+
public static boolean isValidRating(final float rating) {
return rating >= MIN_RATING && rating <= MAX_RATING;
}
diff --git a/main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java b/main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java
index 1cc9706..0ba8932 100644
--- a/main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java
+++ b/main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java
@@ -68,11 +68,6 @@ public abstract class AbstractSearchLoader extends AsyncTaskLoader<SearchResult>
}
@Override
- public boolean takeContentChanged() {
- return super.takeContentChanged();
- }
-
- @Override
protected void onStartLoading() {
forceLoad();
}
@@ -91,7 +86,9 @@ public abstract class AbstractSearchLoader extends AsyncTaskLoader<SearchResult>
@Override
public synchronized void waitForUser() {
try {
- wait();
+ while (getText() == null) {
+ wait();
+ }
} catch (InterruptedException e) {
Log.w("searchThread is not waiting for user…");
}
diff --git a/main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java
index 34b3a61..3874b47 100644
--- a/main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java
+++ b/main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java
@@ -1,18 +1,18 @@
package cgeo.geocaching.loaders;
import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.capability.ISearchByCenter;
-import cgeo.geocaching.connector.gc.GCParser;
import cgeo.geocaching.geopoint.Geopoint;
+import org.eclipse.jdt.annotation.NonNull;
+
import android.content.Context;
public class CoordsGeocacheListLoader extends AbstractSearchLoader {
- private final Geopoint coords;
+ private final @NonNull Geopoint coords;
- public CoordsGeocacheListLoader(Context context, Geopoint coords) {
+ public CoordsGeocacheListLoader(final Context context, final @NonNull Geopoint coords) {
super(context);
this.coords = coords;
}
@@ -21,13 +21,10 @@ public class CoordsGeocacheListLoader extends AbstractSearchLoader {
public SearchResult runSearch() {
SearchResult search = new SearchResult();
- if (Settings.isGCConnectorActive()) {
- search = GCParser.searchByCoords(coords, Settings.getCacheType(), Settings.isShowCaptcha(), this);
- }
for (ISearchByCenter centerConn : ConnectorFactory.getSearchByCenterConnectors()) {
- if (centerConn.isActivated()) {
- search.addSearchResult(centerConn.searchByCenter(coords));
+ if (centerConn.isActive()) {
+ search.addSearchResult(centerConn.searchByCenter(coords, this));
}
}
diff --git a/main/src/cgeo/geocaching/loaders/KeywordGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/KeywordGeocacheListLoader.java
index c8132e7..9c16ee4 100644
--- a/main/src/cgeo/geocaching/loaders/KeywordGeocacheListLoader.java
+++ b/main/src/cgeo/geocaching/loaders/KeywordGeocacheListLoader.java
@@ -3,16 +3,16 @@ package cgeo.geocaching.loaders;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.capability.ISearchByKeyword;
-import cgeo.geocaching.connector.gc.GCParser;
-import cgeo.geocaching.settings.Settings;
+
+import org.eclipse.jdt.annotation.NonNull;
import android.content.Context;
public class KeywordGeocacheListLoader extends AbstractSearchLoader {
- private final String keyword;
+ private final @NonNull String keyword;
- public KeywordGeocacheListLoader(Context context, String keyword) {
+ public KeywordGeocacheListLoader(Context context, final @NonNull String keyword) {
super(context);
this.keyword = keyword;
}
@@ -20,13 +20,10 @@ public class KeywordGeocacheListLoader extends AbstractSearchLoader {
@Override
public SearchResult runSearch() {
SearchResult searchResult = new SearchResult();
- if (Settings.isGCConnectorActive()) {
- searchResult = GCParser.searchByKeyword(keyword, Settings.getCacheType(), Settings.isShowCaptcha(), this);
- }
for (ISearchByKeyword connector : ConnectorFactory.getSearchByKeywordConnectors()) {
- if (connector.isActivated()) {
- searchResult.addSearchResult(connector.searchByName(keyword));
+ if (connector.isActive()) {
+ searchResult.addSearchResult(connector.searchByKeyword(keyword, this));
}
}
diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java
index 28e1b71..927ff28 100644
--- a/main/src/cgeo/geocaching/maps/CGeoMap.java
+++ b/main/src/cgeo/geocaching/maps/CGeoMap.java
@@ -11,7 +11,8 @@ import cgeo.geocaching.SearchResult;
import cgeo.geocaching.Waypoint;
import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.connector.ConnectorFactory;
-import cgeo.geocaching.connector.gc.Login;
+import cgeo.geocaching.connector.gc.GCLogin;
+import cgeo.geocaching.connector.gc.MapTokens;
import cgeo.geocaching.connector.gc.Tile;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy;
@@ -138,7 +139,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
// status data
/** Last search result used for displaying header */
private SearchResult lastSearchResult = null;
- private String[] tokens = null;
+ private MapTokens tokens = null;
private boolean noMapTokenShowed = false;
// map status data
private boolean followMyLocation = false;
@@ -153,8 +154,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
private volatile boolean downloaded = false;
// overlays
private CachesOverlay overlayCaches = null;
- private ScaleOverlay overlayScale = null;
- private PositionOverlay overlayPosition = null;
+ private PositionAndScaleOverlay overlayPositionAndScale = null;
// data for overlays
private static final int[][] INSET_RELIABLE = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; // center, 33x40 / 45x51 / 60x68
private static final int[][] INSET_TYPE = { { 5, 8, 6, 10 }, { 4, 4, 5, 11 }, { 4, 4, 5, 11 } }; // center, 22x22 / 36x36
@@ -347,8 +347,8 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
outState.putInt(BUNDLE_MAP_SOURCE, currentSourceId);
outState.putIntArray(BUNDLE_MAP_STATE, currentMapState());
outState.putBoolean(BUNDLE_LIVE_ENABLED, isLiveEnabled);
- if (overlayPosition != null) {
- outState.putParcelableArrayList(BUNDLE_TRAIL_HISTORY, overlayPosition.getHistory());
+ if (overlayPositionAndScale != null) {
+ outState.putParcelableArrayList(BUNDLE_TRAIL_HISTORY, overlayPositionAndScale.getHistory());
}
}
@@ -429,17 +429,13 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
overlayCaches = mapView.createAddMapOverlay(mapView.getContext(), getResources().getDrawable(R.drawable.marker));
}
- if (overlayPosition == null) {
- overlayPosition = mapView.createAddPositionOverlay(activity);
+ if (overlayPositionAndScale == null) {
+ overlayPositionAndScale = mapView.createAddPositionAndScaleOverlay(activity);
if (trailHistory != null) {
- overlayPosition.setHistory(trailHistory);
+ overlayPositionAndScale.setHistory(trailHistory);
}
}
- if (overlayScale == null) {
- overlayScale = mapView.createAddScaleOverlay(activity);
- }
-
mapView.repaintRequired(null);
mapView.getMapController().setZoom(Settings.getMapZoom());
@@ -517,13 +513,8 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
@Override
public void onPause() {
- if (loadTimer != null) {
- loadTimer.stopIt();
- loadTimer = null;
- }
-
+ stopTimer();
deleteGeoDirObservers();
-
savePrefs();
if (mapView != null) {
@@ -622,7 +613,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
switch (id) {
case R.id.menu_trail_mode:
Settings.setMapTrail(!Settings.isMapTrail());
- mapView.repaintRequired(overlayPosition);
+ mapView.repaintRequired(overlayPositionAndScale);
ActivityMixin.invalidateOptionsMenu(activity);
return true;
case R.id.menu_map_live:
@@ -929,8 +920,8 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
try {
if (mapView != null) {
- if (overlayPosition == null) {
- overlayPosition = mapView.createAddPositionOverlay(activity);
+ if (overlayPositionAndScale == null) {
+ overlayPositionAndScale = mapView.createAddPositionAndScaleOverlay(activity);
}
boolean needsRepaintForDistance = needsRepaintForDistance();
@@ -943,9 +934,9 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
}
if (needsRepaintForDistance || needsRepaintForHeading) {
- overlayPosition.setCoordinates(currentLocation);
- overlayPosition.setHeading(currentHeading);
- mapView.repaintRequired(overlayPosition);
+ overlayPositionAndScale.setCoordinates(currentLocation);
+ overlayPositionAndScale.setHeading(currentHeading);
+ mapView.repaintRequired(overlayPositionAndScale);
}
}
} catch (RuntimeException e) {
@@ -955,7 +946,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
}
boolean needsRepaintForHeading() {
- return Math.abs(AngleUtils.difference(currentHeading, overlayPosition.getHeading())) > MIN_HEADING_DELTA;
+ return Math.abs(AngleUtils.difference(currentHeading, overlayPositionAndScale.getHeading())) > MIN_HEADING_DELTA;
}
boolean needsRepaintForDistance() {
@@ -964,7 +955,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
return false;
}
- final Location lastLocation = overlayPosition.getCoordinates();
+ final Location lastLocation = overlayPositionAndScale.getCoordinates();
float dist = Float.MAX_VALUE;
if (lastLocation != null) {
@@ -994,15 +985,19 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
(new DisplayPointThread()).start();
} else {
// start timer
- if (loadTimer != null) {
- loadTimer.stopIt();
- loadTimer = null;
- }
+ stopTimer();
loadTimer = new LoadTimer();
loadTimer.start();
}
}
+ private synchronized void stopTimer() {
+ if (loadTimer != null) {
+ loadTimer.stopIt();
+ loadTimer = null;
+ }
+ }
+
/**
* loading timer Triggers every 250ms and checks for viewport change and starts a {@link LoadRunnable}.
*/
@@ -1172,8 +1167,8 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
do {
if (tokens == null) {
- tokens = Login.getMapTokens();
- if (noMapTokenHandler != null && tokens == null) {
+ tokens = GCLogin.getMapTokens();
+ if (noMapTokenHandler != null && (StringUtils.isEmpty(tokens.getUserSession()) || StringUtils.isEmpty(tokens.getSessionToken()))) {
noMapTokenHandler.sendEmptyMessage(0);
}
}
@@ -1181,7 +1176,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
searchResult = ConnectorFactory.searchByViewport(viewport.resize(0.8), tokens);
downloaded = true;
if (searchResult.getError() == StatusCode.NOT_LOGGED_IN && Settings.isGCConnectorActive()) {
- Login.login();
+ GCLogin.getInstance().login();
tokens = null;
} else {
break;
@@ -1311,9 +1306,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
protected DoRunnable(final Viewport viewport) {
this.viewport = viewport;
}
-
- @Override
- public abstract void run();
}
/**
@@ -1429,7 +1421,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
}
}
- private static void filter(Collection<Geocache> caches) {
+ private static synchronized void filter(Collection<Geocache> caches) {
boolean excludeMine = Settings.isExcludeMyCaches();
boolean excludeDisabled = Settings.isExcludeDisabledCaches();
@@ -1480,7 +1472,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
mapController.setCenter(mapItemFactory.getGeoPointBase(new Geopoint(mapState[0] / 1.0e6, mapState[1] / 1.0e6)));
mapController.setZoom(mapState[2]);
} catch (RuntimeException e) {
- // nothing at all
+ Log.e("centermap", e);
}
centered = true;
@@ -1504,7 +1496,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
mapController.zoomToSpan((int) (viewport.getLatitudeSpan() * 1e6), (int) (viewport.getLongitudeSpan() * 1e6));
}
} catch (RuntimeException e) {
- // nothing at all
+ Log.e("centermap", e);
}
centered = true;
@@ -1513,7 +1505,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
try {
mapController.setCenter(makeGeoPoint(coordsCenter));
} catch (Exception e) {
- // nothing at all
+ Log.e("centermap", e);
}
centered = true;
diff --git a/main/src/cgeo/geocaching/maps/PositionAndScaleOverlay.java b/main/src/cgeo/geocaching/maps/PositionAndScaleOverlay.java
new file mode 100644
index 0000000..6b34b75
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/PositionAndScaleOverlay.java
@@ -0,0 +1,73 @@
+package cgeo.geocaching.maps;
+
+import cgeo.geocaching.maps.interfaces.GeneralOverlay;
+import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
+import cgeo.geocaching.maps.interfaces.MapViewImpl;
+import cgeo.geocaching.maps.interfaces.OverlayImpl;
+
+import android.app.Activity;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.location.Location;
+
+import java.util.ArrayList;
+
+public class PositionAndScaleOverlay implements GeneralOverlay {
+ private OverlayImpl ovlImpl = null;
+
+ PositionDrawer positionDrawer = null;
+ ScaleDrawer scaleDrawer = null;
+
+ public PositionAndScaleOverlay(Activity activity, OverlayImpl ovlImpl) {
+ this.ovlImpl = ovlImpl;
+ positionDrawer = new PositionDrawer(activity);
+ scaleDrawer = new ScaleDrawer(activity);
+ }
+
+ public void setCoordinates(Location coordinatesIn) {
+ positionDrawer.setCoordinates(coordinatesIn);
+ }
+
+ public Location getCoordinates() {
+ return positionDrawer.getCoordinates();
+ }
+
+ public void setHeading(float bearingNow) {
+ positionDrawer.setHeading(bearingNow);
+ }
+
+ public float getHeading() {
+ return positionDrawer.getHeading();
+ }
+
+ @Override
+ public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+
+ drawInternal(canvas, projection, getOverlayImpl().getMapViewImpl());
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+
+ drawInternal(canvas, mapView.getMapProjection(), mapView);
+ }
+
+ private void drawInternal(Canvas canvas, MapProjectionImpl projection, MapViewImpl mapView) {
+ positionDrawer.drawPosition(canvas, projection);
+ scaleDrawer.drawScale(canvas, mapView);
+ }
+
+ @Override
+ public OverlayImpl getOverlayImpl() {
+ return this.ovlImpl;
+ }
+
+ public ArrayList<Location> getHistory() {
+ return positionDrawer.getHistory();
+ }
+
+ public void setHistory(ArrayList<Location> history) {
+ positionDrawer.setHistory(history);
+ }
+}
diff --git a/main/src/cgeo/geocaching/maps/PositionOverlay.java b/main/src/cgeo/geocaching/maps/PositionDrawer.java
index b371eae..1a5dcaf 100644
--- a/main/src/cgeo/geocaching/maps/PositionOverlay.java
+++ b/main/src/cgeo/geocaching/maps/PositionDrawer.java
@@ -2,12 +2,9 @@ package cgeo.geocaching.maps;
import cgeo.geocaching.R;
import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.maps.interfaces.GeneralOverlay;
import cgeo.geocaching.maps.interfaces.GeoPointImpl;
import cgeo.geocaching.maps.interfaces.MapItemFactory;
import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
-import cgeo.geocaching.maps.interfaces.MapViewImpl;
-import cgeo.geocaching.maps.interfaces.OverlayImpl;
import cgeo.geocaching.settings.Settings;
import android.app.Activity;
@@ -23,7 +20,8 @@ import android.location.Location;
import java.util.ArrayList;
-public class PositionOverlay implements GeneralOverlay {
+public class PositionDrawer {
+
private Location coordinates = null;
private GeoPointImpl location = null;
private float heading = 0f;
@@ -39,47 +37,14 @@ public class PositionOverlay implements GeneralOverlay {
private PaintFlagsDrawFilter remfil = null;
private PositionHistory positionHistory = new PositionHistory();
private Activity activity;
- private MapItemFactory mapItemFactory = null;
- private OverlayImpl ovlImpl = null;
+ private MapItemFactory mapItemFactory;
- public PositionOverlay(Activity activity, OverlayImpl ovlImpl) {
+ public PositionDrawer(Activity activity) {
this.activity = activity;
this.mapItemFactory = Settings.getMapProvider().getMapItemFactory();
- this.ovlImpl = ovlImpl;
- }
-
- public void setCoordinates(Location coordinatesIn) {
- coordinates = coordinatesIn;
- location = mapItemFactory.getGeoPointBase(new Geopoint(coordinates));
- }
-
- public Location getCoordinates() {
- return coordinates;
- }
-
- public void setHeading(float bearingNow) {
- heading = bearingNow;
- }
-
- public float getHeading() {
- return heading;
- }
-
- @Override
- public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
- MapProjectionImpl projection, byte drawZoomLevel) {
-
- drawInternal(canvas, projection);
- }
-
- @Override
- public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
-
- drawInternal(canvas, mapView.getMapProjection());
}
- private void drawInternal(Canvas canvas, MapProjectionImpl projection) {
-
+ void drawPosition(Canvas canvas, MapProjectionImpl projection) {
if (coordinates == null || location == null) {
return;
}
@@ -194,13 +159,6 @@ public class PositionOverlay implements GeneralOverlay {
canvas.drawBitmap(arrow, matrix, null);
canvas.setDrawFilter(remfil);
-
- //super.draw(canvas, mapView, shadow);
- }
-
- @Override
- public OverlayImpl getOverlayImpl() {
- return this.ovlImpl;
}
public ArrayList<Location> getHistory() {
@@ -210,4 +168,22 @@ public class PositionOverlay implements GeneralOverlay {
public void setHistory(ArrayList<Location> history) {
positionHistory.setHistory(history);
}
+
+ public void setHeading(float bearingNow) {
+ heading = bearingNow;
+ }
+
+ public float getHeading() {
+ return heading;
+ }
+
+ public void setCoordinates(Location coordinatesIn) {
+ coordinates = coordinatesIn;
+ location = mapItemFactory.getGeoPointBase(new Geopoint(coordinates));
+ }
+
+ public Location getCoordinates() {
+ return coordinates;
+ }
+
}
diff --git a/main/src/cgeo/geocaching/maps/ScaleOverlay.java b/main/src/cgeo/geocaching/maps/ScaleDrawer.java
index bee6acf..fb46408 100644
--- a/main/src/cgeo/geocaching/maps/ScaleOverlay.java
+++ b/main/src/cgeo/geocaching/maps/ScaleDrawer.java
@@ -2,11 +2,8 @@ package cgeo.geocaching.maps;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.Units;
-import cgeo.geocaching.maps.interfaces.GeneralOverlay;
import cgeo.geocaching.maps.interfaces.GeoPointImpl;
-import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
import cgeo.geocaching.maps.interfaces.MapViewImpl;
-import cgeo.geocaching.maps.interfaces.OverlayImpl;
import org.apache.commons.lang3.tuple.ImmutablePair;
@@ -14,46 +11,29 @@ import android.app.Activity;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
-import android.graphics.Point;
import android.graphics.Typeface;
import android.util.DisplayMetrics;
-public class ScaleOverlay implements GeneralOverlay {
-
+public class ScaleDrawer {
private static final double SCALE_WIDTH_FACTOR = 1.0 / 2.5;
private Paint scale = null;
private Paint scaleShadow = null;
private BlurMaskFilter blur = null;
private float pixelDensity = 0;
- private OverlayImpl ovlImpl = null;
-
- public ScaleOverlay(Activity activity, OverlayImpl overlayImpl) {
- this.ovlImpl = overlayImpl;
+ public ScaleDrawer(Activity activity) {
DisplayMetrics metrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
pixelDensity = metrics.density;
}
- @Override
- public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
- MapProjectionImpl projection, byte drawZoomLevel) {
- drawInternal(canvas, getOverlayImpl().getMapViewImpl());
- }
-
- @Override
- public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
- drawInternal(canvas, mapView);
- }
-
static private double keepSignificantDigit(final double distance) {
final double scale = Math.pow(10, Math.floor(Math.log10(distance)));
return scale * Math.floor(distance / scale);
}
- private void drawInternal(Canvas canvas, MapViewImpl mapView) {
-
+ void drawScale(Canvas canvas, MapViewImpl mapView) {
final double span = mapView.getLongitudeSpan() / 1e6;
final GeoPointImpl center = mapView.getMapViewCenter();
@@ -109,8 +89,4 @@ public class ScaleOverlay implements GeneralOverlay {
canvas.drawText(String.format(formatString, distanceRound) + " " + scaled.right, (float) (pixels - (10 * pixelDensity)), (bottom - (10 * pixelDensity)), scale);
}
- @Override
- public OverlayImpl getOverlayImpl() {
- return ovlImpl;
- }
}
diff --git a/main/src/cgeo/geocaching/maps/google/GoogleMapView.java b/main/src/cgeo/geocaching/maps/google/GoogleMapView.java
index 3cf258e..d02e3c2 100644
--- a/main/src/cgeo/geocaching/maps/google/GoogleMapView.java
+++ b/main/src/cgeo/geocaching/maps/google/GoogleMapView.java
@@ -2,11 +2,9 @@ package cgeo.geocaching.maps.google;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.geopoint.Viewport;
import cgeo.geocaching.maps.CachesOverlay;
-import cgeo.geocaching.maps.PositionOverlay;
-import cgeo.geocaching.maps.ScaleOverlay;
+import cgeo.geocaching.maps.PositionAndScaleOverlay;
import cgeo.geocaching.maps.interfaces.GeneralOverlay;
import cgeo.geocaching.maps.interfaces.GeoPointImpl;
import cgeo.geocaching.maps.interfaces.MapControllerImpl;
@@ -14,13 +12,15 @@ 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.maps.interfaces.OverlayImpl.OverlayType;
+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;
+
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
@@ -31,6 +31,7 @@ import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.Gravity;
import android.view.MotionEvent;
import android.widget.FrameLayout;
+import android.widget.ZoomButtonsController;
public class GoogleMapView extends MapView implements MapViewImpl {
private GestureDetector gestureDetector;
@@ -71,9 +72,14 @@ public class GoogleMapView extends MapView implements MapViewImpl {
// Push zoom controls to the right
FrameLayout.LayoutParams zoomParams = new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
zoomParams.gravity = Gravity.RIGHT;
- getZoomButtonsController().getZoomControls().setLayoutParams(zoomParams);
+ // The call to retrieve the zoom buttons controller is undocumented and works so far on all devices
+ // supported by Google Play, but fails at least on one Jolla.
+ final ZoomButtonsController controller = (ZoomButtonsController) MethodUtils.invokeMethod(this, "getZoomButtonsController");
+ controller.getZoomControls().setLayoutParams(zoomParams);
super.displayZoomControls(takeFocus);
+ } catch (NoSuchMethodException e) {
+ Log.w("GoogleMapView.displayZoomControls: unable to explicitly place the zoom buttons");
} catch (Exception e) {
Log.e("GoogleMapView.displayZoomControls", e);
}
@@ -119,19 +125,11 @@ public class GoogleMapView extends MapView implements MapViewImpl {
}
@Override
- public PositionOverlay createAddPositionOverlay(Activity activity) {
-
- GoogleOverlay ovl = new GoogleOverlay(activity, OverlayType.PositionOverlay);
- getOverlays().add(ovl);
- return (PositionOverlay) ovl.getBase();
- }
-
- @Override
- public ScaleOverlay createAddScaleOverlay(Activity activity) {
+ public PositionAndScaleOverlay createAddPositionAndScaleOverlay(Activity activity) {
- GoogleOverlay ovl = new GoogleOverlay(activity, OverlayType.ScaleOverlay);
+ GoogleOverlay ovl = new GoogleOverlay(activity);
getOverlays().add(ovl);
- return (ScaleOverlay) ovl.getBase();
+ return (PositionAndScaleOverlay) ovl.getBase();
}
@Override
diff --git a/main/src/cgeo/geocaching/maps/google/GoogleOverlay.java b/main/src/cgeo/geocaching/maps/google/GoogleOverlay.java
index bf4f606..e937773 100644
--- a/main/src/cgeo/geocaching/maps/google/GoogleOverlay.java
+++ b/main/src/cgeo/geocaching/maps/google/GoogleOverlay.java
@@ -1,7 +1,6 @@
package cgeo.geocaching.maps.google;
-import cgeo.geocaching.maps.PositionOverlay;
-import cgeo.geocaching.maps.ScaleOverlay;
+import cgeo.geocaching.maps.PositionAndScaleOverlay;
import cgeo.geocaching.maps.interfaces.GeneralOverlay;
import cgeo.geocaching.maps.interfaces.MapViewImpl;
import cgeo.geocaching.maps.interfaces.OverlayImpl;
@@ -17,20 +16,11 @@ import java.util.concurrent.locks.ReentrantLock;
public class GoogleOverlay extends Overlay implements OverlayImpl {
- private GeneralOverlay overlayBase = null;
+ private PositionAndScaleOverlay overlayBase = null;
private Lock lock = new ReentrantLock();
- public GoogleOverlay(Activity activityIn, OverlayType ovlType) {
- switch (ovlType) {
- case PositionOverlay:
- overlayBase = new PositionOverlay(activityIn, this);
- break;
- case ScaleOverlay:
- overlayBase = new ScaleOverlay(activityIn, this);
- break;
- default:
- throw new IllegalArgumentException();
- }
+ public GoogleOverlay(Activity activityIn) {
+ overlayBase = new PositionAndScaleOverlay(activityIn, this);
}
@Override
diff --git a/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java b/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java
index 5481891..cb7ddc6 100644
--- a/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java
+++ b/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java
@@ -2,8 +2,7 @@ package cgeo.geocaching.maps.interfaces;
import cgeo.geocaching.geopoint.Viewport;
import cgeo.geocaching.maps.CachesOverlay;
-import cgeo.geocaching.maps.PositionOverlay;
-import cgeo.geocaching.maps.ScaleOverlay;
+import cgeo.geocaching.maps.PositionAndScaleOverlay;
import android.app.Activity;
import android.content.Context;
@@ -47,9 +46,7 @@ public interface MapViewImpl {
CachesOverlay createAddMapOverlay(Context context, Drawable drawable);
- ScaleOverlay createAddScaleOverlay(Activity activity);
-
- PositionOverlay createAddPositionOverlay(Activity activity);
+ PositionAndScaleOverlay createAddPositionAndScaleOverlay(Activity activity);
void setMapSource();
diff --git a/main/src/cgeo/geocaching/maps/interfaces/OverlayImpl.java b/main/src/cgeo/geocaching/maps/interfaces/OverlayImpl.java
index a17b5fb..0984755 100644
--- a/main/src/cgeo/geocaching/maps/interfaces/OverlayImpl.java
+++ b/main/src/cgeo/geocaching/maps/interfaces/OverlayImpl.java
@@ -6,11 +6,6 @@ package cgeo.geocaching.maps.interfaces;
*/
public interface OverlayImpl {
- public enum OverlayType {
- PositionOverlay,
- ScaleOverlay
- }
-
void lock();
void unlock();
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java
index dc4e82c..78aa47d 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java
@@ -3,8 +3,7 @@ package cgeo.geocaching.maps.mapsforge;
import cgeo.geocaching.R;
import cgeo.geocaching.geopoint.Viewport;
import cgeo.geocaching.maps.CachesOverlay;
-import cgeo.geocaching.maps.PositionOverlay;
-import cgeo.geocaching.maps.ScaleOverlay;
+import cgeo.geocaching.maps.PositionAndScaleOverlay;
import cgeo.geocaching.maps.interfaces.GeneralOverlay;
import cgeo.geocaching.maps.interfaces.GeoPointImpl;
import cgeo.geocaching.maps.interfaces.MapControllerImpl;
@@ -13,7 +12,6 @@ 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.maps.interfaces.OverlayImpl.OverlayType;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
@@ -111,17 +109,10 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
}
@Override
- public PositionOverlay createAddPositionOverlay(Activity activity) {
- MapsforgeOverlay ovl = new MapsforgeOverlay(activity, OverlayType.PositionOverlay);
+ public PositionAndScaleOverlay createAddPositionAndScaleOverlay(Activity activity) {
+ MapsforgeOverlay ovl = new MapsforgeOverlay(activity);
getOverlays().add(ovl);
- return (PositionOverlay) ovl.getBase();
- }
-
- @Override
- public ScaleOverlay createAddScaleOverlay(Activity activity) {
- MapsforgeOverlay ovl = new MapsforgeOverlay(activity, OverlayType.ScaleOverlay);
- getOverlays().add(ovl);
- return (ScaleOverlay) ovl.getBase();
+ return (PositionAndScaleOverlay) ovl.getBase();
}
@Override
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java
index f61e523..74a8601 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java
@@ -1,7 +1,6 @@
package cgeo.geocaching.maps.mapsforge;
-import cgeo.geocaching.maps.PositionOverlay;
-import cgeo.geocaching.maps.ScaleOverlay;
+import cgeo.geocaching.maps.PositionAndScaleOverlay;
import cgeo.geocaching.maps.interfaces.GeneralOverlay;
import cgeo.geocaching.maps.interfaces.MapViewImpl;
import cgeo.geocaching.maps.interfaces.OverlayImpl;
@@ -18,21 +17,11 @@ import java.util.concurrent.locks.ReentrantLock;
public class MapsforgeOverlay extends Overlay implements OverlayImpl {
- private GeneralOverlay overlayBase = null;
+ private PositionAndScaleOverlay overlayBase = null;
private Lock lock = new ReentrantLock();
- public MapsforgeOverlay(Activity activityIn, OverlayImpl.OverlayType ovlType) {
-
- switch (ovlType) {
- case PositionOverlay:
- overlayBase = new PositionOverlay(activityIn, this);
- break;
- case ScaleOverlay:
- overlayBase = new ScaleOverlay(activityIn, this);
- break;
- default:
- throw new IllegalStateException();
- }
+ public MapsforgeOverlay(Activity activityIn) {
+ overlayBase = new PositionAndScaleOverlay(activityIn, this);
}
@Override
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java
index a074e70..c741a31 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java
@@ -1,11 +1,9 @@
package cgeo.geocaching.maps.mapsforge.v024;
import cgeo.geocaching.R;
-import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.geopoint.Viewport;
import cgeo.geocaching.maps.CachesOverlay;
-import cgeo.geocaching.maps.PositionOverlay;
-import cgeo.geocaching.maps.ScaleOverlay;
+import cgeo.geocaching.maps.PositionAndScaleOverlay;
import cgeo.geocaching.maps.interfaces.GeneralOverlay;
import cgeo.geocaching.maps.interfaces.GeoPointImpl;
import cgeo.geocaching.maps.interfaces.MapControllerImpl;
@@ -13,7 +11,7 @@ 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.maps.interfaces.OverlayImpl.OverlayType;
+import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
import org.mapsforge.android.mapsold.GeoPoint;
@@ -102,17 +100,10 @@ public class MapsforgeMapView024 extends MapView implements MapViewImpl {
}
@Override
- public PositionOverlay createAddPositionOverlay(Activity activity) {
- MapsforgeOverlay ovl = new MapsforgeOverlay(activity, OverlayType.PositionOverlay);
- getOverlays().add(ovl);
- return (PositionOverlay) ovl.getBase();
- }
-
- @Override
- public ScaleOverlay createAddScaleOverlay(Activity activity) {
- MapsforgeOverlay ovl = new MapsforgeOverlay(activity, OverlayType.ScaleOverlay);
+ public PositionAndScaleOverlay createAddPositionAndScaleOverlay(Activity activity) {
+ MapsforgeOverlay ovl = new MapsforgeOverlay(activity);
getOverlays().add(ovl);
- return (ScaleOverlay) ovl.getBase();
+ return (PositionAndScaleOverlay) ovl.getBase();
}
@Override
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeOverlay.java
index 8c9e0c3..655e0b9 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeOverlay.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeOverlay.java
@@ -1,7 +1,6 @@
package cgeo.geocaching.maps.mapsforge.v024;
-import cgeo.geocaching.maps.PositionOverlay;
-import cgeo.geocaching.maps.ScaleOverlay;
+import cgeo.geocaching.maps.PositionAndScaleOverlay;
import cgeo.geocaching.maps.interfaces.GeneralOverlay;
import cgeo.geocaching.maps.interfaces.MapViewImpl;
import cgeo.geocaching.maps.interfaces.OverlayImpl;
@@ -18,21 +17,11 @@ import java.util.concurrent.locks.ReentrantLock;
public class MapsforgeOverlay extends Overlay implements OverlayImpl {
- private GeneralOverlay overlayBase = null;
+ private PositionAndScaleOverlay overlayBase = null;
private Lock lock = new ReentrantLock();
- public MapsforgeOverlay(Activity activityIn, OverlayImpl.OverlayType ovlType) {
-
- switch (ovlType) {
- case PositionOverlay:
- overlayBase = new PositionOverlay(activityIn, this);
- break;
- case ScaleOverlay:
- overlayBase = new ScaleOverlay(activityIn, this);
- break;
- default:
- throw new IllegalStateException();
- }
+ public MapsforgeOverlay(Activity activityIn) {
+ overlayBase = new PositionAndScaleOverlay(activityIn, this);
}
@Override
diff --git a/main/src/cgeo/geocaching/settings/AbstractAttributeBasedPrefence.java b/main/src/cgeo/geocaching/settings/AbstractAttributeBasedPrefence.java
new file mode 100644
index 0000000..1930c17
--- /dev/null
+++ b/main/src/cgeo/geocaching/settings/AbstractAttributeBasedPrefence.java
@@ -0,0 +1,54 @@
+package cgeo.geocaching.settings;
+
+import org.eclipse.jdt.annotation.Nullable;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.preference.Preference;
+import android.util.AttributeSet;
+
+/**
+ * Base class for preferences which evaluate their XML attributes for further processing.
+ *
+ */
+public abstract class AbstractAttributeBasedPrefence extends Preference {
+
+ public AbstractAttributeBasedPrefence(Context context) {
+ super(context);
+ }
+
+ public AbstractAttributeBasedPrefence(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ processAttributes(context, attrs, 0);
+ }
+
+ public AbstractAttributeBasedPrefence(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ processAttributes(context, attrs, defStyle);
+ }
+
+ private void processAttributes(Context context, @Nullable AttributeSet attrs, int defStyle) {
+ if (attrs == null) {
+ return;
+ }
+ TypedArray types = context.obtainStyledAttributes(attrs, getAttributeNames(),
+ defStyle, 0);
+
+ processAttributeValues(types);
+
+ types.recycle();
+ }
+
+ /**
+ * Evaluate the attributes which where requested in {@link AbstractAttributeBasedPrefence#getAttributeNames()}.
+ *
+ * @param values
+ */
+ protected abstract void processAttributeValues(TypedArray values);
+
+ /**
+ * @return the names of the attributes you want to read in your preference implementation
+ */
+ protected abstract int[] getAttributeNames();
+
+}
diff --git a/main/src/cgeo/geocaching/settings/AbstractCheckCredentialsPreference.java b/main/src/cgeo/geocaching/settings/AbstractCheckCredentialsPreference.java
new file mode 100644
index 0000000..d3aae5c
--- /dev/null
+++ b/main/src/cgeo/geocaching/settings/AbstractCheckCredentialsPreference.java
@@ -0,0 +1,116 @@
+package cgeo.geocaching.settings;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.activity.ActivityMixin;
+import cgeo.geocaching.enumerations.StatusCode;
+import cgeo.geocaching.network.Cookies;
+import cgeo.geocaching.ui.dialog.Dialogs;
+import cgeo.geocaching.utils.Log;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+
+import android.annotation.SuppressLint;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+public abstract class AbstractCheckCredentialsPreference extends Preference {
+
+ public AbstractCheckCredentialsPreference(Context context) {
+ super(context);
+ }
+
+ public AbstractCheckCredentialsPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public AbstractCheckCredentialsPreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ protected View onCreateView(ViewGroup parent) {
+ setOnPreferenceClickListener(new LoginCheckClickListener());
+ return super.onCreateView(parent);
+ }
+
+ protected abstract ImmutablePair<String, String> getCredentials();
+
+ protected abstract Object login();
+
+ private class LoginCheckClickListener implements OnPreferenceClickListener {
+ private Resources res;
+ private SettingsActivity activity;
+
+ private ProgressDialog loginDialog;
+ @SuppressLint("HandlerLeak")
+ private Handler logInHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (loginDialog != null && loginDialog.isShowing()) {
+ loginDialog.dismiss();
+ }
+
+ if (msg.obj == null || (msg.obj instanceof Drawable)) {
+ Dialogs.message(activity, R.string.init_login_popup, R.string.init_login_popup_ok, (Drawable) msg.obj);
+ } else {
+ Dialogs.message(activity, R.string.init_login_popup,
+ res.getString(R.string.init_login_popup_failed_reason)
+ + " "
+ + ((StatusCode) msg.obj).getErrorString(res)
+ + ".");
+ }
+ } catch (Exception e) {
+ ActivityMixin.showToast(activity, R.string.err_login_failed);
+ Log.e("SettingsActivity.logInHandler", e);
+ } finally {
+ if (loginDialog != null && loginDialog.isShowing()) {
+ loginDialog.dismiss();
+ }
+ // enable/disable basic member preferences
+ activity.initBasicMemberPreferences();
+ }
+ }
+ };
+
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ this.activity = (SettingsActivity) AbstractCheckCredentialsPreference.this.getContext();
+ this.res = activity.getResources();
+
+ ImmutablePair<String, String> credentials = getCredentials();
+
+ // check credentials for validity
+ if (StringUtils.isBlank(credentials.getLeft())
+ || StringUtils.isBlank(credentials.getRight())) {
+ ActivityMixin.showToast(activity, R.string.err_missing_auth);
+ return false;
+ }
+
+ loginDialog = ProgressDialog.show(activity,
+ res.getString(R.string.init_login_popup),
+ res.getString(R.string.init_login_popup_working), true);
+ loginDialog.setCancelable(false);
+ Cookies.clearCookies();
+
+ (new Thread() {
+ @Override
+ public void run() {
+ Object payload = login();
+ logInHandler.obtainMessage(0, payload).sendToTarget();
+ }
+ }).start();
+
+ return false; // no shared preference has to be changed
+ }
+ }
+}
diff --git a/main/src/cgeo/geocaching/settings/CapabilitiesPreference.java b/main/src/cgeo/geocaching/settings/CapabilitiesPreference.java
new file mode 100644
index 0000000..d2e19b7
--- /dev/null
+++ b/main/src/cgeo/geocaching/settings/CapabilitiesPreference.java
@@ -0,0 +1,91 @@
+package cgeo.geocaching.settings;
+
+import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.R;
+import cgeo.geocaching.connector.ConnectorFactory;
+import cgeo.geocaching.connector.IConnector;
+
+import org.apache.commons.lang3.StringUtils;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.TypedArray;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebView;
+
+/**
+ * Preference for displaying the supported capabilities of an {@link IConnector} implementation.
+ */
+public class CapabilitiesPreference extends AbstractAttributeBasedPrefence {
+
+ private String connectorCode;
+
+ public CapabilitiesPreference(Context context) {
+ super(context);
+ }
+
+ public CapabilitiesPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public CapabilitiesPreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public View getView(View convertView, ViewGroup parent) {
+ setOnPreferenceClickListener(new ClickListener());
+ return super.getView(convertView, parent);
+ }
+
+ private final class ClickListener implements OnPreferenceClickListener {
+ @Override
+ public boolean onPreferenceClick(final Preference preference) {
+ WebView htmlView = new WebView(preference.getContext());
+ htmlView.loadData(createCapabilitiesMessage(), "text/html", null);
+ AlertDialog.Builder builder = new AlertDialog.Builder(preference.getContext());
+ builder.setView(htmlView)
+ .setIcon(android.R.drawable.ic_dialog_info)
+ .setTitle(R.string.settings_features)
+ .setPositiveButton(R.string.err_none, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+ builder.create().show();
+ return false;
+ }
+ }
+
+ public String createCapabilitiesMessage() {
+ // TODO: this needs a better key for the connectors
+ IConnector connector = ConnectorFactory.getConnector(connectorCode + "1234");
+ if (connector == null) {
+ return StringUtils.EMPTY;
+ }
+ StringBuilder builder = new StringBuilder("<p>"
+ + CgeoApplication.getInstance().getString(R.string.feature_description) + "<ul>");
+
+ for (String capability : connector.getCapabilities()) {
+ builder.append("<li>").append(capability).append("</li>");
+ }
+
+ builder.append("</ul></p>");
+ return builder.toString();
+ }
+
+ @Override
+ protected void processAttributeValues(TypedArray values) {
+ connectorCode = values.getString(0);
+ }
+
+ @Override
+ protected int[] getAttributeNames() {
+ return new int[] { R.attr.connector };
+ }
+}
diff --git a/main/src/cgeo/geocaching/settings/CheckBoxWithPopupPreference.java b/main/src/cgeo/geocaching/settings/CheckBoxWithPopupPreference.java
index 4e64b9a..e36e007 100644
--- a/main/src/cgeo/geocaching/settings/CheckBoxWithPopupPreference.java
+++ b/main/src/cgeo/geocaching/settings/CheckBoxWithPopupPreference.java
@@ -1,13 +1,10 @@
package cgeo.geocaching.settings;
import cgeo.geocaching.R;
+import cgeo.geocaching.ui.UrlPopup;
-import android.app.AlertDialog;
import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
import android.content.res.TypedArray;
-import android.net.Uri;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.util.AttributeSet;
@@ -63,26 +60,7 @@ public class CheckBoxWithPopupPreference extends CheckBoxPreference {
if (!(Boolean) newValue) {
return true;
}
- AlertDialog.Builder builder = new AlertDialog.Builder(
- preference.getContext());
- builder.setMessage(text)
- .setIcon(android.R.drawable.ic_dialog_info)
- .setTitle(title)
- .setPositiveButton(R.string.err_none, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- })
- .setNegativeButton(urlButton, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- Intent i = new Intent(Intent.ACTION_VIEW);
- i.setData(Uri.parse(url));
- preference.getContext().startActivity(i);
- }
- });
- builder.create().show();
+ new UrlPopup(preference.getContext()).show(title, text, url, urlButton);
return true;
}
});
diff --git a/main/src/cgeo/geocaching/settings/CheckECCredentialsPreference.java b/main/src/cgeo/geocaching/settings/CheckECCredentialsPreference.java
new file mode 100644
index 0000000..46a3661
--- /dev/null
+++ b/main/src/cgeo/geocaching/settings/CheckECCredentialsPreference.java
@@ -0,0 +1,40 @@
+package cgeo.geocaching.settings;
+
+import cgeo.geocaching.connector.ec.ECConnector;
+import cgeo.geocaching.connector.ec.ECLogin;
+import cgeo.geocaching.enumerations.StatusCode;
+
+import org.apache.commons.lang3.tuple.ImmutablePair;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+public class CheckECCredentialsPreference extends AbstractCheckCredentialsPreference {
+
+ public CheckECCredentialsPreference(Context context) {
+ super(context);
+ }
+
+ public CheckECCredentialsPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public CheckECCredentialsPreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ protected ImmutablePair<String, String> getCredentials() {
+ return Settings.getCredentials(ECConnector.getInstance());
+ }
+
+ @Override
+ protected Object login() {
+ final StatusCode loginResult = ECLogin.getInstance().login();
+ Object payload = loginResult;
+ if (loginResult == StatusCode.NO_ERROR) {
+ payload = null;
+ }
+ return payload;
+ }
+}
diff --git a/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java b/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java
index 724ab80..12c8b24 100644
--- a/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java
+++ b/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java
@@ -1,28 +1,14 @@
package cgeo.geocaching.settings;
-import cgeo.geocaching.R;
-import cgeo.geocaching.activity.ActivityMixin;
-import cgeo.geocaching.connector.gc.Login;
+import cgeo.geocaching.connector.gc.GCLogin;
import cgeo.geocaching.enumerations.StatusCode;
-import cgeo.geocaching.network.Cookies;
-import cgeo.geocaching.utils.Log;
-import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
-import android.annotation.SuppressLint;
-import android.app.ProgressDialog;
import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.Message;
-import android.preference.Preference;
import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-public class CheckGcCredentialsPreference extends Preference {
+public class CheckGcCredentialsPreference extends AbstractCheckCredentialsPreference {
public CheckGcCredentialsPreference(Context context) {
super(context);
@@ -37,87 +23,18 @@ public class CheckGcCredentialsPreference extends Preference {
}
@Override
- protected View onCreateView(ViewGroup parent) {
- setOnPreferenceClickListener(GC_LOGIN_CHECK);
- return super.onCreateView(parent);
+ protected ImmutablePair<String, String> getCredentials() {
+ return Settings.getGcCredentials();
}
- private final GcLoginCheck GC_LOGIN_CHECK = new GcLoginCheck();
-
- private class GcLoginCheck implements OnPreferenceClickListener {
- private Resources res;
- private SettingsActivity activity;
-
- private ProgressDialog loginDialog;
- @SuppressLint("HandlerLeak")
- private Handler logInHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- try {
- if (loginDialog != null && loginDialog.isShowing()) {
- loginDialog.dismiss();
- }
-
- if (msg.obj == null || (msg.obj instanceof Drawable)) {
- ActivityMixin.helpDialog(activity,
- res.getString(R.string.init_login_popup),
- res.getString(R.string.init_login_popup_ok),
- (Drawable) msg.obj);
- } else {
- ActivityMixin.helpDialog(activity,
- res.getString(R.string.init_login_popup),
- res.getString(R.string.init_login_popup_failed_reason)
- + " "
- + ((StatusCode) msg.obj).getErrorString(res)
- + ".");
- }
- } catch (Exception e) {
- ActivityMixin.showToast(activity, R.string.err_login_failed);
- Log.e("SettingsActivity.logInHandler", e);
- } finally {
- if (loginDialog != null && loginDialog.isShowing()) {
- loginDialog.dismiss();
- }
- // enable/disable basic member preferences
- activity.initBasicMemberPreferences();
- }
- }
- };
-
- @Override
- public boolean onPreferenceClick(Preference preference) {
- this.activity = (SettingsActivity) CheckGcCredentialsPreference.this.getContext();
- this.res = activity.getResources();
-
- ImmutablePair<String, String> credentials = Settings.getGcLogin();
-
- // check credentials for validity
- if (StringUtils.isBlank(credentials.getLeft())
- || StringUtils.isBlank(credentials.getRight())) {
- ActivityMixin.showToast(activity, R.string.err_missing_auth);
- return false;
- }
-
- loginDialog = ProgressDialog.show(activity,
- res.getString(R.string.init_login_popup),
- res.getString(R.string.init_login_popup_working), true);
- loginDialog.setCancelable(false);
- Cookies.clearCookies();
-
- (new Thread() {
- @Override
- public void run() {
- final StatusCode loginResult = Login.login();
- Object payload = loginResult;
- if (loginResult == StatusCode.NO_ERROR) {
- Login.detectGcCustomDate();
- payload = Login.downloadAvatarAndGetMemberStatus();
- }
- logInHandler.obtainMessage(0, payload).sendToTarget();
- }
- }).start();
-
- return false; // no shared preference has to be changed
+ @Override
+ protected Object login() {
+ final StatusCode loginResult = GCLogin.getInstance().login();
+ Object payload = loginResult;
+ if (loginResult == StatusCode.NO_ERROR) {
+ GCLogin.detectGcCustomDate();
+ payload = GCLogin.getInstance().downloadAvatarAndGetMemberStatus();
}
+ return payload;
}
}
diff --git a/main/src/cgeo/geocaching/settings/EditPasswordPreference.java b/main/src/cgeo/geocaching/settings/EditPasswordPreference.java
index 20d0250..af07041 100644
--- a/main/src/cgeo/geocaching/settings/EditPasswordPreference.java
+++ b/main/src/cgeo/geocaching/settings/EditPasswordPreference.java
@@ -1,15 +1,16 @@
package cgeo.geocaching.settings;
+import org.apache.commons.lang3.StringUtils;
+
import android.content.Context;
import android.preference.EditTextPreference;
import android.util.AttributeSet;
/**
- * This is just a dummy preference, to be able check for the type.
+ * Password preference. It will only show a row of asterisks as summary instead of the password.
* <p>
* Use it exactly as an EditTextPreference
- *
- * @see SettingsActivity - search for EditPasswordPreference
+ *
*/
public class EditPasswordPreference extends EditTextPreference {
@@ -25,4 +26,13 @@ public class EditPasswordPreference extends EditTextPreference {
super(context, attrs, defStyle);
}
+ @Override
+ public void setSummary(CharSequence summary) {
+ if (StringUtils.isBlank(summary)) {
+ super.setSummary(StringUtils.EMPTY);
+ } else {
+ super.setSummary(StringUtils.repeat("\u2022 ", 10));
+ }
+ }
+
}
diff --git a/main/src/cgeo/geocaching/settings/InfoPreference.java b/main/src/cgeo/geocaching/settings/InfoPreference.java
index ea740b4..8040a62 100644
--- a/main/src/cgeo/geocaching/settings/InfoPreference.java
+++ b/main/src/cgeo/geocaching/settings/InfoPreference.java
@@ -1,14 +1,11 @@
package cgeo.geocaching.settings;
import cgeo.geocaching.R;
+import cgeo.geocaching.ui.UrlPopup;
import android.app.Activity;
-import android.app.AlertDialog;
import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
import android.content.res.TypedArray;
-import android.net.Uri;
import android.preference.Preference;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -17,48 +14,61 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
-public class InfoPreference extends Preference {
-
- // strings for the popup dialog
+/**
+ * Preference which shows a dialog containing textual explanation. The dialog has two buttons, where one will open a
+ * hyper link with more detailed information.
+ * <p>
+ * The URL for the hyper link and the text are given as custom attributes in the preference XML definition.
+ * </p>
+ *
+ */
+public class InfoPreference extends AbstractAttributeBasedPrefence {
+
+ /**
+ * Content of the dialog, filled from preferences XML.
+ */
private String text;
+ /**
+ * URL for the second button, filled from preferences XML.
+ */
private String url;
+ /**
+ * text for the second button to open an URL, filled from preferences XML.
+ */
private String urlButton;
private LayoutInflater inflater;
public InfoPreference(Context context) {
super(context);
- init(context, null, 0);
+ init(context);
}
public InfoPreference(Context context, AttributeSet attrs) {
super(context, attrs);
- init(context, attrs, 0);
+ init(context);
}
public InfoPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- init(context, attrs, defStyle);
+ init(context);
}
- private void init(Context context, AttributeSet attrs, int defStyle) {
+ private void init(Context context) {
inflater = ((Activity) context).getLayoutInflater();
-
setPersistent(false);
+ }
- if (attrs == null) {
- return; // coward's retreat
- }
-
- TypedArray types = context.obtainStyledAttributes(attrs, new int[] {
- android.R.attr.text, R.attr.url, R.attr.urlButton },
- defStyle, 0);
-
- text = types.getString(0);
- url = types.getString(1);
- urlButton = types.getString(2);
+ @Override
+ protected int[] getAttributeNames() {
+ return new int[] { android.R.attr.text, R.attr.url, R.attr.urlButton };
+ }
- types.recycle();
+ @Override
+ protected void processAttributeValues(TypedArray values) {
+ text = values.getString(0);
+ url = values.getString(1);
+ urlButton = values.getString(2);
}
@Override
@@ -69,39 +79,30 @@ public class InfoPreference extends Preference {
@Override
public boolean onPreferenceClick(final Preference preference) {
- AlertDialog.Builder builder = new AlertDialog.Builder(
- preference.getContext());
- builder.setMessage(text)
- .setIcon(android.R.drawable.ic_dialog_info)
- .setTitle(preference.getTitle())
- .setPositiveButton(R.string.err_none, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- })
- .setNegativeButton(urlButton, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- Intent i = new Intent(Intent.ACTION_VIEW);
- i.setData(Uri.parse(url));
- preference.getContext().startActivity(i);
- }
- });
- builder.create().show();
+ new UrlPopup(preference.getContext()).show(preference.getTitle().toString(), text, url, urlButton);
+ // don't update the preference value
return false;
}
});
- // show an Info Icon
- View v = super.onCreateView(parent);
-
- ImageView i = (ImageView) inflater.inflate(R.layout.preference_info_icon, parent, false);
- LinearLayout l = (LinearLayout) v.findViewById(android.R.id.widget_frame);
- l.setVisibility(View.VISIBLE);
- l.addView(i);
+ return addInfoIcon(parent);
+ }
- return v;
+ /**
+ * Add an info icon at the left hand side of the preference.
+ *
+ * @param parent
+ * @return
+ */
+ private View addInfoIcon(ViewGroup parent) {
+ View preferenceView = super.onCreateView(parent);
+
+ ImageView iconView = (ImageView) inflater.inflate(R.layout.preference_info_icon, parent, false);
+ LinearLayout frame = (LinearLayout) preferenceView.findViewById(android.R.id.widget_frame);
+ frame.setVisibility(View.VISIBLE);
+ frame.addView(iconView);
+
+ return preferenceView;
}
}
diff --git a/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java b/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java
index fbf08fa..094b8f5 100644
--- a/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java
+++ b/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.R;
import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
+import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.HttpResponse;
@@ -45,14 +46,11 @@ public class RegisterSend2CgeoPreference extends Preference {
}
if (msg.what > 0) {
- ActivityMixin.helpDialog(activity,
- activity.getString(R.string.init_sendToCgeo),
+ Dialogs.message(activity, R.string.init_sendToCgeo,
activity.getString(R.string.init_sendToCgeo_register_ok)
.replace("####", String.valueOf(msg.what)));
} else {
- ActivityMixin.helpDialog(activity,
- activity.getString(R.string.init_sendToCgeo),
- activity.getString(R.string.init_sendToCgeo_register_fail));
+ Dialogs.message(activity, R.string.init_sendToCgeo, R.string.init_sendToCgeo_register_fail);
}
} catch (Exception e) {
ActivityMixin.showToast(activity, R.string.init_sendToCgeo_register_fail);
diff --git a/main/src/cgeo/geocaching/settings/Settings.java b/main/src/cgeo/geocaching/settings/Settings.java
index 146182a..186e5d9 100644
--- a/main/src/cgeo/geocaching/settings/Settings.java
+++ b/main/src/cgeo/geocaching/settings/Settings.java
@@ -3,8 +3,10 @@ package cgeo.geocaching.settings;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
import cgeo.geocaching.apps.cache.navi.NavigationAppFactory.NavigationAppsEnum;
+import cgeo.geocaching.connector.capability.ICredentials;
+import cgeo.geocaching.connector.gc.GCConnector;
import cgeo.geocaching.connector.gc.GCConstants;
-import cgeo.geocaching.connector.gc.Login;
+import cgeo.geocaching.connector.gc.GCLogin;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy;
import cgeo.geocaching.enumerations.LogType;
@@ -24,6 +26,7 @@ import cgeo.geocaching.utils.Log;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import android.content.Context;
@@ -270,14 +273,22 @@ public class Settings {
}
/**
- * Get login and password information.
+ * Get login and password information of Geocaching.com.
*
* @return a pair either with (login, password) or (empty, empty) if no valid information is stored
*/
- public static ImmutablePair<String, String> getGcLogin() {
+ public static ImmutablePair<String, String> getGcCredentials() {
+ return getCredentials(GCConnector.getInstance());
+ }
- final String username = getString(R.string.pref_username, null);
- final String password = getString(R.string.pref_password, null);
+ /**
+ * Get login and password information.
+ *
+ * @return a pair either with (login, password) or (empty, empty) if no valid information is stored
+ */
+ public static ImmutablePair<String, String> getCredentials(final @NonNull ICredentials connector) {
+ final String username = getString(connector.getUsernamePreferenceKey(), null);
+ final String password = getString(connector.getPasswordPreferenceKey(), null);
if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
return new ImmutablePair<String, String>(StringUtils.EMPTY, StringUtils.EMPTY);
@@ -294,6 +305,14 @@ public class Settings {
return getBoolean(R.string.pref_connectorGCActive, true);
}
+ public static boolean isECConnectorActive() {
+ return getBoolean(R.string.pref_connectorECActive, false);
+ }
+
+ public static boolean isOXConnectorActive() {
+ return getBoolean(R.string.pref_connectorOXActive, false);
+ }
+
public static boolean isPremiumMember() {
// Basic Member, Premium Member, ???
return GCConstants.MEMBER_STATUS_PM.equalsIgnoreCase(Settings.getMemberStatus());
@@ -468,7 +487,7 @@ public class Settings {
/**
* @return User selected date format on GC.com
- * @see Login#GC_CUSTOM_DATE_FORMATS
+ * @see GCLogin#GC_CUSTOM_DATE_FORMATS
*/
public static String getGcCustomDate() {
return getString(R.string.pref_gccustomdate, null);
@@ -611,8 +630,6 @@ public class Settings {
* @return
*/
private static int getConvertedMapId() {
- // what the heck is happening here?? hashCodes of Strings?
- // why not strings?
final int id = Integer.parseInt(getString(R.string.pref_mapsource,
String.valueOf(MAP_SOURCE_DEFAULT)));
switch (id) {
@@ -925,18 +942,16 @@ public class Settings {
putBoolean(R.string.pref_excludemine, exclude);
}
- static boolean setLogin(final String username, final String password) {
-
+ static void setLogin(final String username, final String password) {
if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
// erase username and password
- boolean a = remove(R.string.pref_username);
- boolean b = remove(R.string.pref_password);
- return a && b;
+ remove(R.string.pref_username);
+ remove(R.string.pref_password);
+ return;
}
// save username and password
- boolean a = putString(R.string.pref_username, username);
- boolean b = putString(R.string.pref_password, password);
- return a && b;
+ putString(R.string.pref_username, username);
+ putString(R.string.pref_password, password);
}
public static long getFieldnoteExportDate() {
@@ -982,4 +997,8 @@ public class Settings {
return getBoolean(R.string.pref_fieldNoteExportOnlyNew, false);
}
+ public static String getECIconSet() {
+ return getString(R.string.pref_ec_icons, "1");
+ }
+
}
diff --git a/main/src/cgeo/geocaching/settings/SettingsActivity.java b/main/src/cgeo/geocaching/settings/SettingsActivity.java
index 403b11d..cd9296e 100644
--- a/main/src/cgeo/geocaching/settings/SettingsActivity.java
+++ b/main/src/cgeo/geocaching/settings/SettingsActivity.java
@@ -9,7 +9,7 @@ import cgeo.geocaching.apps.cache.navi.NavigationAppFactory;
import cgeo.geocaching.apps.cache.navi.NavigationAppFactory.NavigationAppsEnum;
import cgeo.geocaching.compatibility.Compatibility;
import cgeo.geocaching.connector.gc.GCConnector;
-import cgeo.geocaching.connector.gc.Login;
+import cgeo.geocaching.connector.gc.GCLogin;
import cgeo.geocaching.files.SimpleDirChooser;
import cgeo.geocaching.maps.MapProviderFactory;
import cgeo.geocaching.maps.interfaces.MapSource;
@@ -128,7 +128,8 @@ public class SettingsActivity extends PreferenceActivity {
R.string.pref_gpxExportDir, R.string.pref_gpxImportDir,
R.string.pref_mapDirectory, R.string.pref_defaultNavigationTool,
R.string.pref_defaultNavigationTool2, R.string.pref_webDeviceName,
- R.string.pref_fakekey_preference_backup_info, R.string.pref_twitter_cache_message, R.string.pref_twitter_trackable_message }) {
+ R.string.pref_fakekey_preference_backup_info, R.string.pref_twitter_cache_message, R.string.pref_twitter_trackable_message,
+ R.string.pref_ecusername, R.string.pref_ecpassword, R.string.pref_ec_icons }) {
bindSummaryToStringValue(k);
}
getPreference(R.string.pref_units).setDefaultValue(Settings.getImperialUnitsDefault());
@@ -149,9 +150,11 @@ public class SettingsActivity extends PreferenceActivity {
getPreference(R.string.pref_connectorOCActive).setOnPreferenceChangeListener(VALUE_CHANGE_LISTENER);
getPreference(R.string.pref_connectorOCPLActive).setOnPreferenceChangeListener(VALUE_CHANGE_LISTENER);
getPreference(R.string.pref_connectorGCActive).setOnPreferenceChangeListener(VALUE_CHANGE_LISTENER);
+ getPreference(R.string.pref_connectorECActive).setOnPreferenceChangeListener(VALUE_CHANGE_LISTENER);
setWebsite(R.string.pref_fakekey_gc_website, GCConnector.getInstance().getHost());
setWebsite(R.string.pref_fakekey_ocde_website, "opencaching.de");
setWebsite(R.string.pref_fakekey_ocpl_website, "opencaching.pl");
+ setWebsite(R.string.pref_fakekey_ec_website, "extremcaching.com");
setWebsite(R.string.pref_fakekey_gcvote_website, "gcvote.com");
setWebsite(R.string.pref_fakekey_sendtocgeo_website, "send2.cgeo.org");
}
@@ -466,20 +469,14 @@ public class SettingsActivity extends PreferenceActivity {
public boolean onPreferenceChange(final Preference preference, final Object value) {
String stringValue = value.toString();
- if (preference instanceof EditPasswordPreference) {
- if (StringUtils.isBlank((String) value)) {
- preference.setSummary(StringUtils.EMPTY);
- } else {
- preference.setSummary(StringUtils.repeat("\u2022 ", 10));
- }
- } else if (isPreference(preference, R.string.pref_mapsource)) {
+ if (isPreference(preference, R.string.pref_mapsource)) {
// reset the cached map source
MapSource mapSource;
try {
- final int mapSourceId = Integer.valueOf(stringValue);
+ final int mapSourceId = Integer.parseInt(stringValue);
mapSource = MapProviderFactory.getMapSource(mapSourceId);
} catch (final NumberFormatException e) {
- Log.e("SettingsActivity.onPreferenceChange: bad source id `" + stringValue + "'");
+ Log.e("SettingsActivity.onPreferenceChange: bad source id '" + stringValue + "'");
mapSource = null;
}
// If there is no corresponding map source (because some map sources were
@@ -495,7 +492,7 @@ public class SettingsActivity extends PreferenceActivity {
}
Settings.setMapSource(mapSource);
preference.setSummary(mapSource.getName());
- } else if (isPreference(preference, R.string.pref_connectorOCActive) || isPreference(preference, R.string.pref_connectorOCPLActive) || isPreference(preference, R.string.pref_connectorGCActive)) {
+ } else if (isPreference(preference, R.string.pref_connectorOCActive) || isPreference(preference, R.string.pref_connectorOCPLActive) || isPreference(preference, R.string.pref_connectorGCActive) || isPreference(preference, R.string.pref_connectorECActive)) {
// // reset log-in status if connector activation was changed
CgeoApplication.getInstance().checkLogin = true;
} else if (preference instanceof ListPreference) {
@@ -523,10 +520,10 @@ public class SettingsActivity extends PreferenceActivity {
// simple string representation.
preference.setSummary(stringValue);
}
- if ((isPreference(preference, R.string.pref_username) && !stringValue.equals(Settings.getUsername())) || (isPreference(preference, R.string.pref_password) && !stringValue.equals(Settings.getGcLogin().getRight()))) {
+ if ((isPreference(preference, R.string.pref_username) && !stringValue.equals(Settings.getUsername())) || (isPreference(preference, R.string.pref_password) && !stringValue.equals(Settings.getGcCredentials().getRight()))) {
// reset log-in if gc user or password is changed
- if (Login.isActualLoginStatus()) {
- Login.logout();
+ if (GCLogin.getInstance().isActualLoginStatus()) {
+ GCLogin.getInstance().logout();
}
CgeoApplication.getInstance().checkLogin = true;
}
diff --git a/main/src/cgeo/geocaching/settings/TemplateTextPreference.java b/main/src/cgeo/geocaching/settings/TemplateTextPreference.java
index 9eaaa67..a703231 100644
--- a/main/src/cgeo/geocaching/settings/TemplateTextPreference.java
+++ b/main/src/cgeo/geocaching/settings/TemplateTextPreference.java
@@ -48,7 +48,7 @@ public class TemplateTextPreference extends DialogPreference {
settingsActivity = (SettingsActivity) this.getContext();
editText = (EditText) view.findViewById(R.id.signature_dialog_text);
- editText.setText(getPersistedString(initialValue != null ? initialValue.toString() : StringUtils.EMPTY));
+ editText.setText(getPersistedString(initialValue != null ? initialValue : StringUtils.EMPTY));
Button button = (Button) view.findViewById(R.id.signature_templates);
button.setOnClickListener(new View.OnClickListener() {
diff --git a/main/src/cgeo/geocaching/settings/TextPreference.java b/main/src/cgeo/geocaching/settings/TextPreference.java
index bcd03ff..eecf4cc 100644
--- a/main/src/cgeo/geocaching/settings/TextPreference.java
+++ b/main/src/cgeo/geocaching/settings/TextPreference.java
@@ -4,21 +4,26 @@ import cgeo.geocaching.R;
import android.content.Context;
import android.content.res.TypedArray;
-import android.preference.Preference;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
- * Preference to simply show a text message.
+ * Preference to simply show a text message. Links are not shown.
* <p>
- * Links are not shown - I tried everything (koem)
- * <p>
- * example: <cgeo.geocaching.settings.TextPreference android:text="@string/legal_note"
- * android:layout="@string/text_preference_default_layout" />
+ * Usage: The displayed text is taken from the "android:text" attribute of the preference definition. Example:
+ *
+ * <pre>
+ * <cgeo.geocaching.settings.TextPreference
+ * android:text="@string/legal_note"
+ * android:layout="@string/text_preference_default_layout"
+ * />
+ * </pre>
+ *
+ * </p>
*/
-public class TextPreference extends Preference {
+public class TextPreference extends AbstractAttributeBasedPrefence {
private String text;
private TextView summaryView;
@@ -30,23 +35,20 @@ public class TextPreference extends Preference {
public TextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
- processAttributes(context, attrs, 0);
}
public TextPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- processAttributes(context, attrs, defStyle);
}
- private void processAttributes(Context context, AttributeSet attrs, int defStyle) {
- if (attrs == null) {
- return;
- }
+ @Override
+ protected int[] getAttributeNames() {
+ return new int[] { android.R.attr.text };
+ }
- TypedArray types = context.obtainStyledAttributes(attrs, new int[] {
- android.R.attr.text }, defStyle, 0);
- this.text = types.getString(0);
- types.recycle();
+ @Override
+ protected void processAttributeValues(TypedArray values) {
+ this.text = values.getString(0);
}
@Override
@@ -67,20 +69,21 @@ public class TextPreference extends Preference {
@Override
public void setSummary(CharSequence summaryText) {
// the layout hasn't been inflated yet, save the summaryText for later use
- if (this.summaryView == null) {
+ if (summaryView == null) {
this.summaryText = summaryText;
return;
}
- // if summaryText is null, take it from the previous saved summary
+ // if summaryText is null, take it from the previously saved summary
if (summaryText == null) {
if (this.summaryText == null) {
return;
}
- this.summaryView.setText(this.summaryText);
+ summaryView.setText(this.summaryText);
} else {
- this.summaryView.setText(summaryText);
+ summaryView.setText(summaryText);
}
this.summaryView.setVisibility(View.VISIBLE);
}
+
}
diff --git a/main/src/cgeo/geocaching/settings/WpThresholdPreference.java b/main/src/cgeo/geocaching/settings/WpThresholdPreference.java
index 867714f..4c43acf 100644
--- a/main/src/cgeo/geocaching/settings/WpThresholdPreference.java
+++ b/main/src/cgeo/geocaching/settings/WpThresholdPreference.java
@@ -1,7 +1,6 @@
package cgeo.geocaching.settings;
import cgeo.geocaching.R;
-import cgeo.geocaching.settings.Settings;
import android.content.Context;
import android.preference.Preference;
@@ -14,7 +13,7 @@ import android.widget.TextView;
public class WpThresholdPreference extends Preference {
- TextView valueView;
+ private TextView valueView;
public WpThresholdPreference(Context context) {
super(context);
diff --git a/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java b/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java
index 2dee713..a1c04a4 100644
--- a/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java
+++ b/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java
@@ -45,4 +45,5 @@ public abstract class AbstractCacheComparator implements CacheComparator {
* cache2.
*/
protected abstract int compareCaches(final Geocache cache1, final Geocache cache2);
+
}
diff --git a/main/src/cgeo/geocaching/sorting/FindsComparator.java b/main/src/cgeo/geocaching/sorting/FindsComparator.java
index b147fad..c889776 100644
--- a/main/src/cgeo/geocaching/sorting/FindsComparator.java
+++ b/main/src/cgeo/geocaching/sorting/FindsComparator.java
@@ -1,8 +1,6 @@
package cgeo.geocaching.sorting;
-import cgeo.geocaching.DataStore;
import cgeo.geocaching.Geocache;
-import cgeo.geocaching.enumerations.LogType;
public class FindsComparator extends AbstractCacheComparator {
@@ -13,20 +11,9 @@ public class FindsComparator extends AbstractCacheComparator {
@Override
protected int compareCaches(Geocache cache1, Geocache cache2) {
- int finds1 = getFindsCount(cache1);
- int finds2 = getFindsCount(cache2);
+ int finds1 = cache1.getFindsCount();
+ int finds2 = cache2.getFindsCount();
return finds2 - finds1;
}
- private static int getFindsCount(Geocache cache) {
- if (cache.getLogCounts().isEmpty()) {
- cache.setLogCounts(DataStore.loadLogCounts(cache.getGeocode()));
- }
- Integer logged = cache.getLogCounts().get(LogType.FOUND_IT);
- if (logged != null) {
- return logged;
- }
- return 0;
- }
-
}
diff --git a/main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java b/main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java
index b5edf17..f438762 100644
--- a/main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java
+++ b/main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java
@@ -3,9 +3,7 @@
*/
package cgeo.geocaching.sorting;
-import cgeo.geocaching.DataStore;
import cgeo.geocaching.Geocache;
-import cgeo.geocaching.enumerations.LogType;
/**
* sorts caches by popularity ratio (favorites per find in %).
@@ -23,8 +21,8 @@ public class PopularityRatioComparator extends AbstractCacheComparator {
float ratio1 = 0.0f;
float ratio2 = 0.0f;
- int finds1 = getFindsCount(cache1);
- int finds2 = getFindsCount(cache2);
+ int finds1 = cache1.getFindsCount();
+ int finds2 = cache2.getFindsCount();
if (finds1 != 0) {
ratio1 = (((float) cache1.getFavoritePoints()) / ((float) finds1));
@@ -41,15 +39,4 @@ public class PopularityRatioComparator extends AbstractCacheComparator {
return 0;
}
-
- private static int getFindsCount(Geocache cache) {
- if (cache.getLogCounts().isEmpty()) {
- cache.setLogCounts(DataStore.loadLogCounts(cache.getGeocode()));
- }
- Integer logged = cache.getLogCounts().get(LogType.FOUND_IT);
- if (logged != null) {
- return logged;
- }
- return 0;
- }
}
diff --git a/main/src/cgeo/geocaching/ui/AbstractCachingListViewPageViewCreator.java b/main/src/cgeo/geocaching/ui/AbstractCachingListViewPageViewCreator.java
new file mode 100644
index 0000000..799b695
--- /dev/null
+++ b/main/src/cgeo/geocaching/ui/AbstractCachingListViewPageViewCreator.java
@@ -0,0 +1,57 @@
+package cgeo.geocaching.ui;
+
+import cgeo.geocaching.activity.AbstractViewPagerActivity.PageViewCreator;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+import android.os.Bundle;
+import android.support.v4.view.ViewPager;
+import android.view.View;
+import android.widget.ListView;
+
+/**
+ * {@link PageViewCreator} for {@link ListView}, which can save scroll state on purging a page from the
+ * {@link ViewPager}, and restore the state on re-recreation.
+ *
+ */
+public abstract class AbstractCachingListViewPageViewCreator extends AbstractCachingPageViewCreator<ListView> {
+ private static final String STATE_POSITION_FROM_TOP = "positionFromTop";
+ private static final String STATE_POSITION = "position";
+
+ /**
+ * Get the state of the current view
+ *
+ * @return the state encapsulated in a bundle
+ */
+ @Override
+ public @Nullable
+ Bundle getViewState() {
+ if (view == null) {
+ return null;
+ }
+ int position = view.getFirstVisiblePosition();
+ View child = view.getChildAt(0);
+ int positionFromTop = (child == null) ? 0 : child.getTop();
+ Bundle state = new Bundle();
+ state.putInt(STATE_POSITION, position);
+ state.putInt(STATE_POSITION_FROM_TOP, positionFromTop);
+ return state;
+ }
+
+ /**
+ * Restore a previously stored state of the view
+ *
+ */
+ @Override
+ public void setViewState(@NonNull Bundle state) {
+ if (view == null) {
+ return;
+ }
+ int logViewPosition = state.getInt(STATE_POSITION);
+ int logViewPositionFromTop = state.getInt(STATE_POSITION_FROM_TOP);
+ view.setSelectionFromTop(logViewPosition, logViewPositionFromTop);
+ return;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java b/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java
index 333ef11..ed5d182 100644
--- a/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java
+++ b/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java
@@ -2,6 +2,12 @@ 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;
+
+import android.os.Bundle;
import android.view.View;
/**
@@ -28,5 +34,25 @@ public abstract class AbstractCachingPageViewCreator<ViewClass extends View> imp
}
@Override
+ @SuppressFBWarnings("USM_USELESS_ABSTRACT_METHOD")
public abstract ViewClass getDispatchedView();
+
+ /**
+ * Gets the state of the view but returns an empty state if not overridden
+ *
+ * @return empty bundle
+ */
+ @Override
+ public @Nullable
+ Bundle getViewState() {
+ return new Bundle();
+ }
+
+ /**
+ * Restores the state of the view but just returns if not overridden.
+ */
+ @Override
+ public void setViewState(@NonNull Bundle state) {
+ return;
+ }
}
diff --git a/main/src/cgeo/geocaching/ui/AddressListAdapter.java b/main/src/cgeo/geocaching/ui/AddressListAdapter.java
index 0d5fba7..8134235 100644
--- a/main/src/cgeo/geocaching/ui/AddressListAdapter.java
+++ b/main/src/cgeo/geocaching/ui/AddressListAdapter.java
@@ -11,7 +11,6 @@ import cgeo.geocaching.geopoint.Units;
import org.apache.commons.lang3.StringUtils;
import android.app.Activity;
-import android.content.Context;
import android.location.Address;
import android.view.LayoutInflater;
import android.view.View;
@@ -35,9 +34,9 @@ public class AddressListAdapter extends ArrayAdapter<Address> {
}
}
- public AddressListAdapter(final Context context) {
+ public AddressListAdapter(final Activity context) {
super(context, 0);
- inflater = ((Activity) context).getLayoutInflater();
+ inflater = context.getLayoutInflater();
location = CgeoApplication.getInstance().currentGeo().getCoords();
}
diff --git a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
index f1cee05..7fe77c4 100644
--- a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
+++ b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
import cgeo.geocaching.Waypoint;
+import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.Units;
@@ -53,24 +54,28 @@ public final class CacheDetailsCreator {
}
public RelativeLayout addStars(final int nameId, final float value) {
+ return addStars(nameId, value, 5);
+ }
+
+ public RelativeLayout addStars(final int nameId, final float value, final int max) {
final RelativeLayout layout = (RelativeLayout) activity.getLayoutInflater().inflate(R.layout.cache_information_item, null);
final TextView nameView = (TextView) layout.findViewById(R.id.name);
lastValueView = (TextView) layout.findViewById(R.id.value);
final LinearLayout layoutStars = (LinearLayout) layout.findViewById(R.id.stars);
nameView.setText(activity.getResources().getString(nameId));
- lastValueView.setText(String.format("%.1f", value) + ' ' + activity.getResources().getString(R.string.cache_rating_of) + " 5");
- createStarImages(layoutStars, value);
+ lastValueView.setText(String.format("%.1f", value) + ' ' + activity.getResources().getString(R.string.cache_rating_of) + " " + String.format("%d", max));
+ createStarImages(layoutStars, value, max);
layoutStars.setVisibility(View.VISIBLE);
parentView.addView(layout);
return layout;
}
- private void createStarImages(final ViewGroup starsContainer, final float value) {
+ private void createStarImages(final ViewGroup starsContainer, final float value, final int max) {
final LayoutInflater inflater = LayoutInflater.from(activity);
- for (int i = 0; i < 5; i++) {
+ for (int i = 0; i < max; i++) {
ImageView star = (ImageView) inflater.inflate(R.layout.star_image, null);
if (value - i >= 0.75) {
star.setImageResource(R.drawable.star_on);
@@ -130,7 +135,7 @@ public final class CacheDetailsCreator {
public void addTerrain(Geocache cache) {
if (cache.getTerrain() > 0) {
- addStars(R.string.cache_terrain, cache.getTerrain());
+ addStars(R.string.cache_terrain, cache.getTerrain(), ConnectorFactory.getConnector(cache).getMaxTerrain());
}
}
diff --git a/main/src/cgeo/geocaching/ui/CompassView.java b/main/src/cgeo/geocaching/ui/CompassView.java
index 3b4ed36..5e80f32 100644
--- a/main/src/cgeo/geocaching/ui/CompassView.java
+++ b/main/src/cgeo/geocaching/ui/CompassView.java
@@ -80,7 +80,9 @@ public class CompassView extends View implements PeriodicHandlerListener {
setfil = new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG);
remfil = new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0);
- initialDisplay = true;
+ synchronized (this) {
+ initialDisplay = true;
+ }
redrawHandler.start();
}
@@ -148,7 +150,7 @@ public class CompassView extends View implements PeriodicHandlerListener {
}
@Override
- public void onPeriodic() {
+ public synchronized void onPeriodic() {
final float newAzimuthShown = smoothUpdate(northMeasured, azimuthShown);
final float newCacheHeadingShown = smoothUpdate(cacheHeadingMeasured, cacheHeadingShown);
if (Math.abs(AngleUtils.difference(azimuthShown, newAzimuthShown)) >= 2 ||
diff --git a/main/src/cgeo/geocaching/ui/GPXListAdapter.java b/main/src/cgeo/geocaching/ui/GPXListAdapter.java
index 988bb81..ae18ab4 100644
--- a/main/src/cgeo/geocaching/ui/GPXListAdapter.java
+++ b/main/src/cgeo/geocaching/ui/GPXListAdapter.java
@@ -5,11 +5,11 @@ import butterknife.InjectView;
import cgeo.geocaching.GpxFileListActivity;
import cgeo.geocaching.R;
import cgeo.geocaching.files.GPXImporter;
+import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.FileUtils;
import cgeo.geocaching.utils.Log;
import android.app.Activity;
-import android.app.AlertDialog;
import android.content.DialogInterface;
import android.view.LayoutInflater;
import android.view.View;
@@ -74,25 +74,13 @@ public class GPXListAdapter extends ArrayAdapter<File> {
@Override
public boolean onLongClick(View v) {
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- builder.setTitle(R.string.gpx_import_delete_title)
- .setMessage(activity.getString(R.string.gpx_import_delete_message, file.getName()))
- .setCancelable(false)
- .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- FileUtils.deleteIgnoringFailure(file);
- GPXListAdapter.this.remove(file);
- }
- })
- .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- });
- AlertDialog alert = builder.create();
- alert.show();
+ Dialogs.confirmYesNo(activity, R.string.gpx_import_delete_title, activity.getString(R.string.gpx_import_delete_message, file.getName()), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ FileUtils.deleteIgnoringFailure(file);
+ GPXListAdapter.this.remove(file);
+ }
+ });
return true;
}
});
diff --git a/main/src/cgeo/geocaching/ui/UrlPopup.java b/main/src/cgeo/geocaching/ui/UrlPopup.java
new file mode 100644
index 0000000..5a8dba4
--- /dev/null
+++ b/main/src/cgeo/geocaching/ui/UrlPopup.java
@@ -0,0 +1,40 @@
+package cgeo.geocaching.ui;
+
+import cgeo.geocaching.R;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+
+public class UrlPopup {
+
+ private final Context context;
+
+ public UrlPopup(final Context context) {
+ this.context = context;
+ }
+
+ public void show(final String title, final String message, final String url, final String urlButtonTitle) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setMessage(message)
+ .setIcon(android.R.drawable.ic_dialog_info)
+ .setTitle(title)
+ .setPositiveButton(R.string.err_none, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ })
+ .setNegativeButton(urlButtonTitle, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ Intent i = new Intent(Intent.ACTION_VIEW);
+ i.setData(Uri.parse(url));
+ context.startActivity(i);
+ }
+ });
+ builder.create().show();
+ }
+}
diff --git a/main/src/cgeo/geocaching/ui/dialog/Dialogs.java b/main/src/cgeo/geocaching/ui/dialog/Dialogs.java
new file mode 100644
index 0000000..6064c41
--- /dev/null
+++ b/main/src/cgeo/geocaching/ui/dialog/Dialogs.java
@@ -0,0 +1,291 @@
+package cgeo.geocaching.ui.dialog;
+
+import cgeo.geocaching.CgeoApplication;
+
+import org.eclipse.jdt.annotation.Nullable;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.content.DialogInterface.OnClickListener;
+import android.graphics.drawable.Drawable;
+
+/**
+ * Wrapper for {@link AlertDialog}. If you want to show a simple text, use one of the
+ * {@link #message(Activity, String, String, Drawable)} variants. If you want the user to confirm using Okay/Cancel or
+ * Yes/No, select one of the {@link #confirm(Activity, String, String, String, OnClickListener)} or
+ * {@link #confirmYesNo(Activity, String, String, OnClickListener)} variants.
+ *
+ */
+public final class Dialogs {
+ private Dialogs() {
+ // utility class
+ }
+
+ /**
+ * Confirm using two buttons "yourText" and "Cancel", where "Cancel" just closes the dialog.
+ *
+ * @param context
+ * activity hosting the dialog
+ * @param title
+ * dialog title
+ * @param msg
+ * dialog message
+ * @param positiveButton
+ * text of the positive button (which would typically be the OK button)
+ * @param okayListener
+ * listener of the positive button
+ */
+ public static AlertDialog.Builder confirm(final Activity context, final String title, final String msg, final String positiveButton, final OnClickListener okayListener) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ AlertDialog dialog = builder.setTitle(title)
+ .setCancelable(true)
+ .setMessage(msg)
+ .setPositiveButton(positiveButton, okayListener)
+ .setNegativeButton(android.R.string.cancel, null)
+ .create();
+ dialog.setOwnerActivity(context);
+ dialog.show();
+ return builder;
+ }
+
+ /**
+ * Confirm using two buttons "yourText" and "Cancel", where "Cancel" just closes the dialog.
+ *
+ * @param context
+ * activity hosting the dialog
+ * @param title
+ * dialog title
+ * @param msg
+ * dialog message
+ * @param positiveButton
+ * text of the positive button (which would typically be the OK button)
+ * @param okayListener
+ * listener of the positive button
+ */
+ public static AlertDialog.Builder confirm(final Activity context, final int title, final int msg, final int positiveButton, final OnClickListener okayListener) {
+ return confirm(context, getString(title), getString(msg), getString(positiveButton), okayListener);
+ }
+
+ /**
+ * Confirm using two buttons "Yes" and "No", where "No" just closes the dialog.
+ *
+ * @param context
+ * activity hosting the dialog
+ * @param title
+ * dialog title
+ * @param msg
+ * dialog message
+ * @param yesListener
+ * listener of the positive button
+ */
+ public static AlertDialog.Builder confirmYesNo(final Activity context, final String title, final String msg, final OnClickListener yesListener) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ AlertDialog dialog = builder.setTitle(title)
+ .setCancelable(true)
+ .setMessage(msg)
+ .setPositiveButton(android.R.string.yes, yesListener)
+ .setNegativeButton(android.R.string.no, null)
+ .create();
+ dialog.setOwnerActivity(context);
+ dialog.show();
+ return builder;
+ }
+
+ /**
+ * Confirm using two buttons "Yes" and "No", where "No" just closes the dialog.
+ *
+ * @param context
+ * activity hosting the dialog
+ * @param title
+ * dialog title
+ * @param msg
+ * dialog message
+ * @param yesListener
+ * listener of the positive button
+ */
+ public static AlertDialog.Builder confirmYesNo(final Activity context, final String title, final int msg, final OnClickListener yesListener) {
+ return confirmYesNo(context, title, getString(msg), yesListener);
+ }
+
+ /**
+ * Confirm using two buttons "Yes" and "No", where "No" just closes the dialog.
+ *
+ * @param context
+ * activity hosting the dialog
+ * @param title
+ * dialog title
+ * @param msg
+ * dialog message
+ * @param yesListener
+ * listener of the positive button
+ */
+ public static AlertDialog.Builder confirmYesNo(final Activity context, final int title, final String msg, final OnClickListener yesListener) {
+ return confirmYesNo(context, getString(title), msg, yesListener);
+ }
+
+ /**
+ * Confirm using two buttons "Yes" and "No", where "No" just closes the dialog.
+ *
+ * @param context
+ * activity hosting the dialog
+ * @param title
+ * dialog title
+ * @param msg
+ * dialog message
+ * @param yesListener
+ * listener of the positive button
+ */
+ public static AlertDialog.Builder confirmYesNo(final Activity context, final int title, final int msg, final OnClickListener yesListener) {
+ return confirmYesNo(context, getString(title), getString(msg), yesListener);
+ }
+
+ /**
+ * Confirm using two buttons "OK" and "Cancel", where "Cancel" just closes the dialog.
+ *
+ * @param context
+ * activity hosting the dialog
+ * @param title
+ * dialog title
+ * @param msg
+ * dialog message
+ * @param okayListener
+ * listener of the positive button
+ */
+ public static AlertDialog.Builder confirm(final Activity context, final String title, final String msg, final OnClickListener okayListener) {
+ return confirm(context, title, msg, getString(android.R.string.ok), okayListener);
+ }
+
+ /**
+ * Confirm using two buttons "OK" and "Cancel", where "Cancel" just closes the dialog.
+ *
+ * @param context
+ * activity hosting the dialog
+ * @param title
+ * dialog title
+ * @param msg
+ * dialog message
+ * @param okayListener
+ * listener of the positive button
+ */
+ public static AlertDialog.Builder confirm(final Activity context, final int title, final String msg, final OnClickListener okayListener) {
+ return confirm(context, getString(title), msg, okayListener);
+ }
+
+ /**
+ * Confirm using two buttons "OK" and "Cancel", where "Cancel" just closes the dialog.
+ *
+ * @param context
+ * activity hosting the dialog
+ * @param title
+ * dialog title
+ * @param msg
+ * dialog message
+ * @param okayListener
+ * listener of the positive button
+ */
+ public static AlertDialog.Builder confirm(final Activity context, final int title, final int msg, final OnClickListener okayListener) {
+ return confirm(context, getString(title), getString(msg), okayListener);
+ }
+
+ private static String getString(int resourceId) {
+ return CgeoApplication.getInstance().getString(resourceId);
+ }
+
+ /**
+ * Show a message dialog with a single "OK" button.
+ *
+ * @param context
+ * activity owning the dialog
+ * @param message
+ * message dialog content
+ */
+ public static void message(final Activity context, final String message) {
+ message(context, null, message);
+ }
+
+ /**
+ * Show a message dialog with a single "OK" button.
+ *
+ * @param context
+ * activity owning the dialog
+ * @param title
+ * message dialog title
+ * @param message
+ * message dialog content
+ */
+ public static void message(final Activity context, final @Nullable String title, final String message) {
+ message(context, title, message, null);
+ }
+
+ /**
+ * Show a message dialog with a single "OK" button and an icon.
+ *
+ * @param context
+ * activity owning the dialog
+ * @param title
+ * message dialog title
+ * @param message
+ * message dialog content
+ * @param icon
+ * message dialog title icon
+ */
+ public static void message(final Activity context, final @Nullable String title, final String message, final @Nullable Drawable icon) {
+ Builder builder = new AlertDialog.Builder(context)
+ .setMessage(message)
+ .setCancelable(true)
+ .setPositiveButton(getString(android.R.string.ok), null);
+ if (title != null) {
+ builder.setTitle(title);
+ }
+ if (icon != null) {
+ builder.setIcon(icon);
+ }
+ builder.create().show();
+ }
+
+ /**
+ * Show a message dialog with a single "OK" button and an icon.
+ *
+ * @param context
+ * activity owning the dialog
+ * @param title
+ * message dialog title
+ * @param message
+ * message dialog content
+ */
+ public static void message(final Activity context, final int title, final String message) {
+ message(context, getString(title), message);
+ }
+
+ /**
+ * Show a message dialog with a single "OK" button and an icon.
+ *
+ * @param context
+ * activity owning the dialog
+ * @param title
+ * message dialog title
+ * @param message
+ * message dialog content
+ */
+ public static void message(final Activity context, final int title, final int message) {
+ message(context, getString(title), getString(message));
+ }
+
+ /**
+ * Show a message dialog with a single "OK" button and an icon.
+ *
+ * @param context
+ * activity owning the dialog
+ * @param title
+ * message dialog title
+ * @param message
+ * message dialog content
+ * @param icon
+ * message dialog title icon
+ */
+ public static void message(final Activity context, final int title, final int message, final @Nullable Drawable icon) {
+ message(context, getString(title), getString(message), icon);
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/ui/dialog/NoTitleDialog.java b/main/src/cgeo/geocaching/ui/dialog/NoTitleDialog.java
index fc5ebe6..8660a7b 100644
--- a/main/src/cgeo/geocaching/ui/dialog/NoTitleDialog.java
+++ b/main/src/cgeo/geocaching/ui/dialog/NoTitleDialog.java
@@ -1,5 +1,7 @@
package cgeo.geocaching.ui.dialog;
+import cgeo.geocaching.utils.Log;
+
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
@@ -24,7 +26,7 @@ public abstract class NoTitleDialog extends Dialog {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
} catch (final Exception e) {
- // nothing
+ Log.e("NoTitleDialog.onCreate", e);
}
}
}
diff --git a/main/src/cgeo/geocaching/ui/logs/CacheLogsViewCreator.java b/main/src/cgeo/geocaching/ui/logs/CacheLogsViewCreator.java
index 8fe3866..6311476 100644
--- a/main/src/cgeo/geocaching/ui/logs/CacheLogsViewCreator.java
+++ b/main/src/cgeo/geocaching/ui/logs/CacheLogsViewCreator.java
@@ -1,10 +1,10 @@
package cgeo.geocaching.ui.logs;
import cgeo.geocaching.CacheDetailActivity;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.LogEntry;
import cgeo.geocaching.R;
-import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.ui.UserActionsClickListener;
@@ -109,4 +109,4 @@ public class CacheLogsViewCreator extends LogsViewCreator {
return new UserActionsClickListener(getCache());
}
-} \ No newline at end of file
+}
diff --git a/main/src/cgeo/geocaching/ui/logs/LogsViewCreator.java b/main/src/cgeo/geocaching/ui/logs/LogsViewCreator.java
index 15634d3..fb72ee5 100644
--- a/main/src/cgeo/geocaching/ui/logs/LogsViewCreator.java
+++ b/main/src/cgeo/geocaching/ui/logs/LogsViewCreator.java
@@ -8,7 +8,7 @@ import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.activity.Progress;
import cgeo.geocaching.list.StoredList;
import cgeo.geocaching.network.HtmlImage;
-import cgeo.geocaching.ui.AbstractCachingPageViewCreator;
+import cgeo.geocaching.ui.AbstractCachingListViewPageViewCreator;
import cgeo.geocaching.ui.AnchorAwareLinkMovementMethod;
import cgeo.geocaching.ui.DecryptTextClickListener;
import cgeo.geocaching.ui.Formatter;
@@ -30,7 +30,7 @@ import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
-public abstract class LogsViewCreator extends AbstractCachingPageViewCreator<ListView> {
+public abstract class LogsViewCreator extends AbstractCachingListViewPageViewCreator {
protected final AbstractActivity activity;
diff --git a/main/src/cgeo/geocaching/utils/DatabaseBackupUtils.java b/main/src/cgeo/geocaching/utils/DatabaseBackupUtils.java
index b291a8a..4ce2e0c 100644
--- a/main/src/cgeo/geocaching/utils/DatabaseBackupUtils.java
+++ b/main/src/cgeo/geocaching/utils/DatabaseBackupUtils.java
@@ -3,8 +3,8 @@ package cgeo.geocaching.utils;
import cgeo.geocaching.DataStore;
import cgeo.geocaching.MainActivity;
import cgeo.geocaching.R;
-import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.ui.Formatter;
+import cgeo.geocaching.ui.dialog.Dialogs;
import org.apache.commons.lang3.StringUtils;
@@ -42,7 +42,7 @@ public class DatabaseBackupUtils {
dialog.dismiss();
boolean restored = restoreSuccessful.get();
String message = restored ? res.getString(R.string.init_restore_success) : res.getString(R.string.init_restore_failed);
- ActivityMixin.helpDialog(activity, res.getString(R.string.init_backup_restore), message);
+ Dialogs.message(activity, R.string.init_backup_restore, message);
if (activity instanceof MainActivity) {
((MainActivity) activity).updateCacheCounter();
}
@@ -57,9 +57,7 @@ public class DatabaseBackupUtils {
// avoid overwriting an existing backup with an empty database
// (can happen directly after reinstalling the app)
if (DataStore.getAllCachesCount() == 0) {
- ActivityMixin.helpDialog(activity,
- context.getString(R.string.init_backup),
- context.getString(R.string.init_backup_unnecessary));
+ Dialogs.message(activity, R.string.init_backup, R.string.init_backup_unnecessary);
return false;
}
@@ -74,8 +72,8 @@ public class DatabaseBackupUtils {
@Override
public void run() {
dialog.dismiss();
- ActivityMixin.helpDialog(activity,
- context.getString(R.string.init_backup_backup),
+ Dialogs.message(activity,
+ R.string.init_backup_backup,
backupFileName != null
? context.getString(R.string.init_backup_success)
+ "\n" + backupFileName
diff --git a/main/src/cgeo/geocaching/utils/MatcherWrapper.java b/main/src/cgeo/geocaching/utils/MatcherWrapper.java
index 78b1170..c99d3c4 100644
--- a/main/src/cgeo/geocaching/utils/MatcherWrapper.java
+++ b/main/src/cgeo/geocaching/utils/MatcherWrapper.java
@@ -1,5 +1,7 @@
package cgeo.geocaching.utils;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -44,6 +46,7 @@ public class MatcherWrapper {
* @param input
* @return
*/
+ @SuppressFBWarnings("DM_STRING_CTOR")
private static String newString(String input) {
if (input == null) {
return null;
diff --git a/main/src/cgeo/geocaching/utils/TextUtils.java b/main/src/cgeo/geocaching/utils/TextUtils.java
index 14caf1d..efbb2d7 100644
--- a/main/src/cgeo/geocaching/utils/TextUtils.java
+++ b/main/src/cgeo/geocaching/utils/TextUtils.java
@@ -3,6 +3,8 @@
*/
package cgeo.geocaching.utils;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
import org.eclipse.jdt.annotation.Nullable;
import java.util.regex.Matcher;
@@ -36,6 +38,7 @@ public final class TextUtils {
* Find the last occurring value
* @return defaultValue or the n-th group if the pattern matches (trimmed if wanted)
*/
+ @SuppressFBWarnings("DM_STRING_CTOR")
public static String getMatch(@Nullable final String data, final Pattern p, final boolean trim, final int group, final String defaultValue, final boolean last) {
if (data != null) {