aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore28
-rw-r--r--cgeo-contacts/res/values-it/strings.xml6
-rw-r--r--main/.factorypath2
-rw-r--r--main/.settings/org.eclipse.jdt.core.prefs6
-rw-r--r--main/.settings/org.eclipse.jdt.ui.prefs5
-rw-r--r--main/AndroidManifest.xml106
-rw-r--r--main/compile-libs/androidannotations-2.7.1.jarbin555665 -> 0 bytes
-rw-r--r--main/compile-libs/androidannotations-3.0.1.jarbin0 -> 617458 bytes
-rw-r--r--main/libs/android-support-v4.jarbin621451 -> 627582 bytes
-rw-r--r--main/libs/androidannotations-api-2.7.1.jarbin61745 -> 0 bytes
-rw-r--r--main/libs/androidannotations-api-3.0.1.jarbin0 -> 87369 bytes
-rw-r--r--main/libs/commons-lang3-3.1.jarbin315805 -> 0 bytes
-rw-r--r--main/libs/commons-lang3-3.1.jar.properties1
-rw-r--r--main/libs/commons-lang3-3.2.1.jarbin0 -> 385091 bytes
-rw-r--r--main/libs/commons-lang3-3.2.1.jar.properties1
-rw-r--r--main/libs/rxjava-android-0.16.0.jarbin0 -> 20068 bytes
-rw-r--r--main/libs/rxjava-core-0.16.0.jarbin0 -> 630272 bytes
-rw-r--r--main/libs/src/commons-lang3-3.1-src.zipbin880646 -> 0 bytes
-rw-r--r--main/libs/src/commons-lang3-3.2.1-sources.jarbin0 -> 440579 bytes
-rw-r--r--main/proguard-project.txt6
-rw-r--r--main/res/layout/livemapinfo.xml7
-rw-r--r--main/res/layout/main_activity.xml17
-rw-r--r--main/res/layout/search_activity.xml8
-rw-r--r--main/res/menu/details_context.xml5
-rw-r--r--main/res/values-cs/strings.xml4
-rw-r--r--main/res/values-da/strings.xml1
-rw-r--r--main/res/values-de/strings.xml9
-rw-r--r--main/res/values-es/strings.xml2
-rw-r--r--main/res/values-fr/strings.xml5
-rw-r--r--main/res/values-hu/strings.xml4
-rw-r--r--main/res/values-it/strings.xml98
-rw-r--r--main/res/values-ja/strings.xml4
-rw-r--r--main/res/values-nb/strings.xml2
-rw-r--r--main/res/values-nl/strings.xml4
-rw-r--r--main/res/values-pl/strings.xml4
-rw-r--r--main/res/values-pt/strings.xml4
-rw-r--r--main/res/values-sk/strings.xml4
-rw-r--r--main/res/values-sl/strings.xml4
-rw-r--r--main/res/values-sv/strings.xml4
-rw-r--r--main/res/values/changelog_master.xml10
-rw-r--r--main/res/values/preference_keys.xml14
-rw-r--r--main/res/values/strings.xml17
-rw-r--r--main/res/xml/preferences.xml69
-rw-r--r--main/res/xml/searchable.xml1
-rw-r--r--main/src/cgeo/calendar/CalendarAddon.java58
-rw-r--r--main/src/cgeo/calendar/ICalendar.java2
-rw-r--r--main/src/cgeo/contacts/IContacts.java2
-rw-r--r--main/src/cgeo/geocaching/AbstractPopupActivity.java2
-rw-r--r--main/src/cgeo/geocaching/CacheDetailActivity.java326
-rw-r--r--main/src/cgeo/geocaching/CacheListActivity.java185
-rw-r--r--main/src/cgeo/geocaching/CacheMenuHandler.java55
-rw-r--r--main/src/cgeo/geocaching/CachePopup.java6
-rw-r--r--main/src/cgeo/geocaching/CgeoApplication.java76
-rw-r--r--main/src/cgeo/geocaching/CompassActivity.java5
-rw-r--r--main/src/cgeo/geocaching/CreateShortcutActivity.java10
-rw-r--r--main/src/cgeo/geocaching/DataStore.java182
-rw-r--r--main/src/cgeo/geocaching/DirectionProvider.java90
-rw-r--r--main/src/cgeo/geocaching/EditWaypointActivity.java10
-rw-r--r--main/src/cgeo/geocaching/GeoDataProvider.java146
-rw-r--r--main/src/cgeo/geocaching/Geocache.java29
-rw-r--r--main/src/cgeo/geocaching/ImageSelectActivity.java3
-rw-r--r--main/src/cgeo/geocaching/Intents.java4
-rw-r--r--main/src/cgeo/geocaching/LogCacheActivity.java8
-rw-r--r--main/src/cgeo/geocaching/LogTrackableActivity.java4
-rw-r--r--main/src/cgeo/geocaching/MainActivity.java195
-rw-r--r--main/src/cgeo/geocaching/PocketQueryList.java138
-rw-r--r--main/src/cgeo/geocaching/SearchActivity.java78
-rw-r--r--main/src/cgeo/geocaching/SearchResult.java2
-rw-r--r--main/src/cgeo/geocaching/StaticMapsActivity.java9
-rw-r--r--main/src/cgeo/geocaching/StatusFragment.java129
-rw-r--r--main/src/cgeo/geocaching/TrackableActivity.java2
-rw-r--r--main/src/cgeo/geocaching/UsefulAppsActivity.java1
-rw-r--r--main/src/cgeo/geocaching/activity/AbstractListActivity.java23
-rw-r--r--main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java1
-rw-r--r--main/src/cgeo/geocaching/activity/ActivityMixin.java2
-rw-r--r--main/src/cgeo/geocaching/apps/AbstractLocusApp.java7
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java9
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java22
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/PebbleApp.java8
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/RadarApp.java15
-rw-r--r--main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java2
-rw-r--r--main/src/cgeo/geocaching/concurrent/PriorityThreadFactory.java3
-rw-r--r--main/src/cgeo/geocaching/connector/AbstractConnector.java16
-rw-r--r--main/src/cgeo/geocaching/connector/ConnectorFactory.java41
-rw-r--r--main/src/cgeo/geocaching/connector/UserAction.java10
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECApi.java4
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECConnector.java2
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECLogin.java1
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCConnector.java31
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCLogin.java13
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCMap.java2
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCParser.java59
-rw-r--r--main/src/cgeo/geocaching/connector/gc/RecaptchaHandler.java114
-rw-r--r--main/src/cgeo/geocaching/connector/gc/SearchHandler.java126
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OkapiClient.java44
-rw-r--r--main/src/cgeo/geocaching/connector/ox/OXGPXParser.java4
-rw-r--r--main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java1
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java4
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java27
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java8
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java4
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java17
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheAttribute.java8
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheListType.java31
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheSize.java37
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheType.java2
-rw-r--r--main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java2
-rw-r--r--main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java23
-rw-r--r--main/src/cgeo/geocaching/enumerations/StatusCode.java2
-rw-r--r--main/src/cgeo/geocaching/export/FieldnoteExport.java26
-rw-r--r--main/src/cgeo/geocaching/export/GpxExport.java2
-rw-r--r--main/src/cgeo/geocaching/export/GpxSerializer.java4
-rw-r--r--main/src/cgeo/geocaching/files/LocalStorage.java20
-rw-r--r--main/src/cgeo/geocaching/files/SimpleDirChooser.java4
-rw-r--r--main/src/cgeo/geocaching/filter/DistanceFilter.java2
-rw-r--r--main/src/cgeo/geocaching/filter/FilterUserInterface.java13
-rw-r--r--main/src/cgeo/geocaching/filter/ModifiedFilter.java2
-rw-r--r--main/src/cgeo/geocaching/geopoint/Geopoint.java26
-rw-r--r--main/src/cgeo/geocaching/geopoint/GeopointParser.java36
-rw-r--r--main/src/cgeo/geocaching/geopoint/Viewport.java68
-rw-r--r--main/src/cgeo/geocaching/list/PseudoList.java6
-rw-r--r--main/src/cgeo/geocaching/list/StoredList.java40
-rw-r--r--main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java35
-rw-r--r--main/src/cgeo/geocaching/loaders/AddressGeocacheListLoader.java2
-rw-r--r--main/src/cgeo/geocaching/loaders/HistoryGeocacheListLoader.java2
-rw-r--r--main/src/cgeo/geocaching/loaders/NextPageGeocacheListLoader.java2
-rw-r--r--main/src/cgeo/geocaching/loaders/OfflineGeocacheListLoader.java4
-rw-r--r--main/src/cgeo/geocaching/loaders/RecaptchaReceiver.java2
-rw-r--r--main/src/cgeo/geocaching/maps/CGeoMap.java15
-rw-r--r--main/src/cgeo/geocaching/maps/MapProviderFactory.java2
-rw-r--r--main/src/cgeo/geocaching/maps/google/GoogleCacheOverlay.java5
-rw-r--r--main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java2
-rw-r--r--main/src/cgeo/geocaching/maps/google/GoogleMapView.java9
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/ItemizedOverlayImpl.java2
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java2
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java5
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java8
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java5
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java6
-rw-r--r--main/src/cgeo/geocaching/network/HtmlImage.java285
-rw-r--r--main/src/cgeo/geocaching/network/Network.java26
-rw-r--r--main/src/cgeo/geocaching/network/OAuth.java1
-rw-r--r--main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java1
-rw-r--r--main/src/cgeo/geocaching/network/StatusUpdater.java58
-rw-r--r--main/src/cgeo/geocaching/search/AutoCompleteAdapter.java71
-rw-r--r--main/src/cgeo/geocaching/search/SuggestionProvider.java57
-rw-r--r--main/src/cgeo/geocaching/settings/OAuthPreference.java4
-rw-r--r--main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java1
-rw-r--r--main/src/cgeo/geocaching/settings/Settings.java12
-rw-r--r--main/src/cgeo/geocaching/settings/SettingsActivity.java110
-rw-r--r--main/src/cgeo/geocaching/settings/TemplateTextPreference.java2
-rw-r--r--main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java35
-rw-r--r--main/src/cgeo/geocaching/sorting/CacheComparator.java4
-rw-r--r--main/src/cgeo/geocaching/sorting/ComparatorUserInterface.java9
-rw-r--r--main/src/cgeo/geocaching/sorting/DateComparator.java7
-rw-r--r--main/src/cgeo/geocaching/sorting/DifficultyComparator.java4
-rw-r--r--main/src/cgeo/geocaching/sorting/DistanceComparator.java5
-rw-r--r--main/src/cgeo/geocaching/sorting/FindsComparator.java4
-rw-r--r--main/src/cgeo/geocaching/sorting/GeocodeComparator.java13
-rw-r--r--main/src/cgeo/geocaching/sorting/InventoryComparator.java5
-rw-r--r--main/src/cgeo/geocaching/sorting/NameComparator.java4
-rw-r--r--main/src/cgeo/geocaching/sorting/PopularityComparator.java5
-rw-r--r--main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java5
-rw-r--r--main/src/cgeo/geocaching/sorting/RatingComparator.java5
-rw-r--r--main/src/cgeo/geocaching/sorting/SizeComparator.java4
-rw-r--r--main/src/cgeo/geocaching/sorting/StateComparator.java5
-rw-r--r--main/src/cgeo/geocaching/sorting/StorageTimeComparator.java5
-rw-r--r--main/src/cgeo/geocaching/sorting/TerrainComparator.java4
-rw-r--r--main/src/cgeo/geocaching/sorting/VisitComparator.java5
-rw-r--r--main/src/cgeo/geocaching/sorting/VoteComparator.java5
-rw-r--r--main/src/cgeo/geocaching/speech/SpeechService.java4
-rw-r--r--main/src/cgeo/geocaching/speech/TextFactory.java2
-rw-r--r--main/src/cgeo/geocaching/twitter/Twitter.java1
-rw-r--r--main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java1
-rw-r--r--main/src/cgeo/geocaching/ui/AnchorAwareLinkMovementMethod.java2
-rw-r--r--main/src/cgeo/geocaching/ui/CacheDetailsCreator.java21
-rw-r--r--main/src/cgeo/geocaching/ui/EditNoteDialog.java2
-rw-r--r--main/src/cgeo/geocaching/ui/ImagesList.java94
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java4
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/Dialogs.java21
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java13
-rw-r--r--main/src/cgeo/geocaching/utils/CancellableHandler.java16
-rw-r--r--main/src/cgeo/geocaching/utils/GeoDirHandler.java107
-rw-r--r--main/src/cgeo/geocaching/utils/IObserver.java22
-rw-r--r--main/src/cgeo/geocaching/utils/ISubject.java57
-rw-r--r--main/src/cgeo/geocaching/utils/ImageUtils.java2
-rw-r--r--main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java3
-rw-r--r--main/src/cgeo/geocaching/utils/LogTemplateProvider.java4
-rw-r--r--main/src/cgeo/geocaching/utils/MemorySubject.java45
-rw-r--r--main/src/cgeo/geocaching/utils/RunnableWithArgument.java7
-rw-r--r--main/src/cgeo/geocaching/utils/Subject.java76
-rw-r--r--main/src/cgeo/geocaching/utils/SynchronizedDateFormat.java11
-rw-r--r--main/src/cgeo/geocaching/utils/TextUtils.java1
-rw-r--r--main/thirdparty/android/support/v4/app/FragmentListActivity.java4
-rw-r--r--main/thirdparty/com/viewpagerindicator/TitlePageIndicator.java6
-rw-r--r--tests/.settings/org.eclipse.jdt.core.prefs28
-rw-r--r--tests/libs/org.eclipse.jdt.annotation_1.1.0.v20130513-1648.jarbin0 -> 14613 bytes
-rw-r--r--tests/src/cgeo/geocaching/CgeoApplicationTest.java28
-rw-r--r--tests/src/cgeo/geocaching/GeocacheTest.java8
-rw-r--r--tests/src/cgeo/geocaching/SettingsTest.java2
-rw-r--r--tests/src/cgeo/geocaching/connector/ConnectorFactoryTest.java24
-rw-r--r--tests/src/cgeo/geocaching/connector/gc/GCConnectorTest.java10
-rw-r--r--tests/src/cgeo/geocaching/connector/gc/GCParserTest.java11
-rw-r--r--tests/src/cgeo/geocaching/connector/trackable/GeokretyConnectorTest.java13
-rw-r--r--tests/src/cgeo/geocaching/connector/trackable/TravelBugConnectorTest.java11
-rw-r--r--tests/src/cgeo/geocaching/enumerations/CacheAttributeTest.java3
-rw-r--r--tests/src/cgeo/geocaching/enumerations/CacheSizeTest.java2
-rw-r--r--tests/src/cgeo/geocaching/enumerations/LogTypeTrackableTest.java6
-rw-r--r--tests/src/cgeo/geocaching/geopoint/GeoPointParserTest.java16
-rw-r--r--tests/src/cgeo/geocaching/geopoint/ViewportTest.java17
-rw-r--r--tests/src/cgeo/geocaching/network/OAuthTest.java8
-rw-r--r--tests/src/cgeo/geocaching/sorting/DistanceComparatorTest.java2
-rw-r--r--tests/src/cgeo/geocaching/utils/LogTemplateProviderTest.java4
-rw-r--r--tests/src/cgeo/geocaching/utils/MemorySubjectTest.java79
214 files changed, 2556 insertions, 2304 deletions
diff --git a/.gitignore b/.gitignore
index 20b6028..0cdff83 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,18 +1,22 @@
+# generated code
bin/
gen/
+annotation_gen/
+
+# vm crash logs
+hs_err_pid*.log
+
+# developer specific settings and credentials
+local.properties
+private.properties
+/crowdin/credentials
+/main/res/values/mapsapikey.xml
+
+# eclipse plugin settings which cannot be shared
+org.moreunit.prefs
+
/main/project/localization/*.missing
/main/project/attributes/drawable-mdpi/
/main/project/attributes/iconlist1res.html
/main/project/settings/drawable-mdpi/
-/main/local.properties
-/main/private.properties
-/main/res/values/mapsapikey.xml
-/tests/local.properties
-/tests/private.properties
-/tests/hs_err_pid*.log
-/cgeo-calendar/local.properties
-/cgeo-calendar/private.properties
-/crowdin/credentials
-.directory
-org.moreunit.prefs
-annotation_gen/
+.directory \ No newline at end of file
diff --git a/cgeo-contacts/res/values-it/strings.xml b/cgeo-contacts/res/values-it/strings.xml
new file mode 100644
index 0000000..dbe5be1
--- /dev/null
+++ b/cgeo-contacts/res/values-it/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.net-->
+<resources>
+ <string name="app_name">c:geo - contacts (add-on)</string>
+ <string name="contact_not_found">Contatto con alias/nickname %s non trovato. Aggiungilo prima nei tuoi contatti.</string>
+</resources>
diff --git a/main/.factorypath b/main/.factorypath
index f18f942..323bc61 100644
--- a/main/.factorypath
+++ b/main/.factorypath
@@ -1,4 +1,4 @@
<factorypath>
<factorypathentry kind="WKSPJAR" id="/cgeo/libs/butterknife-4.0.1.jar" enabled="true" runInBatchMode="false"/>
- <factorypathentry kind="WKSPJAR" id="/cgeo/compile-libs/androidannotations-2.7.1.jar" enabled="true" runInBatchMode="false"/>
+ <factorypathentry kind="WKSPJAR" id="/cgeo/compile-libs/androidannotations-3.0.1.jar" enabled="true" runInBatchMode="false"/>
</factorypath>
diff --git a/main/.settings/org.eclipse.jdt.core.prefs b/main/.settings/org.eclipse.jdt.core.prefs
index 3e9e8a8..2fc1133 100644
--- a/main/.settings/org.eclipse.jdt.core.prefs
+++ b/main/.settings/org.eclipse.jdt.core.prefs
@@ -1,5 +1,5 @@
eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=enabled
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
@@ -83,7 +83,7 @@ org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
-org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
+org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=enabled
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
@@ -192,7 +192,7 @@ org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
org.eclipse.jdt.core.formatter.indentation.size=4
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
diff --git a/main/.settings/org.eclipse.jdt.ui.prefs b/main/.settings/org.eclipse.jdt.ui.prefs
index 92e2c88..a80d8c1 100644
--- a/main/.settings/org.eclipse.jdt.ui.prefs
+++ b/main/.settings/org.eclipse.jdt.ui.prefs
@@ -1,11 +1,14 @@
-#Tue Feb 21 06:54:46 CET 2012
eclipse.preferences.version=1
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
formatter_profile=_cgeo
formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
org.eclipse.jdt.ui.ignorelowercasenames=true
org.eclipse.jdt.ui.importorder=cgeo;com;org;android;java;javax;
+org.eclipse.jdt.ui.keywordthis=false
org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
org.eclipse.jdt.ui.staticondemandthreshold=99
sp_cleanup.add_default_serial_version_id=true
sp_cleanup.add_generated_serial_version_id=false
diff --git a/main/AndroidManifest.xml b/main/AndroidManifest.xml
index 1884a9b..d83f2b3 100644
--- a/main/AndroidManifest.xml
+++ b/main/AndroidManifest.xml
@@ -111,8 +111,8 @@
android:name=".twitter.TwitterAuthorizationActivity"
android:configChanges="keyboardHidden|orientation"
android:label="@string/auth_twitter"
- android:windowSoftInputMode="stateHidden"
- android:launchMode="singleTask" >
+ android:launchMode="singleTask"
+ android:windowSoftInputMode="stateHidden" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@@ -142,11 +142,11 @@
android:label="@string/search_address_result"
android:windowSoftInputMode="stateHidden" >
</activity>
- <activity
+ <activity
android:name=".settings.SettingsActivity"
+ android:configChanges="keyboardHidden|orientation"
android:label="@string/settings_titlebar"
- android:theme="@style/settings"
- android:configChanges="keyboardHidden|orientation" >
+ android:theme="@style/settings" >
</activity>
<activity
android:name=".CacheListActivity"
@@ -308,6 +308,8 @@
android:name="cgeo.geocaching.TrackableActivity"
android:configChanges="keyboardHidden|orientation"
android:label="@string/app_name" >
+
+ <!-- TravelBug URL via coord.info redirection -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@@ -326,6 +328,19 @@
<category android:name="android.intent.category.BROWSABLE" />
<data
+ android:host="www.coord.info"
+ android:pathPrefix="/TB"
+ android:scheme="http" />
+ </intent-filter>
+
+ <!-- TravelBug URL tracking page -->
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
android:host="geocaching.com"
android:pathPrefix="/track/details.aspx"
android:scheme="http" />
@@ -341,6 +356,56 @@
android:pathPrefix="/track/details.aspx"
android:scheme="http" />
</intent-filter>
+
+ <!-- GeoKrety URLs -->
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="geokrety.org"
+ android:pathPrefix="/konkret.php"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.geokrety.org"
+ android:pathPrefix="/konkret.php"
+ android:scheme="http" />
+ </intent-filter>
+
+ <!--
+ Geokrety QR code URLs, not yet implemented
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="geokrety.org"
+ android:pathPrefix="/m/qr.php"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.geokrety.org"
+ android:pathPrefix="/m/qr.php"
+ android:scheme="http" />
+ </intent-filter>
+ -->
</activity>
<activity
android:name=".CompassActivity"
@@ -358,10 +423,6 @@
android:label="@string/map_file_select_title" >
</activity>
- <provider
- android:name=".apps.LocusDataStorageProvider"
- android:authorities="cgeo.geocaching.apps.locusdatastorageprovider" />
-
<activity
android:name="WaypointPopup"
android:configChanges="keyboardHidden|orientation"
@@ -387,8 +448,8 @@
android:name=".connector.oc.OCDEAuthorizationActivity"
android:configChanges="keyboardHidden|orientation"
android:label="@string/app_name"
- android:windowSoftInputMode="stateHidden"
- android:launchMode="singleTask">
+ android:launchMode="singleTask"
+ android:windowSoftInputMode="stateHidden" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@@ -405,8 +466,8 @@
android:name=".connector.oc.OCPLAuthorizationActivity"
android:configChanges="keyboardHidden|orientation"
android:label="@string/app_name"
- android:windowSoftInputMode="stateHidden"
- android:launchMode="singleTask">
+ android:launchMode="singleTask"
+ android:windowSoftInputMode="stateHidden" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@@ -421,12 +482,23 @@
</activity>
<activity
android:name=".CreateShortcutActivity"
- android:label="@string/create_shortcut" >
+ android:label="@string/cgeo_shortcut" >
<intent-filter>
- <action android:name="android.intent.action.CREATE_SHORTCUT"/>
- <category android:name="android.intent.category.DEFAULT"/>
+ <action android:name="android.intent.action.CREATE_SHORTCUT" />
+
+ <category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
+ <!-- provide enhanced meta data for caches (and waypoints) when invoking Locus from c:geo -->
+ <provider
+ android:name=".apps.LocusDataStorageProvider"
+ android:authorities="cgeo.geocaching.apps.locusdatastorageprovider" />
+
+ <!-- search suggestions for the search bar at the top -->
+ <provider
+ android:name=".search.SuggestionProvider"
+ android:authorities="cgeo.geocaching.search.SuggestionProvider" />
</application>
-</manifest>
+
+</manifest> \ No newline at end of file
diff --git a/main/compile-libs/androidannotations-2.7.1.jar b/main/compile-libs/androidannotations-2.7.1.jar
deleted file mode 100644
index 5fb9634..0000000
--- a/main/compile-libs/androidannotations-2.7.1.jar
+++ /dev/null
Binary files differ
diff --git a/main/compile-libs/androidannotations-3.0.1.jar b/main/compile-libs/androidannotations-3.0.1.jar
new file mode 100644
index 0000000..4c96d6c
--- /dev/null
+++ b/main/compile-libs/androidannotations-3.0.1.jar
Binary files differ
diff --git a/main/libs/android-support-v4.jar b/main/libs/android-support-v4.jar
index 9056828..96644ed 100644
--- a/main/libs/android-support-v4.jar
+++ b/main/libs/android-support-v4.jar
Binary files differ
diff --git a/main/libs/androidannotations-api-2.7.1.jar b/main/libs/androidannotations-api-2.7.1.jar
deleted file mode 100644
index a829474..0000000
--- a/main/libs/androidannotations-api-2.7.1.jar
+++ /dev/null
Binary files differ
diff --git a/main/libs/androidannotations-api-3.0.1.jar b/main/libs/androidannotations-api-3.0.1.jar
new file mode 100644
index 0000000..90bfe7a
--- /dev/null
+++ b/main/libs/androidannotations-api-3.0.1.jar
Binary files differ
diff --git a/main/libs/commons-lang3-3.1.jar b/main/libs/commons-lang3-3.1.jar
deleted file mode 100644
index a85e539..0000000
--- a/main/libs/commons-lang3-3.1.jar
+++ /dev/null
Binary files differ
diff --git a/main/libs/commons-lang3-3.1.jar.properties b/main/libs/commons-lang3-3.1.jar.properties
deleted file mode 100644
index adbaad3..0000000
--- a/main/libs/commons-lang3-3.1.jar.properties
+++ /dev/null
@@ -1 +0,0 @@
-src=src/commons-lang3-3.1-src.zip \ No newline at end of file
diff --git a/main/libs/commons-lang3-3.2.1.jar b/main/libs/commons-lang3-3.2.1.jar
new file mode 100644
index 0000000..6bf4f93
--- /dev/null
+++ b/main/libs/commons-lang3-3.2.1.jar
Binary files differ
diff --git a/main/libs/commons-lang3-3.2.1.jar.properties b/main/libs/commons-lang3-3.2.1.jar.properties
new file mode 100644
index 0000000..7a8b7da
--- /dev/null
+++ b/main/libs/commons-lang3-3.2.1.jar.properties
@@ -0,0 +1 @@
+src=src/commons-lang3-3.2.1-sources.jar \ No newline at end of file
diff --git a/main/libs/rxjava-android-0.16.0.jar b/main/libs/rxjava-android-0.16.0.jar
new file mode 100644
index 0000000..60f4cf1
--- /dev/null
+++ b/main/libs/rxjava-android-0.16.0.jar
Binary files differ
diff --git a/main/libs/rxjava-core-0.16.0.jar b/main/libs/rxjava-core-0.16.0.jar
new file mode 100644
index 0000000..596027b
--- /dev/null
+++ b/main/libs/rxjava-core-0.16.0.jar
Binary files differ
diff --git a/main/libs/src/commons-lang3-3.1-src.zip b/main/libs/src/commons-lang3-3.1-src.zip
deleted file mode 100644
index 13010f4..0000000
--- a/main/libs/src/commons-lang3-3.1-src.zip
+++ /dev/null
Binary files differ
diff --git a/main/libs/src/commons-lang3-3.2.1-sources.jar b/main/libs/src/commons-lang3-3.2.1-sources.jar
new file mode 100644
index 0000000..efe36e8
--- /dev/null
+++ b/main/libs/src/commons-lang3-3.2.1-sources.jar
Binary files differ
diff --git a/main/proguard-project.txt b/main/proguard-project.txt
index 03ef6b3..bb064b9 100644
--- a/main/proguard-project.txt
+++ b/main/proguard-project.txt
@@ -13,6 +13,11 @@
# apache.commons.collections has some bean related collections, which are undefined in Android
-dontwarn java.beans.*
+# rxjava includes references to the test frameworks within their class files
+-dontwarn org.mockito.**
+-dontwarn org.junit.**
+-dontwarn org.robolectric.**
+
#-dontnote org.apache.commons.logging.**
-keep public class cgeo.geocaching.*
@@ -23,6 +28,7 @@
-keep class ch.boye.httpclientandroidlib.client.HttpClient { *; }
-dontnote ch.boye.httpclientandroidlib.**
-dontwarn ch.boye.httpclientandroidlib.impl.auth.NegotiateScheme
+-dontwarn org.springframework.**
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
diff --git a/main/res/layout/livemapinfo.xml b/main/res/layout/livemapinfo.xml
index 1b1e9ea..889febc 100644
--- a/main/res/layout/livemapinfo.xml
+++ b/main/res/layout/livemapinfo.xml
@@ -19,13 +19,6 @@
android:textColor="?text_color"
android:textSize="14sp" />
- <CheckBox
- android:id="@+id/live_map_hint_hide"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="left"
- android:text="@string/live_map_note_dontshow"
- android:visibility="gone" />
</LinearLayout>
</ScrollView> \ No newline at end of file
diff --git a/main/res/layout/main_activity.xml b/main/res/layout/main_activity.xml
index ef86954..9e124a1 100644
--- a/main/res/layout/main_activity.xml
+++ b/main/res/layout/main_activity.xml
@@ -35,8 +35,7 @@
android:gravity="center"
android:orientation="vertical" >
- <LinearLayout
- style="@style/icon_mainscreen_row" >
+ <LinearLayout style="@style/icon_mainscreen_row" >
<LinearLayout
style="@style/icon_mainscreen_cell"
@@ -52,8 +51,7 @@
android:text="@string/live_map_button" />
</LinearLayout>
- <LinearLayout
- style="@style/icon_mainscreen_cell" >
+ <LinearLayout style="@style/icon_mainscreen_cell" >
<ImageView
android:id="@+id/nearest"
@@ -76,8 +74,7 @@
style="@style/icon_mainscreen_count"
android:textIsSelectable="false" />
- <LinearLayout
- style="@style/icon_mainscreen_cell_counter" >
+ <LinearLayout style="@style/icon_mainscreen_cell_counter" >
<ImageView
android:id="@+id/search_offline"
@@ -91,8 +88,7 @@
</RelativeLayout>
</LinearLayout>
- <LinearLayout
- style="@style/icon_mainscreen_row" >
+ <LinearLayout style="@style/icon_mainscreen_row" >
<LinearLayout
style="@style/icon_mainscreen_cell"
@@ -146,7 +142,6 @@
android:layout_alignParentBottom="true"
android:layout_marginLeft="6dip"
android:layout_marginRight="6dip"
- android:onClick="cgeoNavSettings"
android:orientation="vertical" >
<LinearLayout
@@ -158,11 +153,13 @@
<TextView
android:id="@+id/nav_location"
style="@style/location_current"
+ android:onClick="cgeoNavSettings"
android:text="@string/loc_trying" />
<RelativeLayout
android:layout_width="fill_parent"
- android:layout_height="wrap_content" >
+ android:layout_height="wrap_content"
+ android:onClick="cgeoNavSettings" >
<TextView
android:id="@+id/nav_type"
diff --git a/main/res/layout/search_activity.xml b/main/res/layout/search_activity.xml
index 25f914b..28256f1 100644
--- a/main/res/layout/search_activity.xml
+++ b/main/res/layout/search_activity.xml
@@ -53,7 +53,7 @@
android:text="@string/search_address" />
</RelativeLayout>
- <EditText
+ <AutoCompleteTextView
android:id="@+id/address"
style="@style/edittext_full"
android:hint="@string/search_address"
@@ -98,7 +98,7 @@
android:text="@string/search_kw" />
</RelativeLayout>
- <EditText
+ <AutoCompleteTextView
android:id="@+id/keyword"
style="@style/edittext_full"
android:hint="@string/search_kw_prefill"
@@ -119,7 +119,7 @@
android:text="@string/search_fbu" />
</RelativeLayout>
- <EditText
+ <AutoCompleteTextView
android:id="@+id/finder"
style="@style/edittext_full"
android:hint="@string/search_fbu_prefill"
@@ -140,7 +140,7 @@
android:text="@string/search_hbu" />
</RelativeLayout>
- <EditText
+ <AutoCompleteTextView
android:id="@+id/owner"
style="@style/edittext_full"
android:hint="@string/search_hbu_prefill"
diff --git a/main/res/menu/details_context.xml b/main/res/menu/details_context.xml
index 0ae2f6d..3125459 100644
--- a/main/res/menu/details_context.xml
+++ b/main/res/menu/details_context.xml
@@ -17,5 +17,10 @@
android:id="@+id/menu_cache_share_field"
android:title="@string/cache_share_field">
</item>
+ <item
+ android:id="@+id/menu_calendar"
+ android:title="@string/cache_menu_event"
+ android:visible="false">
+ </item>
</menu> \ No newline at end of file
diff --git a/main/res/values-cs/strings.xml b/main/res/values-cs/strings.xml
index 66286f0..39b4b1f 100644
--- a/main/res/values-cs/strings.xml
+++ b/main/res/values-cs/strings.xml
@@ -121,7 +121,6 @@
<string name="translate_to_english">Přeložit do angličtiny</string>
<string name="translate_length_warning">Při velkém množství textu může překládání selhat.</string>
<string name="err_none">OK</string>
- <string name="err_start">Komunikace nezačala</string>
<string name="err_parse">Čtení přihlašovací obrazovky selhalo</string>
<string name="err_server">Nelze se připojit na Geocaching.com. Stránka může být nedostupná nebo je chyba v tvém připojení k Internetu</string>
<string name="err_login">Nejsou uloženy žádné přihlašovací údaje</string>
@@ -177,7 +176,6 @@
<string name="err_log_load_data">c:geo nemůže načíst data požadovaná k zalogování návštěvy.</string>
<string name="err_log_load_data_again">c:geo nemůže načíst data požadovaná k zalogování návštěvy. Zkouší to znovu.</string>
<string name="err_log_load_data_still">c:geo stále načítá data požadovaná k odeslání Logu. Prosím, počkej ještě chvíli.</string>
- <string name="err_log_failed_server">c:geo nemůže odeslat Log, protože server neodpovídá.</string>
<string name="err_log_post_failed">Zdá se, že tvůj Log nebyl odeslán. Prosím, zkontroluj to na Geocaching.com.</string>
<string name="err_logimage_post_failed">Zdá se, že tvůj obrázek nebyl nahrán. Zkontroluj to, prosím, na Geocaching.com.</string>
<string name="err_search_address_forgot">c:geo zapomnělo hledanou adresu.</string>
@@ -599,7 +597,6 @@
<string name="cache_coordinates">Souřadnice</string>
<string name="cache_coordinates_original">Původní souřadnice</string>
<string name="cache_spoiler_images_title">Obrázky s nápovědou</string>
- <string name="cache_images_title">Obrázky</string>
<string name="cache_log_types">Typy zápisů</string>
<string name="cache_coordinates_no">Tato keš nemá souřadnice.</string>
<string name="cache_clear_history">Vymazat historii</string>
@@ -705,7 +702,6 @@
<string name="map_strategy_auto">Závislá na rychlosti</string>
<string name="map_strategy_detailed">Detailní</string>
<string name="live_map_notification">Na nové Aktivní mapě nemusí být souřadnice vždy přesné. Případné nepřesné souřadnice jsou na mapě označeny oranžovým kruhem.\nPři otevření detailů keše nebo jejím uložení pro Offline použití jsou již souřadnice přesné.\n\nVíce informací o všech změnách lze najít na stránce \"O programu\" v aplikaci.</string>
- <string name="live_map_note_dontshow">Příště nezobrazovat</string>
<string name="search_bar_hint">Hledaní kešek</string>
<string name="search_bar_desc">Keše (GC-kód, klíčové slovo), Sledovatelné předměty (TB-kód)</string>
<string name="search_coordinates">Souřadnice</string>
diff --git a/main/res/values-da/strings.xml b/main/res/values-da/strings.xml
index d784056..6b23d3d 100644
--- a/main/res/values-da/strings.xml
+++ b/main/res/values-da/strings.xml
@@ -53,7 +53,6 @@
<string name="log_clear">Fjern</string>
<string name="log_webcam">Webcamfoto taget</string>
<string name="err_none">Ok</string>
- <string name="err_start">Forbindelse ikke oprettet</string>
<string name="err_parse">Login-side kan ikke indlæses</string>
<string name="err_server">Kan ikke forbinde til Geocaching.com (server eller forbindelsesfejl?)</string>
<string name="err_login">Ingen login gemt</string>
diff --git a/main/res/values-de/strings.xml b/main/res/values-de/strings.xml
index 927cce0..0d84b58 100644
--- a/main/res/values-de/strings.xml
+++ b/main/res/values-de/strings.xml
@@ -121,7 +121,6 @@
<string name="translate_to_english">Übersetze in Englisch</string>
<string name="translate_length_warning">Die Übersetzung kann bei sehr langen Texten evtl. fehlschlagen.</string>
<string name="err_none">OK</string>
- <string name="err_start">Kommunikation nicht gestartet</string>
<string name="err_parse">Parsing der Anmeldung gescheitert</string>
<string name="err_server">Verbindung zu Geocaching.com konnte nicht hergestellt werden (Server oder Verbindung inaktiv?)</string>
<string name="err_server_ec">Verbindung zu Extremcaching.com konnte nicht hergestellt werden (Server oder Verbindung inaktiv?)</string>
@@ -178,7 +177,6 @@
<string name="err_log_load_data">c:geo konnte die benötigten Daten nicht laden, um den Besuch zu loggen.</string>
<string name="err_log_load_data_again">c:geo konnte die benötigten Daten nicht laden, um den Besuch zu loggen. Bitte erneut versuchen.</string>
<string name="err_log_load_data_still">c:geo lädt gerade die benötigten Daten. Bitte kurz warten.</string>
- <string name="err_log_failed_server">c:geo konnte Log nicht senden, weil der Server nicht antwortete.</string>
<string name="err_log_post_failed">c:geo konnte Log nicht absenden.</string>
<string name="err_log_post_failed_ec">Es scheint dass Ihr Log nicht hochgeladen werden konnte. Bitte prüfen Sie es auf Extremcaching.com nach.</string>
<string name="err_logimage_post_failed">Es scheint dass Ihr Logfoto nicht hochgeladen werden konnte. Bitte prüfen Sie es auf Geocaching.com nach.</string>
@@ -638,7 +636,6 @@
<string name="cache_coordinates">Koordinaten</string>
<string name="cache_coordinates_original">Ursprüngliche Koordinaten</string>
<string name="cache_spoiler_images_title">Hinweisbilder</string>
- <string name="cache_images_title">Bilder</string>
<string name="cache_log_types">Logs</string>
<string name="cache_coordinates_no">Dieser Cache hat keine Koordinaten.</string>
<string name="cache_clear_history">Verlauf leeren</string>
@@ -745,7 +742,6 @@
<string name="map_strategy_auto">Geschwindigkeitsabhängig</string>
<string name="map_strategy_detailed">Detailliert</string>
<string name="live_map_notification">Auf der neuen Live-Karte sind die Koordinaten nicht immer genau. Eventuell ungenaue Koordinaten sind mit einem orangen Kreis markiert.\nDas Öffnen der Cache-Details oder das Speichern des Cache liefert immer genaue Koordinaten.\n\nMehr Informationen über alle Änderungen befinden sich auf der \"Über c:geo\"-Seite in der App.</string>
- <string name="live_map_note_dontshow">Nicht mehr anzeigen</string>
<string name="search_bar_hint">Suche nach Caches</string>
<string name="search_bar_desc">Caches (Geocode, Stichwort), Trackables (TB-Code)</string>
<string name="search_coordinates">Koordinaten</string>
@@ -806,7 +802,7 @@
<string name="user_menu_view_found">Gefundene Caches</string>
<string name="user_menu_open_browser">Profil im Browser öffnen</string>
<string name="user_menu_send_message">Nachricht senden</string>
- <string name="user_menu_open_contact">Öffne Adressbuch</string>
+ <string name="user_menu_open_contact">Öffne Kontakt</string>
<string name="navigation">Navigation</string>
<string name="compass_title">Kompass</string>
<string name="use_gps">Nur GPS nutzen</string>
@@ -821,6 +817,8 @@
<string name="helper_calendar_title">c:geo Kalender Add-on</string>
<string name="helper_calendar_missing">c:geo Kalender Add-on nicht installiert</string>
<string name="helper_calendar_description">Ermöglicht die Übernahme von Event-Caches in den Kalender.</string>
+ <string name="helper_contacts_title">c:geo Kontakte Add-on</string>
+ <string name="helper_contacts_description">Ermöglicht das direkte Öffnen von Kontakten (aus dem eigenen Adressbuch) von Logeinträgen aus, so dass man Freunde einfacher um Hilfe fragen kann.</string>
<string name="helper_locus_title">Locus</string>
<string name="helper_locus_description">Sehr gute App für Online- und Offline-Karten (nur Rasterkarten) mit vielen weiteren Funktionen wie z.B. Trackaufzeichnung, POIs und vieles mehr.</string>
<string name="helper_gpsstatus_title">GPS-Status</string>
@@ -1111,5 +1109,6 @@
<item quantity="other">%s Favoriten</item>
</plurals>
<string name="percent_favorite_points">% Favoriten</string>
+ <string name="cgeo_shortcut">c:geo Shortcut</string>
<string name="create_shortcut">Shortcut erstellen</string>
</resources>
diff --git a/main/res/values-es/strings.xml b/main/res/values-es/strings.xml
index b502385..9287073 100644
--- a/main/res/values-es/strings.xml
+++ b/main/res/values-es/strings.xml
@@ -114,7 +114,6 @@
<string name="log_image_description">Descripción</string>
<string name="log_image_scale">Redimensionamiento</string>
<string name="err_none">Aceptar</string>
- <string name="err_start">Comunicación no iniciada</string>
<string name="err_parse">Error procesando la página de acceso</string>
<string name="err_server">Error conectando a Geocaching.com (¿servidor o conexión caidos?)</string>
<string name="err_login">No hay información de acceso guardada</string>
@@ -160,7 +159,6 @@
<string name="err_log_load_data">Lo siento, c:geo no puede cargar los datos necesarios para registrar la visita.</string>
<string name="err_log_load_data_again">Lo siento, c:geo no puede cargar los datos necesarios para registrar la visita. Intentándolo de nuevo.</string>
<string name="err_log_load_data_still">c:geo sigue cargando datos para registrar el escondite. Debes esperar un poquito mas.</string>
- <string name="err_log_failed_server">Lo siento, c:geo no ha podido enviar el registro porque el servidor no responde.</string>
<string name="err_log_post_failed">Lo siento, c:geo no ha podido enviar el registro.</string>
<string name="err_search_address_forgot">Lo siento, c:geo ha olvidado la dirección que buscabas.</string>
<string name="err_parse_lat">Lo siento, c:geo no puede procesar la latitud.</string>
diff --git a/main/res/values-fr/strings.xml b/main/res/values-fr/strings.xml
index 7b8a8d7..8920c05 100644
--- a/main/res/values-fr/strings.xml
+++ b/main/res/values-fr/strings.xml
@@ -121,7 +121,6 @@
<string name="translate_to_english">Traduire en anglais</string>
<string name="translate_length_warning">La traduction d\'un texte trop long peut échouer.</string>
<string name="err_none">ok</string>
- <string name="err_start">Communication non démarrée</string>
<string name="err_parse">Échec login lecture page</string>
<string name="err_server">Échec de la connexion à Geocaching.com (probléme de serveur ou de connexion?)</string>
<string name="err_server_ec">Impossible de contacter Extremcaching.com. Le site web peut ne pas fonctionner ou votre connexion Internet peut être défectueuse.</string>
@@ -178,7 +177,6 @@
<string name="err_log_load_data">c:geo ne peut pas charger les données pour enregistrer votre visite.</string>
<string name="err_log_load_data_again">c:geo ne peut pas charger les données pour enregistrer votre visite. Essayer plus tard.</string>
<string name="err_log_load_data_still">c:geo est en train de charger les données pour enregistrer votre visite. Veuillez patienter encore un peu.</string>
- <string name="err_log_failed_server">c:geo n\'a pas réussi à charger les données pour enregistrer votre visite car le serveur ne répond pas.</string>
<string name="err_log_post_failed">Il semble que votre visite n\'a pas été enregistrée. Veuillez vérifier sur le site Geocaching.com.</string>
<string name="err_log_post_failed_ec">Il semble que votre visite n\'a pas été enregistrée. Veuillez vérifier sur le site Extremcaching.com.</string>
<string name="err_logimage_post_failed">Il semble que l\'envoi de l\'image ait échoué. Veuillez vérifier sur le site Geocaching.com.</string>
@@ -651,7 +649,6 @@
<string name="cache_coordinates">Coordonnées</string>
<string name="cache_coordinates_original">Coordonnées d\'origine</string>
<string name="cache_spoiler_images_title">Images indices</string>
- <string name="cache_images_title">Images</string>
<string name="cache_log_types">Types de visites</string>
<string name="cache_coordinates_no">Cette cache n\'a pas de coordonnées.</string>
<string name="cache_clear_history">Effacer l\'historique</string>
@@ -759,7 +756,6 @@
<string name="map_strategy_auto">En fonction du déplacement</string>
<string name="map_strategy_detailed">Détaillée</string>
<string name="live_map_notification">Lors de l\'affichage de la carte active, certaines coordonnées de géocaches peuvent être imprécises et sont indiquées par un cercle orange.\nDemander les détails d\'une géocache ou la sauver pour une utilisation hors-ligne récupérera les coordonnées exactes.\n\nVous trouverez plus d\'informations sur les changements sur la page \"À propos de c:geo\".</string>
- <string name="live_map_note_dontshow">Ne plus afficher</string>
<string name="search_bar_hint">Recherche de caches</string>
<string name="search_bar_desc">Caches (géocode, mot clé), Objets voyageurs (code TB)</string>
<string name="search_coordinates">Coordonnées</string>
@@ -1117,6 +1113,7 @@
<string name="tts_oclock">%s heures</string>
<string name="clipboard_copy_ok">Copié dans le presse-papiers</string>
<string name="percent_favorite_points">%\ favoris</string>
+ <string name="cgeo_shortcut">c:geo raccourci</string>
<string name="create_shortcut">Créer un raccourci</string>
<string-array name="log_image_scales">
<item>Taille originale</item>
diff --git a/main/res/values-hu/strings.xml b/main/res/values-hu/strings.xml
index f46885f..ecb767d 100644
--- a/main/res/values-hu/strings.xml
+++ b/main/res/values-hu/strings.xml
@@ -105,7 +105,6 @@
<string name="translate_to_english">Fordítás angolra</string>
<string name="translate_length_warning">A fordítás sikertelen lehet hosszú szövegeknél.</string>
<string name="err_none">Ok</string>
- <string name="err_start">A kommunikáció nem indult el</string>
<string name="err_parse">Hiba a belépőoldalon</string>
<string name="err_server">Hiba a kapcsolatban a geocaching.com-mal (a szerver vagy a kapcsolat nem működik?)</string>
<string name="err_login">Nincs mentett belépési adat</string>
@@ -157,7 +156,6 @@
<string name="err_log_load_data">Sajnáljuk, a c:geo nem tudja betölteni az adatokat amik a megtalálás bejelentéséhez szükségesek.</string>
<string name="err_log_load_data_again">Sajnáljuk, a c:geo nem tudja betölteni az adatokat amik a megtalálás bejelentéséhez szükségesek. Újrapróbálkozás.</string>
<string name="err_log_load_data_still">A c:geo még tölti az adatokat amik a megtalálás bejelentéséhez szükségesek. Kérlek várj egy kicsit tovább.</string>
- <string name="err_log_failed_server">Sajnáljuk, a c:geo-nak nem sikerült hozzáadni a logot mert a szerver nem válaszol.</string>
<string name="err_log_post_failed">Úgy tűnik a logot nem került hozzáadásra. Kérlek ellenőrizd a geocaching.com-on.</string>
<string name="err_search_address_forgot">Sajnáljuk, a c:geo elfelejtette a címet amit kerestél.</string>
<string name="err_parse_lat">Sajnáljuk, a c:geo nem tudja értelmezni a szélességet.</string>
@@ -503,7 +501,6 @@
<string name="cache_coordinates">Koordináták</string>
<string name="cache_coordinates_original">Eredeti koordináták</string>
<string name="cache_spoiler_images_title">Spoiler képek</string>
- <string name="cache_images_title">Képek</string>
<string name="cache_log_types">Bejegyzés típusok</string>
<string name="cache_coordinates_no">Ennek a ládának nincsenek koordinátái.</string>
<string name="cache_clear_history">Előzmények törlése</string>
@@ -590,7 +587,6 @@
<string name="map_strategy_auto">Sebességfüggő</string>
<string name="map_strategy_detailed">Részletes</string>
<string name="live_map_notification">A koordináták az élő térképen nem mindig pontosak. A vélhetően pontatlan koordinátákat narancssárga kör jelöli.\nA geoláda részleteinek megnyitása vagy a geoláda mentése mindig pontos koordinátákkal történik.\n\nTovábbi információ az összes változásról a \"A c:georól\" oldalon található az appon belül.</string>
- <string name="live_map_note_dontshow">Ne mutasd újra</string>
<string name="search_bar_hint">Ládák keresése</string>
<string name="search_bar_desc">Ládák (GC-kód, kulcsszó), Nyomonkövethető tárgyak (TB-kód)</string>
<string name="search_coordinates">Koordináták</string>
diff --git a/main/res/values-it/strings.xml b/main/res/values-it/strings.xml
index ae86197..bd80eb2 100644
--- a/main/res/values-it/strings.xml
+++ b/main/res/values-it/strings.xml
@@ -121,9 +121,9 @@
<string name="translate_to_english">Traduci in inglese</string>
<string name="translate_length_warning">La traduzione può fallire quando c\'è molto testo.</string>
<string name="err_none">OK</string>
- <string name="err_start">Comunicazione non avviata</string>
<string name="err_parse">Errore analizzando la pagina di login</string>
<string name="err_server">Connessione fallita con Geocaching.com (server o connessione non disponibile?)</string>
+ <string name="err_server_ec">Impossibile contattare Extremcaching.com. Il sito Web potrebbe essere non attivoo la tua connessione internet non funziona.</string>
<string name="err_login">Informazioni di login non memorizzate</string>
<string name="err_login_failed">c:geo non può effettuare login.</string>
<string name="err_login_failed_toast">c:geo non può effettuare login. Attivata la modalità offline. Verificare le informazioni di login nelle impostazioni o abilitare una connessione internet.</string>
@@ -177,8 +177,8 @@
<string name="err_log_load_data">c:geo non riesce a caricare i dati necessari per salvare il log della tua visita.</string>
<string name="err_log_load_data_again">c:geo non riesce a caricare i dati necessari per salvare il log della tua visita. Nuovo tentativo in corso.</string>
<string name="err_log_load_data_still">c:geo sta ancora caricando i dati necessari per salvare il log. Per cortesia attendere ancora un pochino.</string>
- <string name="err_log_failed_server">c:geo non è riuscito ad inviare il log perché il server non risponde.</string>
<string name="err_log_post_failed">Sembra che il log non sia stato inviato. Prego verificare su Geocaching.com.</string>
+ <string name="err_log_post_failed_ec">Sembra che il tuo log non sia stato pubblicato. Controlla su Extremcaching.com.</string>
<string name="err_logimage_post_failed">Sembra che l\'immagine del tuo log non sia stata caricata. Si prega di controllare su Geocaching.com.</string>
<string name="err_search_address_forgot">c:geo ha dimenticato l\'indirizzo che vuoi trovare.</string>
<string name="err_parse_lat">c:geo non riesce ad interpretare la latitudine.</string>
@@ -202,6 +202,8 @@
<string name="warn_deprecated_mapfile">Stai usando una vecchia mappa 0.2.4.\nAggiornala alla 0.3.0 appena puoi.\nIl supporto alla 0.2.4 sarà rimosso nella prossima versione.</string>
<string name="warn_nonexistant_mapfile">La mappa selezionata non esiste.\nMappa offline non disponibile.</string>
<string name="warn_rendertheme_missing">Tema mappa non trovato.</string>
+ <string name="warn_pocket_query_select">Nessuna Pocket query selezionata.</string>
+ <string name="warn_no_pocket_query_found">Nessuna Pocket query trovata online.</string>
<string name="info_log_posted">c:geo ha inviato il log con successo.</string>
<string name="info_log_saved">c:geo ha salvato il log.</string>
<string name="info_log_cleared">Il log è stato azzerato.</string>
@@ -222,6 +224,8 @@
<string name="menu_history">Cronologia</string>
<string name="menu_filter">Filtri</string>
<string name="menu_scan_geo">Scansiona geocode</string>
+ <string name="menu_pocket_queries">Pocket query</string>
+ <string name="menu_scan_description">c:geo può eseguire una scansione di geocodes stampati oppure di immagini QR code. L\'applicazione necessaria non è installata. Desideri aprire Google Play per installarla?</string>
<string name="live_map_button">Mappa</string>
<string name="caches_nearby_button">Vicini</string>
<string name="advanced_search_button">Cerca</string>
@@ -245,8 +249,8 @@
<string name="caches_sort_difficulty">Difficoltà</string>
<string name="caches_sort_terrain">Terreno</string>
<string name="caches_sort_size">Dimensione</string>
- <string name="caches_sort_favorites">Popolarità</string>
- <string name="caches_sort_favorites_ratio">Popolarità [%]</string>
+ <string name="caches_sort_favorites">Preferiti</string>
+ <string name="caches_sort_favorites_ratio">Preferiti [%]</string>
<string name="caches_sort_name">Nome</string>
<string name="caches_sort_geocode">Geo Code</string>
<string name="caches_sort_rating">Voto</string>
@@ -289,6 +293,9 @@
<string name="caches_filter_modified">Con coordinate modificate</string>
<string name="caches_filter_origin">Origine</string>
<string name="caches_filter_distance">Distanza</string>
+ <string name="caches_filter_personal_note">Con una nota personale</string>
+ <string name="caches_filter_popularity">Preferiti</string>
+ <string name="caches_filter_popularity_ratio">Preferiti [%]</string>
<string name="caches_removing_from_history">Rimozione dalla cronologia…</string>
<string name="caches_clear_offlinelogs">Cancella i log offline</string>
<string name="caches_clear_offlinelogs_progress">Cancellazione logs offline</string>
@@ -328,6 +335,7 @@
<string name="settings_title_map_data">Dati mappa</string>
<string name="settings_title_map_content">Contenuto Mappa</string>
<string name="settings_title_gpx">GPX</string>
+ <string name="settings_title_basicmembers">Opzioni per i membri di base (non Premium)</string>
<string name="settings_title_navigation">Navigazione</string>
<string name="settings_title_system">Sistema</string>
<string name="settings_title_navigation_menu">Menu \"Naviga\"</string>
@@ -337,7 +345,11 @@
<string name="settings_category_logging_other">Altre opzioni di log</string>
<string name="settings_goto_url_button">altro …</string>
<string name="settings_title_gc">Geocaching.com</string>
+ <string name="settings_title_ec">Extremcaching.com</string>
+ <string name="settings_title_ox">OpenCaching.com (Garmin)</string>
<string name="settings_activate_gc">Attiva</string>
+ <string name="settings_activate_ec">Attivare</string>
+ <string name="settings_activate_ox">Attivare</string>
<string name="settings_gc_legal_note">Per usare i servizi di Geocaching.com, si applicano i termini e le condizioni del Contratto Groundspeak che deve essere approvato dall\'utente.</string>
<string name="settings_info_facebook_login_title">Facebook Login</string>
<string name="settings_info_facebook_login">Con il tuo account di Facebook non puoi fare login su geocaching.com. Ma c\'è una soluzione semplice …</string>
@@ -361,7 +373,10 @@
<string name="init_login_popup_failed">Login fallito.</string>
<string name="init_login_popup_failed_reason">Login fallito: </string>
<string name="init_login_popup_not_authorized">Non autorizzato</string>
+ <string name="init_login_popup_invalid_timestamp">Ora locale non valida, regolare l\'orologio del dispositivo</string>
+ <string name="init_login_popup_invalid_token">Autorizzazione non valida, ri-autorizzare</string>
<string name="init_signature">Firma</string>
+ <string name="init_template_help">Stringhe segnaposto come [NAME] saranno espanse più tardi, quando verrà utilizzato questo modello.</string>
<string name="init_signature_template_button">Stringhe speciali</string>
<string name="init_signature_template_date">Data</string>
<string name="init_signature_template_time">Ora</string>
@@ -369,6 +384,9 @@
<string name="init_signature_template_user">Utente</string>
<string name="init_signature_template_number">Numero cache</string>
<string name="init_signature_template_owner">Proprietario</string>
+ <string name="init_signature_template_name">Nome</string>
+ <string name="init_signature_template_url">URL</string>
+ <string name="init_signature_template_log">Testo di Log</string>
<string name="init_ratingwanted">Rating GCvote.com</string>
<string name="init_summary_ratingwanted">Carica il rating del cache da GCvote.com</string>
<string name="init_friendlogswanted">Visualizza log dei miei amici</string>
@@ -461,6 +479,22 @@
<string name="settings_open_website">Apri il sito</string>
<string name="settings_settings">Impostazioni</string>
<string name="settings_information">Informazioni</string>
+ <string name="settings_twitter_cache_message">Messaggio per cache trovato</string>
+ <string name="settings_twitter_trackable_message">Messaggio per Trackable trovato</string>
+ <string name="init_ec_icons">Icone Mappa</string>
+ <string name="settings_ec_icons_other">Proprio stile</string>
+ <string name="settings_ec_icons_oc">Come OC</string>
+ <string name="settings_features">Caratteristiche supportate</string>
+ <string name="feature_description">Le seguenti funzioni <b>online</b> di questo sito Web sono supportate in c:geo (oltre alle funzionalità offline):</string>
+ <string name="feature_personal_notes">Note personali</string>
+ <string name="feature_online_logging">Log online</string>
+ <string name="feature_log_images">Immagini allegate ai Log</string>
+ <string name="feature_watch_list">Watchlist</string>
+ <string name="feature_own_coordinates">Memorizzazione delle coordinate modificate</string>
+ <string name="feature_search_keyword">Ricerca per parola chiave</string>
+ <string name="feature_search_live_map">Mappa Live</string>
+ <string name="feature_search_center">Cerca per posizione</string>
+ <string name="feature_search_geocode">Cerca per geocode</string>
<string name="map_source_google_map">Google: Map</string>
<string name="map_source_google_satellite">Google: Satellite</string>
<string name="map_source_osm_mapnik">OSM: Mapnik</string>
@@ -485,6 +519,7 @@
<string name="auth_explain_long">Premendo il pulsante \"autorizza c:geo\" avrà inizio il processo. Verrà aperto un browser web con la pagina %s. Effettuare login alla pagina e lasciare che <b>c:geo</b> acceda al tuo account.</string>
<string name="auth_dialog_completed_twitter">c:geo è ora autorizzato a postare su Twitter.</string>
<string name="auth_ocde">opencaching.de</string>
+ <string name="auth_ocpl">opencaching.pl</string>
<string name="auth_dialog_completed_oc">c:geo è ora autorizzato ad accedere a %s.</string>
<string name="cache_offline">Offline</string>
<string name="cache_offline_refresh">Aggiorna</string>
@@ -506,6 +541,8 @@
<string name="cache_log_image_default_title">Foto</string>
<string name="cache_personal_note">Note personali</string>
<string name="cache_personal_note_edit">Modifica</string>
+ <string name="cache_personal_note_limit">Limite per le note personali</string>
+ <string name="cache_personal_note_truncation">Questa nota personale verrà troncata da Geocaching.com dopo %d caratteri.</string>
<string name="cache_personal_note_upload">Carica</string>
<string name="cache_personal_note_uploading">Nota personale in caricamento</string>
<string name="cache_personal_note_upload_done">Nota personale caricata</string>
@@ -581,6 +618,8 @@
<string name="cache_menu_whereyougo">WhereYouGo</string>
<string name="cache_menu_oruxmaps">OruxMaps</string>
<string name="cache_menu_cachebeacon">Cache Beacon</string>
+ <string name="cache_menu_navigon">Navigon</string>
+ <string name="cache_menu_pebble">Pebble</string>
<string name="cache_status">Stato</string>
<string name="cache_status_offline_log">Log salvato</string>
<string name="cache_status_found">Trovato</string>
@@ -608,7 +647,6 @@
<string name="cache_coordinates">Coordinate</string>
<string name="cache_coordinates_original">Coordinate originali</string>
<string name="cache_spoiler_images_title">Immagini spoiler</string>
- <string name="cache_images_title">Immagini</string>
<string name="cache_log_types">Tipi di Log</string>
<string name="cache_coordinates_no">Questo cache non ha coordinate.</string>
<string name="cache_clear_history">Cancella cronologia</string>
@@ -627,6 +665,7 @@
<string name="file_title_searching">Ricerca in corso</string>
<string name="simple_dir_chooser_title">Scegli cartella</string>
<string name="simple_dir_chooser_current_path">Path:</string>
+ <string name="simple_dir_chooser_invalid_path">Percorso non valido</string>
<string name="gpx_import_loading_caches">Caricamento dei cache da file GPX</string>
<string name="gpx_import_loading_waypoints">Caricamento file waypoints</string>
<string name="gpx_import_store_static_maps">Salvataggio mappe statiche</string>
@@ -644,6 +683,7 @@
<string name="gpx_import_delete_title">Cancella file</string>
<string name="gpx_import_delete_message">Vuoi cancellare %s?</string>
<string name="gpx_import_select_list_title">Importa GPX nella lista</string>
+ <string name="gpx_import_android">Importazione da Android</string>
<string name="map_file_select_title">Seleziona il file mappa</string>
<string name="web_import_title">Importa dal web</string>
<string name="web_import_waiting">In attesa di nuovi cache dal web…</string>
@@ -714,7 +754,6 @@
<string name="map_strategy_auto">In base alla tua velocità di movimento</string>
<string name="map_strategy_detailed">Dettagliata</string>
<string name="live_map_notification">Nella nuova Mappa Live le coordinate potrebbero non essere sempre precise. Coordinate possibilmente imprecise sono marcate da un cerchio arancione.\nAprendo i dettagli del cache o salvando il cache per uso offline farà calcolare sempre coordinate precise.\n\nInformazioni addizionali su tutte le modifiche si possono trovare nel menu \"Info su c:geo\" sulla pagina principale di questa app.</string>
- <string name="live_map_note_dontshow">Non mostrare ancora</string>
<string name="search_bar_hint">Cerca cache</string>
<string name="search_bar_desc">Cache (geo code, parole chiave), oggetti Trackables (TB-code)</string>
<string name="search_coordinates">Coordinate</string>
@@ -740,6 +779,9 @@
<string name="search_address_started">Cerca per luoghi</string>
<string name="search_address_result">Cerca luoghi</string>
<string name="search_own_caches">Cerca i miei cache</string>
+ <string name="search_pocket_title">Pocket Query</string>
+ <string name="search_pocket_loading">Caricamento di una lista di Pocket query</string>
+ <string name="search_pocket_select">Scegli Pocket Query</string>
<string name="trackable">Oggetto Trackable</string>
<string name="trackable_details_loading">Caricamento dettagli Trackable…</string>
<string name="trackable_log_touch">Documenta il contatto</string>
@@ -772,6 +814,7 @@
<string name="user_menu_view_found">Cache trovati</string>
<string name="user_menu_open_browser">Apri profilo nel browser</string>
<string name="user_menu_send_message">Invia messaggio</string>
+ <string name="user_menu_open_contact">Aprire scheda contatto</string>
<string name="navigation">Navigazione</string>
<string name="compass_title">Bussola</string>
<string name="use_gps">Usa Nord solo da GPS</string>
@@ -787,6 +830,8 @@
<string name="helper_calendar_title">c:geo calendario add-on</string>
<string name="helper_calendar_missing">c:geo calendario add-on non installato</string>
<string name="helper_calendar_description">Permette di esportare gli eventi cache nel calendario del tuo dispositivo.</string>
+ <string name="helper_sendtocgeo_title">Send to c:geo</string>
+ <string name="helper_sendtocgeo_description">Send to c:geo è un\'estensione del browser <strong>per il tuo PC</strong>. Durante la navigazione su geocaching.com, è possibile inviare i cache al vostro smartphone con il clic di un pulsante direttamente all\'interno del browser.</string>
<string name="helper_locus_title">Locus</string>
<string name="helper_locus_description">Applicazione semplice da usare che mostra mappe online permettendo di scaricarle direttamente per l\'uso offline (solo mappe raster). Supporta inoltra la registrazione di traccia, gestione dei waypoints e altre utili funzioni.</string>
<string name="helper_gpsstatus_title">GPS Status</string>
@@ -797,6 +842,8 @@
<string name="helper_barcode_description">Ci sono script Greasemonkey e siti web che consentono di visualizzare un geocode come codice a barre. Con questa app c:geo può leggere il geocode direttamente dallo schermo del tuo computer.</string>
<string name="helper_pocketquery_title">Creatore di Pocket Query</string>
<string name="helper_pocketquery_description">Consente di creare facilmente Pocket Queries centrate sulla tua posizione attuale o un punto scelto dalla mappa. Richiede un account premium su Geocaching.com.</string>
+ <string name="helper_google_translate_title">Google Traduttore</string>
+ <string name="helper_google_translate_description">Se si scaricano i pacchetti di traduzione nell\'applicazione Google Traduttore, puoi facilmente tradurre le descrizioni dei cache in c:geo toccando e tenendo premuto sul testo (senza bisogno di una connessione Internet).</string>
<string name="addon_missing_title">Add-On mancante</string>
<string name="addon_download_prompt">Scaricalo ora da Google Play.</string>
<string name="export">Esporta</string>
@@ -1004,6 +1051,38 @@
<string name="attribute_unknown_no">Senza attributo sconosciuto</string>
<string name="attribute_geotour_yes">Parte di un GeoTour</string>
<string name="attribute_geotour_no">Non fa parte di un GeoTour</string>
+ <string name="attribute_kids_2_yes">Porta i tuoi bambini</string>
+ <string name="attribute_kids_2_no">Non portare bambini</string>
+ <string name="attribute_historic_site_yes">Sito storico</string>
+ <string name="attribute_historic_site_no">Non è un sito storico</string>
+ <string name="attribute_magnetic_yes">Cache magnetico</string>
+ <string name="attribute_magnetic_no">Non è un cache magnetico</string>
+ <string name="attribute_usb_cache_yes">Cache \"Dead drop USB\"</string>
+ <string name="attribute_usb_cache_no">Non è un cache \"Dead drop USB\"</string>
+ <string name="attribute_shovel_yes">Potrebbe essere necessaria una pala</string>
+ <string name="attribute_shovel_no">Non hai bisogno di una pala</string>
+ <string name="attribute_specific_access_yes">Disponibile nelle ore specificate (l\'accesso può essere a pagamento)</string>
+ <string name="attribute_specific_access_no">Disponibile ad ogni ora del giorno</string>
+ <string name="attribute_pedestrian_only_yes">Accesso solo a piedi</string>
+ <string name="attribute_pedestrian_only_no">Accesso non solo a piedi</string>
+ <string name="attribute_nature_cache_yes">Nascosto in un ambiente naturale (boschi, montagne, ecc.)</string>
+ <string name="attribute_nature_cache_no">Non nascosto in un ambiente naturale</string>
+ <string name="attribute_byop_yes">Portati qualcosa per scrivere</string>
+ <string name="attribute_byop_no">Matita non necessaria</string>
+ <string name="attribute_safari_cache_yes">Reverse cache</string>
+ <string name="attribute_safari_cache_no">Non è un reverse cache</string>
+ <string name="attribute_quick_cache_yes">Cache veloce</string>
+ <string name="attribute_quick_cache_no">Non è un cache veloce</string>
+ <string name="attribute_wherigo_yes">Cache Wherigo</string>
+ <string name="attribute_wherigo_no">Non è un cache Wherigo</string>
+ <string name="attribute_audio_cache_yes">La descrizione contiene un file audio</string>
+ <string name="attribute_audio_cache_no">La descrizione non contiene un file audio</string>
+ <string name="attribute_geohotel_yes">Cache GeoHotel</string>
+ <string name="attribute_geohotel_no">Non è un cache GeoHotel</string>
+ <string name="attribute_survey_marker_yes">Vicino ad una targa o marcatore geodedico (Survey Marker)</string>
+ <string name="attribute_survey_marker_no">Non è vicino ad una targa o marcatore geodedico (Survey Marker)</string>
+ <string name="attribute_offset_cache_yes">Offset cache</string>
+ <string name="attribute_offset_cache_no">Non è un offset cache</string>
<string name="quote">Per rendere il geocaching più facile e gli utenti più pigri.</string>
<string name="powered_by">carnero</string>
<string name="support">Supporto: <a href="">support@cgeo.org</a></string>
@@ -1013,6 +1092,7 @@
<string name="nutshellmanual">Manuale: <a href="">c:geo in a Nutshell</a></string>
<string name="market">Android: <a href="">c:geo su Google Play</a></string>
<string name="about_twitter">Può <b>c:geo</b> pubblicare su Twitter ogni volta che logghi un cache?</string>
+ <string name="faq">FAQ: <a href="">faq.cgeo.org</a></string>
<string name="status_new_release" tools:ignore="UnusedResources">Una nuova versione è disponibile.\nClicca per installarla.</string>
<string name="status_new_nightly" tools:ignore="UnusedResources">Una nuova versione nightly è disponibile.\nClicca per installarla.</string>
<string name="status_new_rc" tools:ignore="UnusedResources">Una nuova release candidate è disponibile.\nClicca per installarla.</string>
@@ -1030,6 +1110,8 @@
<string name="tts_one_oclock">a ore una</string>
<string name="tts_oclock">a ore %s</string>
<string name="clipboard_copy_ok">Copiato nella clipboard</string>
+ <string name="percent_favorite_points">%\ preferiti</string>
+ <string name="create_shortcut">Crea collegamento</string>
<string-array name="log_image_scales">
<item>Dimensioni originali</item>
<item>512 px</item>
@@ -1069,4 +1151,8 @@
<item quantity="one">ieri</item>
<item quantity="other">%d giorni fa</item>
</plurals>
+ <plurals name="favorite_points">
+ <item quantity="one">%s preferito</item>
+ <item quantity="other">%s preferiti</item>
+ </plurals>
</resources>
diff --git a/main/res/values-ja/strings.xml b/main/res/values-ja/strings.xml
index d7e5287..089d253 100644
--- a/main/res/values-ja/strings.xml
+++ b/main/res/values-ja/strings.xml
@@ -121,7 +121,6 @@
<string name="translate_to_english">英語に翻訳</string>
<string name="translate_length_warning">文章が長すぎるので翻訳できないかもしれません。</string>
<string name="err_none">OK</string>
- <string name="err_start">通信を始めることができませんでした</string>
<string name="err_parse">ログインページの解析に失敗しました</string>
<string name="err_server">Geocaching.comに接続できません。サーバが停止中かインターネットに未接続かもしれません。</string>
<string name="err_login">ログイン情報が保存されていません</string>
@@ -177,7 +176,6 @@
<string name="err_log_load_data">ログを書くのに必要なデータをロードすることができません。</string>
<string name="err_log_load_data_again">ログを書くのに必要なデータをロードすることができません。もう一度やってみてください。</string>
<string name="err_log_load_data_still">ログを投稿するのに必要なデータをまだロード中です。もう少しお待ちください。</string>
- <string name="err_log_failed_server">サーバの反応がないのでログを投稿することができませんでした。</string>
<string name="err_log_post_failed">ログを投稿することができなかったようです。Geocaching.comで確認してください。</string>
<string name="err_logimage_post_failed">ログの添付画像がアップロードされなかったようです。Geocaching.comで確認してください。</string>
<string name="err_search_address_forgot">c:geo forgot the address you tried to find.</string>
@@ -582,7 +580,6 @@
<string name="cache_coordinates">座標</string>
<string name="cache_coordinates_original">オリジナル座標</string>
<string name="cache_spoiler_images_title">スポイラー画像</string>
- <string name="cache_images_title">画像</string>
<string name="cache_log_types">ログタイプ</string>
<string name="cache_coordinates_no">このキャッシュに座標値はありません。</string>
<string name="cache_clear_history">全履歴を削除</string>
@@ -688,7 +685,6 @@
<string name="map_strategy_auto">自動(移動速度に依存)</string>
<string name="map_strategy_detailed">詳細(「速い」+詳細)</string>
<string name="live_map_notification">現バージョンではオンライン地図の座標は正確とは限りません。不正確と思われる座標のキャッシュはオレンジ色の丸で表示されます。\nキャッシュの詳細を表示したりオフライン用に保存する際には正確な座標を取得します。\n\n詳しくはアプリ内の「c:geoについて」の変更履歴(英語)をご覧ください。</string>
- <string name="live_map_note_dontshow">再び表示しない</string>
<string name="search_bar_hint">キャッシュ検索</string>
<string name="search_bar_desc">キャッシュ(GCコード,キーワード), トラッカブル(TBコード)</string>
<string name="search_coordinates">座標</string>
diff --git a/main/res/values-nb/strings.xml b/main/res/values-nb/strings.xml
index 6eb61a2..d5af0cf 100644
--- a/main/res/values-nb/strings.xml
+++ b/main/res/values-nb/strings.xml
@@ -69,7 +69,6 @@
<string name="log_new_log">Logg</string>
<string name="log_new_log_text">Logg tekst</string>
<string name="err_none">Ok</string>
- <string name="err_start">Klarte ikke å koble til</string>
<string name="err_parse">Klarte ikke å lese innloggings-siden</string>
<string name="err_server">Klarte ikke å koble til Geocaching.com (server eller tilkobling nede?)</string>
<string name="err_login">Ingen innloggings-opplysninger lagret</string>
@@ -103,7 +102,6 @@
<string name="err_log_load_data">Beklager, c:geo klarte ikke å laste den nødvendige informasjonen for å logge funnet.</string>
<string name="err_log_load_data_again">Beklager, c:geo klarte ikke å laste den nødvendige informasjonen for å logge funnet. c:geo prøver på nytt.</string>
<string name="err_log_load_data_still">c:geo laster fortsatt informasjonen som er nødvendig for å logge funnet. Vennligst vent.</string>
- <string name="err_log_failed_server">Beklager, c:geo klarte ikke å logge funnet fordi serveren er nede.</string>
<string name="err_log_post_failed">Beklager, c:geo klarte ikke å logge funnet.</string>
<string name="err_search_address_forgot">Beklager, c:geo glemte adressen du prøvde å finne.</string>
<string name="err_parse_lat">Beklager, c:geo klarte ikke å lese breddegraden.</string>
diff --git a/main/res/values-nl/strings.xml b/main/res/values-nl/strings.xml
index 27081f7..7138538 100644
--- a/main/res/values-nl/strings.xml
+++ b/main/res/values-nl/strings.xml
@@ -121,7 +121,6 @@
<string name="translate_to_english">Vertaal naar engels</string>
<string name="translate_length_warning">Vertaling kan mislukken bij grote stukken tekst.</string>
<string name="err_none">Ok</string>
- <string name="err_start">Communicatie niet gestart</string>
<string name="err_parse">Login pagina verwerken mislukt</string>
<string name="err_server">Verbinding met Geocaching.com mislukt (geen verbinding of server niet bereikbaar)</string>
<string name="err_login">Geen login informatie opgeslagen</string>
@@ -177,7 +176,6 @@
<string name="err_log_load_data">Sorry, c:geo kan data om bezoek te loggen niet laden.</string>
<string name="err_log_load_data_again">Sorry, c:geo kan data om bezoek te loggen niet laden. Bezig nogmaals te proberen.</string>
<string name="err_log_load_data_still">c:geo is nog steeds bezig om data te laden om bezoek te loggen. Graag nog even geduld.</string>
- <string name="err_log_failed_server">Sorry, c:geo kon bezoek niet loggen omdat de server niet reageert.</string>
<string name="err_log_post_failed">Sorry, het is c:geo niet gelukt het log te posten.</string>
<string name="err_logimage_post_failed">Het lijkt erop dat uw log-foto is niet geüpload. Controleer het op Geocaching.com.</string>
<string name="err_search_address_forgot">Sorry, c:geo is het adres dat je zoekt vergeten.</string>
@@ -599,7 +597,6 @@
<string name="cache_coordinates">Coördinaten</string>
<string name="cache_coordinates_original">Originele coordinaten</string>
<string name="cache_spoiler_images_title">Spoiler afbeeldingen</string>
- <string name="cache_images_title">Afbeeldingen</string>
<string name="cache_log_types">Log types</string>
<string name="cache_coordinates_no">Deze cache heeft geen coördinaten.</string>
<string name="cache_clear_history">Maak geschiedenis leeg</string>
@@ -705,7 +702,6 @@
<string name="map_strategy_auto">Afhankelijk van snelheid</string>
<string name="map_strategy_detailed">Gedetailleerd</string>
<string name="live_map_notification">Op de nieuwe live-kaart zullen coördinaten niet altijd exact zijn. Mogelijke onnauwkeurige coördinaten zijn aangegeven met een oranje cirkel.\nHet openen of opslaan van de cache zorgt ervoor dat de exacte coördinaten gebruikt worden.\n\nMeer informatie over de wijzigingen kan gevonden worden op de \"Over c:geo\" pagina in de app.</string>
- <string name="live_map_note_dontshow">Laat niet nogmaals zien</string>
<string name="search_bar_hint">Zoek naar caches</string>
<string name="search_bar_desc">Caches (geo code, trefwoord), Trackables (TB-code)</string>
<string name="search_coordinates">Coördinaten</string>
diff --git a/main/res/values-pl/strings.xml b/main/res/values-pl/strings.xml
index 3fbbda6..88a9105 100644
--- a/main/res/values-pl/strings.xml
+++ b/main/res/values-pl/strings.xml
@@ -121,7 +121,6 @@
<string name="translate_to_english">Przetłumacz na angielski</string>
<string name="translate_length_warning">Tłumaczenie może nie udać się przy dużej ilości tekstu.</string>
<string name="err_none">OK</string>
- <string name="err_start">Komunikacja nie rozpoczeła się</string>
<string name="err_parse">Nieudany odczyt strony logowania.</string>
<string name="err_server">Nieudane połączenie z Geocaching.com. Strona albo Twoje połączenie internetowe nie działa.</string>
<string name="err_login">Brak danych do logowania.</string>
@@ -177,7 +176,6 @@
<string name="err_log_load_data">c:geo nie może załadować danych wymaganych do wpisania wizyty.</string>
<string name="err_log_load_data_again">c:geo nie może załadować danych wymaganych do wpisania wizyty. Próbuję ponownie.</string>
<string name="err_log_load_data_still">Nadal trwa ładowanie danych wymaganych do wpisu w dzienniku. Proszę czekać…</string>
- <string name="err_log_failed_server">c:geo nie może dokonać wpisu ponieważ serwer nie odpowiada.</string>
<string name="err_log_post_failed">Wygląda na to, że Twój wpis nie został zapisany. Proszę sprawdź na Geocaching.com.</string>
<string name="err_logimage_post_failed">Wygląda na to, że Twój obraz nie został dodany. Proszę sprawdź to na Geocaching.com.</string>
<string name="err_search_address_forgot">c:geo zapomniał adresu, którego szukałeś.</string>
@@ -599,7 +597,6 @@
<string name="cache_coordinates">Współrzędne</string>
<string name="cache_coordinates_original">Oryginalne współrzędne</string>
<string name="cache_spoiler_images_title">Zdjęcia spoiler</string>
- <string name="cache_images_title">Zdjęcia</string>
<string name="cache_log_types">Rodzaj wpisu</string>
<string name="cache_coordinates_no">Ta skrzynka nie ma współrzędnych GPS.</string>
<string name="cache_clear_history">Usuń historię</string>
@@ -705,7 +702,6 @@
<string name="map_strategy_auto">Zależna od prędkości</string>
<string name="map_strategy_detailed">Szczegółowa</string>
<string name="live_map_notification">Na nowej mapie live, współrzędnie nie zawsze muszą być dokładne. Prawdopodobne niedokładne współrzędne są zaznaczane za pomocą pomarańczowych okręgów.\nOtworzenie współrzędnych skrzynki lub zapisanie skrzynki do użytku offline zawsze używa precyzyjnych współrzędnych.\n\nWięcej informacji na temat wszystkich zmian można odnaleźć na stronie \"O c:geo\" wewnątrz programu.</string>
- <string name="live_map_note_dontshow">Nie pokazuj ponownie</string>
<string name="search_bar_hint">Szukaj skrzynek</string>
<string name="search_bar_desc">Skrzynki (GC-kod, słowo kluczowe), przedmioty podróżne (TB-kod)</string>
<string name="search_coordinates">Współrzędne</string>
diff --git a/main/res/values-pt/strings.xml b/main/res/values-pt/strings.xml
index 5cb824c..7862957 100644
--- a/main/res/values-pt/strings.xml
+++ b/main/res/values-pt/strings.xml
@@ -121,7 +121,6 @@
<string name="translate_to_english">Traduzir para inglês</string>
<string name="translate_length_warning">A tradução pode falhar se o texto fôr muito grande.</string>
<string name="err_none">Ok</string>
- <string name="err_start">Comunicação não iniciada</string>
<string name="err_parse">Falha na análise da página de login</string>
<string name="err_server">Falha na ligação a Geocaching.com (servidor ou ligação em baixo?)</string>
<string name="err_login">Informação de login não gravada</string>
@@ -177,7 +176,6 @@
<string name="err_log_load_data">O c:geo não consegue carregar os dados necessários para registar a sua visita.</string>
<string name="err_log_load_data_again">O c:geo não consegue carregar os dados necessários para registar a sua visita. A tentar de novo.</string>
<string name="err_log_load_data_still">O c:geo ainda está a carregar dados necessários para publicar o registo. Por favor espere mais um pouco.</string>
- <string name="err_log_failed_server">O c:geo falhou a publicação do registo porque o servidor não responde.</string>
<string name="err_log_post_failed">O c:geo falhou a publicação do registo.</string>
<string name="err_logimage_post_failed">Parece que a sua imagem de registo não foi enviada. Por favor verifique em Geocaching.com.</string>
<string name="err_search_address_forgot">O c:geo esqueceu o endereço que procura.</string>
@@ -606,7 +604,6 @@
<string name="cache_coordinates">Coordenadas</string>
<string name="cache_coordinates_original">Coordenadas originais</string>
<string name="cache_spoiler_images_title">Imagens spoiler</string>
- <string name="cache_images_title">Imagens</string>
<string name="cache_log_types">Tipos de log</string>
<string name="cache_coordinates_no">Esta cache não tem coordenadas.</string>
<string name="cache_clear_history">Apagar histórico</string>
@@ -712,7 +709,6 @@
<string name="map_strategy_auto">Dependente da velocidade</string>
<string name="map_strategy_detailed">Detalhado</string>
<string name="live_map_notification">No novo mapa ao vivo as coordenadas podem nem sempre ser precisas. As coordenadas possivelmente imprecisas são marcadas com um círculo cor de laranja.\nAbrindo os detalhes da cache or gravando a cache para utilização offline fará com que obtenha as coordenadas precisas.\n\nMais informações em todas as alterações podem ser encontradas na página \"Sobre c:geo\" na aplicação.</string>
- <string name="live_map_note_dontshow">Não mostrar novamente</string>
<string name="search_bar_hint">Procurar caches</string>
<string name="search_bar_desc">Caches (código-GC, palavra-chave), Trackables (código-TB)</string>
<string name="search_coordinates">Coordenadas</string>
diff --git a/main/res/values-sk/strings.xml b/main/res/values-sk/strings.xml
index 615a630..7ccc6e5 100644
--- a/main/res/values-sk/strings.xml
+++ b/main/res/values-sk/strings.xml
@@ -105,7 +105,6 @@
<string name="translate_to_english">Preložiť do angličtiny</string>
<string name="translate_length_warning">Pre veľké texty môže preklad zlyhať.</string>
<string name="err_none">Ok</string>
- <string name="err_start">Komunikácia nezačala.</string>
<string name="err_parse">Zlyhalo čítanie prihlasovacej stránky.</string>
<string name="err_server">Zlyhalo pripojenie k serveru Geocaching.com (pripojenie, alebo server nefunkčný?)</string>
<string name="err_login">Nie sú uložené žiadne prihlasovacie údaje.</string>
@@ -157,7 +156,6 @@
<string name="err_log_load_data">c:geo nemôže načítať dáta potrebné pre zalogovanie návštevy.</string>
<string name="err_log_load_data_again">c:geo nemôže načítať dáta potrebné pre zalogovanie návštevy. Skúša to znovu.</string>
<string name="err_log_load_data_still">c:geo stále načítava dáta potrebné pre zalogovanie návštevy. Prosím, počkajte chvíľu.</string>
- <string name="err_log_failed_server">c:geo nemohlo odoslať log, pretože server neodpovedá.</string>
<string name="err_log_post_failed">c:geo nemohlo odoslať log.</string>
<string name="err_search_address_forgot">c:geo zabudlo adresu, ktorú sa pokúšate nájsť.</string>
<string name="err_parse_lat">c:geo nemôže dopočítať šírku.</string>
@@ -504,7 +502,6 @@
<string name="cache_coordinates">Súradnice</string>
<string name="cache_coordinates_original">Pôvodné súradnice</string>
<string name="cache_spoiler_images_title">Spoilerové obrázky</string>
- <string name="cache_images_title">Obrázky</string>
<string name="cache_log_types">Typy záznamov</string>
<string name="cache_coordinates_no">Táto skrýša nemá žiadne súradnice.</string>
<string name="cache_clear_history">Vymazať históriu</string>
@@ -591,7 +588,6 @@
<string name="map_strategy_auto">Podľa rýchlosti</string>
<string name="map_strategy_detailed">Podrobná</string>
<string name="live_map_notification">Na novej aktívnej mape nemusia byť súradnice vždy presné. Súradnice, ktoré môžu byť nepresné, sú označené oranžovým krúžkom.\nPo otvorení detailu skrýše, alebo po jej uložení pre použitie offline, sú získané vždy presné súradnice.\n\nViac informácií ku všetkým zmenám sa nachádzajú na stránke „O c:geo“ v aplikácii.</string>
- <string name="live_map_note_dontshow">Nabudúce nezobrazovať</string>
<string name="search_bar_hint">Hľadanie skrýš</string>
<string name="search_bar_desc">Skrýše (GC kód, kľúčové slovo), trasovateľné predmety (TB-kód)</string>
<string name="search_coordinates">Súradnice</string>
diff --git a/main/res/values-sl/strings.xml b/main/res/values-sl/strings.xml
index 86e7ce7..8adf08b 100644
--- a/main/res/values-sl/strings.xml
+++ b/main/res/values-sl/strings.xml
@@ -121,7 +121,6 @@
<string name="translate_to_english">Prevedi v: angleščino</string>
<string name="translate_length_warning">Prevod lahko spodleti zaradi velike količine besedila.</string>
<string name="err_none">OK</string>
- <string name="err_start">Komunikacija se ni začela</string>
<string name="err_parse">Razčlenjevanje prijavne strani ni uspelo</string>
<string name="err_server">Ni bilo mogoče vzpostaviti povezave z Geocaching.com. Spletna stran ali vaša povezava z internetom je lahko nedosegljiva.</string>
<string name="err_login">Prijavni podatki niso shranjeni</string>
@@ -177,7 +176,6 @@
<string name="err_log_load_data">c:geo ni mogel naložiti podatkov za zapis obiska.</string>
<string name="err_log_load_data_again">c:geo ne more naložiti podatkov za zapis obiska. Ponovni poskus…</string>
<string name="err_log_load_data_still">c:geo še vedno nalaga podatke za zapis obiska. Prosimo počakajte še trenutek.</string>
- <string name="err_log_failed_server">c:geo ni mogel objaviti zapisa, ker se strežnik ne odziva.</string>
<string name="err_log_post_failed">Izgleda, kot da zapis ni bil objavljen. Preverite na Geocaching.com.</string>
<string name="err_logimage_post_failed">Izgleda, kot da slika ni bila naložena. Preverite na Geocaching.com.</string>
<string name="err_search_address_forgot">c:geo je pozabil naslov, ki ste ga hoteli najti.</string>
@@ -598,7 +596,6 @@
<string name="cache_coordinates">Koordinate</string>
<string name="cache_coordinates_original">Originalne koordiante</string>
<string name="cache_spoiler_images_title">Spoiler slike</string>
- <string name="cache_images_title">Slike</string>
<string name="cache_log_types">Tipi zapisov</string>
<string name="cache_coordinates_no">Zaklad nima koordinat.</string>
<string name="cache_clear_history">Počisti zgodovino</string>
@@ -704,7 +701,6 @@
<string name="map_strategy_auto">Odvisna od moje hitrosti</string>
<string name="map_strategy_detailed">Podrobna</string>
<string name="live_map_notification">Na zemljevidu s podatki v živo koordinate niso nujno točne. Nenatančne koordinate so označene z oranžnim krogom.\nČe odprete podrobnosti zaklada se bodo vedno naložile natančne koordinate\n\nVeč informacij o teh spremembah lahko dobite na strani \"O c:geo\" v aplikaciji.</string>
- <string name="live_map_note_dontshow">Ne pokaži tega ponovno</string>
<string name="search_bar_hint">Iskanje zakladov</string>
<string name="search_bar_desc">Zakladi (geo koda, ključne besede), Sledljivčki (TB koda)</string>
<string name="search_coordinates">Koordinate</string>
diff --git a/main/res/values-sv/strings.xml b/main/res/values-sv/strings.xml
index 463730e..904788c 100644
--- a/main/res/values-sv/strings.xml
+++ b/main/res/values-sv/strings.xml
@@ -121,7 +121,6 @@
<string name="translate_to_english">Översätt till engelska</string>
<string name="translate_length_warning">Översättningen kan misslyckas med långa texter.</string>
<string name="err_none">Ok</string>
- <string name="err_start">Kommunikationen har inte påbörjats</string>
<string name="err_parse">Misslyckades att analysera inloggningssidan</string>
<string name="err_server">Misslyckades att ansluta till Geocaching.com. Hemsidan kan vara ur funktion eller så är det problem med din anslutning till Internet.</string>
<string name="err_login">Inloggningsinformationen ej sparad</string>
@@ -177,7 +176,6 @@
<string name="err_log_load_data">Tyvärr kan c:geo inte ladda information som krävs för att logga ditt besök.</string>
<string name="err_log_load_data_again">Tyvärr kan c:geo inte ladda information som krävs för att logga ditt besök. Försöker igen.</string>
<string name="err_log_load_data_still">c:geo laddar fortfarande data för att kunna posta loggen. Vänligen vänta en stund till.</string>
- <string name="err_log_failed_server">Tyvärr misslyckades c:geo att posta loggen eftersom servern inte svarade.</string>
<string name="err_log_post_failed">Tyvärr misslyckades c:geo att posta loggen.</string>
<string name="err_logimage_post_failed">Det verkar som om din bild till loggen inte kunde laddas upp. Vänligen kontrollera den på Geocaching.com.</string>
<string name="err_search_address_forgot">Tyvärr glömde c:geo adressen du sökte efter.</string>
@@ -596,7 +594,6 @@
<string name="cache_coordinates">Koordinater</string>
<string name="cache_coordinates_original">Ursprungliga koordinater</string>
<string name="cache_spoiler_images_title">Spoiler bilder</string>
- <string name="cache_images_title">Bilder</string>
<string name="cache_log_types">Loggtyper</string>
<string name="cache_coordinates_no">Cachen saknar koordinater.</string>
<string name="cache_clear_history">Rensa historik</string>
@@ -702,7 +699,6 @@
<string name="map_strategy_auto">Hastighetsberoende (gps)</string>
<string name="map_strategy_detailed">Exakta positioner</string>
<string name="live_map_notification">I den nya Live kartan så är koordinaterna inte alltid exakta. En cache med potentiellt oexakta koordinater är markerad med en orange cirkel.\nGenom att visa detaljer för cachen eller genom att spara cachen för offline kommer alltid exakta koordinater att hämtas.\n\nMer information om alla förändringar finns på \"Om c:geo\" sidan, som kan nås från c:geo\'s startsida.</string>
- <string name="live_map_note_dontshow">Visa inte mer</string>
<string name="search_bar_hint">Sök cache/TB</string>
<string name="search_bar_desc">Cache (GC-kod, nyckelord), Trackable (TB-kod)</string>
<string name="search_coordinates">Koordinater</string>
diff --git a/main/res/values/changelog_master.xml b/main/res/values/changelog_master.xml
index 1e3c3d4..c2b9049 100644
--- a/main/res/values/changelog_master.xml
+++ b/main/res/values/changelog_master.xml
@@ -2,5 +2,15 @@
<resources>
<!-- changelog for the master branch -->
<string name="changelog_master" translatable="false">
+ <b>Next feature release</b>\n
+ <b>New Features:</b>\n
+ · Parallel loading from different platforms to speed up live map\n
+ · All GCVote related settings moved to Menu-Services-GCVote\n
+ <b>Bugfixing:</b>\n
+ · Corrected wrong field note progress indication\n
+ · When using "external map" sometimes the position marker was not shown\m
+ · Circles on map now also shown for caches with final coords defined\n
+ \n
+ \n
</string>
</resources>
diff --git a/main/res/values/preference_keys.xml b/main/res/values/preference_keys.xml
index 0e4675d..d231795 100644
--- a/main/res/values/preference_keys.xml
+++ b/main/res/values/preference_keys.xml
@@ -6,13 +6,18 @@
and in the Java code as constants and avoid code duplication.
-->
- <string name="pref_fakekey_main_screen">fakekey_main_screen</string>
- <string name="pref_fakekey_services_screen">fakekey_services_screen</string>
- <string name="pref_fakekey_basicmembers_screen">fakekey_basicmembers_screen</string>
+ <string name="preference_screen_main">fakekey_main_screen</string>
+ <string name="preference_screen_services">fakekey_services_screen</string>
+ <string name="preference_screen_gc">preference_screen_gc</string>
+ <string name="preference_screen_basicmembers">fakekey_basicmembers_screen</string>
+ <string name="preference_screen_ocde">preference_screen_ocde</string>
+ <string name="preference_screen_ocpl">preference_screen_ocpl</string>
+ <string name="preference_screen_ec">preference_screen_ec</string>
+ <string name="preference_screen_twitter">preference_screen_twitter</string>
+ <string name="preference_screen_navigation_menu">fakekey_navigation_menu_screen</string>
<string name="pref_fakekey_ocde_authorization">fakekey_ocde_authorization</string>
<string name="pref_fakekey_ocpl_authorization">fakekey_ocpl_authorization</string>
<string name="pref_fakekey_twitter_authorization">fakekey_twitter_authorization</string>
- <string name="pref_fakekey_navigation_menu_screen">fakekey_navigation_menu_screen</string>
<string name="pref_connectorGCActive">connectorGCActive</string>
<string name="pref_username">username</string>
<string name="pref_password">password</string>
@@ -60,6 +65,7 @@
<string name="pref_fakekey_preference_backup_info">fakekey_preference_backup_info</string>
<string name="pref_fakekey_preference_backup">fakekey_preference_backup</string>
<string name="pref_fakekey_preference_restore">fakekey_preference_restore</string>
+ <string name="pref_fakekey_preference_maintenance_directories">pref_fakekey_preference_maintenance_directories</string>
<string name="pref_dbonsdcard">dbonsdcard</string>
<string name="pref_debug">debug</string>
<!-- preferences used internally -->
diff --git a/main/res/values/strings.xml b/main/res/values/strings.xml
index 7b40811..2ee01a8 100644
--- a/main/res/values/strings.xml
+++ b/main/res/values/strings.xml
@@ -45,7 +45,9 @@
<string name="cache_size_virtual">Virtual</string>
<string name="cache_size_notchosen">Not chosen</string>
<string name="cache_size_unknown">Unknown</string>
-
+ <string name="cache_size_nano">Nano</string>
+ <string name="cache_size_very_large">Very large</string>
+
<!-- waypoints -->
<string name="wp_final">Final Location</string>
<string name="wp_stage">Stage of a Multicache</string>
@@ -145,7 +147,6 @@
<!-- errors, warnings, info toasts -->
<string name="err_none">OK</string>
- <string name="err_start">Communication not started</string>
<string name="err_parse">Failed Login page parsing</string>
<string name="err_server">Unable to contact Geocaching.com. The website may be down or your internet connection not working.</string>
<string name="err_server_ec">Unable to contact Extremcaching.com. The website may be down or your internet connection not working.</string>
@@ -202,7 +203,6 @@
<string name="err_log_load_data">c:geo can\'t load data required to log visit.</string>
<string name="err_log_load_data_again">c:geo can\'t load data required to log visit. Trying again.</string>
<string name="err_log_load_data_still">c:geo is still loading data required to post log. Please wait a little while longer.</string>
- <string name="err_log_failed_server">c:geo failed to post log because server is not responding.</string>
<string name="err_log_post_failed">It seems that your log was not posted. Please check it on Geocaching.com.</string>
<string name="err_log_post_failed_ec">It seems that your log was not posted. Please check it on Extremcaching.com.</string>
<string name="err_logimage_post_failed">It seems that your log image was not uploaded. Please check it on Geocaching.com.</string>
@@ -360,7 +360,8 @@
<string name="list_dialog_remove_err">c:geo failed to remove the current list</string>
<string name="list_dialog_rename_title">Rename list</string>
<string name="list_dialog_rename">Rename</string>
-
+ <string name="list_not_available">List no longer available, switching to standard list</string>
+
<!-- about -->
<string name="about_version">Version</string>
<string name="about_changelog">Changelog</string>
@@ -525,6 +526,9 @@
<string name="init_use_native_ua">Android browser</string>
<string name="init_summary_use_native_ua">Identify as Android browser. Solves login problems when using certain network providers.</string>
<string name="init_rendertheme_folder">Map Themes Directory</string>
+ <string name="init_maintenance">Maintenance</string>
+ <string name="init_maintenance_directories_note">c:geo stores images, log images and other files related to a cache in a separate directory. In some cases (like importing/exporting the database) this directory may contain outdated files, which can be deleted here.</string>
+ <string name="init_maintenance_directories">Delete orphaned files</string>
<string name="settings_open_website">Open website</string>
<string name="settings_settings">Settings</string>
<string name="settings_information">Information</string>
@@ -719,7 +723,6 @@
<string name="cache_coordinates">Coordinates</string>
<string name="cache_coordinates_original">Original Coordinates</string>
<string name="cache_spoiler_images_title">Spoiler images</string>
- <string name="cache_images_title">Images</string>
<string name="cache_log_types">Log types</string>
<string name="cache_coordinates_no">This cache has no coordinates.</string>
<string name="cache_clear_history">Clear history</string>
@@ -848,7 +851,6 @@
<string name="map_strategy_auto">Speed dependent</string>
<string name="map_strategy_detailed">Detailed</string>
<string name="live_map_notification">Coordinates on the live map may not always be precise. Possibly imprecise coordinates are marked by an orange circle.\nOpening the cache details or saving the cache for offline use will always obtain precise coordinates.\n\nMore information can be found on the \"About c:geo\" page inside the app.</string>
- <string name="live_map_note_dontshow">Do not show again</string>
<!-- search -->
<string name="search_bar_hint">Search for caches</string>
@@ -939,6 +941,8 @@
<string name="helper_calendar_missing">c:geo calendar add-on not installed.</string>
<string name="helper_calendar_description">Enables you to export event caches to the calendar on your device.</string>
<string name="helper_sendtocgeo_title">Send to c:geo</string>
+ <string name="helper_contacts_title">c:geo contacts add-on</string>
+ <string name="helper_contacts_description">Enables you to open a contact card (of your address book) directly from a log entry, so you can more easily ask friends for help.</string>
<string name="helper_sendtocgeo_description">Send to c:geo is a browser extension <strong>for your PC</strong>. When browsing geocaching.com, you can send caches to your smartphone with the click of a button directly inside the browser.</string>
<string name="helper_locus_title">Locus</string>
<string name="helper_locus_description">Simple, usable application which shows online maps and allows you to download them directly into Offline mode (raster maps only). Also supports track recording, POI handling and many other useful functions.</string>
@@ -1262,5 +1266,6 @@
<string name="percent_favorite_points">%\ favorites</string>
<!-- shortcuts -->
+ <string name="cgeo_shortcut">c:geo shortcut</string>
<string name="create_shortcut">Create shortcut</string>
</resources>
diff --git a/main/res/xml/preferences.xml b/main/res/xml/preferences.xml
index de0914e..454574e 100644
--- a/main/res/xml/preferences.xml
+++ b/main/res/xml/preferences.xml
@@ -1,14 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:cgeo="http://schemas.android.com/apk/res/cgeo.geocaching"
- android:key="@string/pref_fakekey_main_screen" >
+ android:key="@string/preference_screen_main" >
<PreferenceScreen
android:icon="?attr/settings_cloud"
- android:key="@string/pref_fakekey_services_screen"
+ android:key="@string/preference_screen_services"
android:title="@string/settings_title_services" >
<PreferenceCategory android:title="@string/settings_category_geocaching" >
- <PreferenceScreen android:title="@string/settings_title_gc" >
+ <PreferenceScreen
+ android:key="@string/preference_screen_gc"
+ android:title="@string/settings_title_gc" >
<PreferenceCategory android:title="@string/settings_settings" >
<cgeo.geocaching.settings.CheckBoxWithPopupPreference
android:defaultValue="true"
@@ -44,7 +46,7 @@
<PreferenceScreen
android:dependency="@string/pref_connectorGCActive"
- android:key="@string/pref_fakekey_basicmembers_screen"
+ android:key="@string/preference_screen_basicmembers"
android:title="@string/settings_title_basicmembers" >
<CheckBoxPreference
android:defaultValue="false"
@@ -74,7 +76,9 @@
android:title="@string/settings_open_website" />
</PreferenceCategory>
</PreferenceScreen>
- <PreferenceScreen android:title="@string/init_oc" >
+ <PreferenceScreen
+ android:key="@string/preference_screen_ocde"
+ android:title="@string/init_oc" >
<PreferenceCategory android:title="@string/settings_settings" >
<CheckBoxPreference
android:defaultValue="false"
@@ -94,12 +98,15 @@
<cgeo.geocaching.settings.CapabilitiesPreference
android:title="@string/settings_features"
cgeo:connector="OC" />
+
<Preference
android:key="@string/pref_fakekey_ocde_website"
android:title="@string/settings_open_website" />
</PreferenceCategory>
</PreferenceScreen>
- <PreferenceScreen android:title="@string/init_oc_pl" >
+ <PreferenceScreen
+ android:key="@string/preference_screen_ocpl"
+ android:title="@string/init_oc_pl" >
<PreferenceCategory android:title="@string/settings_settings" >
<CheckBoxPreference
android:defaultValue="false"
@@ -119,13 +126,13 @@
<cgeo.geocaching.settings.CapabilitiesPreference
android:title="@string/settings_features"
cgeo:connector="OP" />
+
<Preference
android:key="@string/pref_fakekey_ocpl_website"
android:title="@string/settings_open_website" />
</PreferenceCategory>
</PreferenceScreen>
-
- <PreferenceScreen android:title="@string/settings_title_ec" >
+ <PreferenceScreen android:title="@string/settings_title_ec" android:key="@string/preference_screen_ec">
<PreferenceCategory android:title="@string/settings_settings" >
<CheckBoxPreference
android:defaultValue="false"
@@ -150,30 +157,31 @@
android:key="@string/pref_ecpassword"
android:singleLine="true"
android:title="@string/init_password" />
+
<cgeo.geocaching.settings.CheckECCredentialsPreference
android:dependency="@string/pref_connectorECActive"
android:title="@string/init_login" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/settings_title_appearance" >
- <ListPreference
- android:dependency="@string/pref_connectorECActive"
- android:defaultValue="1"
- android:dialogTitle="@string/init_ec_icons"
- android:key="@string/pref_ec_icons"
- android:title="@string/init_ec_icons"
- android:entries="@array/ECIcons"
- android:entryValues="@array/ECIconsValues" />
+ <ListPreference
+ android:defaultValue="1"
+ android:dependency="@string/pref_connectorECActive"
+ android:dialogTitle="@string/init_ec_icons"
+ android:entries="@array/ECIcons"
+ android:entryValues="@array/ECIconsValues"
+ android:key="@string/pref_ec_icons"
+ android:title="@string/init_ec_icons" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/settings_information" >
<cgeo.geocaching.settings.CapabilitiesPreference
android:title="@string/settings_features"
cgeo:connector="EC" />
+
<Preference
android:key="@string/pref_fakekey_ec_website"
android:title="@string/settings_open_website" />
</PreferenceCategory>
</PreferenceScreen>
-
<PreferenceScreen android:title="@string/settings_title_ox" >
<PreferenceCategory android:title="@string/settings_settings" >
<CheckBoxPreference
@@ -185,14 +193,19 @@
<cgeo.geocaching.settings.CapabilitiesPreference
android:title="@string/settings_features"
cgeo:connector="OX" />
+
<Preference
android:key="@string/pref_fakekey_ox_website"
android:title="@string/settings_open_website" />
</PreferenceCategory>
</PreferenceScreen>
-
<PreferenceScreen android:title="@string/init_gcvote" >
<PreferenceCategory android:title="@string/settings_settings" >
+ <CheckBoxPreference
+ android:defaultValue="true"
+ android:key="@string/pref_ratingwanted"
+ android:summary="@string/init_summary_ratingwanted"
+ android:title="@string/init_ratingwanted" />
<cgeo.geocaching.settings.EditPasswordPreference
android:dialogTitle="@string/init_password"
android:hint="@string/init_password"
@@ -233,7 +246,9 @@
</PreferenceScreen>
</PreferenceCategory>
<PreferenceCategory android:title="@string/settings_category_social" >
- <PreferenceScreen android:title="@string/init_twitter" >
+ <PreferenceScreen
+ android:key="@string/preference_screen_twitter"
+ android:title="@string/init_twitter" >
<CheckBoxPreference
android:defaultValue="false"
android:key="@string/pref_twitter"
@@ -307,11 +322,6 @@
android:title="@string/init_autoload" />
<CheckBoxPreference
android:defaultValue="true"
- android:key="@string/pref_ratingwanted"
- android:summary="@string/init_summary_ratingwanted"
- android:title="@string/init_ratingwanted" />
- <CheckBoxPreference
- android:defaultValue="true"
android:key="@string/pref_friendlogswanted"
android:summary="@string/init_summary_friendlogswanted"
android:title="@string/init_friendlogswanted" />
@@ -470,7 +480,7 @@
android:text="@string/init_navigation_menu_description" />
<PreferenceScreen
- android:key="@string/pref_fakekey_navigation_menu_screen"
+ android:key="@string/preference_screen_navigation_menu"
android:title="@string/settings_title_navigation_menu" >
<CheckBoxPreference
android:defaultValue="true"
@@ -609,6 +619,15 @@
android:key="@string/pref_dbonsdcard"
android:title="@string/init_dbonsdcard" />
</PreferenceCategory>
+ <PreferenceCategory android:title="@string/init_maintenance" >
+ <cgeo.geocaching.settings.TextPreference
+ android:layout="@layout/text_preference"
+ android:text="@string/init_maintenance_directories_note" />
+
+ <Preference
+ android:key="@string/pref_fakekey_preference_maintenance_directories"
+ android:title="@string/init_maintenance_directories" />
+ </PreferenceCategory>
<PreferenceCategory android:title="@string/init_debug_title" >
<cgeo.geocaching.settings.TextPreference
android:layout="@layout/text_preference"
diff --git a/main/res/xml/searchable.xml b/main/res/xml/searchable.xml
index 13e34c5..a3844cf 100644
--- a/main/res/xml/searchable.xml
+++ b/main/res/xml/searchable.xml
@@ -6,6 +6,7 @@
android:inputType="textNoSuggestions"
android:label="@string/app_name"
android:searchSettingsDescription="@string/search_bar_desc"
+ android:searchSuggestAuthority="cgeo.geocaching.search.SuggestionProvider"
android:voiceSearchMode="showVoiceSearchButton|launchRecognizer" >
</searchable> \ No newline at end of file
diff --git a/main/src/cgeo/calendar/CalendarAddon.java b/main/src/cgeo/calendar/CalendarAddon.java
new file mode 100644
index 0000000..117fb9a
--- /dev/null
+++ b/main/src/cgeo/calendar/CalendarAddon.java
@@ -0,0 +1,58 @@
+package cgeo.calendar;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.R;
+import cgeo.geocaching.geopoint.GeopointFormatter;
+import cgeo.geocaching.network.Parameters;
+import cgeo.geocaching.ui.dialog.Dialogs;
+import cgeo.geocaching.utils.ProcessUtils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import android.app.Activity;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.Uri;
+
+import java.util.Date;
+
+public class CalendarAddon {
+ public static boolean isAvailable() {
+ return ProcessUtils.isIntentAvailable(ICalendar.INTENT, Uri.parse(ICalendar.URI_SCHEME + "://" + ICalendar.URI_HOST));
+ }
+
+ public static void addToCalendarWithIntent(final Activity activity, final Geocache cache) {
+ final Resources res = activity.getResources();
+ if (CalendarAddon.isAvailable()) {
+ final Date hiddenDate = cache.getHiddenDate();
+ final Parameters params = new Parameters(
+ ICalendar.PARAM_NAME, cache.getName(),
+ ICalendar.PARAM_NOTE, StringUtils.defaultString(cache.getPersonalNote()),
+ ICalendar.PARAM_HIDDEN_DATE, hiddenDate != null ? String.valueOf(hiddenDate.getTime()) : StringUtils.EMPTY,
+ ICalendar.PARAM_URL, StringUtils.defaultString(cache.getUrl()),
+ ICalendar.PARAM_COORDS, cache.getCoords() == null ? "" : cache.getCoords().format(GeopointFormatter.Format.LAT_LON_DECMINUTE_RAW),
+ ICalendar.PARAM_LOCATION, StringUtils.defaultString(cache.getLocation()),
+ ICalendar.PARAM_SHORT_DESC, StringUtils.defaultString(cache.getShortDescription()),
+ ICalendar.PARAM_START_TIME_MINUTES, StringUtils.defaultString(cache.guessEventTimeMinutes())
+ );
+
+ activity.startActivity(new Intent(ICalendar.INTENT,
+ Uri.parse(ICalendar.URI_SCHEME + "://" + ICalendar.URI_HOST + "?" + params.toString())));
+ } else {
+ // Inform user the calendar add-on is not installed and let them get it from Google Play
+ Dialogs.confirmYesNo(activity, R.string.addon_missing_title, new StringBuilder(res.getString(R.string.helper_calendar_missing))
+ .append(' ')
+ .append(res.getString(R.string.addon_download_prompt))
+ .toString(), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ final Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(ICalendar.CALENDAR_ADDON_URI));
+ activity.startActivity(intent);
+ }
+ });
+ }
+ }
+
+}
diff --git a/main/src/cgeo/calendar/ICalendar.java b/main/src/cgeo/calendar/ICalendar.java
index 933d248..6ecb6d5 100644
--- a/main/src/cgeo/calendar/ICalendar.java
+++ b/main/src/cgeo/calendar/ICalendar.java
@@ -14,6 +14,6 @@ public interface ICalendar {
static final String PARAM_NOTE = "note"; // personal note
static final String PARAM_NAME = "name"; // cache name
static final String PARAM_LOCATION = "location"; // cache location, or empty string
- static final String PARAM_COORDS = "coords"; // cache coords, or empty string
+ static final String PARAM_COORDS = "coords"; // cache coordinates, or empty string
static final String PARAM_START_TIME_MINUTES = "time"; // time of start
}
diff --git a/main/src/cgeo/contacts/IContacts.java b/main/src/cgeo/contacts/IContacts.java
index d46a5a4..d68b78a 100644
--- a/main/src/cgeo/contacts/IContacts.java
+++ b/main/src/cgeo/contacts/IContacts.java
@@ -1,8 +1,6 @@
package cgeo.contacts;
public interface IContacts {
- static final String CALENDAR_ADDON_URI = "market://details?id=cgeo.contacts";
-
static final String INTENT = "cgeo.contacts.FIND";
static final String URI_SCHEME = "find";
diff --git a/main/src/cgeo/geocaching/AbstractPopupActivity.java b/main/src/cgeo/geocaching/AbstractPopupActivity.java
index 5f24030..38e37da 100644
--- a/main/src/cgeo/geocaching/AbstractPopupActivity.java
+++ b/main/src/cgeo/geocaching/AbstractPopupActivity.java
@@ -40,7 +40,7 @@ public abstract class AbstractPopupActivity extends AbstractActivity implements
private final GeoDirHandler geoUpdate = new GeoDirHandler() {
@Override
- protected void updateGeoData(final IGeoData geo) {
+ public void updateGeoData(final IGeoData geo) {
try {
if (geo.getCoords() != null && cache != null && cache.getCoords() != null) {
cacheDistance.setText(Units.getDistanceFromKilometers(geo.getCoords().distanceTo(cache.getCoords())));
diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java
index 4068e38..3fe37c4 100644
--- a/main/src/cgeo/geocaching/CacheDetailActivity.java
+++ b/main/src/cgeo/geocaching/CacheDetailActivity.java
@@ -3,6 +3,7 @@ package cgeo.geocaching;
import butterknife.ButterKnife;
import butterknife.InjectView;
+import cgeo.calendar.CalendarAddon;
import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.activity.AbstractViewPagerActivity;
import cgeo.geocaching.activity.Progress;
@@ -45,7 +46,6 @@ import cgeo.geocaching.utils.HtmlUtils;
import cgeo.geocaching.utils.ImageUtils;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.MatcherWrapper;
-import cgeo.geocaching.utils.RunnableWithArgument;
import cgeo.geocaching.utils.SimpleCancellableHandler;
import cgeo.geocaching.utils.SimpleHandler;
import cgeo.geocaching.utils.TextUtils;
@@ -58,6 +58,15 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
+import rx.Observable;
+import rx.Observable.OnSubscribeFunc;
+import rx.Observer;
+import rx.Subscription;
+import rx.android.observables.AndroidObservable;
+import rx.schedulers.Schedulers;
+import rx.subscriptions.Subscriptions;
+import rx.util.functions.Action1;
+
import android.R.color;
import android.app.AlertDialog;
import android.app.ProgressDialog;
@@ -80,7 +89,6 @@ import android.text.Editable;
import android.text.Html;
import android.text.Spannable;
import android.text.Spanned;
-import android.text.format.DateUtils;
import android.text.style.ForegroundColorSpan;
import android.text.style.StrikethroughSpan;
import android.text.style.StyleSpan;
@@ -109,7 +117,6 @@ import android.widget.TextView.BufferType;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Date;
import java.util.EnumSet;
import java.util.List;
import java.util.Locale;
@@ -176,24 +183,15 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
// set title in code, as the activity needs a hard coded title due to the intent filters
setTitle(res.getString(R.string.cache));
- String geocode = null;
-
- // TODO Why can it happen that search is not null? onCreate should be called only once and it is not set before.
- if (search != null) {
- cache = search.getFirstCacheFromResult(LoadFlags.LOAD_ALL_DB_ONLY);
- if (cache != null && cache.getGeocode() != null) {
- geocode = cache.getGeocode();
- }
- }
-
// get parameters
final Bundle extras = getIntent().getExtras();
final Uri uri = getIntent().getData();
// try to get data from extras
String name = null;
+ String geocode = null;
String guid = null;
- if (geocode == null && extras != null) {
+ if (extras != null) {
geocode = extras.getString(Intents.EXTRA_GEOCODE);
name = extras.getString(Intents.EXTRA_NAME);
guid = extras.getString(Intents.EXTRA_GUID);
@@ -327,6 +325,14 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
@Override
+ public void onDestroy() {
+ if (imagesList != null) {
+ imagesList.removeAllViews();
+ }
+ super.onDestroy();
+ }
+
+ @Override
public void onStop() {
if (cache != null) {
cache.setChangeNotificationHandler(null);
@@ -382,6 +388,12 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
clickedItemText = ((TextView) view).getText();
buildDetailsContextMenu(menu, res.getString(R.string.cache_logs), false);
break;
+ case R.id.date: // event date
+ assert view instanceof TextView;
+ clickedItemText = ((TextView) view).getText();
+ buildDetailsContextMenu(menu, res.getString(R.string.cache_event), true);
+ menu.findItem(R.id.menu_calendar).setVisible(cache.canBeAddedToCalendar());
+ break;
case R.id.waypoint:
menu.setHeaderTitle(selectedWaypoint.getName() + " (" + res.getString(R.string.waypoint) + ")");
getMenuInflater().inflate(R.menu.waypoint_options, menu);
@@ -484,6 +496,9 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
new ResetCoordsThread(cache, handler, selectedWaypoint, true, false, progressDialog).start();
}
return true;
+ case R.id.menu_calendar:
+ CalendarAddon.addToCalendarWithIntent(this, cache);
+ return true;
default:
break;
}
@@ -542,20 +557,19 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
if (UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) {
updateStatusMsg((String) msg.obj);
} else {
- CacheDetailActivity activity = ((CacheDetailActivity) activityRef.get());
+ final CacheDetailActivity activity = ((CacheDetailActivity) activityRef.get());
if (activity == null) {
return;
}
- SearchResult search = activity.getSearch();
- if (search == null) {
+ if (activity.search == null) {
showToast(R.string.err_dwld_details_failed);
dismissProgress();
finishActivity();
return;
}
- if (search.getError() != null) {
- activity.showToast(activity.getResources().getString(R.string.err_dwld_details_failed) + " " + search.getError().getErrorString(activity.getResources()) + ".");
+ if (activity.search.getError() != null) {
+ activity.showToast(activity.getResources().getString(R.string.err_dwld_details_failed) + " " + activity.search.getError().getErrorString(activity.getResources()) + ".");
dismissProgress();
finishActivity();
return;
@@ -972,17 +986,10 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
ownerView.setOnClickListener(new OwnerActionsClickListener(cache));
}
- // cache hidden
- final Date hiddenDate = cache.getHiddenDate();
- if (hiddenDate != null) {
- final long time = hiddenDate.getTime();
- if (time > 0) {
- String dateString = Formatter.formatFullDate(time);
- if (cache.isEventCache()) {
- dateString = DateUtils.formatDateTime(CgeoApplication.getInstance().getBaseContext(), time, DateUtils.FORMAT_SHOW_WEEKDAY) + ", " + dateString;
- }
- details.add(cache.isEventCache() ? R.string.cache_event : R.string.cache_hidden, dateString);
- }
+ // hidden or event date
+ final TextView hiddenView = details.addHiddenDate(cache);
+ if (hiddenView != null) {
+ registerForContextMenu(hiddenView);
}
// cache location
@@ -1051,9 +1058,9 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
if (Settings.getChooseList()) {
// let user select list to store cache in
new StoredList.UserInterface(CacheDetailActivity.this).promptForListSelection(R.string.list_title,
- new RunnableWithArgument<Integer>() {
+ new Action1<Integer>() {
@Override
- public void run(final Integer selectedListId) {
+ public void call(final Integer selectedListId) {
storeCache(selectedListId, new StoreCacheHandler(CacheDetailActivity.this, progress));
}
}, true, StoredList.TEMPORARY_LIST_ID);
@@ -1302,9 +1309,9 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
@Override
public void onClick(View view) {
new StoredList.UserInterface(CacheDetailActivity.this).promptForListSelection(R.string.list_title,
- new RunnableWithArgument<Integer>() {
+ new Action1<Integer>() {
@Override
- public void run(final Integer selectedListId) {
+ public void call(final Integer selectedListId) {
switchListById(selectedListId);
}
}, true, cache.getListId());
@@ -1368,7 +1375,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
final LinearLayout layout = (LinearLayout) view.findViewById(R.id.favpoint_box);
final boolean supportsFavoritePoints = cache.supportsFavoritePoints();
layout.setVisibility(supportsFavoritePoints ? View.VISIBLE : View.GONE);
- if (!supportsFavoritePoints || cache.isOwner() || !Settings.isPremiumMember()) {
+ if (!supportsFavoritePoints || cache.isOwner() || !Settings.isGCPremiumMember()) {
return;
}
final Button buttonAdd = (Button) view.findViewById(R.id.add_to_favpoint);
@@ -1470,6 +1477,10 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
protected class DescriptionViewCreator extends AbstractCachingPageViewCreator<ScrollView> {
@InjectView(R.id.personalnote) protected TextView personalNoteView;
+ @InjectView(R.id.shortdesc) protected IndexOutOfBoundsAvoidingTextView shortDescView;
+ @InjectView(R.id.longdesc) protected IndexOutOfBoundsAvoidingTextView longDescView;
+ @InjectView(R.id.show_description) protected Button showDesc;
+ @InjectView(R.id.loading) protected View loadingView;
@Override
public ScrollView getDispatchedView() {
@@ -1483,7 +1494,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
// cache short description
if (StringUtils.isNotBlank(cache.getShortDescription())) {
- new LoadDescriptionTask(cache.getShortDescription(), view.findViewById(R.id.shortdesc), null, null).execute();
+ loadDescription(cache.getShortDescription(), shortDescView, null);
}
// long description
@@ -1491,7 +1502,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
if (Settings.isAutoLoadDescription()) {
loadLongDescription();
} else {
- final Button showDesc = (Button) view.findViewById(R.id.show_description);
showDesc.setVisibility(View.VISIBLE);
showDesc.setOnClickListener(new View.OnClickListener() {
@Override
@@ -1605,12 +1615,23 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
private void loadLongDescription() {
- final Button showDesc = (Button) view.findViewById(R.id.show_description);
showDesc.setVisibility(View.GONE);
showDesc.setOnClickListener(null);
view.findViewById(R.id.loading).setVisibility(View.VISIBLE);
- new LoadDescriptionTask(cache.getDescription(), view.findViewById(R.id.longdesc), view.findViewById(R.id.loading), view.findViewById(R.id.shortdesc)).execute();
+ final String longDescription = cache.getDescription();
+ loadDescription(longDescription, longDescView, loadingView);
+
+ // Hide the short description, if it is contained somewhere at the start of the long description.
+ if (shortDescView != null) {
+ final String shortDescription = cache.getShortDescription();
+ if (StringUtils.isNotBlank(shortDescription)) {
+ final int index = longDescription.indexOf(shortDescription);
+ if (index >= 0 && index < 200) {
+ shortDescView.setVisibility(View.GONE);
+ }
+ }
+ }
}
private void warnPersonalNoteNeedsStoring() {
@@ -1641,148 +1662,119 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
- /**
- * Loads the description in background. <br />
- * <br />
- * Params:
- * <ol>
- * <li>description string (String)</li>
- * <li>target description view (TextView)</li>
- * <li>loading indicator view (View, may be null)</li>
- * </ol>
- */
- private class LoadDescriptionTask extends AsyncTask<Object, Void, Void> {
- private final View loadingIndicatorView;
- private final IndexOutOfBoundsAvoidingTextView descriptionView;
- private final String descriptionString;
- private Spanned description;
- private final View shortDescView;
+ /**
+ * Load the description in the background.
+ * @param descriptionString the HTML description as retrieved from the connector
+ * @param descriptionView the view to fill
+ * @param loadingIndicatorView the loading indicator view, will be hidden when completed
+ */
+ private void loadDescription(final String descriptionString, final IndexOutOfBoundsAvoidingTextView descriptionView, final View loadingIndicatorView) {
+ // The producer produces successives (without then with images) versions of the description.
+ final Observable<Spanned> producer = Observable.create(new OnSubscribeFunc<Spanned>() {
+ @Override
+ public Subscription onSubscribe(final Observer<? super Spanned> observer) {
+ try {
+ // Fast preview: parse only HTML without loading any images
+ final HtmlImageCounter imageCounter = new HtmlImageCounter();
+ final UnknownTagsHandler unknownTagsHandler = new UnknownTagsHandler();
+ Spanned description = Html.fromHtml(descriptionString, imageCounter, unknownTagsHandler);
+ addWarning(unknownTagsHandler, description);
+ observer.onNext(description);
+
+ if (imageCounter.getImageCount() > 0) {
+ // Complete view: parse again with loading images - if necessary ! If there are any images causing problems the user can see at least the preview
+ description = Html.fromHtml(descriptionString, new HtmlImage(cache.getGeocode(), true, cache.getListId(), false), unknownTagsHandler);
+ addWarning(unknownTagsHandler, description);
+ observer.onNext(description);
+ }
- public LoadDescriptionTask(final String description, final View descriptionView, final View loadingIndicatorView, final View shortDescView) {
- assert descriptionView instanceof IndexOutOfBoundsAvoidingTextView;
- this.descriptionString = description;
- this.descriptionView = (IndexOutOfBoundsAvoidingTextView) descriptionView;
- this.loadingIndicatorView = loadingIndicatorView;
- this.shortDescView = shortDescView;
- }
+ observer.onCompleted();
+ } catch (final Exception e) {
+ Log.e("loadDescription", e);
+ observer.onError(e);
+ }
+ return Subscriptions.empty();
+ }
- @Override
- protected Void doInBackground(Object... params) {
- try {
- // Fast preview: parse only HTML without loading any images
- final HtmlImageCounter imageCounter = new HtmlImageCounter();
- final UnknownTagsHandler unknownTagsHandler = new UnknownTagsHandler();
- description = Html.fromHtml(descriptionString, imageCounter, unknownTagsHandler);
- publishProgress();
-
- boolean needsRefresh = false;
- if (imageCounter.getImageCount() > 0) {
- // Complete view: parse again with loading images - if necessary ! If there are any images causing problems the user can see at least the preview
- description = Html.fromHtml(descriptionString, new HtmlImage(cache.getGeocode(), true, cache.getListId(), false), unknownTagsHandler);
- needsRefresh = true;
- }
-
- // If description has an HTML construct which may be problematic to render, add a note at the end of the long description.
- // Technically, it may not be a table, but a pre, which has the same problems as a table, so the message is ok even though
- // sometimes technically incorrect.
- if (unknownTagsHandler.isProblematicDetected() && descriptionView != null) {
+ // If description has an HTML construct which may be problematic to render, add a note at the end of the long description.
+ // Technically, it may not be a table, but a pre, which has the same problems as a table, so the message is ok even though
+ // sometimes technically incorrect.
+ private void addWarning(final UnknownTagsHandler unknownTagsHandler, final Spanned description) {
+ if (unknownTagsHandler.isProblematicDetected()) {
final int startPos = description.length();
final IConnector connector = ConnectorFactory.getConnector(cache);
final Spanned tableNote = Html.fromHtml(res.getString(R.string.cache_description_table_note, "<a href=\"" + cache.getUrl() + "\">" + connector.getName() + "</a>"));
((Editable) description).append("\n\n").append(tableNote);
((Editable) description).setSpan(new StyleSpan(Typeface.ITALIC), startPos, description.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- needsRefresh = true;
- }
-
- if (needsRefresh) {
- publishProgress();
}
- } catch (final Exception e) {
- Log.e("LoadDescriptionTask: ", e);
}
- return null;
- }
-
- @Override
- protected void onProgressUpdate(Void... values) {
- if (description == null) {
- showToast(res.getString(R.string.err_load_descr_failed));
- return;
- }
- if (StringUtils.isNotBlank(descriptionString)) {
- try {
- descriptionView.setText(description, TextView.BufferType.SPANNABLE);
- } catch (final Exception e) {
- // On 4.1, there is sometimes a crash on measuring the layout: https://code.google.com/p/android/issues/detail?id=35412
- Log.e("Android bug setting text: ", e);
- // remove the formatting by converting to a simple string
- descriptionView.setText(description.toString());
- }
- descriptionView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
- fixTextColor(descriptionView, descriptionString);
- descriptionView.setVisibility(View.VISIBLE);
- registerForContextMenu(descriptionView);
-
- hideDuplicatedShortDescription();
- }
- }
+ });
- /**
- * Hide the short description, if it is contained somewhere at the start of the long description.
- */
- private void hideDuplicatedShortDescription() {
- if (shortDescView != null) {
- final String shortDescription = cache.getShortDescription();
- if (StringUtils.isNotBlank(shortDescription)) {
- final int index = descriptionString.indexOf(shortDescription);
- if (index >= 0 && index < 200) {
- shortDescView.setVisibility(View.GONE);
+ AndroidObservable.fromActivity(this, producer.subscribeOn(Schedulers.io()))
+ .subscribe(new Observer<Spanned>() {
+ @Override
+ public void onCompleted() {
+ if (null != loadingIndicatorView) {
+ loadingIndicatorView.setVisibility(View.GONE);
+ }
}
- }
- }
- }
- @Override
- protected void onPostExecute(Void result) {
- if (null != loadingIndicatorView) {
- loadingIndicatorView.setVisibility(View.GONE);
- }
- }
+ @Override
+ public void onError(final Throwable throwable) {
+ showToast(res.getString(R.string.err_load_descr_failed));
+ }
- /**
- * Handle caches with black font color in dark skin and white font color in light skin
- * by changing background color of the view
- *
- * @param view
- * containing the text
- * @param text
- * to be checked
- */
- private void fixTextColor(final TextView view, final String text) {
- int backcolor;
- if (Settings.isLightSkin()) {
- backcolor = color.white;
-
- for (final Pattern pattern : LIGHT_COLOR_PATTERNS) {
- final MatcherWrapper matcher = new MatcherWrapper(pattern, text);
- if (matcher.find()) {
- view.setBackgroundResource(color.darker_gray);
- return;
+ @Override
+ public void onNext(final Spanned description) {
+ if (StringUtils.isNotBlank(descriptionString)) {
+ try {
+ descriptionView.setText(description, TextView.BufferType.SPANNABLE);
+ } catch (final Exception e) {
+ // On 4.1, there is sometimes a crash on measuring the layout: https://code.google.com/p/android/issues/detail?id=35412
+ Log.e("Android bug setting text: ", e);
+ // remove the formatting by converting to a simple string
+ descriptionView.setText(description.toString());
+ }
+ descriptionView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
+ fixTextColor(descriptionString);
+ descriptionView.setVisibility(View.VISIBLE);
+ registerForContextMenu(descriptionView);
+ }
}
- }
- } else {
- backcolor = color.black;
- for (final Pattern pattern : DARK_COLOR_PATTERNS) {
- final MatcherWrapper matcher = new MatcherWrapper(pattern, text);
- if (matcher.find()) {
- view.setBackgroundResource(color.darker_gray);
- return;
+ /**
+ * Handle caches with black font color in dark skin and white font color in light skin
+ * by changing background color of the view
+ *
+ * @param text
+ * to be checked
+ */
+ private void fixTextColor(final String text) {
+ int backcolor;
+ if (Settings.isLightSkin()) {
+ backcolor = color.white;
+
+ for (final Pattern pattern : LIGHT_COLOR_PATTERNS) {
+ final MatcherWrapper matcher = new MatcherWrapper(pattern, text);
+ if (matcher.find()) {
+ descriptionView.setBackgroundResource(color.darker_gray);
+ return;
+ }
+ }
+ } else {
+ backcolor = color.black;
+
+ for (final Pattern pattern : DARK_COLOR_PATTERNS) {
+ final MatcherWrapper matcher = new MatcherWrapper(pattern, text);
+ if (matcher.find()) {
+ descriptionView.setBackgroundResource(color.darker_gray);
+ return;
+ }
+ }
+ }
+ descriptionView.setBackgroundResource(backcolor);
}
- }
- }
- view.setBackgroundResource(backcolor);
- }
+ });
}
private class WaypointsViewCreator extends AbstractCachingPageViewCreator<ListView> {
@@ -2255,10 +2247,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
return cache;
}
- public SearchResult getSearch() {
- return search;
- }
-
private static class StoreCacheHandler extends SimpleCancellableHandler {
public StoreCacheHandler(CacheDetailActivity activity, Progress progress) {
diff --git a/main/src/cgeo/geocaching/CacheListActivity.java b/main/src/cgeo/geocaching/CacheListActivity.java
index cc8b178..a12663d 100644
--- a/main/src/cgeo/geocaching/CacheListActivity.java
+++ b/main/src/cgeo/geocaching/CacheListActivity.java
@@ -8,7 +8,7 @@ import cgeo.geocaching.activity.Progress;
import cgeo.geocaching.apps.cache.navi.NavigationAppFactory;
import cgeo.geocaching.apps.cachelist.CacheListAppFactory;
import cgeo.geocaching.compatibility.Compatibility;
-import cgeo.geocaching.connector.gc.SearchHandler;
+import cgeo.geocaching.connector.gc.RecaptchaHandler;
import cgeo.geocaching.enumerations.CacheListType;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LoadFlags;
@@ -18,11 +18,13 @@ import cgeo.geocaching.files.GPXImporter;
import cgeo.geocaching.filter.FilterUserInterface;
import cgeo.geocaching.filter.IFilter;
import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.list.PseudoList;
import cgeo.geocaching.list.StoredList;
import cgeo.geocaching.loaders.AbstractSearchLoader;
import cgeo.geocaching.loaders.AbstractSearchLoader.CacheListLoaderType;
import cgeo.geocaching.loaders.AddressGeocacheListLoader;
import cgeo.geocaching.loaders.CoordsGeocacheListLoader;
+import cgeo.geocaching.loaders.FinderGeocacheListLoader;
import cgeo.geocaching.loaders.HistoryGeocacheListLoader;
import cgeo.geocaching.loaders.KeywordGeocacheListLoader;
import cgeo.geocaching.loaders.NextPageGeocacheListLoader;
@@ -30,7 +32,6 @@ import cgeo.geocaching.loaders.OfflineGeocacheListLoader;
import cgeo.geocaching.loaders.OwnerGeocacheListLoader;
import cgeo.geocaching.loaders.PocketGeocacheListLoader;
import cgeo.geocaching.loaders.RemoveFromHistoryLoader;
-import cgeo.geocaching.loaders.FinderGeocacheListLoader;
import cgeo.geocaching.maps.CGeoMap;
import cgeo.geocaching.network.Cookies;
import cgeo.geocaching.network.Network;
@@ -43,10 +44,10 @@ import cgeo.geocaching.ui.LoggingUI;
import cgeo.geocaching.ui.WeakReferenceHandler;
import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.AsyncTaskWithProgress;
+import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.DateUtils;
import cgeo.geocaching.utils.GeoDirHandler;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.RunnableWithArgument;
import ch.boye.httpclientandroidlib.HttpResponse;
@@ -55,6 +56,8 @@ import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import rx.util.functions.Action1;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
@@ -93,7 +96,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
private static final int MAX_LIST_ITEMS = 1000;
private static final int MSG_DONE = -1;
- private static final int MSG_CANCEL = -99;
private static final int REQUEST_CODE_IMPORT_GPX = 1;
@@ -111,8 +113,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
private int detailTotal = 0;
private int detailProgress = 0;
private long detailProgressTime = 0L;
- private LoadDetailsThread threadDetails = null;
- private LoadFromWebThread threadWeb = null;
private int listId = StoredList.TEMPORARY_LIST_ID; // Only meaningful for the OFFLINE type
private final GeoDirHandler geoDirHandler = new GeoDirHandler() {
@@ -267,10 +267,10 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
}
- private final Handler loadDetailsHandler = new Handler() {
+ private final CancellableHandler loadDetailsHandler = new CancellableHandler() {
@Override
- public void handleMessage(Message msg) {
+ public void handleRegularMessage(Message msg) {
setAdapter();
if (msg.what > -1) {
@@ -287,10 +287,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
} else {
progress.setMessage(res.getString(R.string.caches_downloading) + " " + minutesRemaining + " " + res.getQuantityString(R.plurals.caches_eta_mins, minutesRemaining));
}
- } else if (msg.what == MSG_CANCEL) {
- if (threadDetails != null) {
- threadDetails.kill();
- }
} else {
if (search != null) {
final Set<Geocache> cacheListTmp = search.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB);
@@ -304,13 +300,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
showProgress(false);
progress.dismiss();
-
- if (!isPaused()) {
- // If the current activity has been paused, then we do not want to fiddle with the
- // GPS and direction states. If the activity later gets resumed, its onResume()
- // function will take care of turning the GPS back on.
- startGeoAndDir();
- }
}
}
};
@@ -318,9 +307,9 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
/**
* TODO Possibly parts should be a Thread not a Handler
*/
- private final Handler downloadFromWebHandler = new Handler() {
+ private final CancellableHandler downloadFromWebHandler = new CancellableHandler() {
@Override
- public void handleMessage(Message msg) {
+ public void handleRegularMessage(Message msg) {
setAdapter();
adapter.notifyDataSetChanged();
@@ -340,10 +329,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
progress.dismiss();
showToast(res.getString(R.string.sendToCgeo_no_registration));
finish();
- } else if (msg.what == MSG_CANCEL) {
- if (threadWeb != null) {
- threadWeb.kill();
- }
} else {
adapter.setSelectMode(false);
@@ -353,19 +338,17 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
}
};
- private final Handler clearOfflineLogsHandler = new Handler() {
+ private final CancellableHandler clearOfflineLogsHandler = new CancellableHandler() {
@Override
- public void handleMessage(Message msg) {
- if (msg.what != MSG_CANCEL) {
- adapter.setSelectMode(false);
+ public void handleRegularMessage(Message msg) {
+ adapter.setSelectMode(false);
- refreshCurrentList();
+ refreshCurrentList();
- replaceCacheListFromSearch();
+ replaceCacheListFromSearch();
- progress.dismiss();
- }
+ progress.dismiss();
}
};
@@ -402,7 +385,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
if (isInvokedFromAttachment()) {
type = CacheListType.OFFLINE;
if (coords == null) {
- coords = new Geopoint(0.0, 0.0);
+ coords = Geopoint.ZERO;
}
}
@@ -422,7 +405,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
prepareFilterBar();
- currentLoader = (AbstractSearchLoader) getSupportLoaderManager().initLoader(type.ordinal(), extras, this);
+ currentLoader = (AbstractSearchLoader) getSupportLoaderManager().initLoader(type.getLoaderId(), extras, this);
// init
if (CollectionUtils.isNotEmpty(cacheList)) {
@@ -458,10 +441,10 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
private void importGpxAttachement() {
- new StoredList.UserInterface(this).promptForListSelection(R.string.gpx_import_select_list_title, new RunnableWithArgument<Integer>() {
+ new StoredList.UserInterface(this).promptForListSelection(R.string.gpx_import_select_list_title, new Action1<Integer>() {
@Override
- public void run(Integer listId) {
+ public void call(Integer listId) {
new GPXImporter(CacheListActivity.this, listId, importGpxAttachementFinishedHandler).importGPX();
switchListById(listId);
}
@@ -472,12 +455,15 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
public void onResume() {
super.onResume();
- startGeoAndDir();
+ geoDirHandler.startGeo();
+ if (Settings.isLiveMap()) {
+ geoDirHandler.startDir();
+ }
adapter.setSelectMode(false);
setAdapterCurrentCoordinates(true);
- if (loadCachesHandler != null && search != null) {
+ if (search != null) {
replaceCacheListFromSearch();
loadCachesHandler.sendEmptyMessage(0);
}
@@ -503,8 +489,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
@Override
public void onPause() {
- removeGeoAndDir();
-
+ geoDirHandler.stopGeoAndDir();
super.onPause();
}
@@ -675,9 +660,9 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
return true;
case R.id.menu_sort:
final CacheComparator oldComparator = adapter.getCacheComparator();
- new ComparatorUserInterface(this).selectComparator(oldComparator, new RunnableWithArgument<CacheComparator>() {
+ new ComparatorUserInterface(this).selectComparator(oldComparator, new Action1<CacheComparator>() {
@Override
- public void run(CacheComparator selectedComparator) {
+ public void call(CacheComparator selectedComparator) {
// selecting the same sorting twice will toggle the order
if (selectedComparator != null && oldComparator != null && selectedComparator.getClass().equals(oldComparator.getClass())) {
adapter.toggleInverseSort();
@@ -728,7 +713,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
public void clearOfflineLogs() {
- progress.show(this, null, res.getString(R.string.caches_clear_offlinelogs_progress), true, clearOfflineLogsHandler.obtainMessage(MSG_CANCEL));
+ progress.show(this, null, res.getString(R.string.caches_clear_offlinelogs_progress), true, clearOfflineLogsHandler.cancelMessage());
new ClearOfflineLogsThread(clearOfflineLogsHandler).start();
}
@@ -737,13 +722,12 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
*/
@Override
public void showFilterMenu(final View view) {
- new FilterUserInterface(this).selectFilter(new RunnableWithArgument<IFilter>() {
+ new FilterUserInterface(this).selectFilter(new Action1<IFilter>() {
@Override
- public void run(IFilter selectedFilter) {
+ public void call(IFilter selectedFilter) {
if (selectedFilter != null) {
setFilter(selectedFilter);
- }
- else {
+ } else {
// clear filter
setFilter(null);
}
@@ -793,10 +777,10 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
private void moveCachesToOtherList() {
- new StoredList.UserInterface(this).promptForListSelection(R.string.cache_menu_move_list, new RunnableWithArgument<Integer>() {
+ new StoredList.UserInterface(this).promptForListSelection(R.string.cache_menu_move_list, new Action1<Integer>() {
@Override
- public void run(Integer newListId) {
+ public void call(Integer newListId) {
DataStore.moveToList(adapter.getCheckedOrAllCaches(), newListId);
adapter.setSelectMode(false);
@@ -850,10 +834,10 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
});
break;
case R.id.menu_move_to_list:
- new StoredList.UserInterface(this).promptForListSelection(R.string.cache_menu_move_list, new RunnableWithArgument<Integer>() {
+ new StoredList.UserInterface(this).promptForListSelection(R.string.cache_menu_move_list, new Action1<Integer>() {
@Override
- public void run(Integer newListId) {
+ public void call(Integer newListId) {
DataStore.moveToList(Collections.singletonList(cache), newListId);
adapter.setSelectMode(false);
refreshCurrentList();
@@ -960,7 +944,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
boolean enableMore = (type != CacheListType.OFFLINE && cacheList.size() < MAX_LIST_ITEMS);
if (enableMore && search != null) {
final int count = search.getTotalCountGC();
- enableMore = enableMore && count > 0 && cacheList.size() < count;
+ enableMore = count > 0 && cacheList.size() < count;
}
if (enableMore) {
@@ -973,17 +957,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
listFooter.setClickable(enableMore);
}
- private void startGeoAndDir() {
- geoDirHandler.startGeo();
- if (Settings.isLiveMap()) {
- geoDirHandler.startDir();
- }
- }
-
- private void removeGeoAndDir() {
- geoDirHandler.stopGeoAndDir();
- }
-
private void importGpx() {
GpxFileListActivity.startSubActivity(this, listId);
}
@@ -1002,7 +975,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
// provided to this method as a parameter. Pull that uri using "resultData.getData()"
if (data != null) {
final Uri uri = data.getData();
- new GPXImporter(CacheListActivity.this, listId, importGpxAttachementFinishedHandler).importGPX(uri, null, getDisplayName(uri));
+ new GPXImporter(this, listId, importGpxAttachementFinishedHandler).importGPX(uri, null, getDisplayName(uri));
}
}
@@ -1038,9 +1011,9 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
if (Settings.getChooseList() && type != CacheListType.OFFLINE) {
// let user select list to store cache in
new StoredList.UserInterface(this).promptForListSelection(R.string.list_title,
- new RunnableWithArgument<Integer>() {
+ new Action1<Integer>() {
@Override
- public void run(final Integer selectedListId) {
+ public void call(final Integer selectedListId) {
refreshStored(caches, selectedListId);
}
}, true, StoredList.TEMPORARY_LIST_ID, newListName);
@@ -1062,12 +1035,12 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
message = res.getString(R.string.caches_downloading) + " " + etaTime + " " + res.getQuantityString(R.plurals.caches_eta_mins, etaTime);
}
- progress.show(this, null, message, ProgressDialog.STYLE_HORIZONTAL, loadDetailsHandler.obtainMessage(MSG_CANCEL));
+ progress.show(this, null, message, ProgressDialog.STYLE_HORIZONTAL, loadDetailsHandler.cancelMessage());
progress.setMaxProgressAndReset(detailTotal);
detailProgressTime = System.currentTimeMillis();
- threadDetails = new LoadDetailsThread(loadDetailsHandler, caches, storeListId);
+ final LoadDetailsThread threadDetails = new LoadDetailsThread(loadDetailsHandler, caches, storeListId);
threadDetails.start();
}
@@ -1091,16 +1064,16 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
final Bundle b = new Bundle();
b.putStringArray(Intents.EXTRA_CACHELIST, geocodes);
- getSupportLoaderManager().initLoader(CacheListLoaderType.REMOVE_FROM_HISTORY.ordinal(), b, this);
+ getSupportLoaderManager().initLoader(CacheListLoaderType.REMOVE_FROM_HISTORY.getLoaderId(), b, this);
}
public void importWeb() {
detailProgress = 0;
showProgress(false);
- progress.show(this, null, res.getString(R.string.web_import_waiting), true, downloadFromWebHandler.obtainMessage(MSG_CANCEL));
+ progress.show(this, null, res.getString(R.string.web_import_waiting), true, downloadFromWebHandler.cancelMessage());
- threadWeb = new LoadFromWebThread(downloadFromWebHandler, listId);
+ final LoadFromWebThread threadWeb = new LoadFromWebThread(downloadFromWebHandler, listId);
threadWeb.start();
}
@@ -1127,26 +1100,20 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
private class LoadDetailsThread extends Thread {
- final private Handler handler;
+ final private CancellableHandler handler;
final private int listIdLD;
- private volatile boolean needToStop = false;
final private List<Geocache> caches;
- public LoadDetailsThread(Handler handlerIn, List<Geocache> caches, int listId) {
- handler = handlerIn;
+ public LoadDetailsThread(CancellableHandler handler, List<Geocache> caches, int listId) {
+ this.handler = handler;
this.caches = caches;
// in case of online lists, set the list id to the standard list
this.listIdLD = Math.max(listId, StoredList.STANDARD_LIST_ID);
}
- public void kill() {
- needToStop = true;
- }
-
@Override
public void run() {
- removeGeoAndDir();
// First refresh caches that do not yet have static maps to get them a chance to get a copy
// before the limit expires, unless we do not want to store offline maps.
final List<Geocache> allCaches = Settings.isStoreOfflineMaps() ?
@@ -1173,7 +1140,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
*/
private boolean refreshCache(Geocache cache) {
try {
- if (needToStop) {
+ if (handler.isCancelled()) {
throw new InterruptedException("Stopped storing process.");
}
detailProgress++;
@@ -1190,31 +1157,23 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
}
- private class LoadFromWebThread extends Thread {
+ private static class LoadFromWebThread extends Thread {
- final private Handler handler;
+ final private CancellableHandler handler;
final private int listIdLFW;
- private volatile boolean needToStop = false;
- public LoadFromWebThread(Handler handlerIn, int listId) {
- handler = handlerIn;
+ public LoadFromWebThread(CancellableHandler handler, int listId) {
+ this.handler = handler;
listIdLFW = StoredList.getConcreteList(listId);
}
- public void kill() {
- needToStop = true;
- }
-
@Override
public void run() {
-
- removeGeoAndDir();
-
int delay = -1;
int times = 0;
int ret = MSG_DONE;
- while (!needToStop && times < 3 * 60 / 5) { // maximum: 3 minutes, every 5 seconds
+ while (!handler.isCancelled() && times < 3 * 60 / 5) { // maximum: 3 minutes, every 5 seconds
//download new code
String deviceCode = Settings.getWebDeviceCode();
if (deviceCode == null) {
@@ -1238,7 +1197,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
//Server returned RG (registration) and this device no longer registered.
Settings.setWebNameCode(null, null);
ret = -3;
- needToStop = true;
+ handler.cancel();
break;
} else {
delay = 0;
@@ -1248,7 +1207,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
if (responseFromWeb == null || responseFromWeb.getStatusLine().getStatusCode() != 200) {
ret = -2;
- needToStop = true;
+ handler.cancel();
break;
}
@@ -1267,8 +1226,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
handler.sendEmptyMessage(ret);
-
- startGeoAndDir();
}
}
@@ -1283,9 +1240,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
@Override
protected Void doInBackgroundInternal(Geocache[] caches) {
- removeGeoAndDir();
DataStore.markDropped(Arrays.asList(caches));
- startGeoAndDir();
return null;
}
@@ -1328,7 +1283,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
showFooterLoadingCaches();
listFooter.setOnClickListener(null);
- getSupportLoaderManager().restartLoader(CacheListLoaderType.NEXT_PAGE.ordinal(), null, CacheListActivity.this);
+ getSupportLoaderManager().restartLoader(CacheListLoaderType.NEXT_PAGE.getLoaderId(), null, CacheListActivity.this);
}
}
@@ -1349,11 +1304,11 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
@NonNull
- private RunnableWithArgument<Integer> getListSwitchingRunnable() {
- return new RunnableWithArgument<Integer>() {
+ private Action1<Integer> getListSwitchingRunnable() {
+ return new Action1<Integer>() {
@Override
- public void run(final Integer selectedListId) {
+ public void call(final Integer selectedListId) {
switchListById(selectedListId);
}
};
@@ -1364,6 +1319,12 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
return;
}
+ if (id == PseudoList.HISTORY_LIST.id) {
+ CacheListActivity.startActivityHistory(this);
+ finish();
+ return;
+ }
+
final StoredList list = DataStore.getList(id);
if (list == null) {
return;
@@ -1378,7 +1339,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
showFooterLoadingCaches();
DataStore.moveToList(adapter.getCheckedCaches(), listId);
- currentLoader = (OfflineGeocacheListLoader) getSupportLoaderManager().initLoader(CacheListType.OFFLINE.ordinal(), new Bundle(), this);
+ currentLoader = (OfflineGeocacheListLoader) getSupportLoaderManager().initLoader(CacheListType.OFFLINE.getLoaderId(), new Bundle(), this);
currentLoader.reset();
((OfflineGeocacheListLoader) currentLoader).setListId(listId);
((OfflineGeocacheListLoader) currentLoader).setSearchCenter(coords);
@@ -1483,12 +1444,12 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
return true;
}
- public static void startActivityUserName(final Activity context, final String userName) {
+ public static void startActivityFinder(final Activity context, final String userName) {
if (!isValidUsername(context, userName)) {
return;
}
final Intent cachesIntent = new Intent(context, CacheListActivity.class);
- cachesIntent.putExtra(Intents.EXTRA_LIST_TYPE, CacheListType.USERNAME);
+ cachesIntent.putExtra(Intents.EXTRA_LIST_TYPE, CacheListType.FINDER);
cachesIntent.putExtra(Intents.EXTRA_USERNAME, userName);
context.startActivity(cachesIntent);
}
@@ -1606,6 +1567,9 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
} else {
final StoredList list = DataStore.getList(listId);
// list.id may be different if listId was not valid
+ if (list.id != listId) {
+ showToast(getString(R.string.list_not_available));
+ }
listId = list.id;
title = list.title;
}
@@ -1670,8 +1634,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
break;
case POCKET:
final String guid = extras.getString(Intents.EXTRA_POCKET_GUID);
- final String pocket_name = extras.getString(Intents.EXTRA_NAME);
- title = pocket_name;
+ title = extras.getString(Intents.EXTRA_NAME);
loader = new PocketGeocacheListLoader(app, guid);
break;
}
@@ -1680,7 +1643,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
showFooterLoadingCaches();
if (loader != null) {
- loader.setRecaptchaHandler(new SearchHandler(this, res, loader));
+ loader.setRecaptchaHandler(new RecaptchaHandler(this, loader));
}
return loader;
}
diff --git a/main/src/cgeo/geocaching/CacheMenuHandler.java b/main/src/cgeo/geocaching/CacheMenuHandler.java
index d0f1005..cfe9eeb 100644
--- a/main/src/cgeo/geocaching/CacheMenuHandler.java
+++ b/main/src/cgeo/geocaching/CacheMenuHandler.java
@@ -1,27 +1,17 @@
package cgeo.geocaching;
-import cgeo.calendar.ICalendar;
+import cgeo.calendar.CalendarAddon;
import cgeo.geocaching.apps.cache.navi.NavigationAppFactory;
-import cgeo.geocaching.geopoint.GeopointFormatter;
-import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.ui.AbstractUIFactory;
-import cgeo.geocaching.ui.dialog.Dialogs;
-import cgeo.geocaching.utils.ProcessUtils;
-
-import org.apache.commons.lang3.StringUtils;
import android.app.Activity;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.net.Uri;
import android.view.Menu;
import android.view.MenuItem;
-import java.util.Date;
-
/**
- * Shared menu handling for all activities having menu items related to a cache.
- *
+ * Shared menu handling for all activities having menu items related to a cache. <br>
+ * TODO: replace by a fragment
+ *
*/
public class CacheMenuHandler extends AbstractUIFactory {
@@ -58,7 +48,7 @@ public class CacheMenuHandler extends AbstractUIFactory {
cache.shareCache(activity, res);
return true;
case R.id.menu_calendar:
- addToCalendarWithIntent(activity, cache);
+ CalendarAddon.addToCalendarWithIntent(activity, cache);
return true;
default:
return false;
@@ -84,39 +74,4 @@ public class CacheMenuHandler extends AbstractUIFactory {
activity.getMenuInflater().inflate(R.menu.cache_options, menu);
onPrepareOptionsMenu(menu, cache);
}
-
- private static void addToCalendarWithIntent(final Activity activity, final Geocache cache) {
- final boolean calendarAddOnAvailable = ProcessUtils.isIntentAvailable(ICalendar.INTENT, Uri.parse(ICalendar.URI_SCHEME + "://" + ICalendar.URI_HOST));
-
- if (calendarAddOnAvailable) {
- final Date hiddenDate = cache.getHiddenDate();
- final Parameters params = new Parameters(
- ICalendar.PARAM_NAME, cache.getName(),
- ICalendar.PARAM_NOTE, StringUtils.defaultString(cache.getPersonalNote()),
- ICalendar.PARAM_HIDDEN_DATE, hiddenDate != null ? String.valueOf(hiddenDate.getTime()) : StringUtils.EMPTY,
- ICalendar.PARAM_URL, StringUtils.defaultString(cache.getUrl()),
- ICalendar.PARAM_COORDS, cache.getCoords() == null ? "" : cache.getCoords().format(GeopointFormatter.Format.LAT_LON_DECMINUTE_RAW),
- ICalendar.PARAM_LOCATION, StringUtils.defaultString(cache.getLocation()),
- ICalendar.PARAM_SHORT_DESC, StringUtils.defaultString(cache.getShortDescription()),
- ICalendar.PARAM_START_TIME_MINUTES, StringUtils.defaultString(cache.guessEventTimeMinutes())
- );
-
- activity.startActivity(new Intent(ICalendar.INTENT,
- Uri.parse(ICalendar.URI_SCHEME + "://" + ICalendar.URI_HOST + "?" + params.toString())));
- } else {
- // Inform user the calendar add-on is not installed and let them get it from Google Play
- Dialogs.confirmYesNo(activity, R.string.addon_missing_title, new StringBuilder(res.getString(R.string.helper_calendar_missing))
- .append(' ')
- .append(res.getString(R.string.addon_download_prompt))
- .toString(), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- final Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(ICalendar.CALENDAR_ADDON_URI));
- activity.startActivity(intent);
- }
- });
- }
- }
-
}
diff --git a/main/src/cgeo/geocaching/CachePopup.java b/main/src/cgeo/geocaching/CachePopup.java
index 9186497..5d04ab0 100644
--- a/main/src/cgeo/geocaching/CachePopup.java
+++ b/main/src/cgeo/geocaching/CachePopup.java
@@ -9,9 +9,9 @@ import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.CacheDetailsCreator;
import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.RunnableWithArgument;
import org.apache.commons.lang3.StringUtils;
+import rx.util.functions.Action1;
import android.content.Context;
import android.content.Intent;
@@ -110,9 +110,9 @@ public class CachePopup extends AbstractPopupActivity {
if (Settings.getChooseList()) {
// let user select list to store cache in
new StoredList.UserInterface(CachePopup.this).promptForListSelection(R.string.list_title,
- new RunnableWithArgument<Integer>() {
+ new Action1<Integer>() {
@Override
- public void run(final Integer selectedListId) {
+ public void call(final Integer selectedListId) {
storeCache(selectedListId);
}
}, true, StoredList.TEMPORARY_LIST_ID);
diff --git a/main/src/cgeo/geocaching/CgeoApplication.java b/main/src/cgeo/geocaching/CgeoApplication.java
index 2500d10..7bee97e 100644
--- a/main/src/cgeo/geocaching/CgeoApplication.java
+++ b/main/src/cgeo/geocaching/CgeoApplication.java
@@ -1,10 +1,10 @@
package cgeo.geocaching;
-import cgeo.geocaching.network.StatusUpdater;
import cgeo.geocaching.ui.dialog.Dialogs;
-import cgeo.geocaching.utils.IObserver;
import cgeo.geocaching.utils.Log;
+import rx.Observable;
+
import android.app.Activity;
import android.app.Application;
import android.app.ProgressDialog;
@@ -14,12 +14,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
public class CgeoApplication extends Application {
- private volatile GeoDataProvider geo;
- private volatile DirectionProvider dir;
+ private volatile Observable<IGeoData> geo;
+ private volatile Observable<Float> dir;
private boolean forceRelog = false; // c:geo needs to log into cache providers
public boolean showLoginToast = true; //login toast shown just once.
- private boolean liveMapHintShown = false; // livemap hint has been shown
- final private StatusUpdater statusUpdater = new StatusUpdater();
+ private boolean liveMapHintShownInThisSession = false; // livemap hint has been shown
private static CgeoApplication instance;
public CgeoApplication() {
@@ -35,26 +34,11 @@ public class CgeoApplication extends Application {
}
@Override
- public void onCreate() {
- new Thread(statusUpdater).start();
- }
-
- @Override
public void onLowMemory() {
Log.i("Cleaning applications cache.");
DataStore.removeAllFromCache();
}
- @Override
- public void onTerminate() {
- Log.d("Terminating c:geo…");
-
- DataStore.clean();
- DataStore.closeDb();
-
- super.onTerminate();
- }
-
/**
* Move the database to/from external cgdata in a new thread,
* showing a progress window
@@ -82,29 +66,11 @@ public class CgeoApplication extends Application {
}.start();
}
- /**
- * Register an observer to receive GeoData information.
- * <br/>
- * If there is a chance that no observers are registered before this
- * method is called, it is necessary to call it from a task implementing
- * a looper interface as the data provider will use listeners that
- * require a looper thread to run.
- *
- * @param observer a geodata observer
- */
- public void addGeoObserver(final IObserver<? super IGeoData> observer) {
- currentGeoObject().addObserver(observer);
- }
-
- public void deleteGeoObserver(final IObserver<? super IGeoData> observer) {
- currentGeoObject().deleteObserver(observer);
- }
-
- private GeoDataProvider currentGeoObject() {
+ public Observable<IGeoData> currentGeoObject() {
if (geo == null) {
synchronized(this) {
if (geo == null) {
- geo = new GeoDataProvider(this);
+ geo = GeoDataProvider.create(this);
}
}
}
@@ -112,22 +78,14 @@ public class CgeoApplication extends Application {
}
public IGeoData currentGeo() {
- return currentGeoObject().getMemory();
+ return currentGeoObject().first().toBlockingObservable().single();
}
- public void addDirectionObserver(final IObserver<? super Float> observer) {
- currentDirObject().addObserver(observer);
- }
-
- public void deleteDirectionObserver(final IObserver<? super Float> observer) {
- currentDirObject().deleteObserver(observer);
- }
-
- private DirectionProvider currentDirObject() {
+ public Observable<Float> currentDirObject() {
if (dir == null) {
synchronized(this) {
if (dir == null) {
- dir = new DirectionProvider(this);
+ dir = DirectionProvider.create(this);
}
}
}
@@ -135,19 +93,15 @@ public class CgeoApplication extends Application {
}
public Float currentDirection() {
- return currentDirObject().getMemory();
- }
-
- public StatusUpdater getStatusUpdater() {
- return statusUpdater;
+ return currentDirObject().first().toBlockingObservable().single();
}
- public boolean isLiveMapHintShown() {
- return liveMapHintShown;
+ public boolean isLiveMapHintShownInThisSession() {
+ return liveMapHintShownInThisSession;
}
- public void setLiveMapHintShown() {
- liveMapHintShown = true;
+ public void setLiveMapHintShownInThisSession() {
+ liveMapHintShownInThisSession = true;
}
/**
diff --git a/main/src/cgeo/geocaching/CompassActivity.java b/main/src/cgeo/geocaching/CompassActivity.java
index 8955afd..6fc2de1 100644
--- a/main/src/cgeo/geocaching/CompassActivity.java
+++ b/main/src/cgeo/geocaching/CompassActivity.java
@@ -150,12 +150,13 @@ public class CompassActivity extends AbstractActivity {
final CgeoApplication app = CgeoApplication.getInstance();
final IGeoData geo = app.currentGeo();
if (geo != null) {
- geoDirHandler.update(geo);
+ geoDirHandler.updateGeoData(geo);
}
final Float dir = app.currentDirection();
if (dir != null) {
- geoDirHandler.update(dir);
+ geoDirHandler.updateDirection(dir);
}
+
}
@Override
diff --git a/main/src/cgeo/geocaching/CreateShortcutActivity.java b/main/src/cgeo/geocaching/CreateShortcutActivity.java
index 7b91ba1..0b91da0 100644
--- a/main/src/cgeo/geocaching/CreateShortcutActivity.java
+++ b/main/src/cgeo/geocaching/CreateShortcutActivity.java
@@ -1,8 +1,10 @@
package cgeo.geocaching;
import cgeo.geocaching.activity.AbstractActivity;
+import cgeo.geocaching.list.PseudoList;
import cgeo.geocaching.list.StoredList;
-import cgeo.geocaching.utils.RunnableWithArgument;
+
+import rx.util.functions.Action1;
import android.content.Intent;
import android.content.Intent.ShortcutIconResource;
@@ -21,17 +23,17 @@ public class CreateShortcutActivity extends AbstractActivity {
}
private void promptForShortcut() {
- new StoredList.UserInterface(this).promptForListSelection(R.string.create_shortcut, new RunnableWithArgument<Integer>() {
+ new StoredList.UserInterface(this).promptForListSelection(R.string.create_shortcut, new Action1<Integer>() {
@Override
- public void run(final Integer listId) {
+ public void call(final Integer listId) {
final Intent shortcut = createShortcut(listId.intValue());
setResult(RESULT_OK, shortcut);
// finish activity to return the shortcut
finish();
}
- });
+ }, false, PseudoList.HISTORY_LIST.id);
}
protected Intent createShortcut(int listId) {
diff --git a/main/src/cgeo/geocaching/DataStore.java b/main/src/cgeo/geocaching/DataStore.java
index 6da1af8..5cc77dc 100644
--- a/main/src/cgeo/geocaching/DataStore.java
+++ b/main/src/cgeo/geocaching/DataStore.java
@@ -25,17 +25,20 @@ import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import android.app.SearchManager;
import android.content.ContentValues;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.DatabaseUtils;
+import android.database.MatrixCursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteDoneException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteStatement;
+import android.provider.BaseColumns;
import java.io.File;
import java.io.FilenameFilter;
@@ -811,12 +814,19 @@ public class DataStore {
/**
* Remove obsolete cache directories in c:geo private storage.
+ */
+ public static void removeObsoleteCacheDirectories() {
+ removeObsoleteCacheDirectories(database);
+ }
+
+ /**
+ * Remove obsolete cache directories in c:geo private storage.
*
* @param db
* the read-write database to use
*/
private static void removeObsoleteCacheDirectories(final SQLiteDatabase db) {
- final Pattern oldFilePattern = Pattern.compile("^[GC|TB|O][A-Z0-9]{4,7}$");
+ final Pattern oldFilePattern = Pattern.compile("^[GC|TB|EC|GK|O][A-Z0-9]{4,7}$");
final SQLiteStatement select = db.compileStatement("select count(*) from " + dbTableCaches + " where geocode = ?");
final File[] files = LocalStorage.getStorage().listFiles();
final ArrayList<File> toRemove = new ArrayList<File>(files.length);
@@ -868,28 +878,6 @@ public class DataStore {
db.execSQL("drop table if exists " + dbTableTrackables);
}
- public static String[] getRecentGeocodesForSearch() {
- init();
-
- try {
- long timestamp = System.currentTimeMillis() - DAYS_AFTER_CACHE_IS_DELETED;
- final Cursor cursor = database.query(
- dbTableCaches,
- new String[]{"geocode"},
- "(detailed = 1 and detailedupdate > ?) or reason > 0",
- new String[]{Long.toString(timestamp)},
- null,
- null,
- "detailedupdate desc",
- "100");
-
- return getFirstColumn(cursor);
- } catch (final Exception e) {
- Log.e("DataStore.allDetailedThere", e);
- return new String[0];
- }
- }
-
public static boolean isThere(String geocode, String guid, boolean detailed, boolean checkTime) {
init();
@@ -2302,11 +2290,6 @@ public class DataStore {
return new SearchResult(geocodes);
}
- /** delete caches from the DB store 3 days or more before */
- public static void clean() {
- clean(false);
- }
-
/**
* Remove caches with listId = 0
*
@@ -2355,6 +2338,8 @@ public class DataStore {
cursor.close();
+ geocodes = exceptCachesWithOfflineLog(geocodes);
+
if (!geocodes.isEmpty()) {
Log.d("Database clean: removing " + geocodes.size() + " geocaches from listId=0");
removeCaches(geocodes, LoadFlags.REMOVE_ALL);
@@ -2367,6 +2352,33 @@ public class DataStore {
databaseCleaned = true;
}
+ /**
+ * remove all geocodes from the given list of geocodes where an offline log exists
+ *
+ * @param geocodes
+ * @return
+ */
+ private static Set<String> exceptCachesWithOfflineLog(Set<String> geocodes) {
+ if (geocodes.isEmpty()) {
+ return geocodes;
+ }
+
+ init();
+ final Cursor cursor = database.query(
+ dbTableLogsOffline,
+ new String[] { "geocode" },
+ null,
+ null,
+ null,
+ null,
+ null);
+
+ final List<String> geocodesWithOfflineLog = Arrays.asList(getFirstColumn(cursor));
+
+ geocodes.removeAll(geocodesWithOfflineLog);
+ return geocodes;
+ }
+
public static void removeAllFromCache() {
// clean up CacheCache
cacheCache.removeAllFromCache();
@@ -2897,21 +2909,6 @@ public class DataStore {
return waypoints;
}
- public static String[] getTrackableCodes() {
- init();
-
- final Cursor cursor = database.query(
- dbTableTrackables,
- new String[] { "tbcode" },
- null,
- null,
- null,
- null,
- "updated DESC",
- "100");
- return getFirstColumn(cursor);
- }
-
/**
* Extract the first column of the cursor rows and close the cursor.
*
@@ -3098,4 +3095,103 @@ public class DataStore {
return missingFromSearch;
}
+ public static Cursor findSuggestions(final String searchTerm) {
+ // require 3 characters, otherwise there are to many results
+ if (StringUtils.length(searchTerm) < 3) {
+ return null;
+ }
+ init();
+ final MatrixCursor resultCursor = new MatrixCursor(new String[] {
+ BaseColumns._ID,
+ SearchManager.SUGGEST_COLUMN_TEXT_1,
+ SearchManager.SUGGEST_COLUMN_TEXT_2,
+ SearchManager.SUGGEST_COLUMN_INTENT_ACTION,
+ SearchManager.SUGGEST_COLUMN_QUERY
+ });
+ try {
+ final String selectionArg = getSuggestionArgument(searchTerm);
+ findCaches(resultCursor, selectionArg);
+ findTrackables(resultCursor, selectionArg);
+ } catch (final Exception e) {
+ Log.e("DataStore.loadBatchOfStoredGeocodes", e);
+ }
+ return resultCursor;
+ }
+
+ private static void findCaches(final MatrixCursor resultCursor, final String selectionArg) {
+ Cursor cursor = database.query(
+ dbTableCaches,
+ new String[] { "geocode", "name" },
+ "geocode IS NOT NULL AND geocode != '' AND (geocode LIKE ? OR name LIKE ? OR owner LIKE ?)",
+ new String[] { selectionArg, selectionArg, selectionArg },
+ null,
+ null,
+ "name");
+ while (cursor.moveToNext()) {
+ final String geocode = cursor.getString(0);
+ resultCursor.addRow(new String[] {
+ String.valueOf(resultCursor.getCount()),
+ cursor.getString(1),
+ geocode,
+ Intents.ACTION_GEOCACHE,
+ geocode
+ });
+ }
+ cursor.close();
+ }
+
+ private static String getSuggestionArgument(String input) {
+ return "%" + StringUtils.trim(input) + "%";
+ }
+
+ private static void findTrackables(final MatrixCursor resultCursor, final String selectionArg) {
+ Cursor cursor = database.query(
+ dbTableTrackables,
+ new String[] { "tbcode", "title" },
+ "tbcode IS NOT NULL AND tbcode != '' AND (tbcode LIKE ? OR title LIKE ?)",
+ new String[] { selectionArg, selectionArg },
+ null,
+ null,
+ "title");
+ while (cursor.moveToNext()) {
+ final String tbcode = cursor.getString(0);
+ resultCursor.addRow(new String[] {
+ String.valueOf(resultCursor.getCount()),
+ cursor.getString(1),
+ tbcode,
+ Intents.ACTION_TRACKABLE,
+ tbcode
+ });
+ }
+ cursor.close();
+ }
+
+ public static String[] getSuggestions(final String table, final String column, final String input) {
+ Cursor cursor = database.rawQuery("SELECT DISTINCT " + column
+ + " FROM " + table
+ + " WHERE " + column + " LIKE ?"
+ + " ORDER BY " + column + " COLLATE NOCASE ASC;", new String[] { getSuggestionArgument(input) });
+ return getFirstColumn(cursor);
+ }
+
+ public static String[] getSuggestionsOwnerName(String input) {
+ return getSuggestions(dbTableCaches, "owner", input);
+ }
+
+ public static String[] getSuggestionsTrackableCode(String input) {
+ return getSuggestions(dbTableTrackables, "tbcode", input);
+ }
+
+ public static String[] getSuggestionsFinderName(String input) {
+ return getSuggestions(dbTableLogs, "author", input);
+ }
+
+ public static String[] getSuggestionsGeocode(String input) {
+ return getSuggestions(dbTableCaches, "geocode", input);
+ }
+
+ public static String[] getSuggestionsKeyword(String input) {
+ return getSuggestions(dbTableCaches, "name", input);
+ }
+
}
diff --git a/main/src/cgeo/geocaching/DirectionProvider.java b/main/src/cgeo/geocaching/DirectionProvider.java
index ae58fed..cc44155 100644
--- a/main/src/cgeo/geocaching/DirectionProvider.java
+++ b/main/src/cgeo/geocaching/DirectionProvider.java
@@ -1,9 +1,13 @@
package cgeo.geocaching;
import cgeo.geocaching.compatibility.Compatibility;
-import cgeo.geocaching.utils.MemorySubject;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import rx.Observable;
+import rx.Observable.OnSubscribeFunc;
+import rx.Observer;
+import rx.Subscription;
+import rx.observables.ConnectableObservable;
+import rx.subjects.BehaviorSubject;
import android.app.Activity;
import android.content.Context;
@@ -12,58 +16,61 @@ import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
-public class DirectionProvider extends MemorySubject<Float> implements SensorEventListener {
+public class DirectionProvider implements OnSubscribeFunc<Float> {
private final SensorManager sensorManager;
+ private final BehaviorSubject<Float> subject = BehaviorSubject.create(0.0f);
- // Previous values signaled to observers to avoid re-sending the same value when the
- // device doesn't change orientation. The orientation is usually given with a 1 degree
- // precision by Android, so it is not uncommon to obtain exactly the same value several
- // times.
- private float previous = -1;
-
- public DirectionProvider(final Context context) {
- sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
-
+ static public Observable<Float> create(final Context context) {
+ return new DirectionProvider((SensorManager) context.getSystemService(Context.SENSOR_SERVICE)).worker.refCount();
}
- @Override
- protected void onFirstObserver() {
- @SuppressWarnings("deprecation")
- // This will be removed when using a new location service. Until then, it is okay to be used.
- final Sensor defaultSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
- sensorManager.registerListener(this, defaultSensor, SensorManager.SENSOR_DELAY_NORMAL);
+ private DirectionProvider(final SensorManager sensorManager) {
+ this.sensorManager = sensorManager;
}
@Override
- protected void onLastObserver() {
- sensorManager.unregisterListener(this);
+ public Subscription onSubscribe(final Observer<? super Float> observer) {
+ return subject.distinctUntilChanged().subscribe(observer);
}
- @Override
- public void onAccuracyChanged(final Sensor sensor, int accuracy) {
- /*
- * There is a bug in Android, which apparently causes this method to be called every
- * time the sensor _value_ changed, even if the _accuracy_ did not change. So logging
- * this event leads to the log being flooded with multiple entries _per second_,
- * which I experienced when running cgeo in a building (with GPS and network being
- * unreliable).
- *
- * See for example https://code.google.com/p/android/issues/detail?id=14792
- */
+ private final ConnectableObservable<Float> worker = new ConnectableObservable<Float>(this) {
+ @Override
+ public Subscription connect() {
+ @SuppressWarnings("deprecation")
+ // This will be removed when using a new location service. Until then, it is okay to be used.
+ final Sensor defaultSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
+ final SensorEventListener listener = new SensorEventListener() {
+ @Override
+ public void onSensorChanged(final SensorEvent event) {
+ subject.onNext(event.values[0]);
+ }
- //Log.i(Settings.tag, "Compass' accuracy is low (" + accuracy + ")");
- }
+ @Override
+ public void onAccuracyChanged(final Sensor sensor, final int accuracy) {
+ /*
+ * There is a bug in Android, which apparently causes this method to be called every
+ * time the sensor _value_ changed, even if the _accuracy_ did not change. So logging
+ * this event leads to the log being flooded with multiple entries _per second_,
+ * which I experienced when running cgeo in a building (with GPS and network being
+ * unreliable).
+ *
+ * See for example https://code.google.com/p/android/issues/detail?id=14792
+ */
- @Override
- @SuppressFBWarnings("FE_FLOATING_POINT_EQUALITY")
- public void onSensorChanged(final SensorEvent event) {
- final float direction = event.values[0];
- if (direction != previous) {
- notifyObservers(direction);
- previous = direction;
+ //Log.i(Settings.tag, "Compass' accuracy is low (" + accuracy + ")");
+ }
+ };
+
+ sensorManager.registerListener(listener, defaultSensor, SensorManager.SENSOR_DELAY_NORMAL);
+ return new Subscription() {
+ @Override
+ public void unsubscribe() {
+ sensorManager.unregisterListener(listener);
+ }
+ };
}
- }
+ };
/**
* Take the phone rotation (through a given activity) in account and adjust the direction.
@@ -72,6 +79,7 @@ public class DirectionProvider extends MemorySubject<Float> implements SensorEve
* @param direction the unadjusted direction in degrees, in the [0, 360[ range
* @return the adjusted direction in degrees, in the [0, 360[ range
*/
+
public static float getDirectionNow(final Activity activity, final float direction) {
return Compatibility.getDirectionNow(direction, activity);
}
diff --git a/main/src/cgeo/geocaching/EditWaypointActivity.java b/main/src/cgeo/geocaching/EditWaypointActivity.java
index 6d0f822..9010d3a 100644
--- a/main/src/cgeo/geocaching/EditWaypointActivity.java
+++ b/main/src/cgeo/geocaching/EditWaypointActivity.java
@@ -17,10 +17,10 @@ import cgeo.geocaching.utils.GeoDirHandler;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.TextUtils;
-import com.googlecode.androidannotations.annotations.EActivity;
-import com.googlecode.androidannotations.annotations.Extra;
-import com.googlecode.androidannotations.annotations.InstanceState;
-import com.googlecode.androidannotations.annotations.ViewById;
+import org.androidannotations.annotations.EActivity;
+import org.androidannotations.annotations.Extra;
+import org.androidannotations.annotations.InstanceState;
+import org.androidannotations.annotations.ViewById;
import org.apache.commons.lang3.StringUtils;
@@ -110,12 +110,14 @@ public class EditWaypointActivity extends AbstractActivity {
buttonLon.setText(waypoint.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE));
}
waypointName.setText(Html.fromHtml(StringUtils.trimToEmpty(waypoint.getName())).toString());
+ Dialogs.moveCursorToEnd(waypointName);
if (TextUtils.containsHtml(waypoint.getNote())) {
note.setText(Html.fromHtml(StringUtils.trimToEmpty(waypoint.getNote())).toString());
}
else {
note.setText(StringUtils.trimToEmpty(waypoint.getNote()));
}
+ Dialogs.moveCursorToEnd(note);
}
final Geocache cache = DataStore.loadCache(geocode, LoadFlags.LOAD_CACHE_ONLY);
setCoordsModificationVisibility(ConnectorFactory.getConnector(geocode), cache);
diff --git a/main/src/cgeo/geocaching/GeoDataProvider.java b/main/src/cgeo/geocaching/GeoDataProvider.java
index 73aefce..c61b7e7 100644
--- a/main/src/cgeo/geocaching/GeoDataProvider.java
+++ b/main/src/cgeo/geocaching/GeoDataProvider.java
@@ -3,9 +3,14 @@ package cgeo.geocaching;
import cgeo.geocaching.enumerations.LocationProviderType;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.MemorySubject;
import org.apache.commons.lang3.StringUtils;
+import rx.Observable;
+import rx.Observable.OnSubscribeFunc;
+import rx.Observer;
+import rx.Subscription;
+import rx.observables.ConnectableObservable;
+import rx.subjects.BehaviorSubject;
import android.content.Context;
import android.location.GpsSatellite;
@@ -15,22 +20,14 @@ import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Provide information about the user location. This class should be instantiated only once per application.
- */
-class GeoDataProvider extends MemorySubject<IGeoData> {
+class GeoDataProvider implements OnSubscribeFunc<IGeoData> {
private static final String LAST_LOCATION_PSEUDO_PROVIDER = "last";
private final LocationManager geoManager;
- private final GpsStatus.Listener gpsStatusListener = new GpsStatusListener();
private final LocationData gpsLocation = new LocationData();
private final LocationData netLocation = new LocationData();
- private final Listener networkListener = new Listener(LocationManager.NETWORK_PROVIDER, netLocation);
- private final Listener gpsListener = new Listener(LocationManager.GPS_PROVIDER, gpsLocation);
- private final Unregisterer unregisterer = new Unregisterer();
+ private final BehaviorSubject<IGeoData> subject;
+
public boolean gpsEnabled = false;
public int satellitesVisible = 0;
public int satellitesFixed = 0;
@@ -111,51 +108,6 @@ class GeoDataProvider extends MemorySubject<IGeoData> {
}
}
- private class Unregisterer extends Thread {
-
- private boolean unregisterRequested = false;
- private final ArrayBlockingQueue<Boolean> queue = new ArrayBlockingQueue<Boolean>(1);
-
- public void cancelUnregister() {
- try {
- queue.put(false);
- } catch (final InterruptedException e) {
- // Do nothing
- }
- }
-
- public void lateUnregister() {
- try {
- queue.put(true);
- } catch (final InterruptedException e) {
- // Do nothing
- }
- }
-
- @Override
- public void run() {
- try {
- while (true) {
- if (unregisterRequested) {
- final Boolean element = queue.poll(2500, TimeUnit.MILLISECONDS);
- if (element == null) {
- // Timeout
- unregisterListeners();
- unregisterRequested = false;
- } else {
- unregisterRequested = element;
- }
- } else {
- unregisterRequested = queue.take();
- }
- }
- } catch (final InterruptedException e) {
- // Do nothing
- }
- }
-
- }
-
/**
* Build a new geo data provider object.
* <p/>
@@ -164,10 +116,50 @@ class GeoDataProvider extends MemorySubject<IGeoData> {
*
* @param context the context used to retrieve the system services
*/
- GeoDataProvider(final Context context) {
+ protected GeoDataProvider(final Context context) {
geoManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
- unregisterer.start();
+ subject = BehaviorSubject.create(findInitialLocation());
+ }
+
+ public static Observable<IGeoData> create(final Context context) {
+ final GeoDataProvider provider = new GeoDataProvider(context);
+ return provider.worker.refCount();
+ }
+ @Override
+ public Subscription onSubscribe(final Observer<? super IGeoData> observer) {
+ return subject.subscribe(observer);
+ }
+
+ final ConnectableObservable<IGeoData> worker = new ConnectableObservable<IGeoData>(this) {
+ @Override
+ public Subscription connect() {
+ final GpsStatus.Listener gpsStatusListener = new GpsStatusListener();
+ geoManager.addGpsStatusListener(gpsStatusListener);
+
+ final Listener networkListener = new Listener(LocationManager.NETWORK_PROVIDER, netLocation);
+ final Listener gpsListener = new Listener(LocationManager.GPS_PROVIDER, gpsLocation);
+
+ for (final Listener listener : new Listener[] { networkListener, gpsListener }) {
+ try {
+ geoManager.requestLocationUpdates(listener.locationProvider, 0, 0, listener);
+ } catch (final Exception e) {
+ Log.w("There is no location provider " + listener.locationProvider);
+ }
+ }
+
+ return new Subscription() {
+ @Override
+ public void unsubscribe() {
+ geoManager.removeUpdates(networkListener);
+ geoManager.removeUpdates(gpsListener);
+ geoManager.removeGpsStatusListener(gpsStatusListener);
+ }
+ };
+ }
+ };
+
+ private IGeoData findInitialLocation() {
final Location initialLocation = new Location(LAST_LOCATION_PSEUDO_PROVIDER);
try {
// Try to find a sensible initial location from the last locations known to Android.
@@ -195,45 +187,13 @@ class GeoDataProvider extends MemorySubject<IGeoData> {
}
// Start with an historical GeoData just in case someone queries it before we get
// a chance to get any information.
- notifyObservers(new GeoData(initialLocation, false, 0, 0));
+ return new GeoData(initialLocation, false, 0, 0);
}
private static void copyCoords(final Location target, final Location source) {
target.setLatitude(source.getLatitude());
target.setLongitude(source.getLongitude());
}
- private void registerListeners() {
- geoManager.addGpsStatusListener(gpsStatusListener);
-
- for (final Listener listener : new Listener[] { networkListener, gpsListener }) {
- try {
- geoManager.requestLocationUpdates(listener.locationProvider, 0, 0, listener);
- } catch (final Exception e) {
- Log.w("There is no location provider " + listener.locationProvider);
- }
- }
- }
-
- private synchronized void unregisterListeners() {
- // This method must be synchronized because it will be called asynchronously from the Unregisterer thread.
- // We check that no observers have been re-added to prevent a race condition.
- if (sizeObservers() == 0) {
- geoManager.removeUpdates(networkListener);
- geoManager.removeUpdates(gpsListener);
- geoManager.removeGpsStatusListener(gpsStatusListener);
- }
- }
-
- @Override
- protected void onFirstObserver() {
- unregisterer.cancelUnregister();
- registerListeners();
- }
-
- @Override
- protected void onLastObserver() {
- unregisterer.lateUnregister();
- }
private class Listener implements LocationListener {
private final String locationProvider;
@@ -336,7 +296,7 @@ class GeoDataProvider extends MemorySubject<IGeoData> {
// We do not necessarily get signalled when satellites go to 0/0.
final int visible = gpsLocation.isRecent() ? satellitesVisible : 0;
final IGeoData current = new GeoData(locationData.location, gpsEnabled, visible, satellitesFixed);
- notifyObservers(current);
+ subject.onNext(current);
}
}
diff --git a/main/src/cgeo/geocaching/Geocache.java b/main/src/cgeo/geocaching/Geocache.java
index 156c4b6..364683e 100644
--- a/main/src/cgeo/geocaching/Geocache.java
+++ b/main/src/cgeo/geocaching/Geocache.java
@@ -370,6 +370,7 @@ public class Geocache implements ICache, IWaypoint {
* the other cache to compare this one to
* @return true if both caches have the same content
*/
+ @SuppressWarnings("deprecation")
@SuppressFBWarnings("FE_FLOATING_POINT_EQUALITY")
private boolean isEqualTo(final Geocache other) {
return detailed == other.detailed &&
@@ -817,13 +818,7 @@ public class Geocache implements ICache, IWaypoint {
}
public boolean showSize() {
- if (size == CacheSize.NOT_CHOSEN) {
- return false;
- }
- if (isEventCache() || isVirtual()) {
- return false;
- }
- return true;
+ return !(size == CacheSize.NOT_CHOSEN || isEventCache() || isVirtual());
}
public long getUpdated() {
@@ -1373,17 +1368,6 @@ public class Geocache implements ICache, IWaypoint {
}
/**
- * Retrieve a given waypoint.
- *
- * @param index
- * the index of the waypoint
- * @return waypoint or <code>null</code> if index is out of range
- */
- public Waypoint getWaypoint(final int index) {
- return index >= 0 && index < waypoints.size() ? waypoints.get(index) : null;
- }
-
- /**
* Lookup a waypoint by its id.
*
* @param id
@@ -1660,6 +1644,8 @@ public class Geocache implements ICache, IWaypoint {
StaticMapsProvider.downloadMaps(cache);
+ imgGetter.waitForBackgroundLoading(handler);
+
if (handler != null) {
handler.sendMessage(Message.obtain());
}
@@ -1719,8 +1705,9 @@ public class Geocache implements ICache, IWaypoint {
patterns.add(Pattern.compile("\\b(\\d{1,2})(?:\\.00)?\\s+" + Pattern.quote(hourLocalized), Pattern.CASE_INSENSITIVE));
}
+ final String searchText = getShortDescription() + ' ' + getDescription();
for (Pattern pattern : patterns) {
- final MatcherWrapper matcher = new MatcherWrapper(pattern, getDescription());
+ final MatcherWrapper matcher = new MatcherWrapper(pattern, searchText);
while (matcher.find()) {
try {
final int hours = Integer.parseInt(matcher.group(1));
@@ -1831,4 +1818,8 @@ public class Geocache implements ICache, IWaypoint {
return 0;
}
+ public boolean applyDistanceRule() {
+ return (getType().applyDistanceRule() || hasUserModifiedCoords()) && getConnector() == GCConnector.getInstance();
+ }
+
}
diff --git a/main/src/cgeo/geocaching/ImageSelectActivity.java b/main/src/cgeo/geocaching/ImageSelectActivity.java
index 12d1e84..766149c 100644
--- a/main/src/cgeo/geocaching/ImageSelectActivity.java
+++ b/main/src/cgeo/geocaching/ImageSelectActivity.java
@@ -6,6 +6,7 @@ import butterknife.InjectView;
import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.files.LocalStorage;
import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.ImageUtils;
import cgeo.geocaching.utils.Log;
@@ -111,10 +112,12 @@ public class ImageSelectActivity extends AbstractActivity {
if (StringUtils.isNotBlank(imageCaption)) {
captionView.setText(imageCaption);
+ Dialogs.moveCursorToEnd(captionView);
}
if (StringUtils.isNotBlank(imageDescription)) {
descriptionView.setText(imageDescription);
+ Dialogs.moveCursorToEnd(captionView);
}
scaleView.setSelection(scaleChoiceIndex);
diff --git a/main/src/cgeo/geocaching/Intents.java b/main/src/cgeo/geocaching/Intents.java
index d9d9829..5c969a1 100644
--- a/main/src/cgeo/geocaching/Intents.java
+++ b/main/src/cgeo/geocaching/Intents.java
@@ -29,4 +29,8 @@ public class Intents {
public static final String EXTRA_WAYPOINT_ID = PREFIX + "waypoint_id";
public static final String EXTRA_CACHELIST = PREFIX + "cache_list";
public static final String EXTRA_POCKET_GUID = PREFIX + "pocket_guid";
+
+ private static final String PREFIX_ACTION = "cgeo.geocaching.intent.action.";
+ public static final String ACTION_GEOCACHE = PREFIX_ACTION + "GEOCACHE";
+ public static final String ACTION_TRACKABLE = PREFIX_ACTION + "TRACKABLE";
}
diff --git a/main/src/cgeo/geocaching/LogCacheActivity.java b/main/src/cgeo/geocaching/LogCacheActivity.java
index f17a008..729ec60 100644
--- a/main/src/cgeo/geocaching/LogCacheActivity.java
+++ b/main/src/cgeo/geocaching/LogCacheActivity.java
@@ -13,6 +13,7 @@ import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.twitter.Twitter;
import cgeo.geocaching.ui.Formatter;
import cgeo.geocaching.ui.dialog.DateDialog;
+import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.AsyncTaskWithProgress;
import cgeo.geocaching.utils.DateUtils;
import cgeo.geocaching.utils.Log;
@@ -151,7 +152,7 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
final TextView actionButton = (TextView) inventoryItem.findViewById(R.id.action);
actionButton.setId(tb.id);
actionButtons.put(actionButton.getId(), tb);
- actionButton.setText(res.getString(tb.action.resourceId) + " ▼");
+ actionButton.setText(tb.action.getLabel() + " ▼");
actionButton.setOnClickListener(new View.OnClickListener() {
@Override
@@ -301,6 +302,7 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
final EditText logView = (EditText) findViewById(R.id.log);
if (StringUtils.isBlank(currentLogText()) && StringUtils.isNotBlank(text)) {
logView.setText(text);
+ Dialogs.moveCursorToEnd(logView);
}
tweetCheck.setChecked(true);
@@ -632,11 +634,11 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
alert.create().show();
}
- private String[] getTBLogTypes() {
+ private static String[] getTBLogTypes() {
final LogTypeTrackable[] logTypeValues = LogTypeTrackable.values();
String[] logTypes = new String[logTypeValues.length];
for (int i = 0; i < logTypes.length; i++) {
- logTypes[i] = res.getString(logTypeValues[i].resourceId);
+ logTypes[i] = logTypeValues[i].getLabel();
}
return logTypes;
}
diff --git a/main/src/cgeo/geocaching/LogTrackableActivity.java b/main/src/cgeo/geocaching/LogTrackableActivity.java
index 5246fa9..fabe391 100644
--- a/main/src/cgeo/geocaching/LogTrackableActivity.java
+++ b/main/src/cgeo/geocaching/LogTrackableActivity.java
@@ -3,8 +3,8 @@ package cgeo.geocaching;
import butterknife.ButterKnife;
import butterknife.InjectView;
-import cgeo.geocaching.connector.gc.GCParser;
import cgeo.geocaching.connector.gc.GCLogin;
+import cgeo.geocaching.connector.gc.GCParser;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.network.Network;
@@ -13,6 +13,7 @@ import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.twitter.Twitter;
import cgeo.geocaching.ui.Formatter;
import cgeo.geocaching.ui.dialog.DateDialog;
+import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.LogTemplateProvider.LogContext;
@@ -127,6 +128,7 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
if (StringUtils.isNotBlank(extras.getString(Intents.EXTRA_TRACKING_CODE))) {
trackingEditText.setText(extras.getString(Intents.EXTRA_TRACKING_CODE));
+ Dialogs.moveCursorToEnd(trackingEditText);
}
}
diff --git a/main/src/cgeo/geocaching/MainActivity.java b/main/src/cgeo/geocaching/MainActivity.java
index 924c66d..86ccfa5 100644
--- a/main/src/cgeo/geocaching/MainActivity.java
+++ b/main/src/cgeo/geocaching/MainActivity.java
@@ -10,6 +10,7 @@ import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.Units;
+import cgeo.geocaching.list.PseudoList;
import cgeo.geocaching.list.StoredList;
import cgeo.geocaching.maps.CGeoMap;
import cgeo.geocaching.settings.Settings;
@@ -19,15 +20,22 @@ import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.DatabaseBackupUtils;
import cgeo.geocaching.utils.GeoDirHandler;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.RunnableWithArgument;
import cgeo.geocaching.utils.Version;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
-import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
+import rx.Observable;
+import rx.Observable.OnSubscribeFunc;
+import rx.Observer;
+import rx.Subscription;
+import rx.android.observables.AndroidObservable;
+import rx.schedulers.Schedulers;
+import rx.subscriptions.Subscriptions;
+import rx.util.functions.Action1;
+
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.SearchManager;
@@ -48,7 +56,6 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -77,8 +84,6 @@ public class MainActivity extends AbstractActivity {
private boolean cleanupRunning = false;
private int countBubbleCnt = 0;
private Geopoint addCoords = null;
- private List<Address> addresses = null;
- private boolean addressObtaining = false;
private boolean initialized = false;
private final UpdateLocation locationUpdater = new UpdateLocation();
@@ -104,7 +109,7 @@ public class MainActivity extends AbstractActivity {
if (conn.isLoggedIn()) {
userInfo.append(conn.getUserName());
if (conn.getCachesFound() >= 0) {
- userInfo.append(" (").append(String.valueOf(conn.getCachesFound())).append(')');
+ userInfo.append(" (").append(conn.getCachesFound()).append(')');
}
userInfo.append(Formatter.SEPARATOR);
}
@@ -115,40 +120,24 @@ public class MainActivity extends AbstractActivity {
}
};
- private Handler obtainAddressHandler = new Handler() {
-
- @Override
- public void handleMessage(final Message msg) {
- try {
- if (CollectionUtils.isNotEmpty(addresses)) {
- final Address address = addresses.get(0);
- final ArrayList<String> addressParts = new ArrayList<String>();
-
- final String countryName = address.getCountryName();
- if (countryName != null) {
- addressParts.add(countryName);
- }
- final String locality = address.getLocality();
- if (locality != null) {
- addressParts.add(locality);
- } else {
- final String adminArea = address.getAdminArea();
- if (adminArea != null) {
- addressParts.add(adminArea);
- }
- }
-
- addCoords = app.currentGeo().getCoords();
+ private static String formatAddress(final Address address) {
+ final ArrayList<String> addressParts = new ArrayList<String>();
- navLocation.setText(StringUtils.join(addressParts, ", "));
- }
- } catch (RuntimeException e) {
- // nothing
+ final String countryName = address.getCountryName();
+ if (countryName != null) {
+ addressParts.add(countryName);
+ }
+ final String locality = address.getLocality();
+ if (locality != null) {
+ addressParts.add(locality);
+ } else {
+ final String adminArea = address.getAdminArea();
+ if (adminArea != null) {
+ addressParts.add(adminArea);
}
-
- addresses = null;
}
- };
+ return StringUtils.join(addressParts, ", ");
+ }
private class SatellitesHandler extends GeoDirHandler {
@@ -285,7 +274,7 @@ public class MainActivity extends AbstractActivity {
@Override
public boolean onPrepareOptionsMenu(final Menu menu) {
super.onPrepareOptionsMenu(menu);
- menu.findItem(R.id.menu_pocket_queries).setVisible(Settings.isPremiumMember());
+ menu.findItem(R.id.menu_pocket_queries).setVisible(Settings.isGCPremiumMember());
return true;
}
@@ -309,13 +298,13 @@ public class MainActivity extends AbstractActivity {
startScannerApplication();
return true;
case R.id.menu_pocket_queries:
- if (!Settings.isPremiumMember()) {
+ if (!Settings.isGCPremiumMember()) {
return true;
}
- new PocketQueryList.UserInterface(MainActivity.this).promptForListSelection(new RunnableWithArgument<PocketQueryList>() {
+ PocketQueryList.promptForListSelection(this, new Action1<PocketQueryList>() {
@Override
- public void run(final PocketQueryList pql) {
+ public void call(final PocketQueryList pql) {
CacheListActivity.startActivityPocket(MainActivity.this, pql);
}
});
@@ -388,14 +377,14 @@ public class MainActivity extends AbstractActivity {
@Override
public boolean onLongClick(final View v) {
- new StoredList.UserInterface(MainActivity.this).promptForListSelection(R.string.list_title, new RunnableWithArgument<Integer>() {
+ new StoredList.UserInterface(MainActivity.this).promptForListSelection(R.string.list_title, new Action1<Integer>() {
@Override
- public void run(final Integer selectedListId) {
+ public void call(final Integer selectedListId) {
Settings.saveLastList(selectedListId);
CacheListActivity.startActivityOffline(MainActivity.this);
}
- });
+ }, false, PseudoList.HISTORY_LIST.id);
return true;
}
});
@@ -525,52 +514,61 @@ public class MainActivity extends AbstractActivity {
@Override
public void updateGeoData(final IGeoData geo) {
- try {
- if (geo.getCoords() != null) {
- if (!nearestView.isClickable()) {
- nearestView.setFocusable(true);
- nearestView.setClickable(true);
- nearestView.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(final View v) {
- cgeoFindNearest(v);
- }
- });
- nearestView.setBackgroundResource(R.drawable.main_nearby);
+ if (!nearestView.isClickable()) {
+ nearestView.setFocusable(true);
+ nearestView.setClickable(true);
+ nearestView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ cgeoFindNearest(v);
}
+ });
+ nearestView.setBackgroundResource(R.drawable.main_nearby);
+ }
- navType.setText(res.getString(geo.getLocationProvider().resourceId));
+ navType.setText(res.getString(geo.getLocationProvider().resourceId));
- if (geo.getAccuracy() >= 0) {
- int speed = Math.round(geo.getSpeed()) * 60 * 60 / 1000;
- navAccuracy.setText("±" + Units.getDistanceFromMeters(geo.getAccuracy()) + Formatter.SEPARATOR + Units.getSpeed(speed));
- } else {
- navAccuracy.setText(null);
- }
+ if (geo.getAccuracy() >= 0) {
+ int speed = Math.round(geo.getSpeed()) * 60 * 60 / 1000;
+ navAccuracy.setText("±" + Units.getDistanceFromMeters(geo.getAccuracy()) + Formatter.SEPARATOR + Units.getSpeed(speed));
+ } else {
+ navAccuracy.setText(null);
+ }
- if (Settings.isShowAddress()) {
- if (addCoords == null) {
- navLocation.setText(res.getString(R.string.loc_no_addr));
- }
- if (addCoords == null || (geo.getCoords().distanceTo(addCoords) > 0.5 && !addressObtaining)) {
- (new ObtainAddressThread()).start();
+ if (Settings.isShowAddress()) {
+ if (addCoords == null) {
+ navLocation.setText(R.string.loc_no_addr);
+ }
+ if (addCoords == null || (geo.getCoords().distanceTo(addCoords) > 0.5)) {
+ final Observable<String> address = Observable.create(new OnSubscribeFunc<String>() {
+ @Override
+ public Subscription onSubscribe(final Observer<? super String> observer) {
+ try {
+ addCoords = geo.getCoords();
+ final Geocoder geocoder = new Geocoder(MainActivity.this, Locale.getDefault());
+ final Geopoint coords = app.currentGeo().getCoords();
+ final List<Address> addresses = geocoder.getFromLocation(coords.getLatitude(), coords.getLongitude(), 1);
+ if (!addresses.isEmpty()) {
+ observer.onNext(formatAddress(addresses.get(0)));
+ }
+ observer.onCompleted();
+ } catch (final Exception e) {
+ observer.onError(e);
+ }
+ return Subscriptions.empty();
}
- } else {
- navLocation.setText(geo.getCoords().toString());
- }
- } else {
- if (nearestView.isClickable()) {
- nearestView.setFocusable(false);
- nearestView.setClickable(false);
- nearestView.setOnClickListener(null);
- nearestView.setBackgroundResource(R.drawable.main_nearby_disabled);
- }
- navType.setText(null);
- navAccuracy.setText(null);
- navLocation.setText(res.getString(R.string.loc_trying));
+ }).subscribeOn(Schedulers.io());
+ AndroidObservable.fromActivity(MainActivity.this, address)
+ .onErrorResumeNext(Observable.from(geo.getCoords().toString()))
+ .subscribe(new Action1<String>() {
+ @Override
+ public void call(final String address) {
+ navLocation.setText(address);
+ }
+ });
}
- } catch (RuntimeException e) {
- Log.w("Failed to update location.");
+ } else {
+ navLocation.setText(geo.getCoords().toString());
}
}
}
@@ -714,35 +712,6 @@ public class MainActivity extends AbstractActivity {
}
}
- private class ObtainAddressThread extends Thread {
-
- public ObtainAddressThread() {
- setPriority(Thread.MIN_PRIORITY);
- }
-
- @Override
- public void run() {
- if (addressObtaining) {
- return;
- }
- addressObtaining = true;
-
- try {
- final Geocoder geocoder = new Geocoder(MainActivity.this, Locale.getDefault());
- final Geopoint coords = app.currentGeo().getCoords();
- addresses = geocoder.getFromLocation(coords.getLatitude(), coords.getLongitude(), 1);
- } catch (final IOException e) {
- Log.i("Failed to obtain address");
- } catch (final IllegalArgumentException e) {
- Log.w("ObtainAddressThread.run", e);
- }
-
- obtainAddressHandler.sendEmptyMessage(0);
-
- addressObtaining = false;
- }
- }
-
/**
* @param view
* unused here but needed since this method is referenced from XML layout
diff --git a/main/src/cgeo/geocaching/PocketQueryList.java b/main/src/cgeo/geocaching/PocketQueryList.java
index 9d1110d..8ab0ec3 100644
--- a/main/src/cgeo/geocaching/PocketQueryList.java
+++ b/main/src/cgeo/geocaching/PocketQueryList.java
@@ -2,15 +2,23 @@ package cgeo.geocaching;
import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.connector.gc.GCParser;
-import cgeo.geocaching.utils.RunnableWithArgument;
+
+import org.apache.commons.collections4.CollectionUtils;
+
+import rx.Observable;
+import rx.Observable.OnSubscribeFunc;
+import rx.Observer;
+import rx.Subscription;
+import rx.android.observables.AndroidObservable;
+import rx.schedulers.Schedulers;
+import rx.subscriptions.Subscriptions;
+import rx.util.functions.Action1;
import android.app.Activity;
import android.app.AlertDialog;
+import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
-import android.content.res.Resources;
-import android.os.Handler;
-import android.os.Message;
import java.util.List;
@@ -20,105 +28,63 @@ public final class PocketQueryList {
private final int maxCaches;
private final String name;
- public PocketQueryList(String guid, String name, int maxCaches) {
+ public PocketQueryList(final String guid, final String name, final int maxCaches) {
this.guid = guid;
this.name = name;
this.maxCaches = maxCaches;
}
- public static class UserInterface {
-
- List<PocketQueryList> pocketQueryList = null;
- RunnableWithArgument<PocketQueryList> runAfterwards;
-
- private Handler loadPocketQueryHandler = new Handler() {
-
- @Override
- public void handleMessage(Message msg) {
- if ((pocketQueryList == null) || (pocketQueryList.size() == 0)) {
- if (waitDialog != null) {
- waitDialog.dismiss();
- }
-
- ActivityMixin.showToast(activity, res.getString(R.string.warn_no_pocket_query_found));
-
- return;
- }
-
- if (waitDialog != null) {
- waitDialog.dismiss();
- }
-
- final CharSequence[] items = new CharSequence[pocketQueryList.size()];
-
- for (int i = 0; i < pocketQueryList.size(); i++) {
- PocketQueryList pq = pocketQueryList.get(i);
- items[i] = pq.name;
- }
+ public String getGuid() {
+ return guid;
+ }
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- builder.setTitle(res.getString(R.string.search_pocket_select));
- builder.setItems(items, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int itemId) {
- final PocketQueryList query = pocketQueryList.get(itemId);
- dialogInterface.dismiss();
- runAfterwards.run(query);
- }
- });
- builder.create().show();
+ public int getMaxCaches() {
+ return maxCaches;
+ }
- }
- };
+ public String getName() {
+ return name;
+ }
- private class LoadPocketQueryListThread extends Thread {
- final private Handler handler;
+ public static void promptForListSelection(final Activity activity, final Action1<PocketQueryList> runAfterwards) {
+ final Dialog waitDialog = ProgressDialog.show(activity, activity.getString(R.string.search_pocket_title), activity.getString(R.string.search_pocket_loading), true, true);
- public LoadPocketQueryListThread(Handler handlerIn) {
- handler = handlerIn;
+ AndroidObservable.fromActivity(activity, Observable.create(new OnSubscribeFunc<List<PocketQueryList>>() {
+ @Override
+ public Subscription onSubscribe(final Observer<? super List<PocketQueryList>> observer) {
+ observer.onNext(GCParser.searchPocketQueryList());
+ observer.onCompleted();
+ return Subscriptions.empty();
}
-
+ }).subscribeOn(Schedulers.io())).subscribe(new Action1<List<PocketQueryList>>() {
@Override
- public void run() {
- pocketQueryList = GCParser.searchPocketQueryList();
- handler.sendMessage(Message.obtain());
+ public void call(final List<PocketQueryList> pocketQueryLists) {
+ waitDialog.dismiss();
+ selectFromPocketQueries(activity, pocketQueryLists, runAfterwards);
}
+ });
+ }
+ private static void selectFromPocketQueries(final Activity activity, final List<PocketQueryList> pocketQueryList, final Action1<PocketQueryList> runAfterwards) {
+ if (CollectionUtils.isEmpty(pocketQueryList)) {
+ ActivityMixin.showToast(activity, activity.getString(R.string.warn_no_pocket_query_found));
+ return;
}
- private final Activity activity;
- private final CgeoApplication app;
- private final Resources res;
- private ProgressDialog waitDialog = null;
-
- public UserInterface(final Activity activity) {
- this.activity = activity;
- app = CgeoApplication.getInstance();
- res = app.getResources();
- }
-
- public void promptForListSelection(final RunnableWithArgument<PocketQueryList> runAfterwards) {
+ final CharSequence[] items = new CharSequence[pocketQueryList.size()];
- this.runAfterwards = runAfterwards;
-
- waitDialog = ProgressDialog.show(activity, res.getString(R.string.search_pocket_title), res.getString(R.string.search_pocket_loading), true, true);
-
- LoadPocketQueryListThread thread = new LoadPocketQueryListThread(loadPocketQueryHandler);
- thread.start();
+ for (int i = 0; i < pocketQueryList.size(); i++) {
+ items[i] = pocketQueryList.get(i).name;
}
-
- }
-
- public String getGuid() {
- return guid;
- }
-
- public int getMaxCaches() {
- return maxCaches;
- }
-
- public String getName() {
- return name;
+ new AlertDialog.Builder(activity)
+ .setTitle(activity.getString(R.string.search_pocket_select))
+ .setItems(items, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(final DialogInterface dialogInterface, final int itemId) {
+ dialogInterface.dismiss();
+ runAfterwards.call(pocketQueryList.get(itemId));
+ }
+ }).create().show();
}
}
diff --git a/main/src/cgeo/geocaching/SearchActivity.java b/main/src/cgeo/geocaching/SearchActivity.java
index 0648073..fe9edd0 100644
--- a/main/src/cgeo/geocaching/SearchActivity.java
+++ b/main/src/cgeo/geocaching/SearchActivity.java
@@ -10,12 +10,17 @@ import cgeo.geocaching.connector.capability.ISearchByGeocode;
import cgeo.geocaching.connector.trackable.TrackableConnector;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.GeopointFormatter;
+import cgeo.geocaching.search.AutoCompleteAdapter;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.dialog.CoordinatesInputDialog;
import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.EditUtils;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+import rx.util.functions.Func1;
import android.app.Activity;
import android.app.SearchManager;
@@ -26,10 +31,8 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
-import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
-import android.widget.EditText;
import java.util.Locale;
@@ -39,19 +42,19 @@ public class SearchActivity extends AbstractActivity {
@InjectView(R.id.buttonLongitude) protected Button buttonLongitude;
@InjectView(R.id.search_coordinates) protected Button buttonSearchCoords;
- @InjectView(R.id.address) protected EditText addressEditText;
+ @InjectView(R.id.address) protected AutoCompleteTextView addressEditText;
@InjectView(R.id.search_address) protected Button buttonSearchAddress;
@InjectView(R.id.geocode) protected AutoCompleteTextView geocodeEditText;
@InjectView(R.id.display_geocode) protected Button buttonSearchGeocode;
- @InjectView(R.id.keyword) protected EditText keywordEditText;
+ @InjectView(R.id.keyword) protected AutoCompleteTextView keywordEditText;
@InjectView(R.id.search_keyword) protected Button buttonSearchKeyword;
- @InjectView(R.id.finder) protected EditText finderNameEditText;
+ @InjectView(R.id.finder) protected AutoCompleteTextView finderNameEditText;
@InjectView(R.id.search_finder) protected Button buttonSearchFinder;
- @InjectView(R.id.owner) protected EditText ownerNameEditText;
+ @InjectView(R.id.owner) protected AutoCompleteTextView ownerNameEditText;
@InjectView(R.id.search_owner) protected Button buttonSearchOwner;
@InjectView(R.id.trackable) protected AutoCompleteTextView trackableEditText;
@@ -60,9 +63,23 @@ public class SearchActivity extends AbstractActivity {
@Override
public final void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ final Intent intent = getIntent();
+
+ // search suggestion for a cache
+ if (Intents.ACTION_GEOCACHE.equals(intent.getAction())) {
+ CacheDetailActivity.startActivity(this, intent.getStringExtra(SearchManager.QUERY));
+ finish();
+ return;
+ }
+
+ // search suggestion for a trackable
+ if (Intents.ACTION_TRACKABLE.equals(intent.getAction())) {
+ TrackableActivity.startActivity(this, null, intent.getStringExtra(SearchManager.QUERY), null);
+ finish();
+ return;
+ }
// search query
- final Intent intent = getIntent();
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
hideKeyboard();
final String query = intent.getStringExtra(SearchManager.QUERY);
@@ -173,7 +190,7 @@ public class SearchActivity extends AbstractActivity {
public void run() {
findByAddressFn();
}
- });
+ }, null);
setSearchAction(geocodeEditText, buttonSearchGeocode, new Runnable() {
@@ -181,8 +198,13 @@ public class SearchActivity extends AbstractActivity {
public void run() {
findByGeocodeFn();
}
+ }, new Func1<String, String[]>() {
+
+ @Override
+ public String[] call(final String input) {
+ return DataStore.getSuggestionsGeocode(input);
+ }
});
- addHistoryEntries(geocodeEditText, DataStore.getRecentGeocodesForSearch());
setSearchAction(keywordEditText, buttonSearchKeyword, new Runnable() {
@@ -190,6 +212,12 @@ public class SearchActivity extends AbstractActivity {
public void run() {
findByKeywordFn();
}
+ }, new Func1<String, String[]>() {
+
+ @Override
+ public String[] call(final String input) {
+ return DataStore.getSuggestionsKeyword(input);
+ }
});
setSearchAction(finderNameEditText, buttonSearchFinder, new Runnable() {
@@ -198,6 +226,12 @@ public class SearchActivity extends AbstractActivity {
public void run() {
findByFinderFn();
}
+ }, new Func1<String, String[]>() {
+
+ @Override
+ public String[] call(final String input) {
+ return DataStore.getSuggestionsFinderName(input);
+ }
});
setSearchAction(ownerNameEditText, buttonSearchOwner, new Runnable() {
@@ -206,6 +240,12 @@ public class SearchActivity extends AbstractActivity {
public void run() {
findByOwnerFn();
}
+ }, new Func1<String, String[]>() {
+
+ @Override
+ public String[] call(final String input) {
+ return DataStore.getSuggestionsOwnerName(input);
+ }
});
setSearchAction(trackableEditText, buttonSearchTrackable, new Runnable() {
@@ -214,12 +254,16 @@ public class SearchActivity extends AbstractActivity {
public void run() {
findTrackableFn();
}
+ }, new Func1<String, String[]>() {
+
+ @Override
+ public String[] call(final String input) {
+ return DataStore.getSuggestionsTrackableCode(input);
+ }
});
- addHistoryEntries(trackableEditText, DataStore.getTrackableCodes());
- disableSuggestions(trackableEditText);
}
- private static void setSearchAction(final EditText editText, final Button button, final Runnable runnable) {
+ private static void setSearchAction(final AutoCompleteTextView editText, final Button button, final @NonNull Runnable runnable, final @Nullable Func1<String, String[]> suggestionFunction) {
EditUtils.setActionListener(editText, runnable);
button.setOnClickListener(new View.OnClickListener() {
@Override
@@ -227,12 +271,8 @@ public class SearchActivity extends AbstractActivity {
runnable.run();
}
});
- }
-
- private void addHistoryEntries(final AutoCompleteTextView textView, final String[] entries) {
- if (entries != null) {
- final ArrayAdapter<String> historyAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, entries);
- textView.setAdapter(historyAdapter);
+ if (suggestionFunction != null) {
+ editText.setAdapter(new AutoCompleteAdapter(editText.getContext(), android.R.layout.simple_dropdown_item_1line, suggestionFunction));
}
}
@@ -305,7 +345,7 @@ public class SearchActivity extends AbstractActivity {
return;
}
- CacheListActivity.startActivityUserName(this, usernameText);
+ CacheListActivity.startActivityFinder(this, usernameText);
}
private void findByOwnerFn() {
diff --git a/main/src/cgeo/geocaching/SearchResult.java b/main/src/cgeo/geocaching/SearchResult.java
index 131a01c..46ac38e 100644
--- a/main/src/cgeo/geocaching/SearchResult.java
+++ b/main/src/cgeo/geocaching/SearchResult.java
@@ -10,6 +10,7 @@ import cgeo.geocaching.gcvote.GCVote;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -228,6 +229,7 @@ public class SearchResult implements Parcelable {
return result;
}
+ @Nullable
public Geocache getFirstCacheFromResult(final EnumSet<LoadFlag> loadFlags) {
return CollectionUtils.isNotEmpty(geocodes) ? DataStore.loadCache(geocodes.iterator().next(), loadFlags) : null;
}
diff --git a/main/src/cgeo/geocaching/StaticMapsActivity.java b/main/src/cgeo/geocaching/StaticMapsActivity.java
index 7811da5..16fce37 100644
--- a/main/src/cgeo/geocaching/StaticMapsActivity.java
+++ b/main/src/cgeo/geocaching/StaticMapsActivity.java
@@ -4,11 +4,10 @@ import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.utils.Log;
-import com.googlecode.androidannotations.annotations.EActivity;
-import com.googlecode.androidannotations.annotations.Extra;
-import com.googlecode.androidannotations.annotations.OptionsItem;
-import com.googlecode.androidannotations.annotations.OptionsMenu;
-
+import org.androidannotations.annotations.EActivity;
+import org.androidannotations.annotations.Extra;
+import org.androidannotations.annotations.OptionsItem;
+import org.androidannotations.annotations.OptionsMenu;
import org.apache.commons.collections4.CollectionUtils;
import android.app.ProgressDialog;
diff --git a/main/src/cgeo/geocaching/StatusFragment.java b/main/src/cgeo/geocaching/StatusFragment.java
index 4f70f0e..a4b5973 100644
--- a/main/src/cgeo/geocaching/StatusFragment.java
+++ b/main/src/cgeo/geocaching/StatusFragment.java
@@ -1,15 +1,17 @@
package cgeo.geocaching;
+import cgeo.geocaching.network.StatusUpdater;
import cgeo.geocaching.network.StatusUpdater.Status;
-import cgeo.geocaching.utils.IObserver;
import cgeo.geocaching.utils.Log;
+import rx.Subscription;
+import rx.android.observables.AndroidObservable;
+import rx.util.functions.Action1;
+
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
@@ -20,91 +22,68 @@ import android.widget.TextView;
public class StatusFragment extends Fragment {
- private ViewGroup status;
- private ImageView statusIcon;
- private TextView statusMessage;
-
- final private StatusHandler statusHandler = new StatusHandler();
+ private Subscription statusSubscription;
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
- status = (ViewGroup) inflater.inflate(R.layout.status, container, false);
- statusIcon = (ImageView) status.findViewById(R.id.status_icon);
- statusMessage = (TextView) status.findViewById(R.id.status_message);
- return status;
- }
-
- @Override
- public void onResume() {
- super.onResume();
- CgeoApplication.getInstance().getStatusUpdater().addObserver(statusHandler);
- }
-
- @Override
- public void onPause() {
- CgeoApplication.getInstance().getStatusUpdater().deleteObserver(statusHandler);
- super.onPause();
- }
-
- private class StatusHandler extends Handler implements IObserver<Status> {
-
- @Override
- public void update(final Status data) {
- obtainMessage(0, data).sendToTarget();
- }
-
- @Override
- public void handleMessage(final Message msg) {
- final Status data = (Status) msg.obj;
- updateDisplay(data != null && data.message != null ? data : Status.defaultStatus());
- }
-
- private void updateDisplay(final Status data) {
-
- if (data == null) {
- status.setVisibility(View.INVISIBLE);
- return;
- }
-
- final Resources res = getResources();
- final String packageName = getActivity().getPackageName();
+ final ViewGroup statusGroup = (ViewGroup) inflater.inflate(R.layout.status, container, false);
+ final ImageView statusIcon = (ImageView) statusGroup.findViewById(R.id.status_icon);
+ final TextView statusMessage = (TextView) statusGroup.findViewById(R.id.status_message);
+ statusSubscription = AndroidObservable.fromFragment(this, StatusUpdater.latestStatus).subscribe(new Action1<Status>() {
+ @Override
+ public void call(final Status status) {
+ if (status == null) {
+ statusGroup.setVisibility(View.INVISIBLE);
+ return;
+ }
- if (data.icon != null) {
- final int iconId = res.getIdentifier(data.icon, "drawable", packageName);
- if (iconId != 0) {
- statusIcon.setImageResource(iconId);
- statusIcon.setVisibility(View.VISIBLE);
+ final Resources res = getResources();
+ final String packageName = getActivity().getPackageName();
+
+ if (status.icon != null) {
+ final int iconId = res.getIdentifier(status.icon, "drawable", packageName);
+ if (iconId != 0) {
+ statusIcon.setImageResource(iconId);
+ statusIcon.setVisibility(View.VISIBLE);
+ } else {
+ Log.w("StatusHandler: could not find icon corresponding to @drawable/" + status.icon);
+ statusIcon.setVisibility(View.GONE);
+ }
} else {
- Log.w("StatusHandler: could not find icon corresponding to @drawable/" + data.icon);
statusIcon.setVisibility(View.GONE);
}
- } else {
- statusIcon.setVisibility(View.GONE);
- }
- String message = data.message;
- if (data.messageId != null) {
- final int messageId = res.getIdentifier(data.messageId, "string", packageName);
- if (messageId != 0) {
- message = res.getString(messageId);
+ String message = status.message;
+ if (status.messageId != null) {
+ final int messageId = res.getIdentifier(status.messageId, "string", packageName);
+ if (messageId != 0) {
+ message = res.getString(messageId);
+ }
}
- }
- statusMessage.setText(message);
- status.setVisibility(View.VISIBLE);
+ statusMessage.setText(message);
+ statusGroup.setVisibility(View.VISIBLE);
- if (data.url != null) {
- status.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(final View v) {
- startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(data.url)));
- }
- });
- } else {
- status.setClickable(false);
+ if (status.url != null) {
+ statusGroup.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(status.url)));
+ }
+ });
+ } else {
+ statusGroup.setClickable(false);
+ }
}
- }
+ });
+ return statusGroup;
+ }
+ @Override
+ public void onDestroy() {
+ statusSubscription.unsubscribe();
+ super.onDestroy();
}
+
}
diff --git a/main/src/cgeo/geocaching/TrackableActivity.java b/main/src/cgeo/geocaching/TrackableActivity.java
index dcfd80a..34f546a 100644
--- a/main/src/cgeo/geocaching/TrackableActivity.java
+++ b/main/src/cgeo/geocaching/TrackableActivity.java
@@ -130,6 +130,8 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
// try to get data from URI
if (geocode == null && guid == null && id == null && uri != null) {
+ geocode = ConnectorFactory.getTrackableFromURL(uri.toString());
+
final String uriHost = uri.getHost().toLowerCase(Locale.US);
if (uriHost.contains("geocaching.com")) {
geocode = uri.getQueryParameter("tracker");
diff --git a/main/src/cgeo/geocaching/UsefulAppsActivity.java b/main/src/cgeo/geocaching/UsefulAppsActivity.java
index c70143f..39c527d 100644
--- a/main/src/cgeo/geocaching/UsefulAppsActivity.java
+++ b/main/src/cgeo/geocaching/UsefulAppsActivity.java
@@ -62,6 +62,7 @@ public class UsefulAppsActivity extends AbstractActivity {
private static final HelperApp[] HELPER_APPS = {
new HelperApp(R.string.helper_calendar_title, R.string.helper_calendar_description, R.drawable.cgeo, "cgeo.calendar"),
new HelperApp(R.string.helper_sendtocgeo_title, R.string.helper_sendtocgeo_description, R.drawable.cgeo, "http://send2.cgeo.org"),
+ new HelperApp(R.string.helper_contacts_title, R.string.helper_contacts_description, R.drawable.cgeo, "cgeo.contacts"),
new HelperApp(R.string.helper_pocketquery_title, R.string.helper_pocketquery_description, R.drawable.helper_pocketquery, "org.pquery"),
new HelperApp(R.string.helper_locus_title, R.string.helper_locus_description, R.drawable.helper_locus, "menion.android.locus"),
new HelperApp(R.string.helper_google_translate_title, R.string.helper_google_translate_description, R.drawable.helper_google_translate, "com.google.android.apps.translate"),
diff --git a/main/src/cgeo/geocaching/activity/AbstractListActivity.java b/main/src/cgeo/geocaching/activity/AbstractListActivity.java
index 2adae7a..a5d5c14 100644
--- a/main/src/cgeo/geocaching/activity/AbstractListActivity.java
+++ b/main/src/cgeo/geocaching/activity/AbstractListActivity.java
@@ -11,7 +11,6 @@ public abstract class AbstractListActivity extends FragmentListActivity implemen
IAbstractActivity {
private boolean keepScreenOn = false;
- private boolean paused = true;
protected CgeoApplication app = null;
protected Resources res = null;
@@ -85,26 +84,4 @@ public abstract class AbstractListActivity extends FragmentListActivity implemen
// initialize action bar title with activity title
ActivityMixin.setTitle(this, getTitle());
}
-
- @Override
- public void onResume() {
- paused = false;
- super.onResume();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- paused = true;
- }
-
- /**
- * Check if the current activity is paused. This must be called and acted
- * upon only from the UI thread.
- *
- * @return <code>true</code> if the current activity is paused
- */
- protected boolean isPaused() {
- return paused;
- }
}
diff --git a/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java b/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java
index c7d4507..6e2900d 100644
--- a/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java
+++ b/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java
@@ -5,7 +5,6 @@ import cgeo.geocaching.utils.Log;
import com.viewpagerindicator.TitlePageIndicator;
import com.viewpagerindicator.TitleProvider;
-
import org.apache.commons.lang3.tuple.Pair;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
diff --git a/main/src/cgeo/geocaching/activity/ActivityMixin.java b/main/src/cgeo/geocaching/activity/ActivityMixin.java
index c1a2678..bfd45da 100644
--- a/main/src/cgeo/geocaching/activity/ActivityMixin.java
+++ b/main/src/cgeo/geocaching/activity/ActivityMixin.java
@@ -125,6 +125,6 @@ public final class ActivityMixin {
editText.getText().replace(start, end, completeText);
int newCursor = moveCursor ? start + completeText.length() : start;
- editText.setSelection(newCursor, newCursor);
+ editText.setSelection(newCursor);
}
}
diff --git a/main/src/cgeo/geocaching/apps/AbstractLocusApp.java b/main/src/cgeo/geocaching/apps/AbstractLocusApp.java
index d6c2fe6..8e9181d 100644
--- a/main/src/cgeo/geocaching/apps/AbstractLocusApp.java
+++ b/main/src/cgeo/geocaching/apps/AbstractLocusApp.java
@@ -6,6 +6,7 @@ import cgeo.geocaching.Waypoint;
import cgeo.geocaching.enumerations.CacheSize;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.WaypointType;
+import cgeo.geocaching.utils.SynchronizedDateFormat;
import menion.android.locus.addon.publiclib.DisplayData;
import menion.android.locus.addon.publiclib.LocusUtils;
@@ -14,8 +15,6 @@ import menion.android.locus.addon.publiclib.geoData.PointGeocachingData;
import menion.android.locus.addon.publiclib.geoData.PointGeocachingDataWaypoint;
import menion.android.locus.addon.publiclib.geoData.PointsData;
-import org.apache.commons.lang3.time.FastDateFormat;
-
import android.app.Activity;
import android.location.Location;
@@ -30,7 +29,7 @@ import java.util.Locale;
* @see <a href="http://forum.asamm.cz/viewtopic.php?f=29&t=767">Locus forum</a>
*/
public abstract class AbstractLocusApp extends AbstractApp {
- private static final FastDateFormat ISO8601DATE = FastDateFormat.getInstance("yyyy-MM-dd'T'", Locale.US);
+ private static final SynchronizedDateFormat ISO8601DATE = new SynchronizedDateFormat("yyyy-MM-dd'T'", Locale.US);
protected AbstractLocusApp(final String text, int id, final String intent) {
super(text, id, intent);
@@ -122,7 +121,7 @@ public abstract class AbstractLocusApp extends AbstractApp {
pg.placedBy = cache.getOwnerDisplayName();
final Date hiddenDate = cache.getHiddenDate();
if (hiddenDate != null) {
- pg.hidden = ISO8601DATE.format(hiddenDate.getTime());
+ pg.hidden = ISO8601DATE.format(hiddenDate);
}
int locusId = toLocusType(cache.getType());
if (locusId != NO_LOCUS_ID) {
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java
index a1c752c..7cc5a4f 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java
@@ -8,6 +8,7 @@ import cgeo.geocaching.apps.AbstractApp;
import cgeo.geocaching.geopoint.Geopoint;
import android.app.Activity;
+import android.content.Intent;
/**
* navigation app for simple point navigation (no differentiation between cache/waypoint/point)
@@ -49,4 +50,12 @@ abstract class AbstractPointNavigationApp extends AbstractApp implements CacheNa
public boolean isEnabled(Waypoint waypoint) {
return waypoint.getCoords() != null;
}
+
+ protected static void addIntentExtras(final Geocache cache, final Intent intent) {
+ intent.putExtra("difficulty", cache.getDifficulty());
+ intent.putExtra("terrain", cache.getTerrain());
+ intent.putExtra("name", cache.getName());
+ intent.putExtra("code", cache.getGeocode());
+ intent.putExtra("size", cache.getSize().getL10n());
+ }
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java
index 60d6e31..819638c 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java
@@ -1,6 +1,8 @@
package cgeo.geocaching.apps.cache.navi;
+import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
+import cgeo.geocaching.Waypoint;
import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.utils.Log;
@@ -22,10 +24,15 @@ class GoogleMapsApp extends AbstractPointNavigationApp {
@Override
public void navigate(Activity activity, Geopoint point) {
- // INFO: q parameter works with Google Maps, but breaks cooperation with all other apps
+ navigate(activity, point, activity.getString(R.string.waypoint));
+ }
+
+ private static void navigate(Activity activity, Geopoint point, String label) {
try {
- activity.startActivity(new Intent(Intent.ACTION_VIEW,
- Uri.parse("geo:" + point.getLatitude() + "," + point.getLongitude())));
+ final String geoLocation = "geo:" + point.getLatitude() + "," + point.getLongitude();
+ final String query = point.getLatitude() + "," + point.getLongitude() + "(" + label + ")";
+ final String uriString = geoLocation + "?q=" + Uri.encode(query);
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(uriString)));
return;
} catch (RuntimeException e) {
// nothing
@@ -35,4 +42,13 @@ class GoogleMapsApp extends AbstractPointNavigationApp {
ActivityMixin.showToast(activity, getString(R.string.err_application_no));
}
+ @Override
+ public void navigate(Activity activity, Geocache cache) {
+ navigate(activity, cache.getCoords(), cache.getName());
+ }
+
+ @Override
+ public void navigate(Activity activity, Waypoint waypoint) {
+ navigate(activity, waypoint.getCoords(), waypoint.getName());
+ }
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/PebbleApp.java b/main/src/cgeo/geocaching/apps/cache/navi/PebbleApp.java
index 8ba3bef..9fe2fc1 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/PebbleApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/PebbleApp.java
@@ -9,7 +9,7 @@ import android.content.Intent;
/**
* Application for communication with the Pebble watch.
- *
+ *
*/
class PebbleApp extends AbstractPointNavigationApp {
@@ -33,11 +33,7 @@ class PebbleApp extends AbstractPointNavigationApp {
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());
+ addIntentExtras(cache, pebbleIntent);
activity.startActivity(pebbleIntent);
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/RadarApp.java b/main/src/cgeo/geocaching/apps/cache/navi/RadarApp.java
index ffa6650..23e696b 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/RadarApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/RadarApp.java
@@ -1,5 +1,6 @@
package cgeo.geocaching.apps.cache.navi;
+import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
import cgeo.geocaching.geopoint.Geopoint;
@@ -16,10 +17,22 @@ class RadarApp extends AbstractPointNavigationApp {
}
@Override
- public void navigate(Activity activity, Geopoint point) {
+ public void navigate(final Activity activity, final Geopoint point) {
+ final Intent radarIntent = createRadarIntent(point);
+ activity.startActivity(radarIntent);
+ }
+
+ private static Intent createRadarIntent(final Geopoint point) {
final Intent radarIntent = new Intent(INTENT);
radarIntent.putExtra("latitude", (float) point.getLatitude());
radarIntent.putExtra("longitude", (float) point.getLongitude());
+ return radarIntent;
+ }
+
+ @Override
+ public void navigate(final Activity activity, final Geocache cache) {
+ final Intent radarIntent = createRadarIntent(cache.getCoords());
+ addIntentExtras(cache, radarIntent);
activity.startActivity(radarIntent);
}
} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java b/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java
index ac5809e..40c4d92 100644
--- a/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java
+++ b/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.apps.cachelist;
-import cgeo.geocaching.SearchResult;
import cgeo.geocaching.Geocache;
+import cgeo.geocaching.SearchResult;
import cgeo.geocaching.apps.App;
import android.app.Activity;
diff --git a/main/src/cgeo/geocaching/concurrent/PriorityThreadFactory.java b/main/src/cgeo/geocaching/concurrent/PriorityThreadFactory.java
index 76379de..0da198b 100644
--- a/main/src/cgeo/geocaching/concurrent/PriorityThreadFactory.java
+++ b/main/src/cgeo/geocaching/concurrent/PriorityThreadFactory.java
@@ -1,5 +1,7 @@
package cgeo.geocaching.concurrent;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.concurrent.ThreadFactory;
/**
@@ -12,6 +14,7 @@ public class PriorityThreadFactory implements ThreadFactory {
this.priority = priority;
}
+ @NonNull
@Override
public Thread newThread(Runnable r) {
Thread result = new Thread(r);
diff --git a/main/src/cgeo/geocaching/connector/AbstractConnector.java b/main/src/cgeo/geocaching/connector/AbstractConnector.java
index 53a3bcb..ca05439 100644
--- a/main/src/cgeo/geocaching/connector/AbstractConnector.java
+++ b/main/src/cgeo/geocaching/connector/AbstractConnector.java
@@ -16,10 +16,10 @@ import cgeo.geocaching.connector.capability.ISearchByViewPort;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.utils.RunnableWithArgument;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import rx.util.functions.Action1;
import java.util.ArrayList;
import java.util.Collection;
@@ -255,21 +255,21 @@ public abstract class AbstractConnector implements IConnector {
List<UserAction> actions = getDefaultUserActions();
if (this instanceof ISearchByOwner) {
- actions.add(new UserAction(R.string.user_menu_view_hidden, new RunnableWithArgument<UserAction.Context>() {
+ actions.add(new UserAction(R.string.user_menu_view_hidden, new Action1<Context>() {
@Override
- public void run(Context context) {
+ public void call(Context context) {
CacheListActivity.startActivityOwner(context.activity, context.userName);
}
}));
}
if (this instanceof ISearchByFinder) {
- actions.add(new UserAction(R.string.user_menu_view_found, new RunnableWithArgument<UserAction.Context>() {
+ actions.add(new UserAction(R.string.user_menu_view_found, new Action1<UserAction.Context>() {
@Override
- public void run(Context context) {
- CacheListActivity.startActivityUserName(context.activity, context.userName);
+ public void call(Context context) {
+ CacheListActivity.startActivityFinder(context.activity, context.userName);
}
}));
}
@@ -283,10 +283,10 @@ public abstract class AbstractConnector implements IConnector {
public List<UserAction> getDefaultUserActions() {
final ArrayList<UserAction> actions = new ArrayList<UserAction>();
if (ContactsAddon.isAvailable()) {
- actions.add(new UserAction(R.string.user_menu_open_contact, new RunnableWithArgument<UserAction.Context>() {
+ actions.add(new UserAction(R.string.user_menu_open_contact, new Action1<UserAction.Context>() {
@Override
- public void run(Context context) {
+ public void call(Context context) {
ContactsAddon.openContactCard(context.activity, context.userName);
}
}));
diff --git a/main/src/cgeo/geocaching/connector/ConnectorFactory.java b/main/src/cgeo/geocaching/connector/ConnectorFactory.java
index 0081951..c6cfeb5 100644
--- a/main/src/cgeo/geocaching/connector/ConnectorFactory.java
+++ b/main/src/cgeo/geocaching/connector/ConnectorFactory.java
@@ -28,6 +28,11 @@ import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import rx.Observable;
+import rx.schedulers.Schedulers;
+import rx.util.functions.Func1;
+import rx.util.functions.Func2;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -176,14 +181,30 @@ public final class ConnectorFactory {
}
/** @see ISearchByViewPort#searchByViewport */
- public static SearchResult searchByViewport(final @NonNull Viewport viewport, final MapTokens tokens) {
- final SearchResult result = new SearchResult();
- for (final ISearchByViewPort connector : searchByViewPortConns) {
- if (connector.isActive()) {
- result.addSearchResult(connector.searchByViewport(viewport, tokens));
+ public static Observable<SearchResult> searchByViewport(final @NonNull Viewport viewport, final MapTokens tokens) {
+ return Observable.from(searchByViewPortConns).filter(new Func1<ISearchByViewPort, Boolean>() {
+ @Override
+ public Boolean call(final ISearchByViewPort connector) {
+ return connector.isActive();
}
- }
- return result;
+ }).parallel(new Func1<Observable<ISearchByViewPort>, Observable<SearchResult>>() {
+ @Override
+ public Observable<SearchResult> call(final Observable<ISearchByViewPort> connector) {
+ return connector.map(new Func1<ISearchByViewPort, SearchResult>() {
+ @Override
+ public SearchResult call(final ISearchByViewPort connector) {
+ return connector.searchByViewport(viewport, tokens);
+ }
+ });
+ }
+ }, Schedulers.io()).reduce(new SearchResult(), new Func2<SearchResult, SearchResult, SearchResult>() {
+
+ @Override
+ public SearchResult call(final SearchResult result, final SearchResult searchResult) {
+ result.addSearchResult(searchResult);
+ return result;
+ }
+ });
}
public static String getGeocodeFromURL(final String url) {
@@ -200,6 +221,12 @@ public final class ConnectorFactory {
return TRACKABLE_CONNECTORS;
}
+ /**
+ * Get the geocode of a trackable from a URL.
+ *
+ * @param url
+ * @return {@code null} if the URL cannot be decoded
+ */
public static String getTrackableFromURL(final String url) {
if (url == null) {
return null;
diff --git a/main/src/cgeo/geocaching/connector/UserAction.java b/main/src/cgeo/geocaching/connector/UserAction.java
index d0c97bb..da03a95 100644
--- a/main/src/cgeo/geocaching/connector/UserAction.java
+++ b/main/src/cgeo/geocaching/connector/UserAction.java
@@ -1,8 +1,7 @@
package cgeo.geocaching.connector;
-import cgeo.geocaching.utils.RunnableWithArgument;
-
import org.eclipse.jdt.annotation.NonNull;
+import rx.util.functions.Action1;
import android.app.Activity;
@@ -19,14 +18,15 @@ public class UserAction {
}
public final int displayResourceId;
- private final @NonNull RunnableWithArgument<Context> runnable;
+ private final @NonNull
+ Action1<Context> runnable;
- public UserAction(int displayResourceId, final @NonNull RunnableWithArgument<UserAction.Context> runnable) {
+ public UserAction(int displayResourceId, final @NonNull Action1<Context> runnable) {
this.displayResourceId = displayResourceId;
this.runnable = runnable;
}
public void run(Context context) {
- runnable.run(context);
+ runnable.call(context);
}
}
diff --git a/main/src/cgeo/geocaching/connector/ec/ECApi.java b/main/src/cgeo/geocaching/connector/ec/ECApi.java
index 03fce4d..702e557 100644
--- a/main/src/cgeo/geocaching/connector/ec/ECApi.java
+++ b/main/src/cgeo/geocaching/connector/ec/ECApi.java
@@ -15,12 +15,12 @@ import cgeo.geocaching.list.StoredList;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.SynchronizedDateFormat;
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;
@@ -39,7 +39,7 @@ public class ECApi {
private static final String API_HOST = "https://extremcaching.com/exports/";
private static final ECLogin ecLogin = ECLogin.getInstance();
- private static final FastDateFormat LOG_DATE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSSZ", TimeZone.getTimeZone("UTC"), Locale.US);
+ private static final SynchronizedDateFormat LOG_DATE_FORMAT = new SynchronizedDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ", TimeZone.getTimeZone("UTC"), Locale.US);
public static String getIdFromGeocode(final String geocode) {
return StringUtils.removeStartIgnoreCase(geocode, "EC");
diff --git a/main/src/cgeo/geocaching/connector/ec/ECConnector.java b/main/src/cgeo/geocaching/connector/ec/ECConnector.java
index 6da076b..71716fe 100644
--- a/main/src/cgeo/geocaching/connector/ec/ECConnector.java
+++ b/main/src/cgeo/geocaching/connector/ec/ECConnector.java
@@ -140,7 +140,7 @@ public class ECConnector extends AbstractConnector implements ISearchByGeocode,
// invoke settings activity to insert login details
if (status == StatusCode.NO_LOGIN_INFO_STORED && fromActivity != null) {
- SettingsActivity.jumpToServicesPage(fromActivity);
+ SettingsActivity.openForScreen(R.string.preference_screen_ec, fromActivity);
}
}
return status == StatusCode.NO_ERROR;
diff --git a/main/src/cgeo/geocaching/connector/ec/ECLogin.java b/main/src/cgeo/geocaching/connector/ec/ECLogin.java
index 52bd423..012bdc9 100644
--- a/main/src/cgeo/geocaching/connector/ec/ECLogin.java
+++ b/main/src/cgeo/geocaching/connector/ec/ECLogin.java
@@ -10,7 +10,6 @@ import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.eclipse.jdt.annotation.Nullable;
diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
index e946748..a62b1f6 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
@@ -27,12 +27,12 @@ import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.settings.SettingsActivity;
import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.RunnableWithArgument;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import rx.util.functions.Action1;
import android.content.Context;
import android.content.Intent;
@@ -91,7 +91,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
@Override
public boolean supportsPersonalNote() {
- return Settings.isPremiumMember();
+ return Settings.isGCPremiumMember();
}
@Override
@@ -285,7 +285,22 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
@Override
protected String getCacheUrlPrefix() {
- return CACHE_URL_SHORT;
+ return null; // UNUSED
+ }
+
+ @Override
+ public String getGeocodeFromUrl(String url) {
+ // coord.info URLs
+ String code = StringUtils.substringAfterLast(url, "coord.info/");
+ if (code != null && canHandle(code)) {
+ return code;
+ }
+ // expanded geocaching.com URLs
+ code = StringUtils.substringBetween(url, "/geocache/", "_");
+ if (code != null && canHandle(code)) {
+ return code;
+ }
+ return null;
}
@Override
@@ -316,7 +331,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
// invoke settings activity to insert login details
if (status == StatusCode.NO_LOGIN_INFO_STORED && fromActivity != null) {
- SettingsActivity.jumpToServicesPage(fromActivity);
+ SettingsActivity.openForScreen(R.string.preference_screen_gc, fromActivity);
}
}
return status == StatusCode.NO_ERROR;
@@ -379,17 +394,17 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
public @NonNull
List<UserAction> getUserActions() {
List<UserAction> actions = super.getUserActions();
- actions.add(new UserAction(R.string.user_menu_open_browser, new RunnableWithArgument<UserAction.Context>() {
+ actions.add(new UserAction(R.string.user_menu_open_browser, new Action1<UserAction.Context>() {
@Override
- public void run(cgeo.geocaching.connector.UserAction.Context context) {
+ public void call(cgeo.geocaching.connector.UserAction.Context context) {
context.activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?u=" + Network.encode(context.userName))));
}
}));
- actions.add(new UserAction(R.string.user_menu_send_message, new RunnableWithArgument<UserAction.Context>() {
+ actions.add(new UserAction(R.string.user_menu_send_message, new Action1<UserAction.Context>() {
@Override
- public void run(cgeo.geocaching.connector.UserAction.Context context) {
+ public void call(cgeo.geocaching.connector.UserAction.Context context) {
context.activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/email/?u=" + Network.encode(context.userName))));
}
}));
diff --git a/main/src/cgeo/geocaching/connector/gc/GCLogin.java b/main/src/cgeo/geocaching/connector/gc/GCLogin.java
index a7cf6cf..92d488d 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCLogin.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCLogin.java
@@ -14,7 +14,6 @@ import cgeo.geocaching.utils.MatcherWrapper;
import cgeo.geocaching.utils.TextUtils;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
@@ -97,7 +96,7 @@ public class GCLogin extends AbstractLogin {
}
if (getLoginStatus(loginData)) {
- Log.i("Already logged in Geocaching.com as " + username + " (" + Settings.getMemberStatus() + ')');
+ Log.i("Already logged in Geocaching.com as " + username + " (" + Settings.getGCMemberStatus() + ')');
if (switchToEnglish(loginData) && retry) {
return login(false);
}
@@ -132,7 +131,7 @@ public class GCLogin extends AbstractLogin {
assert loginData != null; // Caught above
if (getLoginStatus(loginData)) {
- Log.i("Successfully logged in Geocaching.com as " + username + " (" + Settings.getMemberStatus() + ')');
+ Log.i("Successfully logged in Geocaching.com as " + username + " (" + Settings.getGCMemberStatus() + ')');
if (switchToEnglish(loginData) && retry) {
return login(false);
@@ -204,9 +203,9 @@ public class GCLogin extends AbstractLogin {
Log.e("getLoginStatus: bad cache count", e);
}
setActualCachesFound(cachesCount);
- Settings.setMemberStatus(TextUtils.getMatch(page, GCConstants.PATTERN_MEMBER_STATUS, true, null));
+ Settings.setGCMemberStatus(TextUtils.getMatch(page, GCConstants.PATTERN_MEMBER_STATUS, true, null));
if ( page.contains(GCConstants.MEMBER_STATUS_RENEW) ) {
- Settings.setMemberStatus(GCConstants.MEMBER_STATUS_PM);
+ Settings.setGCMemberStatus(GCConstants.MEMBER_STATUS_PM);
}
return true;
}
@@ -259,9 +258,9 @@ public class GCLogin extends AbstractLogin {
final String responseData = StringUtils.defaultString(Network.getResponseData(Network.getRequest("http://www.geocaching.com/my/")));
final String profile = TextUtils.replaceWhitespace(responseData);
- Settings.setMemberStatus(TextUtils.getMatch(profile, GCConstants.PATTERN_MEMBER_STATUS, true, null));
+ Settings.setGCMemberStatus(TextUtils.getMatch(profile, GCConstants.PATTERN_MEMBER_STATUS, true, null));
if (profile.contains(GCConstants.MEMBER_STATUS_RENEW)) {
- Settings.setMemberStatus(GCConstants.MEMBER_STATUS_PM);
+ Settings.setGCMemberStatus(GCConstants.MEMBER_STATUS_PM);
}
setActualCachesFound(Integer.parseInt(TextUtils.getMatch(profile, GCConstants.PATTERN_CACHES_FOUND, true, "-1").replaceAll("[,.]", "")));
diff --git a/main/src/cgeo/geocaching/connector/gc/GCMap.java b/main/src/cgeo/geocaching/connector/gc/GCMap.java
index 6c94150..2782b64 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCMap.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCMap.java
@@ -368,7 +368,7 @@ public class GCMap {
}
}
- if (strategy.flags.contains(StrategyFlag.SEARCH_NEARBY) && Settings.isPremiumMember()) {
+ if (strategy.flags.contains(StrategyFlag.SEARCH_NEARBY) && Settings.isGCPremiumMember()) {
final Geopoint center = viewport.getCenter();
if ((lastSearchViewport == null) || !lastSearchViewport.contains(center)) {
//FIXME We don't have a RecaptchaReceiver!?
diff --git a/main/src/cgeo/geocaching/connector/gc/GCParser.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java
index 62ccb14..f60764d 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCParser.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java
@@ -36,7 +36,6 @@ import cgeo.geocaching.utils.SynchronizedDateFormat;
import cgeo.geocaching.utils.TextUtils;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringEscapeUtils;
@@ -68,7 +67,7 @@ public abstract class GCParser {
private final static SynchronizedDateFormat dateTbIn1 = new SynchronizedDateFormat("EEEEE, dd MMMMM yyyy", Locale.ENGLISH); // Saturday, 28 March 2009
private final static SynchronizedDateFormat dateTbIn2 = new SynchronizedDateFormat("EEEEE, MMMMM dd, yyyy", Locale.ENGLISH); // Saturday, March 28, 2009
- private static SearchResult parseSearch(final String url, final String pageContent, final boolean showCaptcha, RecaptchaReceiver thread) {
+ private static SearchResult parseSearch(final String url, final String pageContent, final boolean showCaptcha, final RecaptchaReceiver recaptchaReceiver) {
if (StringUtils.isBlank(pageContent)) {
Log.e("GCParser.parseSearch: No page given");
return null;
@@ -86,12 +85,12 @@ public abstract class GCParser {
final String recaptchaJsParam = TextUtils.getMatch(page, GCConstants.PATTERN_SEARCH_RECAPTCHA, false, null);
if (recaptchaJsParam != null) {
- thread.setKey(recaptchaJsParam.trim());
+ recaptchaReceiver.setKey(recaptchaJsParam.trim());
- thread.fetchChallenge();
+ recaptchaReceiver.fetchChallenge();
}
- if (thread != null && StringUtils.isNotBlank(thread.getChallenge())) {
- thread.notifyNeed();
+ if (recaptchaReceiver != null && StringUtils.isNotBlank(recaptchaReceiver.getChallenge())) {
+ recaptchaReceiver.notifyNeed();
}
}
@@ -277,12 +276,12 @@ public abstract class GCParser {
}
String recaptchaText = null;
- if (thread != null && StringUtils.isNotBlank(thread.getChallenge())) {
- thread.waitForUser();
- recaptchaText = thread.getText();
+ if (recaptchaReceiver != null && StringUtils.isNotBlank(recaptchaReceiver.getChallenge())) {
+ recaptchaReceiver.waitForUser();
+ recaptchaText = recaptchaReceiver.getText();
}
- if (!cids.isEmpty() && (Settings.isPremiumMember() || showCaptcha) && ((thread == null || StringUtils.isBlank(thread.getChallenge())) || StringUtils.isNotBlank(recaptchaText))) {
+ if (!cids.isEmpty() && (Settings.isGCPremiumMember() || showCaptcha) && ((recaptchaReceiver == null || StringUtils.isBlank(recaptchaReceiver.getChallenge())) || StringUtils.isNotBlank(recaptchaText))) {
Log.i("Trying to get .loc for " + cids.size() + " caches");
try {
@@ -303,8 +302,8 @@ public abstract class GCParser {
params.put("CID", cid);
}
- if (thread != null && StringUtils.isNotBlank(thread.getChallenge()) && StringUtils.isNotBlank(recaptchaText)) {
- params.put("recaptcha_challenge_field", thread.getChallenge());
+ if (StringUtils.isNotBlank(recaptchaText) && recaptchaReceiver != null) {
+ params.put("recaptcha_challenge_field", recaptchaReceiver.getChallenge());
params.put("recaptcha_response_field", recaptchaText);
}
params.put("ctl00$ContentBody$uxDownloadLoc", "Download Waypoints");
@@ -347,6 +346,9 @@ public abstract class GCParser {
// attention: parseCacheFromText already stores implicitly through searchResult.addCache
if (searchResult != null && !searchResult.getGeocodes().isEmpty()) {
final Geocache cache = searchResult.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB);
+ if (cache == null) {
+ return null;
+ }
getExtraOnlineInfo(cache, page, handler);
// too late: it is already stored through parseCacheFromText
cache.setDetailedUpdatedNow();
@@ -741,7 +743,7 @@ public abstract class GCParser {
cache.parseWaypointsFromNote();
// logs
- cache.setLogs(loadLogsFromDetails(page, cache, false, true));
+ cache.setLogs(getLogsFromDetails(page, false));
// last check for necessary cache conditions
if (StringUtils.isBlank(cache.getGeocode())) {
@@ -1380,8 +1382,7 @@ public abstract class GCParser {
}
private static boolean changeFavorite(final Geocache cache, final boolean add) {
- final String page = requestHtmlPage(cache.getGeocode(), null, "n", "0");
- final String userToken = TextUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, "");
+ final String userToken = getUserToken(cache);
if (StringUtils.isEmpty(userToken)) {
return false;
}
@@ -1400,6 +1401,11 @@ public abstract class GCParser {
return false;
}
+ private static String getUserToken(final Geocache cache) {
+ final String page = requestHtmlPage(cache.getGeocode(), null, "n", "0");
+ return TextUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, "");
+ }
+
/**
* Removes the cache from the favorites.
*
@@ -1613,19 +1619,20 @@ public abstract class GCParser {
}
/**
- * Load logs from a cache details page.
+ * Extract logs from a cache details page.
*
* @param page
* the text of the details page
- * @param cache
- * the cache object to put the logs in
* @param friends
- * retrieve friend logs
+ * return friends logs only (will require a network request)
+ * @return a list of log entries or <code>null</code> if the logs could not be retrieved
+ *
*/
- private static List<LogEntry> loadLogsFromDetails(final String page, final Geocache cache, final boolean friends, final boolean getDataFromPage) {
+ @Nullable
+ private static List<LogEntry> getLogsFromDetails(final String page, final boolean friends) {
String rawResponse;
- if (!getDataFromPage) {
+ if (friends) {
final MatcherWrapper userTokenMatcher = new MatcherWrapper(GCConstants.PATTERN_USERTOKEN, page);
if (!userTokenMatcher.find()) {
Log.e("GCParser.loadLogsFromDetails: unable to extract userToken");
@@ -1712,7 +1719,7 @@ public abstract class GCParser {
final JSONArray images = entry.getJSONArray("Images");
for (int i = 0; i < images.length(); i++) {
final JSONObject image = images.getJSONObject(i);
- final String url = "http://img.geocaching.com/cache/log/large/" + image.getString("FileName");
+ final String url = "http://imgcdn.geocaching.com/cache/log/large/" + image.getString("FileName");
final String title = TextUtils.removeControlCharacters(image.getString("Name"));
final Image logImage = new Image(url, title);
logDone.addLogImage(logImage);
@@ -1825,7 +1832,7 @@ public abstract class GCParser {
if (Settings.isFriendLogsWanted()) {
CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_logs);
final List<LogEntry> allLogs = cache.getLogs();
- final List<LogEntry> friendLogs = loadLogsFromDetails(page, cache, true, false);
+ final List<LogEntry> friendLogs = getLogsFromDetails(page, true);
if (friendLogs != null) {
for (final LogEntry log : friendLogs) {
if (allLogs.contains(log)) {
@@ -1860,8 +1867,7 @@ public abstract class GCParser {
}
public static boolean editModifiedCoordinates(Geocache cache, Geopoint wpt) {
- final String page = requestHtmlPage(cache.getGeocode(), null, "n", "0");
- final String userToken = TextUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, "");
+ final String userToken = getUserToken(cache);
if (StringUtils.isEmpty(userToken)) {
return false;
}
@@ -1896,8 +1902,7 @@ public abstract class GCParser {
}
public static boolean uploadPersonalNote(Geocache cache) {
- final String page = requestHtmlPage(cache.getGeocode(), null, "n", "0");
- final String userToken = TextUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, "");
+ final String userToken = getUserToken(cache);
if (StringUtils.isEmpty(userToken)) {
return false;
}
diff --git a/main/src/cgeo/geocaching/connector/gc/RecaptchaHandler.java b/main/src/cgeo/geocaching/connector/gc/RecaptchaHandler.java
new file mode 100644
index 0000000..44ad850
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/gc/RecaptchaHandler.java
@@ -0,0 +1,114 @@
+package cgeo.geocaching.connector.gc;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.loaders.RecaptchaReceiver;
+import cgeo.geocaching.network.Network;
+import cgeo.geocaching.utils.Log;
+
+import org.apache.commons.io.IOUtils;
+
+import rx.Observable;
+import rx.android.observables.AndroidObservable;
+import rx.schedulers.Schedulers;
+import rx.util.functions.Action1;
+import rx.util.functions.Func0;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Handler;
+import android.os.Message;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+
+import java.io.InputStream;
+
+public class RecaptchaHandler extends Handler {
+ final public static int SHOW_CAPTCHA = 1;
+
+ final private Activity activity;
+ final private RecaptchaReceiver recaptchaReceiver;
+
+ public RecaptchaHandler(final Activity activity, final RecaptchaReceiver recaptchaReceiver) {
+ this.activity = activity;
+ this.recaptchaReceiver = recaptchaReceiver;
+ }
+
+ private void loadChallenge(final ImageView imageView, final View reloadButton) {
+ getCaptcha().subscribe(new Action1<Bitmap>() {
+ @Override
+ public void call(final Bitmap bitmap) {
+ imageView.setImageBitmap(bitmap);
+ }
+ }, new Action1<Throwable>() {
+ @Override
+ public void call(final Throwable throwable) {
+ // Do nothing
+ }
+ });
+ reloadButton.setEnabled(true);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == SHOW_CAPTCHA) {
+ final AlertDialog.Builder dlg = new AlertDialog.Builder(activity);
+ final View view = activity.getLayoutInflater().inflate(R.layout.recaptcha_dialog, null);
+
+ final ImageView imageView = (ImageView) view.findViewById(R.id.image);
+
+ final ImageButton reloadButton = (ImageButton) view.findViewById(R.id.button_recaptcha_refresh);
+ reloadButton.setEnabled(false);
+ reloadButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ recaptchaReceiver.fetchChallenge();
+ loadChallenge(imageView, reloadButton);
+ }
+ });
+
+ loadChallenge(imageView, reloadButton);
+
+ dlg.setTitle(activity.getString(R.string.caches_recaptcha_title));
+ dlg.setView(view);
+ dlg.setNeutralButton(activity.getString(R.string.caches_recaptcha_continue), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ final String text = ((EditText) view.findViewById(R.id.text)).getText().toString();
+ recaptchaReceiver.setText(text);
+ dialog.cancel();
+ }
+ });
+
+ dlg.create().show();
+ }
+ }
+
+ private Observable<Bitmap> getCaptcha() {
+ return AndroidObservable.fromActivity(activity,
+ Observable.defer(new Func0<Observable<? extends Bitmap>>() {
+ @Override
+ public Observable<? extends Bitmap> call() {
+ final String url = "http://www.google.com/recaptcha/api/image?c=" + recaptchaReceiver.getChallenge();
+ final InputStream is = Network.getResponseStream(Network.getRequest(url));
+ if (is != null) {
+ try {
+ final Bitmap img = BitmapFactory.decodeStream(is);
+ return Observable.from(img);
+ } catch (final Exception e) {
+ Log.e("RecaptchaHandler.getCaptcha", e);
+ return Observable.error(e);
+ } finally {
+ IOUtils.closeQuietly(is);
+ }
+ }
+ return Observable.empty();
+ }
+ }).subscribeOn(Schedulers.io()));
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/gc/SearchHandler.java b/main/src/cgeo/geocaching/connector/gc/SearchHandler.java
deleted file mode 100644
index 795ed2f..0000000
--- a/main/src/cgeo/geocaching/connector/gc/SearchHandler.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package cgeo.geocaching.connector.gc;
-
-import cgeo.geocaching.R;
-import cgeo.geocaching.loaders.RecaptchaReceiver;
-import cgeo.geocaching.utils.Log;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Handler;
-import android.os.Message;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-public class SearchHandler extends Handler {
- private Activity activity = null;
- private Resources res = null;
- private RecaptchaReceiver recaptchaThread = null;
- private ImageView imageView = null;
- private Bitmap img = null;
-
- private Handler imgHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- try {
- if (img != null && imageView != null) {
- imageView.setImageBitmap(img);
- }
- } catch (Exception e) {
- Log.e("Error setting reCAPTCHA image", e);
- }
- }
- };
-
- public SearchHandler(Activity activityIn, Resources resIn, RecaptchaReceiver recaptchaThreadIn) {
- activity = activityIn;
- res = resIn;
- recaptchaThread = recaptchaThreadIn;
- }
-
- @Override
- public void handleMessage(Message msg) {
- try {
- if (msg.what == 1) {
- final AlertDialog.Builder dlg = new AlertDialog.Builder(activity);
- final LayoutInflater inflater = activity.getLayoutInflater();
- final View view = inflater.inflate(R.layout.recaptcha_dialog, null);
-
- imageView = (ImageView) view.findViewById(R.id.image);
-
- ImageButton reloadButton = (ImageButton) view.findViewById(R.id.button_recaptcha_refresh);
- reloadButton.setOnClickListener(new View.OnClickListener() {
-
- @Override
- public void onClick(View v) {
- recaptchaThread.fetchChallenge();
- try {
- (new GetCaptchaThread(new URL("http://www.google.com/recaptcha/api/image?c=" + recaptchaThread.getChallenge()))).start();
- } catch (MalformedURLException e) {
- Log.e("Bad reCAPTCHA image url", e);
- }
- }
- });
-
- (new GetCaptchaThread(new URL("http://www.google.com/recaptcha/api/image?c=" + recaptchaThread.getChallenge()))).start();
-
- dlg.setTitle(res.getString(R.string.caches_recaptcha_title));
- dlg.setView(view);
- dlg.setNeutralButton(res.getString(R.string.caches_recaptcha_continue), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- final String text = ((EditText) view.findViewById(R.id.text)).getText().toString();
-
- recaptchaThread.setText(text);
-
- dialog.cancel();
- }
- });
-
- dlg.create().show();
- }
- } catch (MalformedURLException e) {
- Log.e("Error in reCAPTCHA handler", e);
- }
- }
-
- private class GetCaptchaThread extends Thread {
- private URL uri = null;
-
- public GetCaptchaThread(URL uriIn) {
- uri = uriIn;
- }
-
- @Override
- public void run() {
- try {
- Log.d("Getting reCAPTCHA image from: " + uri.toString());
- HttpURLConnection connection = (HttpURLConnection) uri.openConnection();
- connection.setDoInput(true);
- connection.connect();
-
- InputStream is = connection.getInputStream();
-
- img = BitmapFactory.decodeStream(is);
-
- is.close();
-
- imgHandler.sendEmptyMessage(0);
- } catch (IOException e) {
- Log.e("Failed to download reCAPTCHA image", e);
- }
- }
- }
-}
diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
index 2175935..3ae4e97 100644
--- a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
+++ b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
@@ -34,7 +34,6 @@ import cgeo.geocaching.utils.SynchronizedDateFormat;
import ch.boye.httpclientandroidlib.HttpResponse;
import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.time.FastDateFormat;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
@@ -61,7 +60,7 @@ final class OkapiClient {
private static final char SEPARATOR = '|';
private static final String SEPARATOR_STRING = Character.toString(SEPARATOR);
- private static final FastDateFormat LOG_DATE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSSZ", TimeZone.getTimeZone("UTC"), Locale.US);
+ private static final SynchronizedDateFormat LOG_DATE_FORMAT = new SynchronizedDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ", TimeZone.getTimeZone("UTC"), Locale.US);
private static final SynchronizedDateFormat ISO8601DATEFORMAT = new SynchronizedDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault());
private static final String CACHE_ATTRNAMES = "attrnames";
@@ -75,7 +74,8 @@ final class OkapiClient {
private static final String CACHE_STATUS_ARCHIVED = "Archived";
private static final String CACHE_STATUS_DISABLED = "Temporarily unavailable";
private static final String CACHE_IS_FOUND = "is_found";
- private static final String CACHE_SIZE = "size";
+ private static final String CACHE_SIZE_DEPRECATED = "size";
+ private static final String CACHE_SIZE2 = "size2";
private static final String CACHE_VOTES = "rating_votes";
private static final String CACHE_NOTFOUNDS = "notfounds";
private static final String CACHE_FOUNDS = "founds";
@@ -112,7 +112,7 @@ final class OkapiClient {
// the several realms of possible fields for cache retrieval:
// Core: for livemap requests (L3 - only with level 3 auth)
// Additional: additional fields for full cache (L3 - only for level 3 auth, current - only for connectors with current api)
- private static final String SERVICE_CACHE_CORE_FIELDS = "code|name|location|type|status|difficulty|terrain|size|date_hidden";
+ private static final String SERVICE_CACHE_CORE_FIELDS = "code|name|location|type|status|difficulty|terrain|size|size2|date_hidden";
private static final String SERVICE_CACHE_CORE_L3_FIELDS = "is_found";
private static final String SERVICE_CACHE_ADDITIONAL_FIELDS = "owner|founds|notfounds|rating|rating_votes|recommendations|description|hint|images|latest_logs|alt_wpts|attrnames|req_passwd";
private static final String SERVICE_CACHE_ADDITIONAL_CURRENT_FIELDS = "gc_code|attribution_note|attr_acodes";
@@ -152,19 +152,14 @@ final class OkapiClient {
}
public static List<Geocache> getCachesByOwner(final String username, final OCApiConnector connector) {
- final Parameters params = new Parameters("search_method", METHOD_SEARCH_ALL);
- final Map<String, String> valueMap = new LinkedHashMap<String, String>();
- final @Nullable
- String uuid = getUserUUID(connector, username);
- if (StringUtils.isEmpty(uuid)) {
- return Collections.emptyList();
- }
- valueMap.put("owner_uuid", uuid);
-
- return requestCaches(connector, params, valueMap);
+ return getCachesByUser(username, connector, "owner_uuid");
}
public static List<Geocache> getCachesByFinder(final String username, final OCApiConnector connector) {
+ return getCachesByUser(username, connector, "found_by");
+ }
+
+ private static List<Geocache> getCachesByUser(final String username, final OCApiConnector connector, final String userRequestParam) {
final Parameters params = new Parameters("search_method", METHOD_SEARCH_ALL);
final Map<String, String> valueMap = new LinkedHashMap<String, String>();
final @Nullable
@@ -172,7 +167,7 @@ final class OkapiClient {
if (StringUtils.isEmpty(uuid)) {
return Collections.emptyList();
}
- valueMap.put("found_by", uuid);
+ valueMap.put(userRequestParam, uuid);
return requestCaches(connector, params, valueMap);
}
@@ -567,12 +562,25 @@ final class OkapiClient {
}
private static CacheSize getCacheSize(final JSONObject response) {
- if (response.isNull(CACHE_SIZE)) {
+ if (response.isNull(CACHE_SIZE2)) {
+ return getCacheSizeDeprecated(response);
+ }
+ try {
+ final String size = response.getString(CACHE_SIZE2);
+ return CacheSize.getById(size);
+ } catch (JSONException e) {
+ Log.e("OkapiClient.getCacheSize", e);
+ return getCacheSizeDeprecated(response);
+ }
+ }
+
+ private static CacheSize getCacheSizeDeprecated(final JSONObject response) {
+ if (response.isNull(CACHE_SIZE_DEPRECATED)) {
return CacheSize.NOT_CHOSEN;
}
double size = 0;
try {
- size = response.getDouble(CACHE_SIZE);
+ size = response.getDouble(CACHE_SIZE_DEPRECATED);
} catch (final JSONException e) {
Log.e("OkapiClient.getCacheSize", e);
}
@@ -586,7 +594,7 @@ final class OkapiClient {
case 4:
return CacheSize.LARGE;
case 5:
- return CacheSize.LARGE;
+ return CacheSize.VERY_LARGE;
default:
break;
}
diff --git a/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java b/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java
index f72b698..5f11a11 100644
--- a/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java
+++ b/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java
@@ -28,10 +28,10 @@ public class OXGPXParser extends GPX10Parser {
/**
* The short description of OX caches contains "title by owner, type(T/D/Awesomeness)". That is a lot of
* duplication.
- *
+ *
* @param cache
*/
private static void removeTitleFromShortDescription(final @NonNull Geocache cache) {
- cache.setShortDescription(StringUtils.substringAfterLast(cache.getShortDescription(), ","));
+ cache.setShortDescription(StringUtils.trim(StringUtils.substringAfterLast(cache.getShortDescription(), ",")));
}
}
diff --git a/main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java b/main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java
index 2defc52..0137af4 100644
--- a/main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java
+++ b/main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java
@@ -11,7 +11,6 @@ import cgeo.geocaching.utils.CryptUtils;
import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.collections4.CollectionUtils;
import org.eclipse.jdt.annotation.NonNull;
diff --git a/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java b/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java
index 69efddc..fb554b9 100644
--- a/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java
+++ b/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.connector.AbstractConnector;
import cgeo.geocaching.connector.UserAction;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import java.util.List;
@@ -15,7 +16,8 @@ public abstract class AbstractTrackableConnector implements TrackableConnector {
}
@Override
- public String getTrackableCodeFromUrl(@NonNull String url) {
+ public @Nullable
+ String getTrackableCodeFromUrl(@NonNull String url) {
return null;
}
diff --git a/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java b/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java
index 8387076..03052f9 100644
--- a/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java
+++ b/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java
@@ -4,6 +4,10 @@ import cgeo.geocaching.Trackable;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.utils.Log;
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
import java.util.regex.Pattern;
public class GeokretyConnector extends AbstractTrackableConnector {
@@ -29,7 +33,7 @@ public class GeokretyConnector extends AbstractTrackableConnector {
return GeokretyParser.parse(page);
}
- private static int getId(String geocode) {
+ protected static int getId(String geocode) {
try {
final String hex = geocode.substring(2);
return Integer.parseInt(hex, 16);
@@ -39,4 +43,25 @@ public class GeokretyConnector extends AbstractTrackableConnector {
return -1;
}
+ @Override
+ public @Nullable
+ String getTrackableCodeFromUrl(@NonNull String url) {
+ // http://geokrety.org/konkret.php?id=38545
+ String id = StringUtils.substringAfterLast(url, "konkret.php?id=");
+ if (StringUtils.isNumeric(id)) {
+ return geocode(Integer.parseInt(id));
+ }
+ return null;
+ }
+
+ /**
+ * Get geocode from geokrety id
+ *
+ * @param id
+ * @return
+ */
+ public static String geocode(final int id) {
+ return String.format("GK%04X", id);
+ }
+
}
diff --git a/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java b/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java
index ee8c8c0..0e64abd 100644
--- a/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java
+++ b/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java
@@ -37,8 +37,8 @@ public class GeokretyParser {
public void start(Attributes attributes) {
try {
final String kretyId = attributes.getValue("id");
- if (StringUtils.isNotBlank(kretyId)) {
- trackable.setGeocode(geocode(Integer.parseInt(kretyId)));
+ if (StringUtils.isNumeric(kretyId)) {
+ trackable.setGeocode(GeokretyConnector.geocode(Integer.parseInt(kretyId)));
}
final String distance = attributes.getValue("dist");
if (StringUtils.isNotBlank(distance)) {
@@ -88,8 +88,4 @@ public class GeokretyParser {
}
return null;
}
-
- protected static String geocode(final int id) {
- return String.format("GK%04X", id);
- }
}
diff --git a/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java b/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java
index 0990d96..6071b5f 100644
--- a/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java
+++ b/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.Trackable;
import cgeo.geocaching.connector.UserAction;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import java.util.List;
@@ -21,7 +22,8 @@ public interface TrackableConnector {
public Trackable searchTrackable(String geocode, String guid, String id);
- public String getTrackableCodeFromUrl(final @NonNull String url);
+ public @Nullable
+ String getTrackableCodeFromUrl(final @NonNull String url);
public @NonNull
List<UserAction> getUserActions();
diff --git a/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java b/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java
index dad285c..77848d7 100644
--- a/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java
+++ b/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java
@@ -7,6 +7,7 @@ import cgeo.geocaching.connector.gc.GCParser;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import java.util.List;
import java.util.regex.Pattern;
@@ -20,7 +21,7 @@ public class TravelBugConnector extends AbstractTrackableConnector {
@Override
public boolean canHandleTrackable(String geocode) {
- return TravelBugConnector.PATTERN_TB_CODE.matcher(geocode).matches();
+ return TravelBugConnector.PATTERN_TB_CODE.matcher(geocode).matches() && !StringUtils.startsWithIgnoreCase(geocode, "GC");
}
@Override
@@ -54,8 +55,18 @@ public class TravelBugConnector extends AbstractTrackableConnector {
}
@Override
- public String getTrackableCodeFromUrl(@NonNull String url) {
- return StringUtils.substringAfterLast(url, "?tracker=");
+ public @Nullable
+ String getTrackableCodeFromUrl(@NonNull String url) {
+ // coord.info URLs
+ String code = StringUtils.substringAfterLast(url, "coord.info/");
+ if (code != null && canHandleTrackable(code)) {
+ return code;
+ }
+ code = StringUtils.substringAfterLast(url, "?tracker=");
+ if (code != null && canHandleTrackable(code)) {
+ return code;
+ }
+ return null;
}
@Override
diff --git a/main/src/cgeo/geocaching/enumerations/CacheAttribute.java b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java
index 472bad5..0703c3c 100644
--- a/main/src/cgeo/geocaching/enumerations/CacheAttribute.java
+++ b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java
@@ -164,15 +164,11 @@ public enum CacheAttribute {
}
private final static Map<String, CacheAttribute> FIND_BY_GCRAWNAME;
- private final static SparseArray<CacheAttribute> FIND_BY_GCID = new SparseArray<CacheAttribute>();
private final static SparseArray<CacheAttribute> FIND_BY_OCACODE = new SparseArray<CacheAttribute>();
static {
final HashMap<String, CacheAttribute> mapGcRawNames = new HashMap<String, CacheAttribute>();
for (CacheAttribute attr : values()) {
mapGcRawNames.put(attr.rawName, attr);
- if (attr.gcid != NO_ID) {
- FIND_BY_GCID.put(attr.gcid, attr);
- }
if (attr.ocacode != NO_ID) {
FIND_BY_OCACODE.put(attr.ocacode, attr);
}
@@ -184,10 +180,6 @@ public enum CacheAttribute {
return rawName != null ? FIND_BY_GCRAWNAME.get(rawName) : null;
}
- public static CacheAttribute getByGcId(final int gcid) {
- return FIND_BY_GCID.get(gcid);
- }
-
public static CacheAttribute getByOcACode(final int ocAcode) {
return FIND_BY_OCACODE.get(ocAcode);
}
diff --git a/main/src/cgeo/geocaching/enumerations/CacheListType.java b/main/src/cgeo/geocaching/enumerations/CacheListType.java
index f482d5b..1fce282 100644
--- a/main/src/cgeo/geocaching/enumerations/CacheListType.java
+++ b/main/src/cgeo/geocaching/enumerations/CacheListType.java
@@ -1,23 +1,32 @@
package cgeo.geocaching.enumerations;
+import cgeo.geocaching.loaders.AbstractSearchLoader.CacheListLoaderType;
+
public enum CacheListType {
- OFFLINE(true),
- POCKET(false),
- HISTORY(true),
- NEAREST(false),
- COORDINATE(false),
- KEYWORD(false),
- ADDRESS(false),
- USERNAME(false),
- OWNER(false),
- MAP(false);
+ OFFLINE(true, CacheListLoaderType.OFFLINE),
+ POCKET(false, CacheListLoaderType.POCKET),
+ HISTORY(true, CacheListLoaderType.HISTORY),
+ NEAREST(false, CacheListLoaderType.NEAREST),
+ COORDINATE(false, CacheListLoaderType.COORDINATE),
+ KEYWORD(false, CacheListLoaderType.KEYWORD),
+ ADDRESS(false, CacheListLoaderType.ADDRESS),
+ FINDER(false, CacheListLoaderType.FINDER),
+ OWNER(false, CacheListLoaderType.OWNER),
+ MAP(false, CacheListLoaderType.MAP);
/**
* whether or not this list allows switching to another list
*/
public final boolean canSwitch;
- private CacheListType(final boolean canSwitch) {
+ public final CacheListLoaderType loaderType;
+
+ CacheListType(final boolean canSwitch, final CacheListLoaderType loaderType) {
this.canSwitch = canSwitch;
+ this.loaderType = loaderType;
+ }
+
+ public int getLoaderId() {
+ return loaderType.getLoaderId();
}
}
diff --git a/main/src/cgeo/geocaching/enumerations/CacheSize.java b/main/src/cgeo/geocaching/enumerations/CacheSize.java
index ee42c66..1255455 100644
--- a/main/src/cgeo/geocaching/enumerations/CacheSize.java
+++ b/main/src/cgeo/geocaching/enumerations/CacheSize.java
@@ -12,30 +12,38 @@ import java.util.Map;
* Enum listing cache sizes
*/
public enum CacheSize {
- MICRO("Micro", 1, R.string.cache_size_micro),
- SMALL("Small", 2, R.string.cache_size_small),
- REGULAR("Regular", 3, R.string.cache_size_regular),
- LARGE("Large", 4, R.string.cache_size_large),
- VIRTUAL("Virtual", 0, R.string.cache_size_virtual),
- NOT_CHOSEN("Not chosen", 0, R.string.cache_size_notchosen),
- OTHER("Other", 0, R.string.cache_size_other),
- UNKNOWN("Unknown", 0, R.string.cache_size_unknown); // CacheSize not init. yet
+ NANO("Nano", 0, R.string.cache_size_nano, "nano"), // used by OC only
+ MICRO("Micro", 1, R.string.cache_size_micro, "micro"),
+ SMALL("Small", 2, R.string.cache_size_small, "small"),
+ REGULAR("Regular", 3, R.string.cache_size_regular, "regular"),
+ LARGE("Large", 4, R.string.cache_size_large, "large"),
+ VERY_LARGE("Very large", 5, R.string.cache_size_very_large, "xlarge"), // used by OC only
+ NOT_CHOSEN("Not chosen", 6, R.string.cache_size_notchosen, ""),
+ VIRTUAL("Virtual", 7, R.string.cache_size_virtual, "none"),
+ OTHER("Other", 8, R.string.cache_size_other, "other"),
+ UNKNOWN("Unknown", -1, R.string.cache_size_unknown, ""); // CacheSize not init. yet
public final String id;
public final int comparable;
private final int stringId;
+ /**
+ * lookup for OC JSON requests (the numeric size is deprecated for OC)
+ */
+ private final String ocSize2;
- CacheSize(String id, int comparable, int stringId) {
+ CacheSize(final String id, final int comparable, final int stringId, final String ocSize2) {
this.id = id;
this.comparable = comparable;
this.stringId = stringId;
+ this.ocSize2 = ocSize2;
}
final private static Map<String, CacheSize> FIND_BY_ID;
static {
final HashMap<String, CacheSize> mapping = new HashMap<String, CacheSize>();
- for (CacheSize cs : values()) {
+ for (final CacheSize cs : values()) {
mapping.put(cs.id.toLowerCase(Locale.US), cs);
+ mapping.put(cs.ocSize2.toLowerCase(Locale.US), cs);
}
// add medium as additional string for Regular
mapping.put("medium", CacheSize.REGULAR);
@@ -61,21 +69,21 @@ public enum CacheSize {
/**
* Bad GPX files can contain the container size encoded as number.
- *
+ *
* @param id
* @return
*/
private static CacheSize getByNumber(final String id) {
try {
- int numerical = Integer.parseInt(id);
+ final int numerical = Integer.parseInt(id);
if (numerical != 0) {
- for (CacheSize size : CacheSize.values()) {
+ for (final CacheSize size : CacheSize.values()) {
if (size.comparable == numerical) {
return size;
}
}
}
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException e) {
// ignore, as this might be a number or not
}
return UNKNOWN;
@@ -85,4 +93,3 @@ public enum CacheSize {
return CgeoApplication.getInstance().getBaseContext().getResources().getString(stringId);
}
}
-
diff --git a/main/src/cgeo/geocaching/enumerations/CacheType.java b/main/src/cgeo/geocaching/enumerations/CacheType.java
index c952ba0..35fe7a1 100644
--- a/main/src/cgeo/geocaching/enumerations/CacheType.java
+++ b/main/src/cgeo/geocaching/enumerations/CacheType.java
@@ -1,8 +1,8 @@
package cgeo.geocaching.enumerations;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.ICache;
import cgeo.geocaching.R;
-import cgeo.geocaching.CgeoApplication;
import java.util.Collections;
import java.util.HashMap;
diff --git a/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java b/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java
index 710c3ba..5bcaf4a 100644
--- a/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java
+++ b/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.enumerations;
-import cgeo.geocaching.R;
import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.R;
import java.util.EnumSet;
diff --git a/main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java b/main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java
index 68a17a5..e008294 100644
--- a/main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java
+++ b/main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java
@@ -1,29 +1,22 @@
package cgeo.geocaching.enumerations;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
public enum LogTypeTrackable {
- DO_NOTHING(0, "", R.string.log_tb_nothing),
- VISITED(1, "_Visited", R.string.log_tb_visit),
- DROPPED_OFF(2, "_DroppedOff", R.string.log_tb_drop);
+ DO_NOTHING("", R.string.log_tb_nothing),
+ VISITED("_Visited", R.string.log_tb_visit),
+ DROPPED_OFF("_DroppedOff", R.string.log_tb_drop);
- final public int id;
final public String action;
- final public int resourceId;
+ final private int resourceId;
- LogTypeTrackable(int id, String action, int resourceId) {
- this.id = id;
+ LogTypeTrackable(String action, int resourceId) {
this.action = action;
this.resourceId = resourceId;
}
- public static LogTypeTrackable findById(int id) {
- for (LogTypeTrackable logType : values()) {
- if (logType.id == id) {
- return logType;
- }
- }
- return DO_NOTHING;
+ public String getLabel() {
+ return CgeoApplication.getInstance().getString(resourceId);
}
-
}
diff --git a/main/src/cgeo/geocaching/enumerations/StatusCode.java b/main/src/cgeo/geocaching/enumerations/StatusCode.java
index e1a1aaa..8bda371 100644
--- a/main/src/cgeo/geocaching/enumerations/StatusCode.java
+++ b/main/src/cgeo/geocaching/enumerations/StatusCode.java
@@ -6,7 +6,6 @@ import android.content.res.Resources;
public enum StatusCode {
- COMMUNICATION_NOT_STARTED(R.string.err_start),
NO_ERROR(R.string.err_none),
LOG_SAVED(R.string.info_log_saved),
LOGIN_PARSE_ERROR(R.string.err_parse),
@@ -24,7 +23,6 @@ public enum StatusCode {
LOG_POST_ERROR(R.string.err_log_post_failed),
LOG_POST_ERROR_EC(R.string.err_log_post_failed_ec),
NO_LOG_TEXT(R.string.warn_log_text_fill),
- NO_DATA_FROM_SERVER(R.string.err_log_failed_server),
NOT_LOGGED_IN(R.string.init_login_popup_failed),
LOGIMAGE_POST_ERROR(R.string.err_logimage_post_failed);
diff --git a/main/src/cgeo/geocaching/export/FieldnoteExport.java b/main/src/cgeo/geocaching/export/FieldnoteExport.java
index 4da480a..c4906ac 100644
--- a/main/src/cgeo/geocaching/export/FieldnoteExport.java
+++ b/main/src/cgeo/geocaching/export/FieldnoteExport.java
@@ -14,11 +14,11 @@ import cgeo.geocaching.ui.Formatter;
import cgeo.geocaching.utils.AsyncTaskWithProgress;
import cgeo.geocaching.utils.FileUtils;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.SynchronizedDateFormat;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.CharEncoding;
import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.time.FastDateFormat;
import android.app.Activity;
import android.app.AlertDialog;
@@ -45,13 +45,14 @@ import java.util.TimeZone;
/**
* Exports offline logs in the Groundspeak Field Note format.<br>
* <br>
- *
+ *
* Field Notes are simple plain text files, but poorly documented. Syntax:<br>
* <code>GCxxxxx,yyyy-mm-ddThh:mm:ssZ,Found it,"logtext"</code>
*/
class FieldnoteExport extends AbstractExport {
private static final File exportLocation = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/field-notes");
- private static final FastDateFormat fieldNoteDateFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss'Z'", TimeZone.getTimeZone("UTC"), Locale.US);
+ private static final SynchronizedDateFormat fieldNoteDateFormat = new SynchronizedDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", TimeZone.getTimeZone("UTC"), Locale.US);
+ private static int fieldNotesCount = 0;
protected FieldnoteExport() {
super(getString(R.string.export_fieldnotes));
@@ -89,7 +90,7 @@ class FieldnoteExport extends AbstractExport {
builder.setPositiveButton(R.string.export, new DialogInterface.OnClickListener() {
@Override
- public void onClick(DialogInterface dialog, int which) {
+ public void onClick(final DialogInterface dialog, final int which) {
final boolean upload = uploadOption.isChecked();
final boolean onlyNew = onlyNewOption.isChecked();
Settings.setFieldNoteExportUpload(upload);
@@ -112,7 +113,7 @@ class FieldnoteExport extends AbstractExport {
/**
* Instantiates and configures the task for exporting field notes.
- *
+ *
* @param activity
* optional: Show a progress bar and toasts
* @param upload
@@ -121,14 +122,14 @@ class FieldnoteExport extends AbstractExport {
* Upload/export only new logs since last export
*/
public ExportTask(final Activity activity, final boolean upload, final boolean onlyNew) {
- super(activity, getProgressTitle(), getString(R.string.export_fieldnotes_creating));
+ super(activity, getProgressTitle(), getString(R.string.export_fieldnotes_creating), true);
this.activity = activity;
this.upload = upload;
this.onlyNew = onlyNew;
}
@Override
- protected Boolean doInBackgroundInternal(Geocache[] caches) {
+ protected Boolean doInBackgroundInternal(final Geocache[] caches) {
final StringBuilder fieldNoteBuffer = new StringBuilder();
try {
int i = 0;
@@ -212,7 +213,7 @@ class FieldnoteExport extends AbstractExport {
}
@Override
- protected void onPostExecuteInternal(Boolean result) {
+ protected void onPostExecuteInternal(final Boolean result) {
if (null != activity) {
if (result) {
Settings.setFieldnoteExportDate(System.currentTimeMillis());
@@ -229,18 +230,15 @@ class FieldnoteExport extends AbstractExport {
}
@Override
- protected void onProgressUpdateInternal(int status) {
+ protected void onProgressUpdateInternal(final int status) {
if (null != activity) {
- if (STATUS_UPLOAD == status) {
- setMessage(getString(R.string.export_fieldnotes_uploading));
- } else {
- setMessage(getString(R.string.export_fieldnotes_creating) + " (" + status + ')');
- }
+ setMessage(getString(STATUS_UPLOAD == status ? R.string.export_fieldnotes_uploading : R.string.export_fieldnotes_creating) + " (" + fieldNotesCount + ')');
}
}
}
static void appendFieldNote(final StringBuilder fieldNoteBuffer, final Geocache cache, final LogEntry log) {
+ fieldNotesCount++;
fieldNoteBuffer.append(cache.getGeocode())
.append(',')
.append(fieldNoteDateFormat.format(new Date(log.date)))
diff --git a/main/src/cgeo/geocaching/export/GpxExport.java b/main/src/cgeo/geocaching/export/GpxExport.java
index a2e0f93..08fca0b 100644
--- a/main/src/cgeo/geocaching/export/GpxExport.java
+++ b/main/src/cgeo/geocaching/export/GpxExport.java
@@ -1,8 +1,8 @@
package cgeo.geocaching.export;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
-import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.AsyncTaskWithProgress;
diff --git a/main/src/cgeo/geocaching/export/GpxSerializer.java b/main/src/cgeo/geocaching/export/GpxSerializer.java
index df07f17..962f0d3 100644
--- a/main/src/cgeo/geocaching/export/GpxSerializer.java
+++ b/main/src/cgeo/geocaching/export/GpxSerializer.java
@@ -8,6 +8,7 @@ import cgeo.geocaching.Waypoint;
import cgeo.geocaching.enumerations.CacheAttribute;
import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.utils.SynchronizedDateFormat;
import cgeo.geocaching.utils.TextUtils;
import cgeo.geocaching.utils.XmlUtils;
import cgeo.org.kxml2.io.KXmlSerializer;
@@ -15,7 +16,6 @@ import cgeo.org.kxml2.io.KXmlSerializer;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.CharEncoding;
import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.time.FastDateFormat;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
@@ -29,7 +29,7 @@ import java.util.Set;
public final class GpxSerializer {
- private static final FastDateFormat dateFormatZ = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
+ private static final SynchronizedDateFormat dateFormatZ = new SynchronizedDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
public static final String PREFIX_XSI = "http://www.w3.org/2001/XMLSchema-instance";
public static final String PREFIX_GPX = "http://www.topografix.com/GPX/1/0";
public static final String PREFIX_GROUNDSPEAK = "http://www.groundspeak.com/cache/1/0";
diff --git a/main/src/cgeo/geocaching/files/LocalStorage.java b/main/src/cgeo/geocaching/files/LocalStorage.java
index d57c247..626f6e6 100644
--- a/main/src/cgeo/geocaching/files/LocalStorage.java
+++ b/main/src/cgeo/geocaching/files/LocalStorage.java
@@ -7,7 +7,6 @@ import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.Header;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.Nullable;
@@ -122,7 +121,7 @@ public final class LocalStorage {
* the geocode
* @return the cache directory
*/
- public static File getStorageDir(final String geocode) {
+ public static File getStorageDir(@Nullable final String geocode) {
return storageDir(getStorage(), geocode);
}
@@ -134,11 +133,11 @@ public final class LocalStorage {
* the geocode
* @return the cache directory
*/
- private static File getStorageSecDir(final String geocode) {
+ private static File getStorageSecDir(@Nullable final String geocode) {
return storageDir(getStorageSec(), geocode);
}
- private static File storageDir(final File base, final String geocode) {
+ private static File storageDir(final File base, @Nullable final String geocode) {
return new File(base, StringUtils.defaultIfEmpty(geocode, "_others"));
}
@@ -155,7 +154,7 @@ public final class LocalStorage {
* true if an url was given, false if a file name was given
* @return the file
*/
- public static File getStorageFile(final String geocode, final String fileNameOrUrl, final boolean isUrl, final boolean createDirs) {
+ public static File getStorageFile(@Nullable final String geocode, final String fileNameOrUrl, final boolean isUrl, final boolean createDirs) {
return buildFile(getStorageDir(geocode), fileNameOrUrl, isUrl, createDirs);
}
@@ -276,15 +275,18 @@ public final class LocalStorage {
return false;
}
+
try {
try {
- final FileOutputStream fos = new FileOutputStream(targetFile);
+ final File tempFile = File.createTempFile("download", null, targetFile.getParentFile());
+ final FileOutputStream fos = new FileOutputStream(tempFile);
final boolean written = copy(inputStream, fos);
fos.close();
- if (!written) {
- FileUtils.deleteIgnoringFailure(targetFile);
+ if (written) {
+ return tempFile.renameTo(targetFile);
}
- return written;
+ FileUtils.deleteIgnoringFailure(tempFile);
+ return false;
} finally {
IOUtils.closeQuietly(inputStream);
}
diff --git a/main/src/cgeo/geocaching/files/SimpleDirChooser.java b/main/src/cgeo/geocaching/files/SimpleDirChooser.java
index 3e09cc4..e63c09f 100644
--- a/main/src/cgeo/geocaching/files/SimpleDirChooser.java
+++ b/main/src/cgeo/geocaching/files/SimpleDirChooser.java
@@ -89,9 +89,9 @@ public class SimpleDirChooser extends AbstractListActivity {
}
public void editPath() {
- AlertDialog.Builder builder = new AlertDialog.Builder(SimpleDirChooser.this);
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.simple_dir_chooser_current_path);
- final EditText input = new EditText(SimpleDirChooser.this);
+ final EditText input = new EditText(this);
input.setInputType(InputType.TYPE_CLASS_TEXT);
input.setText(currentDir.getPath());
builder.setView(input);
diff --git a/main/src/cgeo/geocaching/filter/DistanceFilter.java b/main/src/cgeo/geocaching/filter/DistanceFilter.java
index 54225d2..cddcf72 100644
--- a/main/src/cgeo/geocaching/filter/DistanceFilter.java
+++ b/main/src/cgeo/geocaching/filter/DistanceFilter.java
@@ -1,9 +1,9 @@
package cgeo.geocaching.filter;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.IGeoData;
import cgeo.geocaching.R;
-import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.geopoint.Geopoint;
import java.util.ArrayList;
diff --git a/main/src/cgeo/geocaching/filter/FilterUserInterface.java b/main/src/cgeo/geocaching/filter/FilterUserInterface.java
index d77341b..0033b9a 100644
--- a/main/src/cgeo/geocaching/filter/FilterUserInterface.java
+++ b/main/src/cgeo/geocaching/filter/FilterUserInterface.java
@@ -5,7 +5,8 @@ import cgeo.geocaching.R;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.RunnableWithArgument;
+
+import rx.util.functions.Action1;
import android.app.Activity;
import android.app.AlertDialog;
@@ -77,7 +78,7 @@ public final class FilterUserInterface {
registry.add(new FactoryEntry(res.getString(resourceId), factoryClass));
}
- public void selectFilter(final RunnableWithArgument<IFilter> runAfterwards) {
+ public void selectFilter(final Action1<IFilter> runAfterwards) {
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(R.string.caches_filter_title);
@@ -89,7 +90,7 @@ public final class FilterUserInterface {
FactoryEntry entry = adapter.getItem(itemIndex);
// reset?
if (entry.filterFactory == null) {
- runAfterwards.run(null);
+ runAfterwards.call(null);
}
else {
try {
@@ -105,10 +106,10 @@ public final class FilterUserInterface {
builder.create().show();
}
- private void selectFromFactory(final IFilterFactory factory, final String menuTitle, final RunnableWithArgument<IFilter> runAfterwards) {
+ private void selectFromFactory(final IFilterFactory factory, final String menuTitle, final Action1<IFilter> runAfterwards) {
final List<IFilter> filters = Collections.unmodifiableList(factory.getFilters());
if (filters.size() == 1) {
- runAfterwards.run(filters.get(0));
+ runAfterwards.call(filters.get(0));
return;
}
@@ -119,7 +120,7 @@ public final class FilterUserInterface {
builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int item) {
- runAfterwards.run(filters.get(item));
+ runAfterwards.call(filters.get(item));
}
});
diff --git a/main/src/cgeo/geocaching/filter/ModifiedFilter.java b/main/src/cgeo/geocaching/filter/ModifiedFilter.java
index d976b69..2ac088a 100644
--- a/main/src/cgeo/geocaching/filter/ModifiedFilter.java
+++ b/main/src/cgeo/geocaching/filter/ModifiedFilter.java
@@ -1,8 +1,8 @@
package cgeo.geocaching.filter;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
-import cgeo.geocaching.CgeoApplication;
import java.util.Collections;
import java.util.List;
diff --git a/main/src/cgeo/geocaching/geopoint/Geopoint.java b/main/src/cgeo/geocaching/geopoint/Geopoint.java
index f21df01..e91a93d 100644
--- a/main/src/cgeo/geocaching/geopoint/Geopoint.java
+++ b/main/src/cgeo/geocaching/geopoint/Geopoint.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.ICoordinates;
import cgeo.geocaching.R;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
import android.location.Location;
import android.os.Build;
@@ -11,10 +12,13 @@ import android.os.Parcel;
import android.os.Parcelable;
/**
- * Abstraction of geographic point.
+ * Abstraction of geographic point. This class is immutable.
*/
public final class Geopoint implements ICoordinates, Parcelable {
- public static final Geopoint ZERO = new Geopoint(0.0, 0.0);
+ /**
+ * Reusable default object
+ */
+ public static final @NonNull Geopoint ZERO = new Geopoint(0.0, 0.0);
private static final double DEG_TO_RAD = Math.PI / 180;
private static final double RAD_TO_DEG = 180 / Math.PI;
@@ -64,7 +68,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
* longitude string to parse
* @throws Geopoint.ParseException
* if any argument string cannot be parsed
- * @see GeopointParser#parse(String, String)
*/
public Geopoint(final String latText, final String lonText) {
this(GeopointParser.parseLatitude(latText), GeopointParser.parseLongitude(lonText));
@@ -273,19 +276,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
}
/**
- * Checks if given Geopoint is similar to this Geopoint with tolerance.
- *
- * @param gp
- * Geopoint to check
- * @param tolerance
- * tolerance in km
- * @return true if similar, false otherwise
- */
- public boolean isEqualTo(Geopoint gp, double tolerance) {
- return null != gp && distanceTo(gp) <= tolerance;
- }
-
- /**
* Returns formatted coordinates.
*
* @param format
@@ -300,7 +290,7 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Returns formatted coordinates with default format.
* Default format is decimalminutes, e.g. N 52° 36.123 E 010° 03.456
- *
+ *
* @return formatted coordinates
*/
@Override
@@ -365,7 +355,7 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get longitude character (E or W).
- *
+ *
* @return
*/
public char getLonDir() {
diff --git a/main/src/cgeo/geocaching/geopoint/GeopointParser.java b/main/src/cgeo/geocaching/geopoint/GeopointParser.java
index c043d6f..120e02e 100644
--- a/main/src/cgeo/geocaching/geopoint/GeopointParser.java
+++ b/main/src/cgeo/geocaching/geopoint/GeopointParser.java
@@ -70,37 +70,11 @@ class GeopointParser {
}
/**
- * Parses a pair of coordinates (latitude and longitude) out of a String.
- * Accepts following formats and combinations of it:
- * X DD
- * X DD°
- * X DD° MM
- * X DD° MM.MMM
- * X DD° MM SS
- *
- * as well as:
- * DD.DDDDDDD
- *
- * Both . and , are accepted, also variable count of spaces (also 0)
- *
- * @param latitude
- * the latitude string to parse
- * @param longitude
- * the longitude string to parse
- * @return an Geopoint with parsed latitude and longitude
- * @throws Geopoint.ParseException
- * if lat or lon could not be parsed
- */
- public static Geopoint parse(final String latitude, final String longitude) {
- final double lat = parseLatitude(latitude);
- final double lon = parseLongitude(longitude);
-
- return new Geopoint(lat, lon);
- }
-
- /*
- * (non JavaDoc)
- * Helper for coordinates-parsing.
+ * Helper for coordinates-parsing
+ *
+ * @param text
+ * @param latlon
+ * @return
*/
private static ResultWrapper parseHelper(final String text, final LatLon latlon) {
diff --git a/main/src/cgeo/geocaching/geopoint/Viewport.java b/main/src/cgeo/geocaching/geopoint/Viewport.java
index 9d55f69..ba0e040 100644
--- a/main/src/cgeo/geocaching/geopoint/Viewport.java
+++ b/main/src/cgeo/geocaching/geopoint/Viewport.java
@@ -5,16 +5,15 @@ import cgeo.geocaching.ICoordinates;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
-import java.util.Set;
+import java.util.Collection;
-
-public class Viewport {
+public final class Viewport {
public final @NonNull Geopoint center;
public final @NonNull Geopoint bottomLeft;
public final @NonNull Geopoint topRight;
- public Viewport(final ICoordinates point1, final ICoordinates point2) {
+ public Viewport(final @NonNull ICoordinates point1, final @NonNull ICoordinates point2) {
final Geopoint gp1 = point1.getCoords();
final Geopoint gp2 = point2.getCoords();
this.bottomLeft = new Geopoint(Math.min(gp1.getLatitude(), gp2.getLatitude()),
@@ -25,7 +24,7 @@ public class Viewport {
(gp1.getLongitude() + gp2.getLongitude()) / 2);
}
- public Viewport(final ICoordinates center, final double latSpan, final double lonSpan) {
+ public Viewport(final @NonNull ICoordinates center, final double latSpan, final double lonSpan) {
this.center = center.getCoords();
final double centerLat = this.center.getLatitude();
final double centerLon = this.center.getLongitude();
@@ -71,7 +70,7 @@ public class Viewport {
* the coordinates to check
* @return true if the point is contained in this viewport, false otherwise or if the point contains no coordinates
*/
- public boolean contains(final ICoordinates point) {
+ public boolean contains(final @NonNull ICoordinates point) {
final Geopoint coords = point.getCoords();
return coords != null
&& coords.getLongitudeE6() >= bottomLeft.getLongitudeE6()
@@ -87,12 +86,12 @@ public class Viewport {
/**
* Check whether another viewport is fully included into the current one.
- *
+ *
* @param vp
* the other viewport
- * @return true if the vp is fully included into this one, false otherwise
+ * @return true if the viewport is fully included into this one, false otherwise
*/
- public boolean includes(final Viewport vp) {
+ public boolean includes(final @NonNull Viewport vp) {
return contains(vp.bottomLeft) && contains(vp.topRight);
}
@@ -124,46 +123,37 @@ public class Viewport {
}
/**
- * Return a viewport that contains the current viewport as well as another point.
- *
- * @param point
- * the point we want in the viewport
- * @return either the same or an expanded viewport
- */
- public Viewport expand(final ICoordinates point) {
- if (contains(point)) {
- return this;
- }
-
- final Geopoint coords = point.getCoords();
- final double latitude = coords.getLatitude();
- final double longitude = coords.getLongitude();
- final double latMin = Math.min(getLatitudeMin(), latitude);
- final double latMax = Math.max(getLatitudeMax(), latitude);
- final double lonMin = Math.min(getLongitudeMin(), longitude);
- final double lonMax = Math.max(getLongitudeMax(), longitude);
- return new Viewport(new Geopoint(latMin, lonMin), new Geopoint(latMax, lonMax));
- }
-
- /**
* Return the smallest viewport containing all the given points.
*
* @param points
* a set of points. Point with null coordinates (or null themselves) will be ignored
* @return the smallest viewport containing the non-null coordinates, or null if no coordinates are non-null
*/
- static public Viewport containing(final Set<? extends ICoordinates> points) {
- Viewport viewport = null;
+ static public @Nullable
+ Viewport containing(final Collection<? extends ICoordinates> points) {
+ boolean valid = false;
+ double latMin = Double.MAX_VALUE;
+ double latMax = -Double.MAX_VALUE;
+ double lonMin = Double.MAX_VALUE;
+ double lonMax = -Double.MAX_VALUE;
for (final ICoordinates point : points) {
- if (point != null && point.getCoords() != null) {
- if (viewport == null) {
- viewport = new Viewport(point, point);
- } else {
- viewport = viewport.expand(point);
+ if (point != null) {
+ final Geopoint coords = point.getCoords();
+ if (coords != null) {
+ valid = true;
+ final double latitude = coords.getLatitude();
+ final double longitude = coords.getLongitude();
+ latMin = Math.min(latMin, latitude);
+ latMax = Math.max(latMax, latitude);
+ lonMin = Math.min(lonMin, longitude);
+ lonMax = Math.max(lonMax, longitude);
}
}
}
- return viewport;
+ if (!valid) {
+ return null;
+ }
+ return new Viewport(new Geopoint(latMin, lonMin), new Geopoint(latMax, lonMax));
}
@Override
diff --git a/main/src/cgeo/geocaching/list/PseudoList.java b/main/src/cgeo/geocaching/list/PseudoList.java
index 365d6fd..f2cc7ed 100644
--- a/main/src/cgeo/geocaching/list/PseudoList.java
+++ b/main/src/cgeo/geocaching/list/PseudoList.java
@@ -17,6 +17,12 @@ public class PseudoList extends AbstractList {
*/
public static final AbstractList NEW_LIST = new PseudoList(NEW_LIST_ID, R.string.list_menu_create);
+ private static final int HISTORY_LIST_ID = 4;
+ /**
+ * list entry to create a new list
+ */
+ public static final AbstractList HISTORY_LIST = new PseudoList(HISTORY_LIST_ID, R.string.menu_history);
+
/**
* private constructor to have all instances as constants in the class
*/
diff --git a/main/src/cgeo/geocaching/list/StoredList.java b/main/src/cgeo/geocaching/list/StoredList.java
index 8106073..ba8ce35 100644
--- a/main/src/cgeo/geocaching/list/StoredList.java
+++ b/main/src/cgeo/geocaching/list/StoredList.java
@@ -5,11 +5,12 @@ import cgeo.geocaching.DataStore;
import cgeo.geocaching.R;
import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.ui.dialog.Dialogs;
-import cgeo.geocaching.utils.RunnableWithArgument;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import rx.util.functions.Action1;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
@@ -67,15 +68,15 @@ public final class StoredList extends AbstractList {
res = app.getResources();
}
- public void promptForListSelection(final int titleId, @NonNull final RunnableWithArgument<Integer> runAfterwards) {
+ public void promptForListSelection(final int titleId, @NonNull final Action1<Integer> runAfterwards) {
promptForListSelection(titleId, runAfterwards, false, -1);
}
- public void promptForListSelection(final int titleId, @NonNull final RunnableWithArgument<Integer> runAfterwards, final boolean onlyConcreteLists, final int exceptListId) {
+ public void promptForListSelection(final int titleId, @NonNull final Action1<Integer> runAfterwards, final boolean onlyConcreteLists, final int exceptListId) {
promptForListSelection(titleId, runAfterwards, onlyConcreteLists, exceptListId, StringUtils.EMPTY);
}
- public void promptForListSelection(final int titleId, @NonNull final RunnableWithArgument<Integer> runAfterwards, final boolean onlyConcreteLists, final int exceptListId, final String newListName) {
+ public void promptForListSelection(final int titleId, @NonNull final Action1<Integer> runAfterwards, final boolean onlyConcreteLists, final int exceptListId, final String newListName) {
final List<AbstractList> lists = new ArrayList<AbstractList>();
lists.addAll(getSortedLists());
@@ -87,7 +88,12 @@ public final class StoredList extends AbstractList {
}
if (!onlyConcreteLists) {
- lists.add(PseudoList.ALL_LIST);
+ if (exceptListId != PseudoList.ALL_LIST.id) {
+ lists.add(PseudoList.ALL_LIST);
+ }
+ if (exceptListId != PseudoList.HISTORY_LIST.id) {
+ lists.add(PseudoList.HISTORY_LIST);
+ }
}
lists.add(PseudoList.NEW_LIST);
@@ -109,7 +115,7 @@ public final class StoredList extends AbstractList {
promptForListCreation(runAfterwards, newListName);
}
else {
- runAfterwards.run(lists.get(itemId).id);
+ runAfterwards.call(lists.get(itemId).id);
}
}
});
@@ -138,17 +144,17 @@ public final class StoredList extends AbstractList {
return lists;
}
- public void promptForListCreation(@NonNull final RunnableWithArgument<Integer> runAfterwards, String newListName) {
- handleListNameInput(newListName, R.string.list_dialog_create_title, R.string.list_dialog_create, new RunnableWithArgument<String>() {
+ public void promptForListCreation(@NonNull final Action1<Integer> runAfterwards, String newListName) {
+ handleListNameInput(newListName, R.string.list_dialog_create_title, R.string.list_dialog_create, new Action1<String>() {
@Override
- public void run(final String listName) {
+ public void call(final String listName) {
final int newId = DataStore.createList(listName);
new StoredList(newId, listName, 0);
if (newId >= DataStore.customListIdOffset) {
ActivityMixin.showToast(activity, res.getString(R.string.list_dialog_create_ok));
- runAfterwards.run(newId);
+ runAfterwards.call(newId);
} else {
ActivityMixin.showToast(activity, res.getString(R.string.list_dialog_create_err));
}
@@ -156,15 +162,15 @@ public final class StoredList extends AbstractList {
});
}
- private void handleListNameInput(final String defaultValue, int dialogTitle, int buttonTitle, final RunnableWithArgument<String> runnable) {
- Dialogs.input(activity, dialogTitle, defaultValue, buttonTitle, new RunnableWithArgument<String>() {
+ private void handleListNameInput(final String defaultValue, int dialogTitle, int buttonTitle, final Action1<String> runnable) {
+ Dialogs.input(activity, dialogTitle, defaultValue, buttonTitle, new Action1<String>() {
@Override
- public void run(final String input) {
+ public void call(final String input) {
// remove whitespaces added by autocompletion of Android keyboard
String listName = StringUtils.trim(input);
if (StringUtils.isNotBlank(listName)) {
- runnable.run(listName);
+ runnable.call(listName);
}
}
});
@@ -172,10 +178,10 @@ public final class StoredList extends AbstractList {
public void promptForListRename(final int listId, @NonNull final Runnable runAfterRename) {
final StoredList list = DataStore.getList(listId);
- handleListNameInput(list.title, R.string.list_dialog_rename_title, R.string.list_dialog_rename, new RunnableWithArgument<String>() {
+ handleListNameInput(list.title, R.string.list_dialog_rename_title, R.string.list_dialog_rename, new Action1<String>() {
@Override
- public void run(final String listName) {
+ public void call(final String listName) {
DataStore.renameList(listId, listName);
runAfterRename.run();
}
@@ -197,7 +203,7 @@ public final class StoredList extends AbstractList {
* Return the given list, if it is a concrete list. Return the default list otherwise.
*/
public static int getConcreteList(int listId) {
- if (listId == PseudoList.ALL_LIST.id || listId == TEMPORARY_LIST_ID) {
+ if (listId == PseudoList.ALL_LIST.id || listId == TEMPORARY_LIST_ID || listId == PseudoList.HISTORY_LIST.id) {
return STANDARD_LIST_ID;
}
return listId;
diff --git a/main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java b/main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java
index 7524b76..b2cb0b2 100644
--- a/main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java
+++ b/main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java
@@ -2,6 +2,7 @@ package cgeo.geocaching.loaders;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.connector.gc.GCConstants;
+import cgeo.geocaching.connector.gc.RecaptchaHandler;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.utils.Log;
@@ -13,6 +14,8 @@ import android.content.Context;
import android.os.Handler;
import android.support.v4.content.AsyncTaskLoader;
+import java.util.concurrent.CountDownLatch;
+
public abstract class AbstractSearchLoader extends AsyncTaskLoader<SearchResult> implements RecaptchaReceiver {
public enum CacheListLoaderType {
@@ -28,6 +31,10 @@ public abstract class AbstractSearchLoader extends AsyncTaskLoader<SearchResult>
MAP,
REMOVE_FROM_HISTORY,
NEXT_PAGE;
+
+ public int getLoaderId() {
+ return ordinal();
+ }
}
private Handler recaptchaHandler = null;
@@ -36,6 +43,7 @@ public abstract class AbstractSearchLoader extends AsyncTaskLoader<SearchResult>
private String recaptchaText = null;
private SearchResult search;
private boolean loading;
+ private CountDownLatch latch = new CountDownLatch(1);
public AbstractSearchLoader(Context context) {
super(context);
@@ -72,23 +80,21 @@ public abstract class AbstractSearchLoader extends AsyncTaskLoader<SearchResult>
forceLoad();
}
- public void setRecaptchaHandler(Handler recaptchaHandlerIn) {
- recaptchaHandler = recaptchaHandlerIn;
+ public void setRecaptchaHandler(final Handler recaptchaHandler) {
+ this.recaptchaHandler = recaptchaHandler;
}
@Override
public void notifyNeed() {
if (recaptchaHandler != null) {
- recaptchaHandler.sendEmptyMessage(1);
+ recaptchaHandler.sendEmptyMessage(RecaptchaHandler.SHOW_CAPTCHA);
}
}
@Override
- public synchronized void waitForUser() {
+ public void waitForUser() {
try {
- while (getText() == null) {
- wait();
- }
+ latch.await();
} catch (InterruptedException e) {
Log.w("searchThread is not waiting for user…");
}
@@ -100,16 +106,11 @@ public abstract class AbstractSearchLoader extends AsyncTaskLoader<SearchResult>
}
@Override
- public String getKey() {
- return recaptchaKey;
- }
-
- @Override
public void fetchChallenge() {
recaptchaChallenge = null;
if (StringUtils.isNotEmpty(recaptchaKey)) {
- final Parameters params = new Parameters("k", getKey());
+ final Parameters params = new Parameters("k", recaptchaKey);
final String recaptchaJs = Network.getResponseData(Network.getRequest("http://www.google.com/recaptcha/api/challenge", params));
if (StringUtils.isNotBlank(recaptchaJs)) {
@@ -124,18 +125,16 @@ public abstract class AbstractSearchLoader extends AsyncTaskLoader<SearchResult>
}
@Override
- public synchronized void setText(String text) {
+ public void setText(String text) {
recaptchaText = text;
-
- notify();
+ latch.countDown();
}
@Override
- public synchronized String getText() {
+ public String getText() {
return recaptchaText;
}
-
@Override
public void reset() {
super.reset();
diff --git a/main/src/cgeo/geocaching/loaders/AddressGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/AddressGeocacheListLoader.java
index dd7c7a6..e1573c9 100644
--- a/main/src/cgeo/geocaching/loaders/AddressGeocacheListLoader.java
+++ b/main/src/cgeo/geocaching/loaders/AddressGeocacheListLoader.java
@@ -1,8 +1,8 @@
package cgeo.geocaching.loaders;
import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.connector.gc.GCParser;
+import cgeo.geocaching.settings.Settings;
import android.content.Context;
diff --git a/main/src/cgeo/geocaching/loaders/HistoryGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/HistoryGeocacheListLoader.java
index 605f461..fdb35f2 100644
--- a/main/src/cgeo/geocaching/loaders/HistoryGeocacheListLoader.java
+++ b/main/src/cgeo/geocaching/loaders/HistoryGeocacheListLoader.java
@@ -2,9 +2,9 @@ package cgeo.geocaching.loaders;
import cgeo.geocaching.DataStore;
import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.settings.Settings;
import android.content.Context;
diff --git a/main/src/cgeo/geocaching/loaders/NextPageGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/NextPageGeocacheListLoader.java
index 1104f83..05eac18 100644
--- a/main/src/cgeo/geocaching/loaders/NextPageGeocacheListLoader.java
+++ b/main/src/cgeo/geocaching/loaders/NextPageGeocacheListLoader.java
@@ -1,8 +1,8 @@
package cgeo.geocaching.loaders;
import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.connector.gc.GCParser;
+import cgeo.geocaching.settings.Settings;
import android.content.Context;
diff --git a/main/src/cgeo/geocaching/loaders/OfflineGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/OfflineGeocacheListLoader.java
index 5088484..b80a1b8 100644
--- a/main/src/cgeo/geocaching/loaders/OfflineGeocacheListLoader.java
+++ b/main/src/cgeo/geocaching/loaders/OfflineGeocacheListLoader.java
@@ -1,9 +1,9 @@
package cgeo.geocaching.loaders;
-import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.DataStore;
+import cgeo.geocaching.SearchResult;
import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.settings.Settings;
import android.content.Context;
diff --git a/main/src/cgeo/geocaching/loaders/RecaptchaReceiver.java b/main/src/cgeo/geocaching/loaders/RecaptchaReceiver.java
index fd5189c..881e048 100644
--- a/main/src/cgeo/geocaching/loaders/RecaptchaReceiver.java
+++ b/main/src/cgeo/geocaching/loaders/RecaptchaReceiver.java
@@ -10,8 +10,6 @@ public interface RecaptchaReceiver {
public void fetchChallenge();
- public String getKey();
-
public void setKey(String key);
public void notifyNeed();
diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java
index c98ba72..d1ef0a3 100644
--- a/main/src/cgeo/geocaching/maps/CGeoMap.java
+++ b/main/src/cgeo/geocaching/maps/CGeoMap.java
@@ -38,12 +38,13 @@ import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.GeoDirHandler;
import cgeo.geocaching.utils.LeastRecentlyUsedSet;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.RunnableWithArgument;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.HashCodeBuilder;
+import rx.util.functions.Action1;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
@@ -466,7 +467,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
prepareFilterBar();
- if (!app.isLiveMapHintShown() && !Settings.getHideLiveMapHint()) {
+ if (!app.isLiveMapHintShownInThisSession() && !Settings.getHideLiveMapHint() && Settings.getLiveMapHintShowCount() <= 3) {
LiveMapInfoDialogBuilder.create(activity).show();
}
}
@@ -661,9 +662,9 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
if (Settings.getChooseList()) {
// let user select list to store cache in
new StoredList.UserInterface(activity).promptForListSelection(R.string.list_title,
- new RunnableWithArgument<Integer>() {
+ new Action1<Integer>() {
@Override
- public void run(final Integer selectedListId) {
+ public void call(final Integer selectedListId) {
storeCaches(geocodes, selectedListId);
}
}, true, StoredList.TEMPORARY_LIST_ID);
@@ -898,7 +899,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
private long timeLastPositionOverlayCalculation = 0;
@Override
- protected void updateGeoData(final IGeoData geo) {
+ public void updateGeoData(final IGeoData geo) {
if (geo.isPseudoLocation()) {
locationValid = false;
} else {
@@ -1182,7 +1183,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
}
}
}
- final SearchResult searchResult = ConnectorFactory.searchByViewport(viewport.resize(0.8), tokens);
+ final SearchResult searchResult = ConnectorFactory.searchByViewport(viewport.resize(0.8), tokens).toBlockingObservable().single();
downloaded = true;
Set<Geocache> result = searchResult.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB);
@@ -1609,7 +1610,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
}
private CachesOverlayItemImpl getCacheItem(final Geocache cache) {
- final CachesOverlayItemImpl item = mapItemFactory.getCachesOverlayItem(cache, cache.getType().applyDistanceRule());
+ final CachesOverlayItemImpl item = mapItemFactory.getCachesOverlayItem(cache, cache.applyDistanceRule());
final int hashcode = new HashCodeBuilder()
.append(cache.isReliableLatLon())
diff --git a/main/src/cgeo/geocaching/maps/MapProviderFactory.java b/main/src/cgeo/geocaching/maps/MapProviderFactory.java
index 2e43e19..b928a1e 100644
--- a/main/src/cgeo/geocaching/maps/MapProviderFactory.java
+++ b/main/src/cgeo/geocaching/maps/MapProviderFactory.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.maps;
-import cgeo.geocaching.R;
import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.R;
import cgeo.geocaching.maps.google.GoogleMapProvider;
import cgeo.geocaching.maps.interfaces.MapProvider;
import cgeo.geocaching.maps.interfaces.MapSource;
diff --git a/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlay.java b/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlay.java
index 3339650..d14c687 100644
--- a/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlay.java
+++ b/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlay.java
@@ -77,11 +77,6 @@ public class GoogleCacheOverlay extends ItemizedOverlay<GoogleCacheOverlayItem>
}
@Override
- public Drawable superBoundCenter(Drawable markerIn) {
- return ItemizedOverlay.boundCenter(markerIn);
- }
-
- @Override
public Drawable superBoundCenterBottom(Drawable marker) {
return ItemizedOverlay.boundCenterBottom(marker);
}
diff --git a/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java b/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java
index cb95b2c..38d7d96 100644
--- a/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java
+++ b/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.maps.google;
-import cgeo.geocaching.R;
import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.R;
import cgeo.geocaching.maps.AbstractMapProvider;
import cgeo.geocaching.maps.AbstractMapSource;
import cgeo.geocaching.maps.interfaces.MapItemFactory;
diff --git a/main/src/cgeo/geocaching/maps/google/GoogleMapView.java b/main/src/cgeo/geocaching/maps/google/GoogleMapView.java
index d02e3c2..471e061 100644
--- a/main/src/cgeo/geocaching/maps/google/GoogleMapView.java
+++ b/main/src/cgeo/geocaching/maps/google/GoogleMapView.java
@@ -11,13 +11,11 @@ import cgeo.geocaching.maps.interfaces.MapControllerImpl;
import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
import cgeo.geocaching.maps.interfaces.MapViewImpl;
import cgeo.geocaching.maps.interfaces.OnMapDragListener;
-import cgeo.geocaching.maps.interfaces.OverlayImpl;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
-import com.google.android.maps.Overlay;
import org.apache.commons.lang3.reflect.MethodUtils;
@@ -54,7 +52,7 @@ public class GoogleMapView extends MapView implements MapViewImpl {
}
@Override
- public void draw(Canvas canvas) {
+ public void draw(final Canvas canvas) {
try {
if (getMapZoomLevel() > 22) { // to avoid too close zoom level (mostly on Samsung Galaxy S series)
getController().setZoom(22);
@@ -102,11 +100,6 @@ public class GoogleMapView extends MapView implements MapViewImpl {
}
@Override
- public void addOverlay(OverlayImpl ovl) {
- getOverlays().add((Overlay) ovl);
- }
-
- @Override
public void clearOverlays() {
getOverlays().clear();
}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/ItemizedOverlayImpl.java b/main/src/cgeo/geocaching/maps/interfaces/ItemizedOverlayImpl.java
index 90c5b31..ee61f12 100644
--- a/main/src/cgeo/geocaching/maps/interfaces/ItemizedOverlayImpl.java
+++ b/main/src/cgeo/geocaching/maps/interfaces/ItemizedOverlayImpl.java
@@ -18,8 +18,6 @@ public interface ItemizedOverlayImpl extends OverlayImpl {
void superSetLastFocusedItemIndex(int i);
- Drawable superBoundCenter(Drawable markerIn);
-
Drawable superBoundCenterBottom(Drawable marker);
boolean superOnTap(int index);
diff --git a/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java b/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java
index cb7ddc6..c30f65f 100644
--- a/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java
+++ b/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java
@@ -22,8 +22,6 @@ public interface MapViewImpl {
void clearOverlays();
- void addOverlay(OverlayImpl ovl);
-
MapControllerImpl getMapController();
void destroyDrawingCache();
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java
index 9e14e36..b9e40d7 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java
@@ -70,11 +70,6 @@ public class MapsforgeCacheOverlay extends ItemizedOverlay<MapsforgeCacheOverlay
}
@Override
- public Drawable superBoundCenter(Drawable markerIn) {
- return ItemizedOverlay.boundCenter(markerIn);
- }
-
- @Override
public Drawable superBoundCenterBottom(Drawable marker) {
return ItemizedOverlay.boundCenterBottom(marker);
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java
index 78aa47d..e993548 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java
@@ -11,7 +11,6 @@ import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
import cgeo.geocaching.maps.interfaces.MapSource;
import cgeo.geocaching.maps.interfaces.MapViewImpl;
import cgeo.geocaching.maps.interfaces.OnMapDragListener;
-import cgeo.geocaching.maps.interfaces.OverlayImpl;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
@@ -86,11 +85,6 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
}
@Override
- public void addOverlay(OverlayImpl ovl) {
- getOverlays().add((Overlay) ovl);
- }
-
- @Override
public void clearOverlays() {
getOverlays().clear();
}
@@ -229,7 +223,7 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
@Override
public void setMapTheme() {
String customRenderTheme = Settings.getCustomRenderThemeFilePath();
- if (!StringUtils.isEmpty(customRenderTheme)) {
+ if (StringUtils.isNotEmpty(customRenderTheme)) {
try {
setRenderTheme(new File(customRenderTheme));
} catch (FileNotFoundException e) {
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java
index 30355fd..a8111ed 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java
@@ -70,11 +70,6 @@ public class MapsforgeCacheOverlay extends ItemizedOverlay<MapsforgeCacheOverlay
}
@Override
- public Drawable superBoundCenter(Drawable markerIn) {
- return ItemizedOverlay.boundCenter(markerIn);
- }
-
- @Override
public Drawable superBoundCenterBottom(Drawable marker) {
return ItemizedOverlay.boundCenterBottom(marker);
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java
index c741a31..6573304 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java
@@ -10,7 +10,6 @@ import cgeo.geocaching.maps.interfaces.MapControllerImpl;
import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
import cgeo.geocaching.maps.interfaces.MapViewImpl;
import cgeo.geocaching.maps.interfaces.OnMapDragListener;
-import cgeo.geocaching.maps.interfaces.OverlayImpl;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
@@ -77,11 +76,6 @@ public class MapsforgeMapView024 extends MapView implements MapViewImpl {
}
@Override
- public void addOverlay(OverlayImpl ovl) {
- getOverlays().add((Overlay) ovl);
- }
-
- @Override
public void clearOverlays() {
getOverlays().clear();
}
diff --git a/main/src/cgeo/geocaching/network/HtmlImage.java b/main/src/cgeo/geocaching/network/HtmlImage.java
index 0daa588..0019acc 100644
--- a/main/src/cgeo/geocaching/network/HtmlImage.java
+++ b/main/src/cgeo/geocaching/network/HtmlImage.java
@@ -6,6 +6,7 @@ import cgeo.geocaching.compatibility.Compatibility;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.files.LocalStorage;
import cgeo.geocaching.list.StoredList;
+import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.FileUtils;
import cgeo.geocaching.utils.ImageUtils;
import cgeo.geocaching.utils.Log;
@@ -14,6 +15,20 @@ import ch.boye.httpclientandroidlib.HttpResponse;
import ch.boye.httpclientandroidlib.androidextra.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import rx.Observable;
+import rx.Observable.OnSubscribeFunc;
+import rx.Observer;
+import rx.Scheduler;
+import rx.Subscription;
+import rx.schedulers.Schedulers;
+import rx.subjects.PublishSubject;
+import rx.subscriptions.CompositeSubscription;
+import rx.subscriptions.Subscriptions;
+import rx.util.functions.Func1;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -31,9 +46,23 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
public class HtmlImage implements Html.ImageGetter {
+ // This class implements an all-purpose image getter that can also be used as a ImageGetter interface
+ // when displaying caches. An instance mainly has three possible use cases:
+ // - If onlySave is true, getDrawable() will return null immediately and will queue the image retrieval
+ // and saving in the loading subject. Downloads will start in parallel when the blocking
+ // waitForBackgroundLoading() method is called, and they can be cancelled through the given handler.
+ // - If onlySave is false and the instance is called through fetchDrawable(), then an observable for the
+ // given URL will be returned. This observable will emit the local copy of the image if it is present,
+ // regardless of its freshness, then if needed an updated fresher copy after retrieving it from the network.
+ // - If onlySave is false and the instance is used as an ImageGetter, only the final version of the
+ // image will be returned.
+
private static final String[] BLOCKED = new String[] {
"gccounter.de",
"gccounter.com",
@@ -59,105 +88,173 @@ public class HtmlImage implements Html.ImageGetter {
final private boolean returnErrorImage;
final private int listId;
final private boolean onlySave;
- final private BitmapFactory.Options bfOptions;
final private int maxWidth;
final private int maxHeight;
final private Resources resources;
+ // Background loading
+ final private PublishSubject<Observable<String>> loading = PublishSubject.create();
+ final Observable<String> waitForEnd = Observable.merge(loading).publish().refCount();
+ final CompositeSubscription subscription = new CompositeSubscription(waitForEnd.subscribe());
+ final private Scheduler downloadScheduler = Schedulers.executor(new ThreadPoolExecutor(10, 10, 5, TimeUnit.SECONDS,
+ new LinkedBlockingQueue<Runnable>()));
+
public HtmlImage(final String geocode, final boolean returnErrorImage, final int listId, final boolean onlySave) {
this.geocode = geocode;
this.returnErrorImage = returnErrorImage;
this.listId = listId;
this.onlySave = onlySave;
- bfOptions = new BitmapFactory.Options();
- bfOptions.inTempStorage = new byte[16 * 1024];
- bfOptions.inPreferredConfig = Bitmap.Config.RGB_565;
-
Point displaySize = Compatibility.getDisplaySize();
this.maxWidth = displaySize.x - 25;
this.maxHeight = displaySize.y - 25;
this.resources = CgeoApplication.getInstance().getResources();
}
+ @Nullable
@Override
public BitmapDrawable getDrawable(final String url) {
- // Reject empty and counter images URL
- if (StringUtils.isBlank(url) || isCounter(url)) {
- return new BitmapDrawable(resources, getTransparent1x1Image());
+ final Observable<BitmapDrawable> drawable = fetchDrawable(url);
+ if (onlySave) {
+ loading.onNext(drawable.map(new Func1<BitmapDrawable, String>() {
+ @Override
+ public String call(final BitmapDrawable bitmapDrawable) {
+ return url;
+ }
+ }));
+ return null;
+ } else {
+ return drawable.toBlockingObservable().lastOrDefault(null);
}
+ }
+ public Observable<BitmapDrawable> fetchDrawable(final String url) {
final boolean shared = url.contains("/images/icons/icon_");
final String pseudoGeocode = shared ? SHARED : geocode;
- Bitmap imagePre = loadImageFromStorage(url, pseudoGeocode, shared);
-
- // Download image and save it to the cache
- if (imagePre == null) {
- final File file = LocalStorage.getStorageFile(pseudoGeocode, url, true, true);
- if (url.startsWith("data:image/")) {
- if (url.contains(";base64,")) {
- // TODO: when we use SDK level 8 or above, we can use the streaming version of the base64
- // Android utilities.
- byte[] decoded = Base64.decode(StringUtils.substringAfter(url, ";base64,"), Base64.DEFAULT);
- OutputStream out = null;
- try {
- out = new FileOutputStream(file);
- out.write(decoded);
- } catch (final IOException e) {
- Log.e("HtmlImage.getDrawable: cannot write file for decoded inline image", e);
- return null;
- } finally {
- IOUtils.closeQuietly(out);
+ final Observable<Pair<BitmapDrawable, Boolean>> loadFromDisk =
+ Observable.create(new OnSubscribeFunc<Pair<BitmapDrawable, Boolean>>() {
+ @Override
+ public Subscription onSubscribe(final Observer<? super Pair<BitmapDrawable, Boolean>> observer) {
+ final Pair<Bitmap, Boolean> loadResult = loadImageFromStorage(url, pseudoGeocode, shared);
+ final Bitmap bitmap = loadResult.getLeft();
+ observer.onNext(new ImmutablePair<BitmapDrawable, Boolean>(bitmap != null ?
+ ImageUtils.scaleBitmapToFitDisplay(bitmap) :
+ null,
+ loadResult.getRight()));
+ observer.onCompleted();
+ return Subscriptions.empty();
}
- } else {
- Log.e("HtmlImage.getDrawable: unable to decode non-base64 inline image");
- return null;
- }
- } else {
- final String absoluteURL = makeAbsoluteURL(url);
-
- if (absoluteURL != null) {
- try {
- final HttpResponse httpResponse = Network.getRequest(absoluteURL, null, file);
- if (httpResponse != null) {
- final int statusCode = httpResponse.getStatusLine().getStatusCode();
- if (statusCode == 200) {
- LocalStorage.saveEntityToFile(httpResponse, file);
- } else if (statusCode == 304) {
- if (!file.setLastModified(System.currentTimeMillis())) {
- makeFreshCopy(file);
- }
+ }).subscribeOn(Schedulers.computation());
+
+ final Observable<BitmapDrawable> downloadAndSave =
+ Observable.create(new OnSubscribeFunc<BitmapDrawable>() {
+ @Override
+ public Subscription onSubscribe(final Observer<? super BitmapDrawable> observer) {
+ final File file = LocalStorage.getStorageFile(pseudoGeocode, url, true, true);
+ if (url.startsWith("data:image/")) {
+ if (url.contains(";base64,")) {
+ saveBase64ToFile(url, file);
+ } else {
+ Log.e("HtmlImage.getDrawable: unable to decode non-base64 inline image");
+ observer.onCompleted();
+ return Subscriptions.empty();
+ }
+ } else {
+ if (subscription.isUnsubscribed() || downloadOrRefreshCopy(url, file)) {
+ // The existing copy was fresh enough or we were unsubscribed earlier.
+ observer.onCompleted();
+ return Subscriptions.empty();
}
}
- } catch (Exception e) {
- Log.e("HtmlImage.getDrawable (downloading from web)", e);
+ if (onlySave) {
+ observer.onCompleted();
+ } else {
+ loadFromDisk.map(new Func1<Pair<BitmapDrawable, Boolean>, BitmapDrawable>() {
+ @Override
+ public BitmapDrawable call(final Pair<BitmapDrawable, Boolean> loadResult) {
+ final BitmapDrawable image = loadResult.getLeft();
+ if (image != null) {
+ return image;
+ } else {
+ return returnErrorImage ?
+ new BitmapDrawable(resources, BitmapFactory.decodeResource(resources, R.drawable.image_not_loaded)) :
+ getTransparent1x1Image(resources);
+ }
+ }
+ }).subscribe(observer);
+ }
+ return Subscriptions.empty();
}
- }
- }
- }
+ }).subscribeOn(downloadScheduler);
- if (onlySave) {
- return null;
+ if (StringUtils.isBlank(url) || isCounter(url)) {
+ return Observable.from(getTransparent1x1Image(resources));
}
- // now load the newly downloaded image
- if (imagePre == null) {
- imagePre = loadImageFromStorage(url, pseudoGeocode, shared);
+ return loadFromDisk.switchMap(new Func1<Pair<BitmapDrawable, Boolean>, Observable<? extends BitmapDrawable>>() {
+ @Override
+ public Observable<? extends BitmapDrawable> call(final Pair<BitmapDrawable, Boolean> loadResult) {
+ final BitmapDrawable bitmap = loadResult.getLeft();
+ if (loadResult.getRight()) {
+ return Observable.from(bitmap);
+ }
+ return bitmap != null && !onlySave ? downloadAndSave.startWith(bitmap) : downloadAndSave;
+ }
+ });
+ }
+
+ public void waitForBackgroundLoading(@Nullable final CancellableHandler handler) {
+ if (handler != null) {
+ handler.unsubscribeIfCancelled(subscription);
}
+ loading.onCompleted();
+ waitForEnd.toBlockingObservable().lastOrDefault(null);
+ }
- // get image and return
- if (imagePre == null) {
- Log.d("HtmlImage.getDrawable: Failed to obtain image");
+ /**
+ * Download or refresh the copy of <code>url</code> in <code>file</code>.
+ *
+ * @param url the url of the document
+ * @param file the file to save the document in
+ * @return <code>true</code> if the existing file was up-to-date, <code>false</code> otherwise
+ */
+ private boolean downloadOrRefreshCopy(final String url, final File file) {
+ final String absoluteURL = makeAbsoluteURL(url);
- if (returnErrorImage) {
- imagePre = BitmapFactory.decodeResource(resources, R.drawable.image_not_loaded);
- } else {
- imagePre = getTransparent1x1Image();
+ if (absoluteURL != null) {
+ try {
+ final HttpResponse httpResponse = Network.getRequest(absoluteURL, null, file);
+ if (httpResponse != null) {
+ final int statusCode = httpResponse.getStatusLine().getStatusCode();
+ if (statusCode == 200) {
+ LocalStorage.saveEntityToFile(httpResponse, file);
+ } else if (statusCode == 304) {
+ if (!file.setLastModified(System.currentTimeMillis())) {
+ makeFreshCopy(file);
+ }
+ return true;
+ }
+ }
+ } catch (Exception e) {
+ Log.e("HtmlImage.downloadOrRefreshCopy", e);
}
}
+ return false;
+ }
- return imagePre != null ? ImageUtils.scaleBitmapToFitDisplay(imagePre) : null;
+ private static void saveBase64ToFile(final String url, final File file) {
+ // TODO: when we use SDK level 8 or above, we can use the streaming version of the base64
+ // Android utilities.
+ OutputStream out = null;
+ try {
+ out = new FileOutputStream(file);
+ out.write(Base64.decode(StringUtils.substringAfter(url, ";base64,"), Base64.DEFAULT));
+ } catch (final IOException e) {
+ Log.e("HtmlImage.saveBase64ToFile: cannot write file for decoded inline image", e);
+ } finally {
+ IOUtils.closeQuietly(out);
+ }
}
/**
@@ -180,25 +277,35 @@ public class HtmlImage implements Html.ImageGetter {
}
}
- private Bitmap getTransparent1x1Image() {
- return BitmapFactory.decodeResource(resources, R.drawable.image_no_placement);
+ private BitmapDrawable getTransparent1x1Image(final Resources res) {
+ return new BitmapDrawable(res, BitmapFactory.decodeResource(resources, R.drawable.image_no_placement));
}
- private Bitmap loadImageFromStorage(final String url, final String pseudoGeocode, final boolean forceKeep) {
+ /**
+ * Load an image from primary or secondary storage.
+ *
+ * @param url the image URL
+ * @param pseudoGeocode the geocode or the shared name
+ * @param forceKeep keep the image if it is there, without checking its freshness
+ * @return <code>true</code> if the image was there and is fresh enough, <code>false</code> otherwise
+ */
+ @NonNull
+ private Pair<Bitmap, Boolean> loadImageFromStorage(final String url, final String pseudoGeocode, final boolean forceKeep) {
try {
final File file = LocalStorage.getStorageFile(pseudoGeocode, url, true, false);
- final Bitmap image = loadCachedImage(file, forceKeep);
- if (image != null) {
+ final Pair<Bitmap, Boolean> image = loadCachedImage(file, forceKeep);
+ if (image.getRight() || image.getLeft() != null) {
return image;
}
final File fileSec = LocalStorage.getStorageSecFile(pseudoGeocode, url, true);
return loadCachedImage(fileSec, forceKeep);
} catch (Exception e) {
- Log.w("HtmlImage.getDrawable (reading cache)", e);
+ Log.w("HtmlImage.loadImageFromStorage", e);
}
- return null;
+ return new ImmutablePair<Bitmap, Boolean>(null, false);
}
+ @Nullable
private String makeAbsoluteURL(final String url) {
// Check if uri is absolute or not, if not attach the connector hostname
// FIXME: that should also include the scheme
@@ -222,21 +329,39 @@ public class HtmlImage implements Html.ImageGetter {
return null;
}
- private Bitmap loadCachedImage(final File file, final boolean forceKeep) {
+ /**
+ * Load a previously saved image.
+ *
+ * @param file the file on disk
+ * @param forceKeep keep the image if it is there, without checking its freshness
+ * @return a pair with <code>true</code> if the image was there and is fresh enough or <code>false</code> otherwise,
+ * and the image (possibly <code>null</code> if the first component is <code>false</code> and the image
+ * could not be loaded, or if the first component is <code>true</code> and <code>onlySave</code> is also
+ * <code>true</code>)
+ */
+ @NonNull
+ private Pair<Bitmap, Boolean> loadCachedImage(final File file, final boolean forceKeep) {
if (file.exists()) {
- if (listId >= StoredList.STANDARD_LIST_ID || file.lastModified() > (new Date().getTime() - (24 * 60 * 60 * 1000)) || forceKeep) {
- setSampleSize(file);
- final Bitmap image = BitmapFactory.decodeFile(file.getPath(), bfOptions);
- if (image == null) {
- Log.e("Cannot decode bitmap from " + file.getPath());
- }
- return image;
+ final boolean freshEnough = listId >= StoredList.STANDARD_LIST_ID || file.lastModified() > (new Date().getTime() - (24 * 60 * 60 * 1000)) || forceKeep;
+ if (onlySave) {
+ return new ImmutablePair<Bitmap, Boolean>(null, true);
}
+ final BitmapFactory.Options bfOptions = new BitmapFactory.Options();
+ bfOptions.inTempStorage = new byte[16 * 1024];
+ bfOptions.inPreferredConfig = Bitmap.Config.RGB_565;
+ setSampleSize(file, bfOptions);
+ final Bitmap image = BitmapFactory.decodeFile(file.getPath(), bfOptions);
+ if (image == null) {
+ Log.e("Cannot decode bitmap from " + file.getPath());
+ return new ImmutablePair<Bitmap, Boolean>(null, false);
+ }
+ return new ImmutablePair<Bitmap, Boolean>(image,
+ freshEnough);
}
- return null;
+ return new ImmutablePair<Bitmap, Boolean>(null, false);
}
- private void setSampleSize(final File file) {
+ private void setSampleSize(final File file, final BitmapFactory.Options bfOptions) {
//Decode image size only
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
diff --git a/main/src/cgeo/geocaching/network/Network.java b/main/src/cgeo/geocaching/network/Network.java
index e891d3b..ffd58c3 100644
--- a/main/src/cgeo/geocaching/network/Network.java
+++ b/main/src/cgeo/geocaching/network/Network.java
@@ -34,7 +34,6 @@ import ch.boye.httpclientandroidlib.params.CoreProtocolPNames;
import ch.boye.httpclientandroidlib.params.HttpParams;
import ch.boye.httpclientandroidlib.protocol.HttpContext;
import ch.boye.httpclientandroidlib.util.EntityUtils;
-
import org.apache.commons.lang3.CharEncoding;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.Nullable;
@@ -48,6 +47,7 @@ import android.net.Uri;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
@@ -426,6 +426,30 @@ public abstract class Network {
return null;
}
+ /**
+ * Get the input stream corresponding to a HTTP response if it exists.
+ *
+ * @param response a HTTP response, which can be null
+ * @return the input stream if the HTTP request is successful, <code>null</code> otherwise
+ */
+ @Nullable
+ public static InputStream getResponseStream(@Nullable final HttpResponse response) {
+ if (!isSuccess(response)) {
+ return null;
+ }
+ assert(response != null);
+ final HttpEntity entity = response.getEntity();
+ if (entity == null) {
+ return null;
+ }
+ try {
+ return entity.getContent();
+ } catch (final IOException e) {
+ Log.e("Network.getResponseStream", e);
+ return null;
+ }
+ }
+
@Nullable
private static String getResponseDataNoError(final HttpResponse response, boolean replaceWhitespace) {
try {
diff --git a/main/src/cgeo/geocaching/network/OAuth.java b/main/src/cgeo/geocaching/network/OAuth.java
index c033660..1e22551 100644
--- a/main/src/cgeo/geocaching/network/OAuth.java
+++ b/main/src/cgeo/geocaching/network/OAuth.java
@@ -3,7 +3,6 @@ package cgeo.geocaching.network;
import cgeo.geocaching.utils.CryptUtils;
import ch.boye.httpclientandroidlib.NameValuePair;
-
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
diff --git a/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java b/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java
index 888cf77..fd6ccc6 100644
--- a/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java
+++ b/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java
@@ -10,7 +10,6 @@ import cgeo.geocaching.utils.MatcherWrapper;
import ch.boye.httpclientandroidlib.ParseException;
import ch.boye.httpclientandroidlib.client.entity.UrlEncodedFormEntity;
import ch.boye.httpclientandroidlib.util.EntityUtils;
-
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.eclipse.jdt.annotation.NonNull;
diff --git a/main/src/cgeo/geocaching/network/StatusUpdater.java b/main/src/cgeo/geocaching/network/StatusUpdater.java
index cb4c7f4..84df168 100644
--- a/main/src/cgeo/geocaching/network/StatusUpdater.java
+++ b/main/src/cgeo/geocaching/network/StatusUpdater.java
@@ -1,21 +1,23 @@
package cgeo.geocaching.network;
import cgeo.geocaching.CgeoApplication;
-import cgeo.geocaching.utils.MemorySubject;
-import cgeo.geocaching.utils.PeriodicHandler;
-import cgeo.geocaching.utils.PeriodicHandler.PeriodicHandlerListener;
import cgeo.geocaching.utils.Version;
import org.json.JSONException;
import org.json.JSONObject;
+import rx.Observable;
+import rx.schedulers.Schedulers;
+import rx.subjects.BehaviorSubject;
+import rx.util.functions.Func1;
+
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
-import android.os.Looper;
import java.util.Locale;
+import java.util.concurrent.TimeUnit;
-public class StatusUpdater extends MemorySubject<StatusUpdater.Status> implements Runnable, PeriodicHandlerListener {
+public class StatusUpdater {
static public class Status {
final public String message;
@@ -30,24 +32,41 @@ public class StatusUpdater extends MemorySubject<StatusUpdater.Status> implement
this.url = url;
}
+ Status(final JSONObject response) {
+ message = get(response, "message");
+ messageId = get(response, "message_id");
+ icon = get(response, "icon");
+ url = get(response, "url");
+ }
+
final static public Status closeoutStatus =
new Status("", "status_closeout_warning", "attribute_abandonedbuilding", "http://faq.cgeo.org/#7_69");
- final static public Status defaultStatus() {
+ final static public Status defaultStatus(final Status upToDate) {
+ if (upToDate != null && upToDate.message != null) {
+ return upToDate;
+ }
return VERSION.SDK_INT < VERSION_CODES.ECLAIR_MR1 ? closeoutStatus : null;
}
}
- @Override
- public void onPeriodic() {
- final JSONObject response =
- Network.requestJSON("http://status.cgeo.org/api/status.json",
- new Parameters("version_code", String.valueOf(Version.getVersionCode(CgeoApplication.getInstance())),
- "version_name", Version.getVersionName(CgeoApplication.getInstance()),
- "locale", Locale.getDefault().toString()));
- if (response != null) {
- notifyObservers(new Status(get(response, "message"), get(response, "message_id"), get(response, "icon"), get(response, "url")));
- }
+ final static private Observable<Status> statusObservable =
+ Observable.interval(1800, TimeUnit.SECONDS).startWith(-1L).flatMap(new Func1<Long, Observable<Status>>() {
+ @Override
+ public Observable<Status> call(Long id) {
+ final JSONObject response =
+ Network.requestJSON("http://status.cgeo.org/api/status.json",
+ new Parameters("version_code", String.valueOf(Version.getVersionCode(CgeoApplication.getInstance())),
+ "version_name", Version.getVersionName(CgeoApplication.getInstance()),
+ "locale", Locale.getDefault().toString()));
+ return response != null ? Observable.from(Status.defaultStatus((new Status(response)))) : Observable.<Status>empty();
+ }
+ }).subscribeOn(Schedulers.io());
+
+ final static public BehaviorSubject<Status> latestStatus = BehaviorSubject.create(Status.defaultStatus(null));
+
+ static {
+ statusObservable.subscribe(latestStatus);
}
private static String get(final JSONObject json, final String key) {
@@ -58,11 +77,4 @@ public class StatusUpdater extends MemorySubject<StatusUpdater.Status> implement
}
}
- @Override
- public void run() {
- Looper.prepare();
- new PeriodicHandler(1800000L, this).start();
- Looper.loop();
- }
-
}
diff --git a/main/src/cgeo/geocaching/search/AutoCompleteAdapter.java b/main/src/cgeo/geocaching/search/AutoCompleteAdapter.java
new file mode 100644
index 0000000..123469c
--- /dev/null
+++ b/main/src/cgeo/geocaching/search/AutoCompleteAdapter.java
@@ -0,0 +1,71 @@
+package cgeo.geocaching.search;
+
+import org.apache.commons.lang3.StringUtils;
+
+import rx.util.functions.Func1;
+
+import android.content.Context;
+import android.widget.ArrayAdapter;
+import android.widget.Filter;
+
+/**
+ * The standard auto completion only matches user input at word boundaries. Therefore searching "est" will not match
+ * "test". This adapter matches everywhere.
+ *
+ */
+public class AutoCompleteAdapter extends ArrayAdapter<String> {
+
+ private String[] suggestions;
+ private final Func1<String, String[]> suggestionFunction;
+
+ public AutoCompleteAdapter(Context context, int textViewResourceId, final Func1<String, String[]> suggestionFunction) {
+ super(context, textViewResourceId);
+ this.suggestionFunction = suggestionFunction;
+ }
+
+ @Override
+ public int getCount() {
+ return suggestions.length;
+ }
+
+ @Override
+ public String getItem(int index) {
+ return suggestions[index];
+ }
+
+ @Override
+ public Filter getFilter() {
+ Filter filter = new Filter() {
+
+ @Override
+ protected FilterResults performFiltering(CharSequence constraint) {
+ FilterResults filterResults = new FilterResults();
+ if (constraint == null) {
+ return filterResults;
+ }
+ String trimmed = StringUtils.trim(constraint.toString());
+ if (StringUtils.length(trimmed) >= 2) {
+ String[] newResults = suggestionFunction.call(trimmed);
+
+ // Assign the data to the FilterResults, but do not yet store in the global member.
+ // Otherwise we might invalidate the adapter and cause an IllegalStateException.
+ filterResults.values = newResults;
+ filterResults.count = newResults.length;
+ }
+ return filterResults;
+ }
+
+ @Override
+ protected void publishResults(CharSequence constraint, FilterResults filterResults) {
+ if (filterResults != null && filterResults.count > 0) {
+ suggestions = (String[]) filterResults.values;
+ notifyDataSetChanged();
+ }
+ else {
+ notifyDataSetInvalidated();
+ }
+ }
+ };
+ return filter;
+ }
+} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/search/SuggestionProvider.java b/main/src/cgeo/geocaching/search/SuggestionProvider.java
new file mode 100644
index 0000000..c0a7728
--- /dev/null
+++ b/main/src/cgeo/geocaching/search/SuggestionProvider.java
@@ -0,0 +1,57 @@
+package cgeo.geocaching.search;
+
+import cgeo.geocaching.DataStore;
+
+import org.apache.commons.lang3.StringUtils;
+
+import android.app.SearchManager;
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class SuggestionProvider extends ContentProvider {
+
+ private static Cursor lastCursor;
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public String getType(final Uri arg0) {
+ return SearchManager.SUGGEST_MIME_TYPE;
+ }
+
+ @Override
+ public Cursor query(final Uri uri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder) {
+ final String searchTerm = uri.getLastPathSegment();
+ // can be empty when deleting the query
+ if (StringUtils.equals(searchTerm, SearchManager.SUGGEST_URI_PATH_QUERY)) {
+ return lastCursor;
+ }
+ return getSuggestions(searchTerm);
+ }
+
+ private static Cursor getSuggestions(final String searchTerm) {
+ lastCursor = DataStore.findSuggestions(searchTerm);
+ return lastCursor;
+ }
+
+ @Override
+ public int delete(final Uri uri, final String selection, final String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Uri insert(final Uri uri, final ContentValues values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int update(final Uri uri, final ContentValues values, final String selection, final String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/settings/OAuthPreference.java b/main/src/cgeo/geocaching/settings/OAuthPreference.java
index 3550947..06982f5 100644
--- a/main/src/cgeo/geocaching/settings/OAuthPreference.java
+++ b/main/src/cgeo/geocaching/settings/OAuthPreference.java
@@ -23,8 +23,8 @@ public class OAuthPreference extends Preference {
OCPL(R.string.pref_fakekey_ocpl_authorization, OCPLAuthorizationActivity.class),
TWITTER(R.string.pref_fakekey_twitter_authorization, TwitterAuthorizationActivity.class);
- public int prefKeyId;
- public Class<?> authActivity;
+ public final int prefKeyId;
+ public final Class<?> authActivity;
OAuthActivityMapping(int prefKeyId, Class<?> clazz) {
this.prefKeyId = prefKeyId;
diff --git a/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java b/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java
index 3e838ab..2ca8df1 100644
--- a/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java
+++ b/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java
@@ -8,7 +8,6 @@ import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.lang3.StringUtils;
import android.app.ProgressDialog;
diff --git a/main/src/cgeo/geocaching/settings/Settings.java b/main/src/cgeo/geocaching/settings/Settings.java
index 0732866..ee97c13 100644
--- a/main/src/cgeo/geocaching/settings/Settings.java
+++ b/main/src/cgeo/geocaching/settings/Settings.java
@@ -313,16 +313,16 @@ public class Settings {
return getBoolean(R.string.pref_connectorOXActive, false);
}
- public static boolean isPremiumMember() {
+ public static boolean isGCPremiumMember() {
// Basic Member, Premium Member, ???
- return GCConstants.MEMBER_STATUS_PM.equalsIgnoreCase(Settings.getMemberStatus());
+ return GCConstants.MEMBER_STATUS_PM.equalsIgnoreCase(Settings.getGCMemberStatus());
}
- public static String getMemberStatus() {
+ public static String getGCMemberStatus() {
return getString(R.string.pref_memberstatus, "");
}
- public static boolean setMemberStatus(final String memberStatus) {
+ public static boolean setGCMemberStatus(final String memberStatus) {
if (StringUtils.isBlank(memberStatus)) {
return remove(R.string.pref_memberstatus);
}
@@ -478,7 +478,7 @@ public class Settings {
}
public static boolean getLoadDirImg() {
- return !isPremiumMember() && getBoolean(R.string.pref_loaddirectionimg, true);
+ return !isGCPremiumMember() && getBoolean(R.string.pref_loaddirectionimg, true);
}
public static void setGcCustomDate(final String format) {
@@ -506,7 +506,7 @@ public class Settings {
}
public static boolean isShowCaptcha() {
- return !isPremiumMember() && getBoolean(R.string.pref_showcaptcha, false);
+ return !isGCPremiumMember() && getBoolean(R.string.pref_showcaptcha, false);
}
public static boolean isExcludeDisabledCaches() {
diff --git a/main/src/cgeo/geocaching/settings/SettingsActivity.java b/main/src/cgeo/geocaching/settings/SettingsActivity.java
index 58acfc1..bcf6715 100644
--- a/main/src/cgeo/geocaching/settings/SettingsActivity.java
+++ b/main/src/cgeo/geocaching/settings/SettingsActivity.java
@@ -1,6 +1,7 @@
package cgeo.geocaching.settings;
import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.DataStore;
import cgeo.geocaching.Intents;
import cgeo.geocaching.R;
import cgeo.geocaching.SelectMapfileActivity;
@@ -19,8 +20,10 @@ import cgeo.geocaching.utils.Log;
import org.apache.commons.lang3.StringUtils;
import org.openintents.intents.FileManagerIntents;
+import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -52,8 +55,7 @@ import java.util.Locale;
*/
public class SettingsActivity extends PreferenceActivity {
- private static final String INTENT_GOTO = "GOTO";
- private static final int INTENT_GOTO_SERVICES = 1;
+ private static final String INTENT_OPEN_SCREEN = "OPEN_SCREEN";
/**
* Enumeration for directory choosers. This is how we can retrieve information about the
@@ -89,18 +91,21 @@ public class SettingsActivity extends PreferenceActivity {
initPreferences();
Intent intent = getIntent();
- int gotoPage = intent.getIntExtra(INTENT_GOTO, 0);
- if (gotoPage == INTENT_GOTO_SERVICES) {
- // start with services screen
- PreferenceScreen main = (PreferenceScreen) getPreference(R.string.pref_fakekey_main_screen);
- try {
- if (main != null) {
- int index = getPreference(R.string.pref_fakekey_services_screen).getOrder();
- main.onItemClick(null, null, index, 0);
- }
- } catch (RuntimeException e) {
- Log.e("could not open services preferences", e);
- }
+ openInitialScreen(intent.getIntExtra(INTENT_OPEN_SCREEN, 0));
+ }
+
+ private void openInitialScreen(int initialScreen) {
+ if (initialScreen == 0) {
+ return;
+ }
+ PreferenceScreen screen = (PreferenceScreen) getPreference(initialScreen);
+ if (screen == null) {
+ return;
+ }
+ try {
+ setPreferenceScreen(screen);
+ } catch (RuntimeException e) {
+ Log.e("could not open preferences " + initialScreen, e);
}
}
@@ -121,6 +126,7 @@ public class SettingsActivity extends PreferenceActivity {
initSend2CgeoPreferences();
initServicePreferences();
initNavigationMenuPreferences();
+ initMaintenanceButtons();
for (int k : new int[] { R.string.pref_username, R.string.pref_password,
R.string.pref_pass_vote, R.string.pref_signature,
@@ -141,9 +147,9 @@ public class SettingsActivity extends PreferenceActivity {
getPreference(appEnum.preferenceKey).setEnabled(true);
}
}
- getPreference(R.string.pref_fakekey_basicmembers_screen)
- .setEnabled(!Settings.isPremiumMember());
- redrawScreen(R.string.pref_fakekey_navigation_menu_screen);
+ getPreference(R.string.preference_screen_basicmembers)
+ .setEnabled(!Settings.isGCPremiumMember());
+ redrawScreen(R.string.preference_screen_navigation_menu);
}
private void initServicePreferences() {
@@ -310,6 +316,35 @@ public class SettingsActivity extends PreferenceActivity {
});
}
+ public void initMaintenanceButtons() {
+ Preference dirMaintenance = getPreference(R.string.pref_fakekey_preference_maintenance_directories);
+ dirMaintenance.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(final Preference preference) {
+ // disable the button, as the cleanup runs in background and should not be invoked a second time
+ preference.setEnabled(false);
+
+ Resources res = getResources();
+ final SettingsActivity activity = SettingsActivity.this;
+ final ProgressDialog dialog = ProgressDialog.show(activity, res.getString(R.string.init_maintenance), res.getString(R.string.init_maintenance_directories), true, false);
+ new Thread() {
+ @Override
+ public void run() {
+ DataStore.removeObsoleteCacheDirectories();
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ dialog.dismiss();
+ }
+ });
+ }
+ }.start();
+
+ return true;
+ }
+ });
+ }
+
private void initDbLocationPreference() {
Preference p = getPreference(R.string.pref_dbonsdcard);
p.setPersistent(false);
@@ -336,21 +371,29 @@ public class SettingsActivity extends PreferenceActivity {
}
void initBasicMemberPreferences() {
- getPreference(R.string.pref_fakekey_basicmembers_screen)
- .setEnabled(!Settings.isPremiumMember());
+ getPreference(R.string.preference_screen_basicmembers)
+ .setEnabled(!Settings.isGCPremiumMember());
getPreference(R.string.pref_loaddirectionimg)
- .setEnabled(!Settings.isPremiumMember());
+ .setEnabled(!Settings.isGCPremiumMember());
getPreference(R.string.pref_showcaptcha)
- .setEnabled(!Settings.isPremiumMember());
+ .setEnabled(!Settings.isGCPremiumMember());
- redrawScreen(R.string.pref_fakekey_services_screen);
+ redrawScreen(R.string.preference_screen_services);
}
- void redrawScreen(int key) {
- PreferenceScreen screen = (PreferenceScreen) getPreference(key);
- if (screen == null) {
+ /**
+ * Refresh a preference screen. Has no effect when called for a preference, that is not actually a preference
+ * screen.
+ *
+ * @param key
+ * Key of a preference screen.
+ */
+ void redrawScreen(final int key) {
+ final Preference preference = getPreference(key);
+ if (!(preference instanceof PreferenceScreen)) {
return;
}
+ final PreferenceScreen screen = (PreferenceScreen) preference;
ListAdapter adapter = screen.getRootAdapter();
if (adapter instanceof BaseAdapter) {
((BaseAdapter) adapter).notifyDataSetChanged();
@@ -399,9 +442,9 @@ public class SettingsActivity extends PreferenceActivity {
: R.string.settings_authorize));
}
- public static void jumpToServicesPage(final Context fromActivity) {
+ public static void openForScreen(final int preferenceScreenKey, final Context fromActivity) {
final Intent intent = new Intent(fromActivity, SettingsActivity.class);
- intent.putExtra(INTENT_GOTO, INTENT_GOTO_SERVICES);
+ intent.putExtra(INTENT_OPEN_SCREEN, preferenceScreenKey);
fromActivity.startActivity(intent);
}
@@ -445,15 +488,15 @@ public class SettingsActivity extends PreferenceActivity {
break;
case R.string.pref_fakekey_ocde_authorization:
setOCDEAuthTitle();
- redrawScreen(R.string.pref_fakekey_services_screen);
+ redrawScreen(R.string.preference_screen_ocde);
break;
case R.string.pref_fakekey_ocpl_authorization:
setOCPLAuthTitle();
- redrawScreen(R.string.pref_fakekey_services_screen);
+ redrawScreen(R.string.preference_screen_ocpl);
break;
case R.string.pref_fakekey_twitter_authorization:
setTwitterAuthTitle();
- redrawScreen(R.string.pref_fakekey_services_screen);
+ redrawScreen(R.string.preference_screen_twitter);
break;
default:
throw new IllegalArgumentException();
@@ -582,6 +625,13 @@ public class SettingsActivity extends PreferenceActivity {
preferenceActivity.addPreferencesFromResource(preferencesResId);
}
+ @SuppressWarnings("deprecation")
+ @Override
+ public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
+ // TODO replace with fragment based code
+ super.setPreferenceScreen(preferenceScreen);
+ }
+
private static boolean isPreference(final Preference preference, int preferenceKeyId) {
return getKey(preferenceKeyId).equals(preference.getKey());
}
diff --git a/main/src/cgeo/geocaching/settings/TemplateTextPreference.java b/main/src/cgeo/geocaching/settings/TemplateTextPreference.java
index a703231..667b02b 100644
--- a/main/src/cgeo/geocaching/settings/TemplateTextPreference.java
+++ b/main/src/cgeo/geocaching/settings/TemplateTextPreference.java
@@ -2,6 +2,7 @@ package cgeo.geocaching.settings;
import cgeo.geocaching.R;
import cgeo.geocaching.activity.ActivityMixin;
+import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.LogTemplateProvider;
import cgeo.geocaching.utils.LogTemplateProvider.LogTemplate;
@@ -49,6 +50,7 @@ public class TemplateTextPreference extends DialogPreference {
editText = (EditText) view.findViewById(R.id.signature_dialog_text);
editText.setText(getPersistedString(initialValue != null ? initialValue : StringUtils.EMPTY));
+ Dialogs.moveCursorToEnd(editText);
Button button = (Button) view.findViewById(R.id.signature_templates);
button.setOnClickListener(new View.OnClickListener() {
diff --git a/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java b/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java
index a1c04a4..2b171b4 100644
--- a/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java
+++ b/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java
@@ -3,6 +3,7 @@ package cgeo.geocaching.sorting;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.utils.Log;
+import org.apache.commons.lang3.StringUtils;
/**
* abstract super implementation for all cache comparators
@@ -13,25 +14,35 @@ public abstract class AbstractCacheComparator implements CacheComparator {
@Override
public final int compare(final Geocache cache1, final Geocache cache2) {
try {
- // first check that we have all necessary data for the comparison
- if (!canCompare(cache1, cache2)) {
- return 0;
+ final boolean canCompare1 = canCompare(cache1);
+ final boolean canCompare2 = canCompare(cache2);
+ if (!canCompare1) {
+ return canCompare2 ? 1 : fallbackToGeocode(cache1, cache2);
}
- return compareCaches(cache1, cache2);
- } catch (Exception e) {
+ return canCompare2 ? compareCaches(cache1, cache2) : -1;
+ } catch (final Exception e) {
Log.e("AbstractCacheComparator.compare", e);
+ // This may violate the Comparator interface if the exception is not systematic.
+ return fallbackToGeocode(cache1, cache2);
}
- return 0;
+ }
+
+ private static int fallbackToGeocode(final Geocache cache1, final Geocache cache2) {
+ return StringUtils.defaultString(cache1.getGeocode()).compareToIgnoreCase(StringUtils.defaultString(cache2.getGeocode()));
}
/**
- * Check necessary preconditions (like missing fields) before running the comparison itself
- *
- * @param cache1
- * @param cache2
- * @return
+ * Check necessary preconditions (like missing fields) before running the comparison itself.
+ * Caches not filling the conditions will be placed last, sorted by Geocode.
+ *
+ * The default returns <code>true</code> and can be overridden if needed in child classes.
+ *
+ * @param cache
+ * @return <code>true</code> if the cache holds the necessary data to be compared meaningfully
*/
- protected abstract boolean canCompare(final Geocache cache1, final Geocache cache2);
+ protected boolean canCompare(final Geocache cache) {
+ return true;
+ }
/**
* Compares two caches. Logging and exception handling is implemented outside this method already.
diff --git a/main/src/cgeo/geocaching/sorting/CacheComparator.java b/main/src/cgeo/geocaching/sorting/CacheComparator.java
index 7932729..b06a4b0 100644
--- a/main/src/cgeo/geocaching/sorting/CacheComparator.java
+++ b/main/src/cgeo/geocaching/sorting/CacheComparator.java
@@ -1,9 +1,9 @@
package cgeo.geocaching.sorting;
-import java.util.Comparator;
-
import cgeo.geocaching.Geocache;
+import java.util.Comparator;
+
public interface CacheComparator extends Comparator<Geocache> {
}
diff --git a/main/src/cgeo/geocaching/sorting/ComparatorUserInterface.java b/main/src/cgeo/geocaching/sorting/ComparatorUserInterface.java
index 99a535a..8cf3d9d 100644
--- a/main/src/cgeo/geocaching/sorting/ComparatorUserInterface.java
+++ b/main/src/cgeo/geocaching/sorting/ComparatorUserInterface.java
@@ -2,7 +2,8 @@ package cgeo.geocaching.sorting;
import cgeo.geocaching.R;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.RunnableWithArgument;
+
+import rx.util.functions.Action1;
import android.app.Activity;
import android.app.AlertDialog;
@@ -70,7 +71,7 @@ public class ComparatorUserInterface {
registry.add(new ComparatorEntry(res.getString(resourceId), comparatorClass));
}
- public void selectComparator(final CacheComparator current, final RunnableWithArgument<CacheComparator> runAfterwards) {
+ public void selectComparator(final CacheComparator current, final Action1<CacheComparator> runAfterwards) {
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(R.string.caches_sort_title);
@@ -85,11 +86,11 @@ public class ComparatorUserInterface {
ComparatorEntry entry = registry.get(itemIndex);
try {
if (entry.cacheComparator == null) {
- runAfterwards.run(null);
+ runAfterwards.call(null);
}
else {
CacheComparator comparator = entry.cacheComparator.newInstance();
- runAfterwards.run(comparator);
+ runAfterwards.call(comparator);
}
} catch (InstantiationException e) {
Log.e("selectComparator", e);
diff --git a/main/src/cgeo/geocaching/sorting/DateComparator.java b/main/src/cgeo/geocaching/sorting/DateComparator.java
index 091f6a4..9df70f9 100644
--- a/main/src/cgeo/geocaching/sorting/DateComparator.java
+++ b/main/src/cgeo/geocaching/sorting/DateComparator.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.sorting;
-import cgeo.geocaching.Geocache;
import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.Geocache;
import java.util.ArrayList;
import java.util.Date;
@@ -12,11 +12,6 @@ import java.util.Date;
public class DateComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache1, Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(Geocache cache1, Geocache cache2) {
final Date date1 = cache1.getHiddenDate();
final Date date2 = cache2.getHiddenDate();
diff --git a/main/src/cgeo/geocaching/sorting/DifficultyComparator.java b/main/src/cgeo/geocaching/sorting/DifficultyComparator.java
index 73d12fa..459f38d 100644
--- a/main/src/cgeo/geocaching/sorting/DifficultyComparator.java
+++ b/main/src/cgeo/geocaching/sorting/DifficultyComparator.java
@@ -9,8 +9,8 @@ import cgeo.geocaching.Geocache;
public class DifficultyComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache1, Geocache cache2) {
- return cache1.getDifficulty() != 0.0 && cache2.getDifficulty() != 0.0;
+ protected boolean canCompare(Geocache cache) {
+ return cache.getDifficulty() != 0.0;
}
@Override
diff --git a/main/src/cgeo/geocaching/sorting/DistanceComparator.java b/main/src/cgeo/geocaching/sorting/DistanceComparator.java
index 731e356..541ce48 100644
--- a/main/src/cgeo/geocaching/sorting/DistanceComparator.java
+++ b/main/src/cgeo/geocaching/sorting/DistanceComparator.java
@@ -36,11 +36,6 @@ public class DistanceComparator extends AbstractCacheComparator {
}
@Override
- protected boolean canCompare(Geocache cache1, Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
calculateAllDistances();
final Float distance1 = cache1.getDistance();
diff --git a/main/src/cgeo/geocaching/sorting/FindsComparator.java b/main/src/cgeo/geocaching/sorting/FindsComparator.java
index c889776..7f2ef50 100644
--- a/main/src/cgeo/geocaching/sorting/FindsComparator.java
+++ b/main/src/cgeo/geocaching/sorting/FindsComparator.java
@@ -5,8 +5,8 @@ import cgeo.geocaching.Geocache;
public class FindsComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache1, Geocache cache2) {
- return cache1.getLogCounts() != null && cache2.getLogCounts() != null;
+ protected boolean canCompare(Geocache cache) {
+ return cache.getLogCounts() != null;
}
@Override
diff --git a/main/src/cgeo/geocaching/sorting/GeocodeComparator.java b/main/src/cgeo/geocaching/sorting/GeocodeComparator.java
index fff26c6..e700f13 100644
--- a/main/src/cgeo/geocaching/sorting/GeocodeComparator.java
+++ b/main/src/cgeo/geocaching/sorting/GeocodeComparator.java
@@ -2,23 +2,20 @@ package cgeo.geocaching.sorting;
import cgeo.geocaching.Geocache;
-import org.apache.commons.lang3.StringUtils;
-
/**
* sorts caches by geo code, therefore effectively sorting by cache age
- *
+ *
*/
public class GeocodeComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache1, Geocache cache2) {
- return StringUtils.isNotBlank(cache1.getGeocode())
- && StringUtils.isNotBlank(cache2.getGeocode());
+ protected boolean canCompare(final Geocache cache) {
+ // This will fall back to geocode comparisons.
+ return false;
}
@Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
- final int lengthDiff = cache1.getGeocode().length() - cache2.getGeocode().length();
- return lengthDiff != 0 ? lengthDiff : cache1.getGeocode().compareToIgnoreCase(cache2.getGeocode());
+ throw new RuntimeException("should never be called");
}
}
diff --git a/main/src/cgeo/geocaching/sorting/InventoryComparator.java b/main/src/cgeo/geocaching/sorting/InventoryComparator.java
index 73ea2c5..9d19b64 100644
--- a/main/src/cgeo/geocaching/sorting/InventoryComparator.java
+++ b/main/src/cgeo/geocaching/sorting/InventoryComparator.java
@@ -8,11 +8,6 @@ import cgeo.geocaching.Geocache;
public class InventoryComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(final Geocache cache1, final Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
return cache2.getInventoryItems() - cache1.getInventoryItems();
}
diff --git a/main/src/cgeo/geocaching/sorting/NameComparator.java b/main/src/cgeo/geocaching/sorting/NameComparator.java
index b432ad0..2941b1c 100644
--- a/main/src/cgeo/geocaching/sorting/NameComparator.java
+++ b/main/src/cgeo/geocaching/sorting/NameComparator.java
@@ -11,8 +11,8 @@ import org.apache.commons.lang3.StringUtils;
public class NameComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache1, Geocache cache2) {
- return StringUtils.isNotBlank(cache1.getName()) && StringUtils.isNotBlank(cache2.getName());
+ protected boolean canCompare(Geocache cache) {
+ return StringUtils.isNotBlank(cache.getName());
}
@Override
diff --git a/main/src/cgeo/geocaching/sorting/PopularityComparator.java b/main/src/cgeo/geocaching/sorting/PopularityComparator.java
index e256654..2dbee68 100644
--- a/main/src/cgeo/geocaching/sorting/PopularityComparator.java
+++ b/main/src/cgeo/geocaching/sorting/PopularityComparator.java
@@ -9,11 +9,6 @@ import cgeo.geocaching.Geocache;
public class PopularityComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(final Geocache cache1, final Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
return cache2.getFavoritePoints() - cache1.getFavoritePoints();
}
diff --git a/main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java b/main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java
index f438762..1ed8e68 100644
--- a/main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java
+++ b/main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java
@@ -11,11 +11,6 @@ import cgeo.geocaching.Geocache;
public class PopularityRatioComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(final Geocache cache1, final Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
float ratio1 = 0.0f;
diff --git a/main/src/cgeo/geocaching/sorting/RatingComparator.java b/main/src/cgeo/geocaching/sorting/RatingComparator.java
index 72cf6c8..6f2c615 100644
--- a/main/src/cgeo/geocaching/sorting/RatingComparator.java
+++ b/main/src/cgeo/geocaching/sorting/RatingComparator.java
@@ -9,11 +9,6 @@ import cgeo.geocaching.Geocache;
public class RatingComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(final Geocache cache1, final Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
final float rating1 = cache1.getRating();
final float rating2 = cache2.getRating();
diff --git a/main/src/cgeo/geocaching/sorting/SizeComparator.java b/main/src/cgeo/geocaching/sorting/SizeComparator.java
index d128822..c8de586 100644
--- a/main/src/cgeo/geocaching/sorting/SizeComparator.java
+++ b/main/src/cgeo/geocaching/sorting/SizeComparator.java
@@ -9,8 +9,8 @@ import cgeo.geocaching.Geocache;
public class SizeComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache1, Geocache cache2) {
- return cache1.getSize() != null && cache2.getSize() != null;
+ protected boolean canCompare(Geocache cache) {
+ return cache.getSize() != null;
}
@Override
diff --git a/main/src/cgeo/geocaching/sorting/StateComparator.java b/main/src/cgeo/geocaching/sorting/StateComparator.java
index b99c3c0..9488bd9 100644
--- a/main/src/cgeo/geocaching/sorting/StateComparator.java
+++ b/main/src/cgeo/geocaching/sorting/StateComparator.java
@@ -9,11 +9,6 @@ import cgeo.geocaching.Geocache;
public class StateComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(final Geocache cache1, final Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
return getState(cache1) - getState(cache2);
}
diff --git a/main/src/cgeo/geocaching/sorting/StorageTimeComparator.java b/main/src/cgeo/geocaching/sorting/StorageTimeComparator.java
index 78ba742..b718d3b 100644
--- a/main/src/cgeo/geocaching/sorting/StorageTimeComparator.java
+++ b/main/src/cgeo/geocaching/sorting/StorageTimeComparator.java
@@ -5,11 +5,6 @@ import cgeo.geocaching.Geocache;
public class StorageTimeComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache1, Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(Geocache cache1, Geocache cache2) {
if (cache1.getUpdated() < cache2.getUpdated()) {
return -1;
diff --git a/main/src/cgeo/geocaching/sorting/TerrainComparator.java b/main/src/cgeo/geocaching/sorting/TerrainComparator.java
index be1e9bb..9bbb5f7 100644
--- a/main/src/cgeo/geocaching/sorting/TerrainComparator.java
+++ b/main/src/cgeo/geocaching/sorting/TerrainComparator.java
@@ -9,8 +9,8 @@ import cgeo.geocaching.Geocache;
public class TerrainComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(final Geocache cache1, final Geocache cache2) {
- return cache1.getTerrain() != 0.0 && cache2.getTerrain() != 0.0;
+ protected boolean canCompare(final Geocache cache) {
+ return cache.getTerrain() != 0.0;
}
@Override
diff --git a/main/src/cgeo/geocaching/sorting/VisitComparator.java b/main/src/cgeo/geocaching/sorting/VisitComparator.java
index 27d3170..1589a4c 100644
--- a/main/src/cgeo/geocaching/sorting/VisitComparator.java
+++ b/main/src/cgeo/geocaching/sorting/VisitComparator.java
@@ -9,11 +9,6 @@ import cgeo.geocaching.Geocache;
public class VisitComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(final Geocache cache1, final Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
return Long.valueOf(cache2.getVisitedDate()).compareTo(cache1.getVisitedDate());
}
diff --git a/main/src/cgeo/geocaching/sorting/VoteComparator.java b/main/src/cgeo/geocaching/sorting/VoteComparator.java
index dc0304b..cd4ad7e 100644
--- a/main/src/cgeo/geocaching/sorting/VoteComparator.java
+++ b/main/src/cgeo/geocaching/sorting/VoteComparator.java
@@ -8,11 +8,6 @@ import cgeo.geocaching.Geocache;
public class VoteComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache1, Geocache cache2) {
- return true;
- }
-
- @Override
protected int compareCaches(Geocache cache1, Geocache cache2) {
// if there is no vote available, put that cache at the end of the list
return Float.compare(cache2.getMyVote(), cache1.getMyVote());
diff --git a/main/src/cgeo/geocaching/speech/SpeechService.java b/main/src/cgeo/geocaching/speech/SpeechService.java
index 2a72bbf..8c650c3 100644
--- a/main/src/cgeo/geocaching/speech/SpeechService.java
+++ b/main/src/cgeo/geocaching/speech/SpeechService.java
@@ -47,7 +47,7 @@ public class SpeechService extends Service implements OnInitListener {
GeoDirHandler geoHandler = new GeoDirHandler() {
@Override
- protected void updateDirection(float newDirection) {
+ public void updateDirection(float newDirection) {
if (CgeoApplication.getInstance().currentGeo().getSpeed() <= 5) {
direction = DirectionProvider.getDirectionNow(startingActivity, newDirection);
directionInitialized = true;
@@ -56,7 +56,7 @@ public class SpeechService extends Service implements OnInitListener {
}
@Override
- protected void updateGeoData(cgeo.geocaching.IGeoData newGeo) {
+ public void updateGeoData(cgeo.geocaching.IGeoData newGeo) {
position = newGeo.getCoords();
positionInitialized = true;
if (!Settings.isUseCompass() || newGeo.getSpeed() > 5) {
diff --git a/main/src/cgeo/geocaching/speech/TextFactory.java b/main/src/cgeo/geocaching/speech/TextFactory.java
index 2a3b6d7..eb780c6 100644
--- a/main/src/cgeo/geocaching/speech/TextFactory.java
+++ b/main/src/cgeo/geocaching/speech/TextFactory.java
@@ -2,9 +2,9 @@ package cgeo.geocaching.speech;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
-import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.IConversion;
+import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.AngleUtils;
import java.util.Locale;
diff --git a/main/src/cgeo/geocaching/twitter/Twitter.java b/main/src/cgeo/geocaching/twitter/Twitter.java
index 51cf6e2..c89c0b6 100644
--- a/main/src/cgeo/geocaching/twitter/Twitter.java
+++ b/main/src/cgeo/geocaching/twitter/Twitter.java
@@ -17,7 +17,6 @@ import cgeo.geocaching.utils.LogTemplateProvider;
import cgeo.geocaching.utils.LogTemplateProvider.LogContext;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
diff --git a/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java b/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java
index ed5d182..0c67384 100644
--- a/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java
+++ b/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java
@@ -3,7 +3,6 @@ package cgeo.geocaching.ui;
import cgeo.geocaching.activity.AbstractViewPagerActivity.PageViewCreator;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
diff --git a/main/src/cgeo/geocaching/ui/AnchorAwareLinkMovementMethod.java b/main/src/cgeo/geocaching/ui/AnchorAwareLinkMovementMethod.java
index db82e5c..d4c2e10 100644
--- a/main/src/cgeo/geocaching/ui/AnchorAwareLinkMovementMethod.java
+++ b/main/src/cgeo/geocaching/ui/AnchorAwareLinkMovementMethod.java
@@ -8,7 +8,7 @@ import android.widget.TextView;
/**
* <code>LinkMovementMethod</code> with built-in suppression of errors for links, where the URL cannot be handled
* correctly by Android.
- *
+ *
*/
public class AnchorAwareLinkMovementMethod extends LinkMovementMethod {
diff --git a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
index 7fe77c4..5d8ebef 100644
--- a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
+++ b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
@@ -39,6 +39,11 @@ public final class CacheDetailsCreator {
parentView.removeAllViews();
}
+ /**
+ * @param nameId
+ * @param value
+ * @return the view containing the displayed string (i.e. the right side one from the pair of "label": "value")
+ */
public TextView add(final int nameId, final CharSequence value) {
final RelativeLayout layout = (RelativeLayout) activity.getLayoutInflater().inflate(R.layout.cache_information_item, null);
final TextView nameView = (TextView) layout.findViewById(R.id.name);
@@ -188,14 +193,24 @@ public final class CacheDetailsCreator {
if (!cache.isEventCache()) {
return;
}
+ addHiddenDate(cache);
+ }
+
+ public TextView addHiddenDate(final @NonNull Geocache cache) {
final Date hiddenDate = cache.getHiddenDate();
if (hiddenDate == null) {
- return;
+ return null;
}
final long time = hiddenDate.getTime();
if (time > 0) {
- final String dateString = DateUtils.formatDateTime(CgeoApplication.getInstance().getBaseContext(), time, DateUtils.FORMAT_SHOW_WEEKDAY) + ", " + Formatter.formatFullDate(time);
- add(R.string.cache_event, dateString);
+ String dateString = Formatter.formatFullDate(time);
+ if (cache.isEventCache()) {
+ dateString = DateUtils.formatDateTime(CgeoApplication.getInstance().getBaseContext(), time, DateUtils.FORMAT_SHOW_WEEKDAY) + ", " + dateString;
+ }
+ final TextView view = add(cache.isEventCache() ? R.string.cache_event : R.string.cache_hidden, dateString);
+ view.setId(R.id.date);
+ return view;
}
+ return null;
}
}
diff --git a/main/src/cgeo/geocaching/ui/EditNoteDialog.java b/main/src/cgeo/geocaching/ui/EditNoteDialog.java
index 2af1cb8..4bfa140 100644
--- a/main/src/cgeo/geocaching/ui/EditNoteDialog.java
+++ b/main/src/cgeo/geocaching/ui/EditNoteDialog.java
@@ -1,6 +1,7 @@
package cgeo.geocaching.ui;
import cgeo.geocaching.R;
+import cgeo.geocaching.ui.dialog.Dialogs;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -40,6 +41,7 @@ public class EditNoteDialog extends DialogFragment {
String initialNote = getArguments().getString(ARGUMENT_INITIAL_NOTE);
if (initialNote != null) {
mEditText.setText(initialNote);
+ Dialogs.moveCursorToEnd(mEditText);
getArguments().remove(ARGUMENT_INITIAL_NOTE);
}
diff --git a/main/src/cgeo/geocaching/ui/ImagesList.java b/main/src/cgeo/geocaching/ui/ImagesList.java
index 4eaf06d..4058e15 100644
--- a/main/src/cgeo/geocaching/ui/ImagesList.java
+++ b/main/src/cgeo/geocaching/ui/ImagesList.java
@@ -9,6 +9,9 @@ import cgeo.geocaching.utils.Log;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
+import rx.android.observables.AndroidObservable;
+import rx.subscriptions.CompositeSubscription;
+import rx.util.functions.Action1;
import android.app.Activity;
import android.content.Intent;
@@ -18,14 +21,12 @@ import android.graphics.Bitmap.CompressFormat;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
-import android.os.AsyncTask;
import android.text.Html;
import android.util.SparseArray;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
-import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -41,11 +42,11 @@ public class ImagesList {
private BitmapDrawable currentDrawable;
private Image currentImage;
+ private CompositeSubscription subscriptions = new CompositeSubscription();
public enum ImageType {
LogImages(R.string.cache_log_images_title),
- SpoilerImages(R.string.cache_spoiler_images_title),
- AllImages(R.string.cache_images_title);
+ SpoilerImages(R.string.cache_spoiler_images_title);
private final int titleResId;
@@ -76,11 +77,13 @@ public class ImagesList {
}
public void loadImages(final View parentView, final List<Image> images, final boolean offline) {
-
imagesView = (LinearLayout) parentView.findViewById(R.id.spoiler_list);
+ final HtmlImage imgGetter = new HtmlImage(geocode, true, offline ? StoredList.STANDARD_LIST_ID : StoredList.TEMPORARY_LIST_ID, false);
+
for (final Image img : images) {
- LinearLayout rowView = (LinearLayout) inflater.inflate(R.layout.cache_image_item, null);
+ final LinearLayout rowView = (LinearLayout) inflater.inflate(R.layout.cache_image_item, null);
+ assert(rowView != null);
if (StringUtils.isNotBlank(img.getTitle())) {
((TextView) rowView.findViewById(R.id.title)).setText(Html.fromHtml(img.getTitle()));
@@ -93,66 +96,57 @@ public class ImagesList {
descView.setVisibility(View.VISIBLE);
}
- new AsyncImgLoader(rowView, img, offline).execute();
+ final ImageView imageView = (ImageView) inflater.inflate(R.layout.image_item, null);
+ assert(imageView != null);
+ subscriptions.add(AndroidObservable.fromActivity(activity, imgGetter.fetchDrawable(img.getUrl()))
+ .subscribe(new Action1<BitmapDrawable>() {
+ @Override
+ public void call(final BitmapDrawable image) {
+ display(imageView, image, img, rowView);
+ }
+ }));
+ rowView.addView(imageView);
imagesView.addView(rowView);
}
}
- private class AsyncImgLoader extends AsyncTask<Void, Void, BitmapDrawable> {
+ private void display(final ImageView imageView, final BitmapDrawable image, final Image img, final LinearLayout view) {
+ if (image != null) {
+ bitmaps.add(image.getBitmap());
- final private LinearLayout view;
- final private Image img;
- final boolean offline;
+ final Rect bounds = image.getBounds();
- public AsyncImgLoader(final LinearLayout view, final Image img, final boolean offline) {
- this.view = view;
- this.img = img;
- this.offline = offline;
- }
+ imageView.setImageResource(R.drawable.image_not_loaded);
+ imageView.setClickable(true);
+ imageView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ viewImageInStandardApp(image);
+ }
+ });
+ activity.registerForContextMenu(imageView);
+ imageView.setImageDrawable(image);
+ imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
+ imageView.setLayoutParams(new LinearLayout.LayoutParams(bounds.width(), bounds.height()));
- @Override
- protected BitmapDrawable doInBackground(Void... params) {
- final HtmlImage imgGetter = new HtmlImage(geocode, true, offline ? StoredList.STANDARD_LIST_ID : StoredList.TEMPORARY_LIST_ID, false);
- return imgGetter.getDrawable(img.getUrl());
- }
+ view.findViewById(R.id.progress_bar).setVisibility(View.GONE);
- @Override
- protected void onPostExecute(final BitmapDrawable image) {
- if (image != null) {
- bitmaps.add(image.getBitmap());
- final ImageView imageView = (ImageView) inflater.inflate(R.layout.image_item, null);
-
- final Rect bounds = image.getBounds();
-
- imageView.setImageResource(R.drawable.image_not_loaded);
- imageView.setClickable(true);
- imageView.setOnClickListener(new View.OnClickListener() {
-
- @Override
- public void onClick(View arg0) {
- viewImageInStandardApp(image);
- }
- });
- activity.registerForContextMenu(imageView);
- imageView.setImageDrawable(image);
- imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
- imageView.setLayoutParams(new LayoutParams(bounds.width(), bounds.height()));
-
- view.findViewById(R.id.progress_bar).setVisibility(View.GONE);
- view.addView(imageView);
-
- imageView.setId(image.hashCode());
- images.put(imageView.getId(), img);
- }
+ imageView.setId(image.hashCode());
+ images.put(imageView.getId(), img);
+
+ view.invalidate();
}
}
public void removeAllViews() {
- imagesView.removeAllViews();
for (final Bitmap b : bitmaps) {
b.recycle();
}
bitmaps.clear();
+
+ // Stop loading images if some are still in progress
+ subscriptions.unsubscribe();
+ imagesView.removeAllViews();
}
public void onCreateContextMenu(ContextMenu menu, View v) {
diff --git a/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java b/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java
index 93f50e1..651ff6e 100644
--- a/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java
+++ b/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java
@@ -54,7 +54,7 @@ public class CoordinatesInputDialog extends NoTitleDialog {
} else if (geo != null && geo.getCoords() != null) {
this.gp = geo.getCoords();
} else {
- this.gp = new Geopoint(0.0, 0.0);
+ this.gp = Geopoint.ZERO;
}
}
@@ -396,7 +396,7 @@ public class CoordinatesInputDialog extends NoTitleDialog {
if (geo != null && geo.getCoords() != null) {
gp = geo.getCoords();
} else {
- gp = new Geopoint(0.0, 0.0);
+ gp = Geopoint.ZERO;
}
}
}
diff --git a/main/src/cgeo/geocaching/ui/dialog/Dialogs.java b/main/src/cgeo/geocaching/ui/dialog/Dialogs.java
index 865ba70..cbd5c94 100644
--- a/main/src/cgeo/geocaching/ui/dialog/Dialogs.java
+++ b/main/src/cgeo/geocaching/ui/dialog/Dialogs.java
@@ -1,11 +1,12 @@
package cgeo.geocaching.ui.dialog;
import cgeo.geocaching.CgeoApplication;
-import cgeo.geocaching.utils.RunnableWithArgument;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.Nullable;
+import rx.util.functions.Action1;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
@@ -298,7 +299,7 @@ public final class Dialogs {
/**
* Show a message dialog for input from the user. The okay button is only enabled on non empty input.
- *
+ *
* @param context
* activity owning the dialog
* @param title
@@ -310,7 +311,7 @@ public final class Dialogs {
* @param okayListener
* listener to be run on okay
*/
- public static void input(final Activity context, final int title, final String defaultValue, final int buttonTitle, final RunnableWithArgument<String> okayListener) {
+ public static void input(final Activity context, final int title, final String defaultValue, final int buttonTitle, final Action1<String> okayListener) {
final EditText input = new EditText(context);
input.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_CLASS_TEXT);
input.setText(defaultValue);
@@ -322,7 +323,7 @@ public final class Dialogs {
@Override
public void onClick(DialogInterface dialog, int which) {
- okayListener.run(input.getText().toString());
+ okayListener.call(input.getText().toString());
}
});
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@@ -357,8 +358,16 @@ public final class Dialogs {
dialog.show();
enableDialogButtonIfNotEmpty(dialog, defaultValue);
- // position cursor after text
- input.setSelection(input.getText().length());
+ moveCursorToEnd(input);
+ }
+
+ /**
+ * Move the cursor to the end of the input field.
+ *
+ * @param input
+ */
+ public static void moveCursorToEnd(final EditText input) {
+ input.setSelection(input.getText().length(), input.getText().length());
}
private static void enableDialogButtonIfNotEmpty(final AlertDialog dialog, final String input) {
diff --git a/main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java b/main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java
index 6ad59ec..c29f549 100644
--- a/main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java
+++ b/main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java
@@ -1,15 +1,14 @@
package cgeo.geocaching.ui.dialog;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
import cgeo.geocaching.settings.Settings;
-import cgeo.geocaching.CgeoApplication;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.view.ContextThemeWrapper;
import android.view.View;
-import android.widget.CheckBox;
public class LiveMapInfoDialogBuilder {
@@ -20,12 +19,7 @@ public class LiveMapInfoDialogBuilder {
final View layout = View.inflate(new ContextThemeWrapper(activity, R.style.dark), R.layout.livemapinfo, null);
builder.setView(layout);
- final CheckBox checkBoxHide = (CheckBox) layout.findViewById(R.id.live_map_hint_hide);
-
final int showCount = Settings.getLiveMapHintShowCount();
- if (showCount > 2) {
- checkBoxHide.setVisibility(View.VISIBLE);
- }
Settings.setLiveMapHintShowCount(showCount + 1);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@@ -33,10 +27,7 @@ public class LiveMapInfoDialogBuilder {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
- CgeoApplication.getInstance().setLiveMapHintShown();
- if (checkBoxHide.getVisibility() == View.VISIBLE && checkBoxHide.isChecked()) {
- Settings.setHideLiveHint(true);
- }
+ CgeoApplication.getInstance().setLiveMapHintShownInThisSession();
}
});
return builder.create();
diff --git a/main/src/cgeo/geocaching/utils/CancellableHandler.java b/main/src/cgeo/geocaching/utils/CancellableHandler.java
index cb4b9db..01fb568 100644
--- a/main/src/cgeo/geocaching/utils/CancellableHandler.java
+++ b/main/src/cgeo/geocaching/utils/CancellableHandler.java
@@ -2,6 +2,9 @@ package cgeo.geocaching.utils;
import cgeo.geocaching.CgeoApplication;
+import rx.Subscription;
+import rx.subscriptions.CompositeSubscription;
+
import android.os.Handler;
import android.os.Message;
@@ -13,6 +16,7 @@ public abstract class CancellableHandler extends Handler {
protected static final int UPDATE_LOAD_PROGRESS_DETAIL = 42186;
private volatile boolean cancelled = false;
+ private static CompositeSubscription subscriptions = new CompositeSubscription();
private static class CancelHolder {
final Object payload;
@@ -30,6 +34,7 @@ public abstract class CancellableHandler extends Handler {
if (message.obj instanceof CancelHolder) {
cancelled = true;
+ subscriptions.unsubscribe();
handleCancel(((CancelHolder) message.obj).payload);
} else {
handleRegularMessage(message);
@@ -37,6 +42,17 @@ public abstract class CancellableHandler extends Handler {
}
/**
+ * Add a subscription to the list of subscriptions to be subscribed at cancellation time.
+ */
+ final public void unsubscribeIfCancelled(final Subscription subscription) {
+ subscriptions.add(subscription);
+ if (cancelled) {
+ // Protect against race conditions
+ subscriptions.unsubscribe();
+ }
+ }
+
+ /**
* Handle a non-cancel message.<br>
* Subclasses must implement this to handle messages.
*
diff --git a/main/src/cgeo/geocaching/utils/GeoDirHandler.java b/main/src/cgeo/geocaching/utils/GeoDirHandler.java
index c85648b..e55aede 100644
--- a/main/src/cgeo/geocaching/utils/GeoDirHandler.java
+++ b/main/src/cgeo/geocaching/utils/GeoDirHandler.java
@@ -4,12 +4,15 @@ import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.IGeoData;
import cgeo.geocaching.settings.Settings;
-import android.os.Handler;
-import android.os.Message;
+import rx.Observable;
+import rx.Subscription;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.util.functions.Action1;
+
+import java.util.concurrent.TimeUnit;
/**
- * GeoData and Direction handler. Manipulating geodata and direction information
- * through a GeoDirHandler ensures that all listeners are registered from a {@link android.os.Looper} thread.
+ * GeoData and Direction handler.
* <p>
* To use this class, override at least one of {@link #updateDirection(float)} or {@link #updateGeoData(IGeoData)}. You
* need to start the handler using one of
@@ -21,47 +24,11 @@ import android.os.Message;
* A good place might be the {@code onResume} method of the Activity. Stop the Handler accordingly in {@code onPause}.
* </p>
*/
-public abstract class GeoDirHandler extends Handler implements IObserver<Object> {
-
- private static final int OBSERVABLE = 1 << 1;
- private static final int START_GEO = 1 << 2;
- private static final int START_DIR = 1 << 3;
- private static final int STOP_GEO = 1 << 4;
- private static final int STOP_DIR = 1 << 5;
-
+public abstract class GeoDirHandler {
private static final CgeoApplication app = CgeoApplication.getInstance();
- @Override
- final public void handleMessage(final Message message) {
- if ((message.what & START_GEO) != 0) {
- app.addGeoObserver(this);
- }
-
- if ((message.what & START_DIR) != 0) {
- app.addDirectionObserver(this);
- }
-
- if ((message.what & STOP_GEO) != 0) {
- app.deleteGeoObserver(this);
- }
-
- if ((message.what & STOP_DIR) != 0) {
- app.deleteDirectionObserver(this);
- }
-
- if ((message.what & OBSERVABLE) != 0) {
- if (message.obj instanceof IGeoData) {
- updateGeoData((IGeoData) message.obj);
- } else {
- updateDirection((Float) message.obj);
- }
- }
- }
-
- @Override
- final public void update(final Object o) {
- obtainMessage(OBSERVABLE, o).sendToTarget();
- }
+ private Subscription dirSubscription = null;
+ private Subscription geoSubscription = null;
/**
* Update method called when new IGeoData is available.
@@ -69,7 +36,7 @@ public abstract class GeoDirHandler extends Handler implements IObserver<Object>
* @param data
* the new data
*/
- protected void updateGeoData(final IGeoData data) {
+ public void updateGeoData(final IGeoData data) {
// Override this in children
}
@@ -79,24 +46,38 @@ public abstract class GeoDirHandler extends Handler implements IObserver<Object>
* @param direction
* the new direction
*/
- protected void updateDirection(final float direction) {
+ public void updateDirection(final float direction) {
// Override this in children
}
/**
* Register the current GeoDirHandler for GeoData information.
*/
- public void startGeo() {
- sendEmptyMessage(START_GEO);
+ public synchronized void startGeo() {
+ geoSubscription = app.currentGeoObject()
+ .subscribeOn(AndroidSchedulers.mainThread())
+ .subscribe(new Action1<IGeoData>() {
+ @Override
+ public void call(final IGeoData geoData) {
+ updateGeoData(geoData);
+ }
+ });
}
/**
* Register the current GeoDirHandler for direction information if the preferences
* allow it.
*/
- public void startDir() {
+ public synchronized void startDir() {
if (Settings.isUseCompass()) {
- sendEmptyMessage(START_DIR);
+ dirSubscription = app.currentDirObject()
+ .subscribeOn(AndroidSchedulers.mainThread())
+ .subscribe(new Action1<Float>() {
+ @Override
+ public void call(final Float direction) {
+ updateDirection(direction);
+ }
+ });
}
}
@@ -105,27 +86,43 @@ public abstract class GeoDirHandler extends Handler implements IObserver<Object>
* preferences allow it).
*/
public void startGeoAndDir() {
- sendEmptyMessage(START_GEO | (Settings.isUseCompass() ? START_DIR : 0));
+ startGeo();
+ startDir();
}
/**
* Unregister the current GeoDirHandler for GeoData information.
*/
- public void stopGeo() {
- sendEmptyMessage(STOP_GEO);
+ public synchronized void stopGeo() {
+ // Delay the unsubscription by 2.5 seconds, so that another activity has
+ // the time to subscribe and the GPS receiver will not be turned down.
+ if (geoSubscription != null) {
+ final Subscription subscription = geoSubscription;
+ geoSubscription = null;
+ Observable.interval(2500, TimeUnit.MILLISECONDS).take(1).subscribe(new Action1<Long>() {
+ @Override
+ public void call(final Long aLong) {
+ subscription.unsubscribe();
+ }
+ });
+ }
}
/**
* Unregister the current GeoDirHandler for direction information.
*/
- public void stopDir() {
- sendEmptyMessage(STOP_DIR);
+ public synchronized void stopDir() {
+ if (dirSubscription != null) {
+ dirSubscription.unsubscribe();
+ dirSubscription = null;
+ }
}
/**
* Unregister the current GeoDirHandler for GeoData and direction information.
*/
public void stopGeoAndDir() {
- sendEmptyMessage(STOP_GEO | STOP_DIR);
+ stopGeo();
+ stopDir();
}
}
diff --git a/main/src/cgeo/geocaching/utils/IObserver.java b/main/src/cgeo/geocaching/utils/IObserver.java
deleted file mode 100644
index bfcc798..0000000
--- a/main/src/cgeo/geocaching/utils/IObserver.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package cgeo.geocaching.utils;
-
-/**
- * Observer interface.
- * <p/>
- * An observer will receive updates about the observed object (implementing the {@link ISubject} interface) through its
- * {@link #update(Object)} method.
- *
- * @param <T>
- * the kind of data to observe
- */
-public interface IObserver<T> {
-
- /**
- * Called when an observed object has updated its data.
- *
- * @param data
- * the updated data
- */
- void update(final T data);
-
-}
diff --git a/main/src/cgeo/geocaching/utils/ISubject.java b/main/src/cgeo/geocaching/utils/ISubject.java
deleted file mode 100644
index c325db0..0000000
--- a/main/src/cgeo/geocaching/utils/ISubject.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package cgeo.geocaching.utils;
-
-/**
- * Interface for subjects objects. Those can be observed by objects implementing the {@link IObserver} interface.
- *
- * @param <T>
- * the kind of data to observe
- */
-
-public interface ISubject<T> {
-
- /**
- * Add an observer to the observers list.
- * <p/>
- * Observers will be notified with no particular order.
- *
- * @param observer
- * the observer to add
- * @return true if the observer has been added, false if it was present already
- */
- public boolean addObserver(final IObserver<? super T> observer);
-
- /**
- * Delete an observer from the observers list.
- *
- * @param observer
- * the observer to remove
- * @return true if the observer has been removed, false if it was not in the list of observers
- */
- public boolean deleteObserver(final IObserver<? super T> observer);
-
- /**
- * Number of observers currently observing the object.
- *
- * @return the number of observers
- */
- public int sizeObservers();
-
- /**
- * Notify all the observers that new data is available.
- * <p/>
- * The {@link IObserver#update(Object)} method of each observer will be called with no particular order.
- *
- * @param data
- * the updated data
- * @return true if at least one observer was notified, false if there were no observers
- */
- public boolean notifyObservers(final T data);
-
- /**
- * Clear the observers list.
- *
- * @return true if there were observers before calling this method, false if the observers list was empty
- */
- public boolean clearObservers();
-
-}
diff --git a/main/src/cgeo/geocaching/utils/ImageUtils.java b/main/src/cgeo/geocaching/utils/ImageUtils.java
index 73f322c..9f47ead 100644
--- a/main/src/cgeo/geocaching/utils/ImageUtils.java
+++ b/main/src/cgeo/geocaching/utils/ImageUtils.java
@@ -78,7 +78,7 @@ public final class ImageUtils {
* @return BitmapDrawable The scaled image
*/
@NonNull
- public static BitmapDrawable scaleBitmapTo(@NonNull final Bitmap image, final int maxWidth, final int maxHeight) {
+ private static BitmapDrawable scaleBitmapTo(@NonNull final Bitmap image, final int maxWidth, final int maxHeight) {
final CgeoApplication app = CgeoApplication.getInstance();
Bitmap result = image;
int width = image.getWidth();
diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
index 708dff0..259e94a 100644
--- a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
+++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
@@ -1,5 +1,7 @@
package cgeo.geocaching.utils;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
@@ -42,6 +44,7 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E>
*
* @see HashSet
*/
+ @NonNull
@Override
public Iterator<E> iterator() {
return map.keySet().iterator();
diff --git a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java
index 76fa0f7..5fa0982 100644
--- a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java
+++ b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java
@@ -47,10 +47,6 @@ public final class LogTemplateProvider {
this.logEntry = logEntry;
}
- public LogContext(final boolean offline) {
- this(null, null, offline);
- }
-
public LogContext(final Geocache cache, LogEntry logEntry, final boolean offline) {
this.cache = cache;
this.offline = offline;
diff --git a/main/src/cgeo/geocaching/utils/MemorySubject.java b/main/src/cgeo/geocaching/utils/MemorySubject.java
deleted file mode 100644
index c424528..0000000
--- a/main/src/cgeo/geocaching/utils/MemorySubject.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package cgeo.geocaching.utils;
-
-/**
- * Synchronized implementation of the {@link ISubject} interface with an added pull interface.
- *
- * @param <T>
- * the kind of data to observe
- */
-public class MemorySubject<T> extends Subject<T> {
-
- /**
- * The latest version of the observed data.
- * <p/>
- * A child class implementation may want to set this field from its constructors, in case early observers request
- * the data before it got a chance to get updated. Otherwise, <code>null</code> will be returned until updated
- * data is available.
- */
- private T memory;
-
- @Override
- public synchronized boolean addObserver(final IObserver<? super T> observer) {
- final boolean added = super.addObserver(observer);
- if (added && memory != null) {
- observer.update(memory);
- }
- return added;
- }
-
- @Override
- public synchronized boolean notifyObservers(final T data) {
- memory = data;
- return super.notifyObservers(data);
- }
-
- /**
- * Get the memorized version of the data.
- *
- * @return the initial data set by the subject (which may be <code>null</code>),
- * or the updated data if it is available
- */
- public synchronized T getMemory() {
- return memory;
- }
-
-}
diff --git a/main/src/cgeo/geocaching/utils/RunnableWithArgument.java b/main/src/cgeo/geocaching/utils/RunnableWithArgument.java
deleted file mode 100644
index 6137efd..0000000
--- a/main/src/cgeo/geocaching/utils/RunnableWithArgument.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package cgeo.geocaching.utils;
-
-public interface RunnableWithArgument<T> {
-
- abstract void run(final T argument);
-
-}
diff --git a/main/src/cgeo/geocaching/utils/Subject.java b/main/src/cgeo/geocaching/utils/Subject.java
deleted file mode 100644
index b1754cc..0000000
--- a/main/src/cgeo/geocaching/utils/Subject.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package cgeo.geocaching.utils;
-
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-/**
- * Synchronized implementation of the {@link ISubject} interface.
- *
- * @param <T>
- * the kind of data to observe
- */
-public class Subject<T> implements ISubject<T> {
-
- /**
- * Collection of observers.
- */
- protected final Set<IObserver<? super T>> observers = new LinkedHashSet<IObserver<? super T>>();
-
- @Override
- public synchronized boolean addObserver(final IObserver<? super T> observer) {
- final boolean added = observers.add(observer);
- if (added && observers.size() == 1) {
- onFirstObserver();
- }
- return added;
- }
-
- @Override
- public synchronized boolean deleteObserver(final IObserver<? super T> observer) {
- final boolean removed = observers.remove(observer);
- if (removed && observers.isEmpty()) {
- onLastObserver();
- }
- return removed;
- }
-
- @Override
- public synchronized boolean notifyObservers(final T arg) {
- final boolean nonEmpty = !observers.isEmpty();
- for (final IObserver<? super T> observer : observers) {
- observer.update(arg);
- }
- return nonEmpty;
- }
-
- @Override
- public synchronized int sizeObservers() {
- return observers.size();
- }
-
- @Override
- public synchronized boolean clearObservers() {
- final boolean nonEmpty = !observers.isEmpty();
- for (final IObserver<? super T> observer : observers) {
- deleteObserver(observer);
- }
- return nonEmpty;
- }
-
- /**
- * Method called when the collection of observers goes from empty to non-empty.
- * <p/>
- * The default implementation does nothing and may be overwritten by child classes.
- */
- protected void onFirstObserver() {
- }
-
- /**
- * Method called when the collection of observers goes from non-empty to empty.
- * <p/>
- * The default implementation does nothing and may be overwritten by child classes.
- */
- protected void onLastObserver() {
- }
-
-}
diff --git a/main/src/cgeo/geocaching/utils/SynchronizedDateFormat.java b/main/src/cgeo/geocaching/utils/SynchronizedDateFormat.java
index 2368469..7848d1a 100644
--- a/main/src/cgeo/geocaching/utils/SynchronizedDateFormat.java
+++ b/main/src/cgeo/geocaching/utils/SynchronizedDateFormat.java
@@ -4,6 +4,7 @@ import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
+import java.util.TimeZone;
public class SynchronizedDateFormat {
private final SimpleDateFormat format;
@@ -12,7 +13,17 @@ public class SynchronizedDateFormat {
format = new SimpleDateFormat(pattern, locale);
}
+ public SynchronizedDateFormat(String pattern, TimeZone timeZone, Locale locale) {
+ format = new SimpleDateFormat(pattern, locale);
+ format.setTimeZone(timeZone);
+ }
+
public synchronized Date parse(final String input) throws ParseException {
return format.parse(input);
}
+
+ public synchronized String format(final Date date) {
+ return format.format(date);
+ }
+
}
diff --git a/main/src/cgeo/geocaching/utils/TextUtils.java b/main/src/cgeo/geocaching/utils/TextUtils.java
index efbb2d7..c4e1128 100644
--- a/main/src/cgeo/geocaching/utils/TextUtils.java
+++ b/main/src/cgeo/geocaching/utils/TextUtils.java
@@ -4,7 +4,6 @@
package cgeo.geocaching.utils;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
import org.eclipse.jdt.annotation.Nullable;
import java.util.regex.Matcher;
diff --git a/main/thirdparty/android/support/v4/app/FragmentListActivity.java b/main/thirdparty/android/support/v4/app/FragmentListActivity.java
index e3ed42c..fa425ab 100644
--- a/main/thirdparty/android/support/v4/app/FragmentListActivity.java
+++ b/main/thirdparty/android/support/v4/app/FragmentListActivity.java
@@ -16,6 +16,8 @@
package android.support.v4.app;
+import org.eclipse.jdt.annotation.NonNull;
+
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
@@ -215,7 +217,7 @@ public class FragmentListActivity extends FragmentActivity {
*@see Activity#onRestoreInstanceState(Bundle)
*/
@Override
- protected void onRestoreInstanceState(Bundle state) {
+ protected void onRestoreInstanceState(@NonNull Bundle state) {
ensureList();
super.onRestoreInstanceState(state);
}
diff --git a/main/thirdparty/com/viewpagerindicator/TitlePageIndicator.java b/main/thirdparty/com/viewpagerindicator/TitlePageIndicator.java
index 94ac962..0f922c5 100644
--- a/main/thirdparty/com/viewpagerindicator/TitlePageIndicator.java
+++ b/main/thirdparty/com/viewpagerindicator/TitlePageIndicator.java
@@ -19,6 +19,8 @@ package com.viewpagerindicator;
import cgeo.geocaching.R;
+import org.eclipse.jdt.annotation.NonNull;
+
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -445,7 +447,7 @@ public class TitlePageIndicator extends View implements PageIndicator {
}
@Override
- public boolean onTouchEvent(android.view.MotionEvent ev) {
+ public boolean onTouchEvent(@NonNull android.view.MotionEvent ev) {
if ((mViewPager == null) || (mViewPager.getAdapter().getCount() == 0)) {
return false;
}
@@ -751,7 +753,7 @@ public class TitlePageIndicator extends View implements PageIndicator {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(currentPage);
}
diff --git a/tests/.settings/org.eclipse.jdt.core.prefs b/tests/.settings/org.eclipse.jdt.core.prefs
index 5385520..6ba1bbd 100644
--- a/tests/.settings/org.eclipse.jdt.core.prefs
+++ b/tests/.settings/org.eclipse.jdt.core.prefs
@@ -1,9 +1,10 @@
eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=enabled
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
-org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
@@ -11,7 +12,7 @@ org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
-org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=ignore
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
@@ -20,13 +21,13 @@ org.eclipse.jdt.core.compiler.problem.deprecation=warning
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
-org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
-org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=ignore
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
@@ -47,37 +48,39 @@ org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warni
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
-org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.nullReference=error
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
org.eclipse.jdt.core.compiler.problem.parameterAssignment=warning
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
-org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=error
org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
-org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning
-org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=warning
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=warning
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=enabled
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
-org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
-org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=ignore
org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning
-org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
@@ -90,6 +93,7 @@ org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.source=1.6
diff --git a/tests/libs/org.eclipse.jdt.annotation_1.1.0.v20130513-1648.jar b/tests/libs/org.eclipse.jdt.annotation_1.1.0.v20130513-1648.jar
new file mode 100644
index 0000000..daca164
--- /dev/null
+++ b/tests/libs/org.eclipse.jdt.annotation_1.1.0.v20130513-1648.jar
Binary files differ
diff --git a/tests/src/cgeo/geocaching/CgeoApplicationTest.java b/tests/src/cgeo/geocaching/CgeoApplicationTest.java
index b9c03a4..cd80889 100644
--- a/tests/src/cgeo/geocaching/CgeoApplicationTest.java
+++ b/tests/src/cgeo/geocaching/CgeoApplicationTest.java
@@ -114,7 +114,7 @@ public class CgeoApplicationTest extends CGeoTestCase {
public static Geocache testSearchByGeocode(final String geocode) {
final SearchResult search = Geocache.searchByGeocode(geocode, null, 0, true, null);
assertNotNull(search);
- if (Settings.isPremiumMember() || search.getError() == null) {
+ if (Settings.isGCPremiumMember() || search.getError() == null) {
assertEquals(1, search.getGeocodes().size());
assertTrue(search.getGeocodes().contains(geocode));
return DataStore.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB);
@@ -140,14 +140,14 @@ public class CgeoApplicationTest extends CGeoTestCase {
*/
private static void withMockedLoginDo(final Runnable runnable) {
final ImmutablePair<String, String> login = Settings.getGcCredentials();
- final String memberStatus = Settings.getMemberStatus();
+ final String memberStatus = Settings.getGCMemberStatus();
try {
runnable.run();
} finally {
// restore user and password
TestSettings.setLogin(login.left, login.right);
- Settings.setMemberStatus(memberStatus);
+ Settings.setGCMemberStatus(memberStatus);
GCLogin.getInstance().login();
}
}
@@ -171,6 +171,8 @@ public class CgeoApplicationTest extends CGeoTestCase {
assertTrue(search.getGeocodes().contains(cache.getGeocode()));
final Geocache searchedCache = search.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB);
// coords must be null if the user is not logged in
+ assertNotNull(searchedCache);
+ assert (searchedCache != null); // eclipse bug
assertNull(searchedCache.getCoords());
// premium cache. Not visible to guests
@@ -305,25 +307,25 @@ public class CgeoApplicationTest extends CGeoTestCase {
// check coords for DETAILED
Settings.setLiveMapStrategy(Strategy.DETAILED);
- SearchResult search = ConnectorFactory.searchByViewport(viewport, tokens);
+ SearchResult search = ConnectorFactory.searchByViewport(viewport, tokens).toBlockingObservable().single();
assertNotNull(search);
assertTrue(search.getGeocodes().contains(mockedCache.getGeocode()));
Geocache parsedCache = DataStore.loadCache(mockedCache.getGeocode(), LoadFlags.LOAD_CACHE_OR_DB);
- assertEquals(Settings.isPremiumMember(), mockedCache.getCoords().equals(parsedCache.getCoords()));
- assertEquals(Settings.isPremiumMember(), parsedCache.isReliableLatLon());
+ assertEquals(Settings.isGCPremiumMember(), mockedCache.getCoords().equals(parsedCache.getCoords()));
+ assertEquals(Settings.isGCPremiumMember(), parsedCache.isReliableLatLon());
// check update after switch strategy to FAST
Settings.setLiveMapStrategy(Strategy.FAST);
Tile.Cache.removeFromTileCache(mockedCache);
- search = ConnectorFactory.searchByViewport(viewport, tokens);
+ search = ConnectorFactory.searchByViewport(viewport, tokens).toBlockingObservable().single();
assertNotNull(search);
assertTrue(search.getGeocodes().contains(mockedCache.getGeocode()));
parsedCache = DataStore.loadCache(mockedCache.getGeocode(), LoadFlags.LOAD_CACHE_OR_DB);
- assertEquals(Settings.isPremiumMember(), mockedCache.getCoords().equals(parsedCache.getCoords()));
- assertEquals(Settings.isPremiumMember(), parsedCache.isReliableLatLon());
+ assertEquals(Settings.isGCPremiumMember(), mockedCache.getCoords().equals(parsedCache.getCoords()));
+ assertEquals(Settings.isGCPremiumMember(), parsedCache.isReliableLatLon());
} finally {
// restore user settings
@@ -356,7 +358,7 @@ public class CgeoApplicationTest extends CGeoTestCase {
Settings.setCacheType(CacheType.ALL);
Viewport viewport = new Viewport(cache, 0.003, 0.003);
- SearchResult search = ConnectorFactory.searchByViewport(viewport, INVALID_TOKEN);
+ SearchResult search = ConnectorFactory.searchByViewport(viewport, INVALID_TOKEN).toBlockingObservable().single();
assertNotNull(search);
assertTrue(search.getGeocodes().contains(cache.getGeocode()));
@@ -364,7 +366,7 @@ public class CgeoApplicationTest extends CGeoTestCase {
final Geocache cacheFromViewport = DataStore.loadCache(cache.getGeocode(), LoadFlags.LOAD_CACHE_OR_DB);
Log.d("cgeoApplicationTest.testSearchByViewportNotLoggedIn: Coords expected = " + cache.getCoords());
Log.d("cgeoApplicationTest.testSearchByViewportNotLoggedIn: Coords actual = " + cacheFromViewport.getCoords());
- assertFalse(cache.getCoords().isEqualTo(cacheFromViewport.getCoords(), 1e-3));
+ assertFalse(cache.getCoords().distanceTo(cacheFromViewport.getCoords()) <= 1e-3);
// depending on the chosen strategy the coords can be reliable or not
assertEquals(testStrategy == Strategy.DETAILED, cacheFromViewport.isReliableLatLon());
@@ -373,7 +375,7 @@ public class CgeoApplicationTest extends CGeoTestCase {
deleteCacheFromDBAndLogout(cache.getGeocode());
viewport = new Viewport(cache, 0.003, 0.003);
- search = ConnectorFactory.searchByViewport(viewport, INVALID_TOKEN);
+ search = ConnectorFactory.searchByViewport(viewport, INVALID_TOKEN).toBlockingObservable().single();
assertNotNull(search);
// depending on the chosen strategy the cache is part of the search or not
@@ -423,7 +425,7 @@ public class CgeoApplicationTest extends CGeoTestCase {
GCLogin.getInstance().logout();
// Modify login data to avoid an automatic login again
TestSettings.setLogin("c:geo", "c:geo");
- Settings.setMemberStatus("Basic member");
+ Settings.setGCMemberStatus("Basic member");
}
}
diff --git a/tests/src/cgeo/geocaching/GeocacheTest.java b/tests/src/cgeo/geocaching/GeocacheTest.java
index cdca9b7..b49048b 100644
--- a/tests/src/cgeo/geocaching/GeocacheTest.java
+++ b/tests/src/cgeo/geocaching/GeocacheTest.java
@@ -249,6 +249,14 @@ public class GeocacheTest extends CGeoTestCase {
assertTime("from 11 to 13 " + timeHours, 11, 00);
}
+ public static void testGuessEventTimeShortDescription() {
+ Geocache cache = new Geocache();
+ cache.setType(CacheType.EVENT);
+ cache.setDescription(StringUtils.EMPTY);
+ cache.setShortDescription("text 14:20 text");
+ assertEquals(String.valueOf(14 * 60 + 20), cache.guessEventTimeMinutes());
+ }
+
private static void assertTime(final String description, final int hours, final int minutes) {
final Geocache cache = new Geocache();
cache.setDescription(description);
diff --git a/tests/src/cgeo/geocaching/SettingsTest.java b/tests/src/cgeo/geocaching/SettingsTest.java
index c58db08..90a0209 100644
--- a/tests/src/cgeo/geocaching/SettingsTest.java
+++ b/tests/src/cgeo/geocaching/SettingsTest.java
@@ -27,7 +27,7 @@ public class SettingsTest extends ActivityInstrumentationTestCase2<MainActivity>
public static void testSettings() {
// unfortunately, several other tests depend on being a premium member and will fail if run by a basic member
- assertEquals(GCConstants.MEMBER_STATUS_PM, Settings.getMemberStatus());
+ assertEquals(GCConstants.MEMBER_STATUS_PM, Settings.getGCMemberStatus());
}
public static void testDeviceHasNormalLogin() {
diff --git a/tests/src/cgeo/geocaching/connector/ConnectorFactoryTest.java b/tests/src/cgeo/geocaching/connector/ConnectorFactoryTest.java
index e41e316..725f718 100644
--- a/tests/src/cgeo/geocaching/connector/ConnectorFactoryTest.java
+++ b/tests/src/cgeo/geocaching/connector/ConnectorFactoryTest.java
@@ -63,8 +63,32 @@ public class ConnectorFactoryTest extends AbstractResourceInstrumentationTestCas
public static void testGetGeocodeFromUrl() {
assertEquals("GC34PLO", ConnectorFactory.getGeocodeFromURL("http://coord.info/GC34PLO"));
+ assertEquals("GC34PLO", ConnectorFactory.getGeocodeFromURL("http://www.coord.info/GC34PLO"));
assertEquals("OX1234", ConnectorFactory.getGeocodeFromURL("http://www.opencaching.com/#!geocache/OX1234"));
+
+ assertEquals("GC12ABC", GCConnector.getInstance().getGeocodeFromUrl("http://coord.info/GC12ABC"));
+ assertEquals("GC12ABC", GCConnector.getInstance().getGeocodeFromUrl("http://www.coord.info/GC12ABC"));
+ assertEquals("GC12ABC", GCConnector.getInstance().getGeocodeFromUrl("http://www.geocaching.com/geocache/GC12ABC_die-muhlen-im-schondratal-muhle-munchau"));
+ assertEquals("GC12ABC", GCConnector.getInstance().getGeocodeFromUrl("http://geocaching.com/geocache/GC12ABC_die-muhlen-im-schondratal-muhle-munchau"));
+
+ // trackable URLs
+ assertNull(GCConnector.getInstance().getGeocodeFromUrl("http://coord.info/TB1234"));
+ assertNull(GCConnector.getInstance().getGeocodeFromUrl("http://www.coord.info/TB1234"));
+
// make sure that a mixture of different connector and geocode is recognized as invalid
assertNull(ConnectorFactory.getGeocodeFromURL("http://www.opencaching.com/#!geocache/" + "GC12345"));
}
+
+ public static void testGetTrackableFromURL() throws Exception {
+ assertEquals("GK78FA", ConnectorFactory.getTrackableFromURL("http://www.geokrety.org/konkret.php?id=30970"));
+ assertEquals("GK78FA", ConnectorFactory.getTrackableFromURL("http://geokrety.org/konkret.php?id=30970"));
+ assertEquals("TB1234", ConnectorFactory.getTrackableFromURL("http://coord.info/TB1234"));
+ assertEquals("TB1234", ConnectorFactory.getTrackableFromURL("http://www.coord.info/TB1234"));
+ assertEquals("TB1234", ConnectorFactory.getTrackableFromURL("http://geocaching.com/track/details.aspx?tracker=TB1234"));
+ assertEquals("TB1234", ConnectorFactory.getTrackableFromURL("http://www.geocaching.com/track/details.aspx?tracker=TB1234"));
+
+ // cache URLs
+ assertNull(ConnectorFactory.getTrackableFromURL("http://coord.info/GC1234"));
+ assertNull(ConnectorFactory.getTrackableFromURL("http://www.coord.info/GC1234"));
+ }
}
diff --git a/tests/src/cgeo/geocaching/connector/gc/GCConnectorTest.java b/tests/src/cgeo/geocaching/connector/gc/GCConnectorTest.java
index a5b9a44..47c3f6f 100644
--- a/tests/src/cgeo/geocaching/connector/gc/GCConnectorTest.java
+++ b/tests/src/cgeo/geocaching/connector/gc/GCConnectorTest.java
@@ -26,7 +26,7 @@ public class GCConnectorTest extends AbstractResourceInstrumentationTestCase {
{
final Viewport viewport = new Viewport(new Geopoint("N 52° 25.369 E 9° 35.499"), new Geopoint("N 52° 25.600 E 9° 36.200"));
- final SearchResult searchResult = ConnectorFactory.searchByViewport(viewport, tokens);
+ final SearchResult searchResult = ConnectorFactory.searchByViewport(viewport, tokens).toBlockingObservable().single();
assertNotNull(searchResult);
assertFalse(searchResult.isEmpty());
assertTrue(searchResult.getGeocodes().contains("GC4ER5H"));
@@ -35,7 +35,7 @@ public class GCConnectorTest extends AbstractResourceInstrumentationTestCase {
{
final Viewport viewport = new Viewport(new Geopoint("N 52° 24.000 E 9° 34.500"), new Geopoint("N 52° 26.000 E 9° 38.500"));
- final SearchResult searchResult = ConnectorFactory.searchByViewport(viewport, tokens);
+ final SearchResult searchResult = ConnectorFactory.searchByViewport(viewport, tokens).toBlockingObservable().single();
assertNotNull(searchResult);
assertTrue(searchResult.getGeocodes().contains("GC4ER5H"));
}
@@ -88,5 +88,11 @@ public class GCConnectorTest extends AbstractResourceInstrumentationTestCase {
public static void testGetGeocodeFromUrl() {
assertNull(GCConnector.getInstance().getGeocodeFromUrl("some string"));
assertEquals("GC12ABC", GCConnector.getInstance().getGeocodeFromUrl("http://coord.info/GC12ABC"));
+ assertEquals("GC12ABC", GCConnector.getInstance().getGeocodeFromUrl("http://www.coord.info/GC12ABC"));
+ assertEquals("GC12ABC", GCConnector.getInstance().getGeocodeFromUrl("http://www.geocaching.com/geocache/GC12ABC_die-muhlen-im-schondratal-muhle-munchau"));
+ assertEquals("GC12ABC", GCConnector.getInstance().getGeocodeFromUrl("http://geocaching.com/geocache/GC12ABC_die-muhlen-im-schondratal-muhle-munchau"));
+
+ assertNull(GCConnector.getInstance().getGeocodeFromUrl("http://coord.info/TB1234"));
+ assertNull(GCConnector.getInstance().getGeocodeFromUrl("http://www.coord.info/TB1234"));
}
}
diff --git a/tests/src/cgeo/geocaching/connector/gc/GCParserTest.java b/tests/src/cgeo/geocaching/connector/gc/GCParserTest.java
index 43b6d01..1509563 100644
--- a/tests/src/cgeo/geocaching/connector/gc/GCParserTest.java
+++ b/tests/src/cgeo/geocaching/connector/gc/GCParserTest.java
@@ -56,6 +56,8 @@ public class GCParserTest extends AbstractResourceInstrumentationTestCase {
assertNotNull(result);
assertEquals(1, result.getCount());
final Geocache cache = result.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB);
+ assertNotNull(cache);
+ assert (cache != null); // eclipse bug
assertEquals(cacheName, cache.getName());
}
@@ -158,6 +160,8 @@ public class GCParserTest extends AbstractResourceInstrumentationTestCase {
cache.drop(new Handler());
final String page = GCParser.requestHtmlPage(cache.getGeocode(), null, "n", "0");
final Geocache cache2 = GCParser.parseCacheFromText(page, null).getFirstCacheFromResult(LoadFlags.LOAD_CACHE_ONLY);
+ assertNotNull(cache2);
+ assert (cache2 != null); // eclipse bug
assertTrue(cache2.hasUserModifiedCoords());
assertEquals(new Geopoint("N51 21.544", "E07 02.566"), cache2.getCoords());
// delete coordinates
@@ -165,6 +169,8 @@ public class GCParserTest extends AbstractResourceInstrumentationTestCase {
cache2.drop(new Handler());
final String page2 = GCParser.requestHtmlPage(cache.getGeocode(), null, "n", "0");
final Geocache cache3 = GCParser.parseCacheFromText(page2, null).getFirstCacheFromResult(LoadFlags.LOAD_CACHE_ONLY);
+ assertNotNull(cache3);
+ assert (cache3 != null); // eclipse bug
assertFalse(cache3.hasUserModifiedCoords());
}
@@ -172,9 +178,10 @@ public class GCParserTest extends AbstractResourceInstrumentationTestCase {
cache.setPersonalNote(note);
cache.setWaypoints(new ArrayList<Waypoint>(), false);
cache.parseWaypointsFromNote();
- assertEquals(expected.length, cache.getWaypoints().size());
+ final List<Waypoint> waypoints = cache.getWaypoints();
+ assertEquals(expected.length, waypoints.size());
for (int i = 0; i < expected.length; i++) {
- assertTrue(expected[i].equals(cache.getWaypoint(i).getCoords()));
+ assertTrue(expected[i].equals(waypoints.get(i).getCoords()));
}
}
diff --git a/tests/src/cgeo/geocaching/connector/trackable/GeokretyConnectorTest.java b/tests/src/cgeo/geocaching/connector/trackable/GeokretyConnectorTest.java
index f08fb6b..d3633cb 100644
--- a/tests/src/cgeo/geocaching/connector/trackable/GeokretyConnectorTest.java
+++ b/tests/src/cgeo/geocaching/connector/trackable/GeokretyConnectorTest.java
@@ -11,4 +11,17 @@ public class GeokretyConnectorTest extends TestCase {
assertFalse(new GeokretyConnector().canHandleTrackable("UNKNOWN"));
}
+ public static void testGetTrackableCodeFromUrl() throws Exception {
+ assertEquals("GK78FA", new GeokretyConnector().getTrackableCodeFromUrl("http://www.geokrety.org/konkret.php?id=30970"));
+ assertEquals("GK78FA", new GeokretyConnector().getTrackableCodeFromUrl("http://geokrety.org/konkret.php?id=30970"));
+ }
+
+ public static void testGeocode() throws Exception {
+ assertEquals("GK97C1", GeokretyConnector.geocode(38849));
+ }
+
+ public static void testGetId() throws Exception {
+ assertEquals(38849, GeokretyConnector.getId("GK97C1"));
+ }
+
}
diff --git a/tests/src/cgeo/geocaching/connector/trackable/TravelBugConnectorTest.java b/tests/src/cgeo/geocaching/connector/trackable/TravelBugConnectorTest.java
index ef2821d..7e85b71 100644
--- a/tests/src/cgeo/geocaching/connector/trackable/TravelBugConnectorTest.java
+++ b/tests/src/cgeo/geocaching/connector/trackable/TravelBugConnectorTest.java
@@ -38,4 +38,15 @@ public class TravelBugConnectorTest extends TestCase {
private static TravelBugConnector getConnector() {
return TravelBugConnector.getInstance();
}
+
+ public static void testGetTrackableCodeFromUrl() throws Exception {
+ assertEquals("TB1234", TravelBugConnector.getInstance().getTrackableCodeFromUrl("http://coord.info/TB1234"));
+ assertEquals("TB1234", TravelBugConnector.getInstance().getTrackableCodeFromUrl("http://www.coord.info/TB1234"));
+ assertEquals("TB1234", TravelBugConnector.getInstance().getTrackableCodeFromUrl("http://geocaching.com/track/details.aspx?tracker=TB1234"));
+ assertEquals("TB1234", TravelBugConnector.getInstance().getTrackableCodeFromUrl("http://www.geocaching.com/track/details.aspx?tracker=TB1234"));
+
+ // do not match coord.info URLs of caches
+ assertNull(TravelBugConnector.getInstance().getTrackableCodeFromUrl("http://coord.info/GC1234"));
+ assertNull(TravelBugConnector.getInstance().getTrackableCodeFromUrl("http://www.coord.info/GC1234"));
+ }
}
diff --git a/tests/src/cgeo/geocaching/enumerations/CacheAttributeTest.java b/tests/src/cgeo/geocaching/enumerations/CacheAttributeTest.java
index 54db279..d126c0b 100644
--- a/tests/src/cgeo/geocaching/enumerations/CacheAttributeTest.java
+++ b/tests/src/cgeo/geocaching/enumerations/CacheAttributeTest.java
@@ -25,7 +25,7 @@ public class CacheAttributeTest extends AndroidTestCase {
public static void testGetL10n() {
final CacheAttribute attribute = CacheAttribute.HIKING;
- // This test is language dependend. It does not make sense to test it
+ // This test is language dependent. It does not make sense to test it
// with every attribute. We just want to know if getL10n works
// correctly
assertFalse("_yes and _no must not have the same translation",
@@ -37,7 +37,6 @@ public class CacheAttributeTest extends AndroidTestCase {
assertTrue("Test cannot be run with this attribute", attribute.gcid >= 0);
assertTrue("Test cannot be run with this attribute", attribute.ocacode >= 0);
assertSame(CacheAttribute.getByRawName(attribute.rawName), attribute);
- assertSame(CacheAttribute.getByGcId(attribute.gcid), attribute);
assertSame(CacheAttribute.getByOcACode(attribute.ocacode), attribute);
}
diff --git a/tests/src/cgeo/geocaching/enumerations/CacheSizeTest.java b/tests/src/cgeo/geocaching/enumerations/CacheSizeTest.java
index 2f11dfc..26a1953 100644
--- a/tests/src/cgeo/geocaching/enumerations/CacheSizeTest.java
+++ b/tests/src/cgeo/geocaching/enumerations/CacheSizeTest.java
@@ -30,8 +30,6 @@ public class CacheSizeTest extends AndroidTestCase {
public static void testGetByIdNumeric() {
assertEquals(CacheSize.REGULAR, CacheSize.getById("3"));
- assertEquals(CacheSize.UNKNOWN, CacheSize.getById("0"));
- assertEquals(CacheSize.UNKNOWN, CacheSize.getById("9"));
assertEquals(CacheSize.UNKNOWN, CacheSize.getById("-1"));
}
}
diff --git a/tests/src/cgeo/geocaching/enumerations/LogTypeTrackableTest.java b/tests/src/cgeo/geocaching/enumerations/LogTypeTrackableTest.java
index 667eefb..d6b7d33 100644
--- a/tests/src/cgeo/geocaching/enumerations/LogTypeTrackableTest.java
+++ b/tests/src/cgeo/geocaching/enumerations/LogTypeTrackableTest.java
@@ -1,11 +1,15 @@
package cgeo.geocaching.enumerations;
+import org.apache.commons.lang3.StringUtils;
+
import android.test.AndroidTestCase;
public class LogTypeTrackableTest extends AndroidTestCase {
public static void testFindById() {
- assertEquals(LogTypeTrackable.DO_NOTHING, LogTypeTrackable.findById(12345));
+ for (LogTypeTrackable logTypeTrackable : LogTypeTrackable.values()) {
+ assertTrue(StringUtils.isNotEmpty(logTypeTrackable.getLabel()));
+ }
}
}
diff --git a/tests/src/cgeo/geocaching/geopoint/GeoPointParserTest.java b/tests/src/cgeo/geocaching/geopoint/GeoPointParserTest.java
index 1de2e26..28dbe77 100644
--- a/tests/src/cgeo/geocaching/geopoint/GeoPointParserTest.java
+++ b/tests/src/cgeo/geocaching/geopoint/GeoPointParserTest.java
@@ -19,7 +19,13 @@ public class GeoPointParserTest extends AndroidTestCase {
public static void testFullCoordinates() {
final Geopoint goal = new Geopoint(refLatitude, refLongitude);
- assertTrue(goal.isEqualTo(GeopointParser.parse("N 49° 56.031 | E 8° 38.564"), 1e-6));
+ assertEquals(goal, GeopointParser.parse("N 49° 56.031 | E 8° 38.564"), 1e-6);
+ }
+
+ private static void assertEquals(final Geopoint expected, Geopoint actual, double tolerance) {
+ assertNotNull(expected);
+ assertNotNull(actual);
+ assertTrue(expected.distanceTo(actual) <= tolerance);
}
public static void testCoordinateMissingPart() {
@@ -48,18 +54,18 @@ public class GeoPointParserTest extends AndroidTestCase {
public static void testVariousFormats() {
final Geopoint goal1 = GeopointParser.parse("N 49° 43' 57\" | E 2 12' 35");
final Geopoint goal2 = GeopointParser.parse("N 49 43.95 E2°12.5833333333");
- assertTrue(goal1.isEqualTo(goal2, 1e-6));
+ assertEquals(goal1, goal2, 1e-6);
}
public static void testParseOurOwnSeparator() {
final Geopoint separator = GeopointParser.parse("N 49° 43' 57\"" + Formatter.SEPARATOR + "E 2 12' 35");
final Geopoint noSeparator = GeopointParser.parse("N 49 43.95 E2°12.5833333333");
- assertTrue(separator.isEqualTo(noSeparator, 1e-6));
+ assertEquals(separator, noSeparator, 1e-6);
}
public static void testInSentence() {
final Geopoint p1 = GeopointParser.parse("Station3: N51 21.523 / E07 02.680");
- final Geopoint p2 = GeopointParser.parse("N51 21.523", "E07 02.680");
+ final Geopoint p2 = GeopointParser.parse("N51 21.523 E07 02.680");
assertNotNull(p1);
assertNotNull(p2);
assertEquals(p1, p2);
@@ -106,6 +112,6 @@ public class GeoPointParserTest extends AndroidTestCase {
}
public static void testEquatorMeridian() {
- assertEquals(new Geopoint(0, 0), GeopointParser.parse("00° 00.000 00° 00.000"));
+ assertEquals(Geopoint.ZERO, GeopointParser.parse("00° 00.000 00° 00.000"));
}
}
diff --git a/tests/src/cgeo/geocaching/geopoint/ViewportTest.java b/tests/src/cgeo/geocaching/geopoint/ViewportTest.java
index 60766b4..11f78ad 100644
--- a/tests/src/cgeo/geocaching/geopoint/ViewportTest.java
+++ b/tests/src/cgeo/geocaching/geopoint/ViewportTest.java
@@ -2,6 +2,8 @@ package cgeo.geocaching.geopoint;
import cgeo.geocaching.ICoordinates;
+import org.eclipse.jdt.annotation.NonNull;
+
import android.test.AndroidTestCase;
import java.util.Collections;
@@ -11,7 +13,8 @@ import java.util.Set;
public class ViewportTest extends AndroidTestCase {
- final private static Viewport vpRef = new Viewport(new Geopoint(-1.0, -2.0), new Geopoint(3.0, 4.0));
+ final private static @NonNull
+ Viewport vpRef = new Viewport(new Geopoint(-1.0, -2.0), new Geopoint(3.0, 4.0));
public static void assertBounds(final Viewport vp) {
assertEquals(new Geopoint(1.0, 1.0), vp.center);
@@ -49,7 +52,7 @@ public class ViewportTest extends AndroidTestCase {
public static void testInViewport() {
assertFalse(vpRef.contains(new Geopoint(-2.0, -2.0)));
assertFalse(vpRef.contains(new Geopoint(4.0, 4.0)));
- assertTrue(vpRef.contains(new Geopoint(0.0, 0.0)));
+ assertTrue(vpRef.contains(Geopoint.ZERO));
assertTrue(vpRef.contains(new Geopoint(-1.0, -2.0)));
assertTrue(vpRef.contains(new Geopoint(3.0, 4.0)));
}
@@ -86,16 +89,6 @@ public class ViewportTest extends AndroidTestCase {
assertFalse(vpRef.includes(vpRef.resize(2.0)));
}
- public static void testExpands() {
- assertEquals(vpRef, vpRef.expand(new Geopoint(0, 0)));
- final Viewport vp1 = vpRef.expand(new Geopoint(-4.0, 0.0));
- assertEquals(new Geopoint(-4.0, -2.0), vp1.bottomLeft);
- assertEquals(new Geopoint(3.0, 4.0), vp1.topRight);
- final Viewport vp2 = vpRef.expand(new Geopoint(-10.0, 10.0));
- assertEquals(new Geopoint(-10.0, -2.0), vp2.bottomLeft);
- assertEquals(new Geopoint(3.0, 10.0), vp2.topRight);
- }
-
public static void testContaining() {
assertNull(Viewport.containing(Collections.singleton((ICoordinates) null)));
final Set<Geopoint> points = new HashSet<Geopoint>();
diff --git a/tests/src/cgeo/geocaching/network/OAuthTest.java b/tests/src/cgeo/geocaching/network/OAuthTest.java
index fa0104f..6888cec 100644
--- a/tests/src/cgeo/geocaching/network/OAuthTest.java
+++ b/tests/src/cgeo/geocaching/network/OAuthTest.java
@@ -1,5 +1,7 @@
package cgeo.geocaching.network;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.ArrayList;
import java.util.List;
@@ -26,7 +28,8 @@ public class OAuthTest extends TestCase {
public static void testUnreservedCharactersMustNotBeEncoded() {
for (Character c : UNRESERVED) {
- final String charAsString = String.valueOf(c);
+ final @NonNull
+ String charAsString = String.valueOf(c);
assertEquals("wrong OAuth encoding for " + c, charAsString, OAuth.percentEncode(charAsString));
}
}
@@ -35,7 +38,8 @@ public class OAuthTest extends TestCase {
for (int i = 32; i < 127; i++) {
final Character c = (char) i;
if (!UNRESERVED.contains(c)) {
- final String charAsString = String.valueOf(c);
+ final @NonNull
+ String charAsString = String.valueOf(c);
final String encoded = OAuth.percentEncode(charAsString);
assertFalse("Character '" + charAsString + "' not encoded", charAsString.equals(encoded));
assertTrue(encoded.startsWith("%"));
diff --git a/tests/src/cgeo/geocaching/sorting/DistanceComparatorTest.java b/tests/src/cgeo/geocaching/sorting/DistanceComparatorTest.java
index 2db3f59..0cfee49 100644
--- a/tests/src/cgeo/geocaching/sorting/DistanceComparatorTest.java
+++ b/tests/src/cgeo/geocaching/sorting/DistanceComparatorTest.java
@@ -20,7 +20,7 @@ public class DistanceComparatorTest extends AndroidTestCase {
}
caches.add(cache);
}
- Collections.sort(caches, new DistanceComparator(new Geopoint(0, 0), caches));
+ Collections.sort(caches, new DistanceComparator(Geopoint.ZERO, caches));
}
}
diff --git a/tests/src/cgeo/geocaching/utils/LogTemplateProviderTest.java b/tests/src/cgeo/geocaching/utils/LogTemplateProviderTest.java
index 5911218..249cbb1 100644
--- a/tests/src/cgeo/geocaching/utils/LogTemplateProviderTest.java
+++ b/tests/src/cgeo/geocaching/utils/LogTemplateProviderTest.java
@@ -10,11 +10,11 @@ public class LogTemplateProviderTest extends TestCase {
public static void testApplyTemplates() {
final String noTemplates = " no templates ";
- assertEquals(noTemplates, LogTemplateProvider.applyTemplates(noTemplates, new LogContext(true)));
+ assertEquals(noTemplates, LogTemplateProvider.applyTemplates(noTemplates, new LogContext(null, null, true)));
// This test can occasionally fail if the current year changes right after the next line.
final String currentYear = Integer.toString(Calendar.YEAR);
- assertTrue(LogTemplateProvider.applyTemplates("[DATE]", new LogContext(true)).contains(currentYear));
+ assertTrue(LogTemplateProvider.applyTemplates("[DATE]", new LogContext(null, null, true)).contains(currentYear));
}
}
diff --git a/tests/src/cgeo/geocaching/utils/MemorySubjectTest.java b/tests/src/cgeo/geocaching/utils/MemorySubjectTest.java
deleted file mode 100644
index ee46950..0000000
--- a/tests/src/cgeo/geocaching/utils/MemorySubjectTest.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package cgeo.geocaching.utils;
-
-import android.test.AndroidTestCase;
-
-public class MemorySubjectTest extends AndroidTestCase {
-
- private static class Observer implements IObserver<Integer> {
- private int times = 0;
- private Integer value;
-
- @Override
- public void update(final Integer data) {
- value = data;
- times++;
- }
- }
-
- private Observer observer;
- private MemorySubject<Integer> memorySubject;
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- observer = new Observer();
- memorySubject = new MemorySubject<Integer>();
- }
-
- public void testInitial() {
- assertNull(observer.value);
- assertEquals(0, observer.times);
- assertNull(memorySubject.getMemory());
- }
-
- public void testMemory() {
- memorySubject.addObserver(observer);
- memorySubject.notifyObservers(10);
- assertEquals(Integer.valueOf(10), observer.value);
- assertEquals(1, observer.times);
- assertEquals(Integer.valueOf(10), memorySubject.getMemory());
- memorySubject.notifyObservers(20);
- assertEquals(Integer.valueOf(20), observer.value);
- assertEquals(2, observer.times);
- assertEquals(Integer.valueOf(20), memorySubject.getMemory());
- }
-
- public void testAttach() {
- memorySubject.notifyObservers(10);
- assertNull(observer.value);
- assertEquals(0, observer.times);
- memorySubject.addObserver(observer);
- assertEquals(Integer.valueOf(10), observer.value);
- assertEquals(1, observer.times);
- memorySubject.notifyObservers(20);
- assertEquals(Integer.valueOf(20), observer.value);
- assertEquals(2, observer.times);
- }
-
- public void testDetach() {
- memorySubject.addObserver(observer);
- memorySubject.notifyObservers(10);
- assertEquals(Integer.valueOf(10), observer.value);
- assertEquals(1, observer.times);
- assertEquals(Integer.valueOf(10), memorySubject.getMemory());
- memorySubject.deleteObserver(observer);
- memorySubject.notifyObservers(20);
- assertEquals(Integer.valueOf(10), observer.value);
- assertEquals(1, observer.times);
- assertEquals(Integer.valueOf(20), memorySubject.getMemory());
- }
-
- public void testMultiple() {
- final Observer otherObserver = new Observer();
- memorySubject.addObserver(otherObserver);
- testDetach();
- assertEquals(Integer.valueOf(20), otherObserver.value);
- assertEquals(2, otherObserver.times);
- }
-
-}